aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services
diff options
context:
space:
mode:
Diffstat (limited to 'package/network/services')
-rw-r--r--package/network/services/dnsmasq/Makefile88
-rw-r--r--package/network/services/dnsmasq/files/dhcp.conf31
-rw-r--r--package/network/services/dnsmasq/files/dnsmasq.conf37
-rw-r--r--package/network/services/dnsmasq/files/dnsmasq.init529
-rw-r--r--package/network/services/dnsmasq/patches/0001-Set-prefix-on-link-bit-in-RAs.patch42
-rw-r--r--package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch49
-rw-r--r--package/network/services/dropbear/Makefile114
-rw-r--r--package/network/services/dropbear/files/dropbear.config5
-rwxr-xr-xpackage/network/services/dropbear/files/dropbear.init191
-rw-r--r--package/network/services/dropbear/patches/100-pubkey_path.patch91
-rw-r--r--package/network/services/dropbear/patches/110-change_user.patch18
-rw-r--r--package/network/services/dropbear/patches/120-openwrt_options.patch67
-rw-r--r--package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch21
-rw-r--r--package/network/services/dropbear/patches/140-disable_assert.patch14
-rw-r--r--package/network/services/dropbear/patches/150-dbconvert_standalone.patch14
-rw-r--r--package/network/services/dropbear/patches/200-lcrypt_bsdfix.patch29
-rw-r--r--package/network/services/dropbear/patches/300-ipv6_addr_port_split.patch11
-rw-r--r--package/network/services/dropbear/patches/400-CVE-2012-0920.patch91
-rw-r--r--package/network/services/dropbear/patches/500-set-default-path.patch11
-rw-r--r--package/network/services/ead/Makefile57
-rw-r--r--package/network/services/ead/src/Makefile33
-rw-r--r--package/network/services/ead/src/aes.c1061
-rw-r--r--package/network/services/ead/src/ead-client.c433
-rw-r--r--package/network/services/ead/src/ead-crypt.c179
-rw-r--r--package/network/services/ead/src/ead-crypt.h21
-rw-r--r--package/network/services/ead/src/ead-pcap.h71
-rw-r--r--package/network/services/ead/src/ead.c991
-rw-r--r--package/network/services/ead/src/ead.h139
-rw-r--r--package/network/services/ead/src/filter.c25
-rw-r--r--package/network/services/ead/src/libbridge.h84
-rw-r--r--package/network/services/ead/src/libbridge_init.c208
-rw-r--r--package/network/services/ead/src/libbridge_private.h35
-rw-r--r--package/network/services/ead/src/list.h602
-rw-r--r--package/network/services/ead/src/passwd3
-rw-r--r--package/network/services/ead/src/pfc.c54
-rw-r--r--package/network/services/ead/src/pw_encrypt_md5.c646
-rw-r--r--package/network/services/ead/src/sha1.c104
-rw-r--r--package/network/services/ead/src/tinysrp/Makefile.am28
-rw-r--r--package/network/services/ead/src/tinysrp/Makefile.in477
-rw-r--r--package/network/services/ead/src/tinysrp/Notes110
-rw-r--r--package/network/services/ead/src/tinysrp/acconfig.h9
-rw-r--r--package/network/services/ead/src/tinysrp/acinclude.m427
-rw-r--r--package/network/services/ead/src/tinysrp/aclocal.m4157
-rw-r--r--package/network/services/ead/src/tinysrp/bn.h471
-rw-r--r--package/network/services/ead/src/tinysrp/bn_add.c305
-rw-r--r--package/network/services/ead/src/tinysrp/bn_asm.c382
-rw-r--r--package/network/services/ead/src/tinysrp/bn_ctx.c142
-rw-r--r--package/network/services/ead/src/tinysrp/bn_div.c378
-rw-r--r--package/network/services/ead/src/tinysrp/bn_exp.c395
-rw-r--r--package/network/services/ead/src/tinysrp/bn_lcl.h419
-rw-r--r--package/network/services/ead/src/tinysrp/bn_lib.c576
-rw-r--r--package/network/services/ead/src/tinysrp/bn_mul.c176
-rw-r--r--package/network/services/ead/src/tinysrp/bn_prime.h325
-rw-r--r--package/network/services/ead/src/tinysrp/bn_shift.c139
-rw-r--r--package/network/services/ead/src/tinysrp/bn_sqr.c160
-rw-r--r--package/network/services/ead/src/tinysrp/bn_word.c130
-rw-r--r--package/network/services/ead/src/tinysrp/clitest.c112
-rw-r--r--package/network/services/ead/src/tinysrp/config.h.in79
-rwxr-xr-xpackage/network/services/ead/src/tinysrp/configure2421
-rw-r--r--package/network/services/ead/src/tinysrp/configure.in52
-rwxr-xr-xpackage/network/services/ead/src/tinysrp/install-sh250
-rwxr-xr-xpackage/network/services/ead/src/tinysrp/missing134
-rwxr-xr-xpackage/network/services/ead/src/tinysrp/mkinstalldirs39
-rw-r--r--package/network/services/ead/src/tinysrp/srvtest.c111
-rw-r--r--package/network/services/ead/src/tinysrp/stamp-h.in1
-rw-r--r--package/network/services/ead/src/tinysrp/t_client.c287
-rw-r--r--package/network/services/ead/src/tinysrp/t_client.h148
-rw-r--r--package/network/services/ead/src/tinysrp/t_conf.c1080
-rw-r--r--package/network/services/ead/src/tinysrp/t_conv.c226
-rw-r--r--package/network/services/ead/src/tinysrp/t_defines.h169
-rw-r--r--package/network/services/ead/src/tinysrp/t_getconf.c118
-rw-r--r--package/network/services/ead/src/tinysrp/t_getpass.c191
-rw-r--r--package/network/services/ead/src/tinysrp/t_math.c177
-rw-r--r--package/network/services/ead/src/tinysrp/t_misc.c338
-rw-r--r--package/network/services/ead/src/tinysrp/t_pw.c262
-rw-r--r--package/network/services/ead/src/tinysrp/t_pwd.h310
-rw-r--r--package/network/services/ead/src/tinysrp/t_read.c81
-rw-r--r--package/network/services/ead/src/tinysrp/t_read.h55
-rw-r--r--package/network/services/ead/src/tinysrp/t_server.c259
-rw-r--r--package/network/services/ead/src/tinysrp/t_server.h138
-rw-r--r--package/network/services/ead/src/tinysrp/t_sha.c166
-rw-r--r--package/network/services/ead/src/tinysrp/t_sha.h26
-rw-r--r--package/network/services/ead/src/tinysrp/t_truerand.c151
-rw-r--r--package/network/services/ead/src/tinysrp/tconf.c157
-rw-r--r--package/network/services/ead/src/tinysrp/tinysrp.c235
-rw-r--r--package/network/services/ead/src/tinysrp/tinysrp.h18
-rw-r--r--package/network/services/ead/src/tinysrp/tpasswd2
-rw-r--r--package/network/services/ead/src/tinysrp/tphrase.c348
-rw-r--r--package/network/services/hostapd/Config.in47
-rw-r--r--package/network/services/hostapd/Makefile342
-rw-r--r--package/network/services/hostapd/files/hostapd-full.config164
-rw-r--r--package/network/services/hostapd/files/hostapd-mini.config157
-rw-r--r--package/network/services/hostapd/files/hostapd.sh276
-rw-r--r--package/network/services/hostapd/files/multicall.c28
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant-full.config408
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant-mini.config406
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant.sh199
-rw-r--r--package/network/services/hostapd/files/wps-hotplug.sh6
-rw-r--r--package/network/services/hostapd/patches/100-pending_work.patch123
-rw-r--r--package/network/services/hostapd/patches/300-nl80211_multicall_fixes.patch60
-rw-r--r--package/network/services/hostapd/patches/310-multicall_bridge_fix.patch45
-rw-r--r--package/network/services/hostapd/patches/320-madwifi_key_fixes.patch34
-rw-r--r--package/network/services/hostapd/patches/400-noscan.patch32
-rw-r--r--package/network/services/hostapd/patches/410-multicall.patch246
-rw-r--r--package/network/services/hostapd/patches/420-timestamp_check.patch12
-rw-r--r--package/network/services/hostapd/patches/430-rescan_immediately.patch11
-rw-r--r--package/network/services/hostapd/patches/440-optional_rfkill.patch261
-rw-r--r--package/network/services/hostapd/patches/450-reload_freq_change.patch23
-rw-r--r--package/network/services/hostapd/patches/451-nl80211_del_beacon_bss.patch63
-rw-r--r--package/network/services/hostapd/patches/452-ctrl_iface_reload.patch98
-rw-r--r--package/network/services/hostapd/patches/453-ap_sta_support.patch221
-rw-r--r--package/network/services/hostapd/patches/460-disable_ctrl_iface_mib.patch168
-rw-r--r--package/network/services/hostapd/patches/470-wpa_ie_cap_workaround.patch56
-rw-r--r--package/network/services/hostapd/patches/480-terminate_on_setup_failure.patch81
-rw-r--r--package/network/services/hostapd/patches/500-random_pool_add_kernel.patch168
-rw-r--r--package/network/services/hostapd/patches/510-bring_down_interface.patch19
-rw-r--r--package/network/services/hostapd/patches/520-fix_wps_pin_crash.patch12
-rw-r--r--package/network/services/hostapd/patches/530-wps_single_auth_enc_type.patch25
-rw-r--r--package/network/services/hostapd/patches/540-dynamic_20_40_mhz.patch202
-rw-r--r--package/network/services/hostapd/patches/550-limit_debug_messages.patch213
-rw-r--r--package/network/services/hostapd/patches/560-indicate-features.patch82
-rw-r--r--package/network/services/hostapd/patches/570-genl_connect_debug.patch11
-rw-r--r--package/network/services/hostapd/patches/580-fix_bss_addr.patch11
-rw-r--r--package/network/services/hostapd/patches/590-hostapd_cli_ifdef.patch50
-rw-r--r--package/network/services/hostapd/patches/601-wpa_supplicant-add-new-config-params-to-be-used-with.patch211
-rw-r--r--package/network/services/hostapd/patches/602-driver_nl80211-use-new-parameters-during-ibss-join.patch59
-rw-r--r--package/network/services/hostapd/patches/604-wpa_s-support-htmode-param.patch156
-rw-r--r--package/network/services/hostapd/patches/610-max_num_sta_probe.patch13
-rw-r--r--package/network/services/ppp/Makefile263
-rw-r--r--package/network/services/ppp/files/etc/ppp/chap-secrets1
-rw-r--r--package/network/services/ppp/files/etc/ppp/filter23
-rw-r--r--package/network/services/ppp/files/etc/ppp/options10
-rw-r--r--package/network/services/ppp/files/etc/ppp/options.pptp7
-rw-r--r--package/network/services/ppp/files/etc/ppp/radius.conf8
-rw-r--r--package/network/services/ppp/files/etc/ppp/radius/dictionary253
-rw-r--r--package/network/services/ppp/files/etc/ppp/radius/dictionary.asnet3
-rw-r--r--package/network/services/ppp/files/etc/ppp/radius/dictionary.microsoft80
-rw-r--r--package/network/services/ppp/files/etc/ppp/radius/servers2
-rwxr-xr-xpackage/network/services/ppp/files/lib/netifd/ppp-down13
-rwxr-xr-xpackage/network/services/ppp/files/lib/netifd/ppp-up22
-rwxr-xr-xpackage/network/services/ppp/files/ppp.sh222
-rw-r--r--package/network/services/ppp/patches/010-use_target_for_configure.patch24
-rw-r--r--package/network/services/ppp/patches/100-debian_ip-ip_option.patch96
-rw-r--r--package/network/services/ppp/patches/101-debian_close_dev_ppp.patch28
-rw-r--r--package/network/services/ppp/patches/103-debian_fix_link_pidfile.patch23
-rw-r--r--package/network/services/ppp/patches/105-debian_demand.patch172
-rw-r--r--package/network/services/ppp/patches/106-debian_stripMSdomain.patch47
-rw-r--r--package/network/services/ppp/patches/107-debian_pppoatm_wildcard.patch25
-rw-r--r--package/network/services/ppp/patches/110-debian_defaultroute.patch313
-rw-r--r--package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch95
-rw-r--r--package/network/services/ppp/patches/200-makefile.patch55
-rw-r--r--package/network/services/ppp/patches/201-mppe_mppc_1.1.patch1495
-rw-r--r--package/network/services/ppp/patches/202-no_strip.patch88
-rw-r--r--package/network/services/ppp/patches/203-opt_flags.patch32
-rw-r--r--package/network/services/ppp/patches/204-radius_config.patch72
-rw-r--r--package/network/services/ppp/patches/205-no_exponential_timeout.patch29
-rw-r--r--package/network/services/ppp/patches/206-compensate_time_change.patch94
-rw-r--r--package/network/services/ppp/patches/207-lcp_mtu_max.patch25
-rw-r--r--package/network/services/ppp/patches/208-fix_status_code.patch24
-rw-r--r--package/network/services/ppp/patches/300-filter-pcap-includes-lib.patch20
-rw-r--r--package/network/services/ppp/patches/310-precompile_filter.patch196
-rw-r--r--package/network/services/ppp/patches/320-custom_iface_names.patch135
-rw-r--r--package/network/services/ppp/patches/330-retain_foreign_default_routes.patch22
-rw-r--r--package/network/services/ppp/patches/340-populate_default_gateway.patch34
-rw-r--r--package/network/services/ppp/patches/400-simplify_kernel_checks.patch154
-rw-r--r--package/network/services/ppp/patches/401-no_record_file.patch39
-rw-r--r--package/network/services/ppp/patches/403-no_wtmp.patch25
-rw-r--r--package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch151
-rw-r--r--package/network/services/ppp/patches/405-no_multilink_option.patch28
-rw-r--r--package/network/services/ppp/patches/430-pppol2tpv3-struct.patch30
-rw-r--r--package/network/services/ppp/patches/500-add-pptp-plugin.patch3065
-rw-r--r--package/network/services/ppp/utils/pfc.c51
-rw-r--r--package/network/services/relayd/Makefile44
-rw-r--r--package/network/services/relayd/files/relay.hotplug2
-rw-r--r--package/network/services/relayd/files/relay.init97
-rw-r--r--package/network/services/uhttpd/Makefile164
-rw-r--r--package/network/services/uhttpd/files/uhttpd.config89
-rwxr-xr-xpackage/network/services/uhttpd/files/uhttpd.init135
-rw-r--r--package/network/services/uhttpd/src/Makefile89
-rw-r--r--package/network/services/uhttpd/src/uhttpd-cgi.c556
-rw-r--r--package/network/services/uhttpd/src/uhttpd-cgi.h43
-rw-r--r--package/network/services/uhttpd/src/uhttpd-file.c438
-rw-r--r--package/network/services/uhttpd/src/uhttpd-file.h36
-rw-r--r--package/network/services/uhttpd/src/uhttpd-lua.c579
-rw-r--r--package/network/services/uhttpd/src/uhttpd-lua.h44
-rw-r--r--package/network/services/uhttpd/src/uhttpd-mimetypes.h86
-rw-r--r--package/network/services/uhttpd/src/uhttpd-tls.c170
-rw-r--r--package/network/services/uhttpd/src/uhttpd-tls.h36
-rw-r--r--package/network/services/uhttpd/src/uhttpd-ubus.c957
-rw-r--r--package/network/services/uhttpd/src/uhttpd-ubus.h70
-rw-r--r--package/network/services/uhttpd/src/uhttpd-utils.c1081
-rw-r--r--package/network/services/uhttpd/src/uhttpd-utils.h140
-rw-r--r--package/network/services/uhttpd/src/uhttpd.c1288
-rw-r--r--package/network/services/uhttpd/src/uhttpd.h214
194 files changed, 37897 insertions, 0 deletions
diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
new file mode 100644
index 0000000000..4ad0f37742
--- /dev/null
+++ b/package/network/services/dnsmasq/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:=dnsmasq
+PKG_VERSION:=2.62
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
+PKG_MD5SUM:=f47e5cb8f5bac6343f24b2dbe317ab40
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/dnsmasq/Default
+ SECTION:=net
+ CATEGORY:=Base system
+ TITLE:=A lightweight DNS and DHCP server
+ URL:=http://www.thekelleys.org.uk/dnsmasq/
+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 +kmod-ipv6
+ VARIANT:=dhcpv6
+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/conffiles
+/etc/config/dhcp
+/etc/dnsmasq.conf
+endef
+
+Package/dnsmasq-dhcpv6/conffiles = $(Package/dnsmasq/conffiles)
+
+TARGET_CFLAGS += \
+ -ffunction-sections -fdata-sections \
+ $(if $(CONFIG_IPV6),,-DNO_IPV6)
+
+ifeq ($(BUILD_VARIANT),nodhcpv6)
+ TARGET_CFLAGS += -DNO_DHCP6
+endif
+
+MAKE_FLAGS := \
+ $(TARGET_CONFIGURE_OPTS) \
+ CFLAGS="$(TARGET_CFLAGS)" \
+ LDFLAGS="-Wl,--gc-sections" \
+ 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
+endef
+
+Package/dnsmasq-dhcpv6/install = $(Package/dnsmasq/install)
+
+$(eval $(call BuildPackage,dnsmasq))
+$(eval $(call BuildPackage,dnsmasq-dhcpv6))
diff --git a/package/network/services/dnsmasq/files/dhcp.conf b/package/network/services/dnsmasq/files/dhcp.conf
new file mode 100644
index 0000000000..660b06ad4f
--- /dev/null
+++ b/package/network/services/dnsmasq/files/dhcp.conf
@@ -0,0 +1,31 @@
+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'
+
+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..85c22c3745
--- /dev/null
+++ b/package/network/services/dnsmasq/files/dnsmasq.init
@@ -0,0 +1,529 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2007-2012 OpenWrt.org
+
+START=60
+
+SERVICE_USE_PID=1
+
+DNS_SERVERS=""
+DOMAIN=""
+
+ADD_LOCAL_DOMAIN=1
+ADD_LOCAL_HOSTNAME=1
+
+CONFIGFILE="/var/etc/dnsmasq.conf"
+
+xappend() {
+ local value="$1"
+
+ echo "${value#--}" >> $CONFIGFILE
+}
+
+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"
+}
+
+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 _loctmp
+ config_get _loctmp "$section" "$option"
+ [ -z "$_loctmp" ] && return 0
+ xappend "$switch=$_loctmp"
+}
+
+append_server() {
+ xappend "--server=$1"
+}
+
+append_address() {
+ xappend "--address=$1"
+}
+
+append_interface() {
+ local ifname=$(uci_get_state network "$1" ifname "$1")
+ xappend "--interface=$ifname"
+}
+
+append_notinterface() {
+ local ifname=$(uci_get_state network "$1" ifname "$1")
+ xappend "--except-interface=$ifname"
+}
+
+append_addnhosts() {
+ xappend "--addn-hosts=$1"
+}
+
+append_bogusnxdomain() {
+ xappend "--bogus-nxdomain=$1"
+}
+
+dnsmasq() {
+ local cfg="$1"
+ 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"
+ 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"
+ append_bool "$cfg" enable_tftp "--enable-tftp"
+ append_bool "$cfg" nonwildcard "--bind-interfaces"
+ append_bool "$cfg" fqdn "--dhcp-fqdn"
+
+ 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" "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" "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"
+ append_parm "$cfg" "resolvfile" "--resolv-file"
+ append_parm "$cfg" "tftp_root" "--tftp-root"
+ append_parm "$cfg" "dhcp_boot" "--dhcp-boot"
+ append_parm "$cfg" "local_ttl" "--local-ttl"
+
+ 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 leasefile $cfg leasefile
+ [ -n "$leasefile" -a \! -e "$leasefile" ] && touch "$leasefile"
+ config_get_bool cachelocal "$cfg" cachelocal 1
+
+ config_get hostsfile "$cfg" dhcphostsfile
+ [ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile"
+
+ local rebind
+ config_get_bool rebind "$cfg" rebind_protection 1
+ [ $rebind -gt 0 ] && {
+ logger -t dnsmasq \
+ "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 ] && {
+ logger -t dnsmasq "Allowing 127.0.0.0/8 responses"
+ xappend "--rebind-localhost-ok"
+ }
+
+ append_rebind_domain() {
+ logger -t dnsmasq "Allowing RFC1918 responses for domain $1"
+ xappend "--rebind-domain-ok=$1"
+ }
+
+ config_list_foreach "$cfg" rebind_domain append_rebind_domain
+ }
+
+ dhcp_option_add "$cfg" "" 0
+
+ echo >> $CONFIGFILE
+}
+
+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_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 name "$cfg" name
+ config_get ip "$cfg" ip
+ [ -n "$ip" -o -n "$name" ] || return 0
+
+ macs=""
+ config_get mac "$cfg" mac
+ for m in $mac; do append macs "$m" ","; done
+ [ -n "$macs" ] || return 0
+
+ config_get tag "$cfg" tag
+
+ xappend "--dhcp-host=$macs${networkid:+,net:$networkid}${tag:+,set:$tag}${ip:+,$ip}${name:+,$name}"
+}
+
+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
+ [ -n "$servername" ] || return 0
+
+ config_get serveraddress "$cfg" serveraddress
+ [ -n "$serveraddress" ] || return 0
+
+ xappend "--dhcp-boot=${networkid:+net:$networkid,}$filename,$servername,$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 networkid "$cfg" networkid
+ [ -n "$networkid" ] || networkid="$net"
+
+ config_get ifname "$net" ifname
+ [ -n "$ifname" ] || return 0
+
+ config_get dnsserver "$net" dns
+ [ "$cachelocal" = "0" -a -n "$dnsserver" ] && {
+ DNS_SERVERS="$DNS_SERVERS $dnsserver"
+ }
+
+ append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && return 0
+
+ config_get proto "$net" proto
+ [ static = "$proto" ] || return 0
+
+ config_get ipaddr "$net" ipaddr
+ config_get netmask "$cfg" netmask
+ [ -n "$netmask" ] || config_get netmask "$net" netmask
+
+ #check for an already active dhcp server on the interface, unless 'force' is set
+ config_get_bool force "$cfg" force 0
+ [ $force -gt 0 ] || {
+ udhcpc -n -q -s /bin/true -t 1 -i $ifname >&- && {
+ logger -t dnsmasq \
+ "found already running DHCP-server on interface '$ifname'" \
+ "refusing to start, use 'option force 1' to override"
+ 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 $ipaddr $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
+
+ config_get names "$cfg" name "$2"
+ [ -n "$names" ] || return 0
+
+ config_get ip "$cfg" ip "$3"
+ [ -n "$ip" ] || return 0
+
+ local oIFS="$IFS"; IFS="."; set -- $ip; IFS="$oIFS"
+ local raddr="${4:+$4.$3.$2.$1.in-addr.arpa}"
+
+ for name in $names; do
+ local fqdn="$name"
+
+ [ "${fqdn%.*}" == "$fqdn" ] && \
+ fqdn="$fqdn${DOMAIN:+.$DOMAIN}"
+
+ xappend "--address=/$fqdn/$ip"
+
+ [ -n "$raddr" ] && {
+ xappend "--ptr-record=$raddr,$fqdn"
+ raddr=""
+ }
+ done
+}
+
+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}"
+}
+
+start() {
+ include /lib/network
+ scan_interfaces
+
+ local lanaddr
+ config_get lanaddr "lan" ipaddr
+
+ config_load dhcp
+
+ # before we can call xappend
+ mkdir -p $(dirname $CONFIGFILE)
+
+ echo "# auto-generated config file from /etc/config/dhcp" > $CONFIGFILE
+
+ # if we did this last, we could override auto-generated config
+ [ -f /etc/dnsmasq.conf ] && {
+ xappend "--conf-file=/etc/dnsmasq.conf"
+ }
+
+ args=""
+ config_foreach dnsmasq dnsmasq
+ config_foreach dhcp_host_add host
+ echo >> $CONFIGFILE
+ config_foreach dhcp_boot_add boot
+ config_foreach dhcp_mac_add mac
+ config_foreach dhcp_tag_add tag
+ config_foreach dhcp_vendorclass_add vendorclass
+ config_foreach dhcp_userclass_add userclass
+ config_foreach dhcp_circuitid_add circuitid
+ config_foreach dhcp_remoteid_add remoteid
+ config_foreach dhcp_subscrid_add subscrid
+ config_foreach dhcp_domain_add domain
+ echo >> $CONFIGFILE
+ config_foreach dhcp_srv_add srvhost
+ config_foreach dhcp_mx_add mxhost
+ echo >> $CONFIGFILE
+ config_foreach dhcp_add dhcp
+ echo >> $CONFIGFILE
+ config_foreach dhcp_cname_add cname
+ echo >> $CONFIGFILE
+
+ # add own hostname
+ [ $ADD_LOCAL_HOSTNAME -eq 1 ] && [ -n "$lanaddr" ] && {
+ local hostname="$(uci_get system.@system[0].hostname)"
+ dhcp_domain_add "" "${hostname:-OpenWrt}" "$lanaddr"
+ }
+
+ service_start /usr/sbin/dnsmasq -C $CONFIGFILE && {
+ 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
+ }
+}
+
+stop() {
+ service_stop /usr/sbin/dnsmasq && {
+ [ -f /tmp/resolv.conf ] && {
+ rm -f /tmp/resolv.conf
+ ln -s /tmp/resolv.conf.auto /tmp/resolv.conf
+ }
+ }
+}
diff --git a/package/network/services/dnsmasq/patches/0001-Set-prefix-on-link-bit-in-RAs.patch b/package/network/services/dnsmasq/patches/0001-Set-prefix-on-link-bit-in-RAs.patch
new file mode 100644
index 0000000000..8ead9afa59
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/0001-Set-prefix-on-link-bit-in-RAs.patch
@@ -0,0 +1,42 @@
+From fd05f127909bbf4f6983a4de2dcb611947488dee Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Sun, 12 Aug 2012 17:48:50 +0100
+Subject: [PATCH] Set prefix on-link bit in RAs
+
+---
+ CHANGELOG | 3 +++
+ src/radv.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 8828694..e1daeef 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -45,6 +45,9 @@ version 2.63
+ uk.org.thekelleys.dnsmasq. Thanks to Mathieu
+ Trudel-Lapierre for the patch.
+
++ Set the "prefix on-link" bit in Router
++ Advertisements. Thanks to Gui Iribarren for the patch.
++
+
+ version 2.62
+ Update German translation. Thanks to Conrad Kostecki.
+diff --git a/src/radv.c b/src/radv.c
+index a3e691a..d1f5268 100644
+--- a/src/radv.c
++++ b/src/radv.c
+@@ -412,8 +412,8 @@ static int add_prefixes(struct in6_addr *local, int prefix,
+ opt->type = ICMP6_OPT_PREFIX;
+ opt->len = 4;
+ opt->prefix_len = prefix;
+- /* autonomous only if we're not doing dhcp */
+- opt->flags = do_slaac ? 0x40 : 0x00;
++ /* autonomous only if we're not doing dhcp, always set "on-link" */
++ opt->flags = do_slaac ? 0xC0 : 0x80;
+ opt->valid_lifetime = htonl(time);
+ opt->preferred_lifetime = htonl(deprecate ? 0 : time);
+ opt->reserved = 0;
+--
+1.7.10.GIT
+
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..d108a7d3bc
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
@@ -0,0 +1,49 @@
+--- a/src/dhcp.c
++++ b/src/dhcp.c
+@@ -134,7 +134,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+ struct iovec iov;
+ ssize_t sz;
+ int iface_index = 0, unicast_dest = 0, is_inform = 0;
+- struct in_addr iface_addr;
++ struct in_addr iface_addr, *addrp = NULL;
+ struct iface_param parm;
+ #ifdef HAVE_LINUX_NETWORK
+ struct arpreq arp_req;
+@@ -246,11 +246,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)
+@@ -272,7 +270,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+ parm.current = NULL;
+ parm.ind = iface_index;
+
+- if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
++ if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name))
+ {
+ /* If we failed to match the primary address of the interface, see if we've got a --listen-address
+ for a secondary */
+@@ -291,7 +289,13 @@ void dhcp_packet(time_t now, int pxe_fd)
+ there is more than one address on the interface in the same subnet */
+ complete_context(match.addr, iface_index, 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/dropbear/Makefile b/package/network/services/dropbear/Makefile
new file mode 100644
index 0000000000..63cf86e147
--- /dev/null
+++ b/package/network/services/dropbear/Makefile
@@ -0,0 +1,114 @@
+#
+# 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:=dropbear
+PKG_VERSION:=2011.54
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+ http://matt.ucc.asn.au/dropbear/releases/ \
+ http://www.mirrors.wiretapped.net/security/cryptography/apps/ssh/dropbear/
+PKG_MD5SUM:=c627ffe09570fad7aa94d8eac2b9320c
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/dropbear/Default
+ URL:=http://matt.ucc.asn.au/dropbear/
+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/dropbear/dropbear_dss_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 += \
+ --with-shared \
+ --disable-pam \
+ --enable-openpty \
+ --enable-syslog \
+ $(if $(CONFIG_SHADOW_PASSWORDS),,--disable-shadow) \
+ --disable-lastlog \
+ --disable-utmp \
+ --disable-utmpx \
+ --disable-wtmp \
+ --disable-wtmpx \
+ --disable-loginfunc \
+ --disable-pututline \
+ --disable-pututxline \
+ --disable-zlib \
+ --enable-bundled-libtom
+
+TARGET_CFLAGS += -DARGTYPE=3 -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+define Build/Configure
+ $(SED) 's,^/\* #define PKG_MULTI.*,#define PKG_MULTI,g' $(PKG_BUILD_DIR)/options.h
+ $(SED) 's,^#define DO_HOST_LOOKUP,/* & */,g' $(PKG_BUILD_DIR)/options.h
+ $(call Build/Configure/Default)
+endef
+
+define Build/Compile
+ +$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+ $(TARGET_CONFIGURE_OPTS) \
+ LD="$(TARGET_CC)" \
+ PROGRAMS="dropbear dbclient dropbearkey scp" \
+ MULTI=1 SCPPROGRESS=1
+ +$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+ $(TARGET_CONFIGURE_OPTS) \
+ LD="$(TARGET_CC)" \
+ 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 -sf ../sbin/dropbear $(1)/usr/bin/scp
+ ln -sf ../sbin/dropbear $(1)/usr/bin/ssh
+ ln -sf ../sbin/dropbear $(1)/usr/bin/dbclient
+ ln -sf ../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
+ touch $(1)/etc/dropbear/dropbear_dss_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..c909d28965
--- /dev/null
+++ b/package/network/services/dropbear/files/dropbear.init
@@ -0,0 +1,191 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006-2010 OpenWrt.org
+# Copyright (C) 2006 Carlos Sobrinho
+
+START=50
+STOP=50
+
+SERVICE_USE_PID=1
+
+NAME=dropbear
+PROG=/usr/sbin/dropbear
+PIDCOUNT=0
+EXTRA_COMMANDS="killclients"
+EXTRA_HELP=" killclients Kill ${NAME} processes except servers and yourself"
+
+dropbear_start()
+{
+ append_ports()
+ {
+ local ifname="$1"
+ local port="$2"
+
+ grep -qs "^ *$ifname:" /proc/net/dev || {
+ append args "-p $port"
+ return
+ }
+
+ for addr in $(
+ ifconfig "$ifname" | sed -ne '
+ /addr: *fe[89ab][0-9a-f]:/d
+ s/.* addr: *\([0-9a-f:\.]*\).*/\1/p
+ '
+ ); do
+ append args "-p $addr:$port"
+ done
+ }
+
+
+ local section="$1"
+
+ # check if section is enabled (default)
+ local enabled
+ config_get_bool enabled "${section}" enable 1
+ [ "${enabled}" -eq 0 ] && return 1
+
+ # verbose parameter
+ local verbosed
+ config_get_bool verbosed "${section}" verbose 0
+
+ # increase pid file count to handle multiple instances correctly
+ PIDCOUNT="$(( ${PIDCOUNT} + 1))"
+
+ # prepare parameters (initialise with pid file)
+ local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
+ local args="-P $pid_file"
+ local val
+ # A) password authentication
+ config_get_bool val "${section}" PasswordAuth 1
+ [ "${val}" -eq 0 ] && append args "-s"
+ # B) listen interface and port
+ local port
+ local interface
+ config_get interface "${section}" Interface
+ config_get interface "${interface}" ifname "$interface"
+ config_get port "${section}" Port 22
+ append_ports "$interface" "$port"
+ # C) banner file
+ config_get val "${section}" BannerFile
+ [ -f "${val}" ] && append args "-b ${val}"
+ # D) gatewayports
+ config_get_bool val "${section}" GatewayPorts 0
+ [ "${val}" -eq 1 ] && append args "-a"
+ # E) root password authentication
+ config_get_bool val "${section}" RootPasswordAuth 1
+ [ "${val}" -eq 0 ] && append args "-g"
+ # F) root login
+ config_get_bool val "${section}" RootLogin 1
+ [ "${val}" -eq 0 ] && append args "-w"
+ # G) host keys
+ config_get val "${section}" rsakeyfile
+ [ -f "${val}" ] && append args "-r ${val}"
+ config_get val "${section}" dsskeyfile
+ [ -f "${val}" ] && append args "-d ${val}"
+
+ # execute program and return its exit code
+ [ "${verbosed}" -ne 0 ] && echo "${initscript}: section ${section} starting ${PROG} ${args}"
+ SERVICE_PID_FILE="$pid_file" service_start ${PROG} ${args}
+}
+
+keygen()
+{
+ for keytype in rsa dss; 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
+}
+
+start()
+{
+ [ -s /etc/dropbear/dropbear_rsa_host_key -a \
+ -s /etc/dropbear/dropbear_dss_host_key ] || keygen
+
+ include /lib/network
+ scan_interfaces
+ config_load "${NAME}"
+ config_foreach dropbear_start dropbear
+}
+
+stop()
+{
+ local pid_file pid_files
+
+ pid_files=`ls /var/run/${NAME}.*.pid 2>/dev/null`
+
+ [ -z "$pid_files" ] && return 1
+
+ for pid_file in $pid_files; do
+ SERVICE_PID_FILE="$pid_file" service_stop ${PROG} && {
+ rm -f ${pid_file}
+ }
+ done
+}
+
+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..c1802f51e5
--- /dev/null
+++ b/package/network/services/dropbear/patches/100-pubkey_path.patch
@@ -0,0 +1,91 @@
+--- a/svr-authpubkey.c
++++ b/svr-authpubkey.c
+@@ -209,17 +209,21 @@ static int checkpubkey(unsigned char* al
+ 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;
+ }
+@@ -372,26 +376,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..55747bc4d7
--- /dev/null
+++ b/package/network/services/dropbear/patches/110-change_user.patch
@@ -0,0 +1,18 @@
+--- a/svr-chansession.c
++++ b/svr-chansession.c
+@@ -884,12 +884,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..42204aa646
--- /dev/null
+++ b/package/network/services/dropbear/patches/120-openwrt_options.patch
@@ -0,0 +1,67 @@
+--- a/options.h
++++ b/options.h
+@@ -38,7 +38,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
+@@ -49,7 +49,7 @@
+ several kB in binary size however will make the symmetrical ciphers and hashes
+ slower, perhaps by 50%. Recommended for small systems that aren't doing
+ much traffic. */
+-/*#define DROPBEAR_SMALL_CODE*/
++#define DROPBEAR_SMALL_CODE
+
+ /* Enable X11 Forwarding - server only */
+ #define ENABLE_X11FWD
+@@ -78,7 +78,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*/
+
+ /* Encryption - at least one required.
+ * Protocol RFC requires 3DES and recommends AES128 for interoperability.
+@@ -89,8 +89,8 @@ much traffic. */
+ #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 "Counter Mode" for ciphers. This is more secure than normal
+ * CBC mode against certain attacks. This adds around 1kB to binary
+@@ -110,7 +110,7 @@ much traffic. */
+ * 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_SHA1_96_HMAC*/
+ #define DROPBEAR_MD5_HMAC
+
+ /* Hostkey/public key algorithms - at least one required, these are used
+@@ -148,7 +148,7 @@ much traffic. */
+
+ /* 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
+@@ -192,7 +192,7 @@ much traffic. */
+ * 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_o_and_x_args.patch b/package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch
new file mode 100644
index 0000000000..93647a99e5
--- /dev/null
+++ b/package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch
@@ -0,0 +1,21 @@
+--- a/cli-runopts.c
++++ b/cli-runopts.c
+@@ -287,6 +287,10 @@ void cli_getopts(int argc, char ** argv)
+ debug_trace = 1;
+ break;
+ #endif
++ case 'o':
++ next = &dummy;
++ case 'x':
++ break;
+ case 'F':
+ case 'e':
+ case 'c':
+@@ -298,7 +302,6 @@ void cli_getopts(int argc, char ** argv)
+ #ifndef ENABLE_CLI_LOCALTCPFWD
+ case 'L':
+ #endif
+- case 'o':
+ case 'b':
+ next = &dummy;
+ default:
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..e99376333c
--- /dev/null
+++ b/package/network/services/dropbear/patches/140-disable_assert.patch
@@ -0,0 +1,14 @@
+--- a/dbutil.h
++++ b/dbutil.h
+@@ -94,6 +94,10 @@ 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)
+
+ #endif /* _DBUTIL_H_ */
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..3e0b008552
--- /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 _OPTIONS_H_
+ #define _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/200-lcrypt_bsdfix.patch b/package/network/services/dropbear/patches/200-lcrypt_bsdfix.patch
new file mode 100644
index 0000000000..57eb9670dc
--- /dev/null
+++ b/package/network/services/dropbear/patches/200-lcrypt_bsdfix.patch
@@ -0,0 +1,29 @@
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -56,7 +56,7 @@ HEADERS=options.h dbutil.h session.h pac
+ loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
+ listener.h fake-rfc2553.h
+
+-dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
++dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
+ dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
+ dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
+ dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
+@@ -77,7 +77,7 @@ STRIP=@STRIP@
+ INSTALL=@INSTALL@
+ CPPFLAGS=@CPPFLAGS@
+ CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
+-LIBS+=@LIBS@
++LIBS+=@CRYPTLIB@ @LIBS@
+ LDFLAGS=@LDFLAGS@
+
+ EXEEXT=@EXEEXT@
+@@ -169,7 +169,7 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
+ # multi-binary compilation.
+ MULTIOBJS=
+ ifeq ($(MULTI),1)
+- MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@
++ MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
+ CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
+ endif
+
diff --git a/package/network/services/dropbear/patches/300-ipv6_addr_port_split.patch b/package/network/services/dropbear/patches/300-ipv6_addr_port_split.patch
new file mode 100644
index 0000000000..7da435ab15
--- /dev/null
+++ b/package/network/services/dropbear/patches/300-ipv6_addr_port_split.patch
@@ -0,0 +1,11 @@
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -325,7 +325,7 @@ static void addportandaddress(char* spec
+ myspec = m_strdup(spec);
+
+ /* search for ':', that separates address and port */
+- svr_opts.ports[svr_opts.portcount] = strchr(myspec, ':');
++ svr_opts.ports[svr_opts.portcount] = strrchr(myspec, ':');
+
+ if (svr_opts.ports[svr_opts.portcount] == NULL) {
+ /* no ':' -> the whole string specifies just a port */
diff --git a/package/network/services/dropbear/patches/400-CVE-2012-0920.patch b/package/network/services/dropbear/patches/400-CVE-2012-0920.patch
new file mode 100644
index 0000000000..164909f561
--- /dev/null
+++ b/package/network/services/dropbear/patches/400-CVE-2012-0920.patch
@@ -0,0 +1,91 @@
+
+# HG changeset patch
+# User Matt Johnston <matt@ucc.asn.au>
+# Date 1322947885 -28800
+# Node ID 818108bf7749bfecd4715a30e2583aac9dbe25e8
+# Parent 5e8d84f3ee7256d054ecf7e9f248765ccaa7f24f
+- Fix use-after-free if multiple command requests were sent. Move
+the original_command into chansess struct since that makes more sense
+
+--- a/auth.h
++++ b/auth.h
+@@ -133,7 +133,6 @@ struct PubKeyOptions {
+ int no_pty_flag;
+ /* "command=" option. */
+ unsigned char * forced_command;
+- unsigned char * original_command;
+ };
+ #endif
+
+--- a/chansession.h
++++ b/chansession.h
+@@ -69,6 +69,10 @@ struct ChanSess {
+ char * agentfile;
+ char * agentdir;
+ #endif
++
++#ifdef ENABLE_SVR_PUBKEY_OPTIONS
++ char *original_command;
++#endif
+ };
+
+ struct ChildPid {
+--- a/svr-authpubkeyoptions.c
++++ b/svr-authpubkeyoptions.c
+@@ -92,14 +92,15 @@ int svr_pubkey_allows_pty() {
+ * by any 'command' public key option. */
+ void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
+ if (ses.authstate.pubkey_options) {
+- ses.authstate.pubkey_options->original_command = chansess->cmd;
+- if (!chansess->cmd)
+- {
+- ses.authstate.pubkey_options->original_command = m_strdup("");
++ if (chansess->cmd) {
++ /* original_command takes ownership */
++ chansess->original_command = chansess->cmd;
++ } else {
++ chansess->original_command = m_strdup("");
+ }
+- chansess->cmd = ses.authstate.pubkey_options->forced_command;
++ chansess->cmd = m_strdup(ses.authstate.pubkey_options->forced_command);
+ #ifdef LOG_COMMANDS
+- dropbear_log(LOG_INFO, "Command forced to '%s'", ses.authstate.pubkey_options->original_command);
++ dropbear_log(LOG_INFO, "Command forced to '%s'", chansess->original_command);
+ #endif
+ }
+ }
+--- a/svr-chansession.c
++++ b/svr-chansession.c
+@@ -217,6 +217,8 @@ static int newchansess(struct Channel *c
+
+ struct ChanSess *chansess;
+
++ TRACE(("new chansess %p", channel))
++
+ dropbear_assert(channel->typedata == NULL);
+
+ chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
+@@ -279,6 +281,10 @@ static void closechansess(struct Channel
+ m_free(chansess->cmd);
+ m_free(chansess->term);
+
++#ifdef ENABLE_SVR_PUBKEY_OPTIONS
++ m_free(chansess->original_command);
++#endif
++
+ if (chansess->tty) {
+ /* write the utmp/wtmp login record */
+ li = chansess_login_alloc(chansess);
+@@ -924,10 +930,8 @@ static void execchild(void *user_data) {
+ }
+
+ #ifdef ENABLE_SVR_PUBKEY_OPTIONS
+- if (ses.authstate.pubkey_options &&
+- ses.authstate.pubkey_options->original_command) {
+- addnewvar("SSH_ORIGINAL_COMMAND",
+- ses.authstate.pubkey_options->original_command);
++ if (chansess->original_command) {
++ addnewvar("SSH_ORIGINAL_COMMAND", chansess->original_command);
+ }
+ #endif
+
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..0bd3ffcc38
--- /dev/null
+++ b/package/network/services/dropbear/patches/500-set-default-path.patch
@@ -0,0 +1,11 @@
+--- a/options.h
++++ b/options.h
+@@ -297,7 +297,7 @@ be overridden at runtime with -I. 0 disa
+ #define DEFAULT_IDLE_TIMEOUT 0
+
+ /* The default path. This will often get replaced by the shell */
+-#define DEFAULT_PATH "/usr/bin:/bin"
++#define DEFAULT_PATH "/bin:/sbin:/usr/bin:/usr/sbin"
+
+ /* Some other defines (that mostly should be left alone) are defined
+ * in sysoptions.h */
diff --git a/package/network/services/ead/Makefile b/package/network/services/ead/Makefile
new file mode 100644
index 0000000000..5633a315a1
--- /dev/null
+++ b/package/network/services/ead/Makefile
@@ -0,0 +1,57 @@
+#
+# 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@openwrt.org>
+
+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$(LINUX_DIR)/include \
+ -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 Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+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..faef3b7997
--- /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
+
+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..54d8b1343f
--- /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@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 <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..03721721d9
--- /dev/null
+++ b/package/network/services/ead/src/ead-crypt.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@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 <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..831ec8a280
--- /dev/null
+++ b/package/network/services/ead/src/ead-crypt.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@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.
+ */
+
+#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..36235207bc
--- /dev/null
+++ b/package/network/services/ead/src/ead.c
@@ -0,0 +1,991 @@
+/*
+ * Emergency Access Daemon
+ * Copyright (C) 2008 Felix Fietkau <nbd@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 <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 "list.h"
+#include "ead.h"
+#include "ead-pcap.h"
+#include "ead-crypt.h"
+
+#include "filter.c"
+
+#ifdef linux
+#include "libbridge_init.c"
+#endif
+
+#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;
+#ifdef linux
+ char bridge[16];
+ bool br_check;
+#endif
+};
+
+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 ifindex, mask;
+ int fd, ret;
+
+ fd = pcap_get_selectable_fd(p);
+ if (fd < 0)
+ return;
+
+ if (rx)
+ mask = 1 << PACKET_BROADCAST;
+ else
+ mask = 0;
+
+ ret = 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 {
+#ifdef linux
+ if (instance->bridge[0]) {
+ pcap_fp_rx = ead_open_pcap(instance->bridge, errbuf, 1);
+ pcap_fp = ead_open_pcap(instance->ifname, errbuf, 0);
+ } else
+#endif
+ {
+ 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);
+}
+
+#ifdef linux
+static int
+check_bridge_port(const char *br, const char *port, void *arg)
+{
+ struct ead_instance *in;
+ struct list_head *p, *tmp;
+
+ 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;
+}
+#endif
+
+static void
+check_all_interfaces(void)
+{
+#ifdef linux
+ struct ead_instance *in;
+ struct list_head *p, *tmp;
+
+ 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);
+ }
+ }
+#endif
+}
+
+
+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);
+#ifdef linux
+ br_init();
+#endif
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ while (1) {
+ check_all_interfaces();
+ start_servers(true);
+ sleep(1);
+ }
+#ifdef linux
+ br_shutdown();
+#endif
+
+ 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..54505ce28c
--- /dev/null
+++ b/package/network/services/ead/src/ead.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@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.
+ */
+
+#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..6b70e46f6d
--- /dev/null
+++ b/package/network/services/ead/src/libbridge.h
@@ -0,0 +1,84 @@
+/*
+ * 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
+
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_bridge.h>
+
+/* defined in net/if.h but that conflicts with linux/if.h... */
+extern unsigned int if_nametoindex (const char *__ifname);
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
+struct bridge_id
+{
+ unsigned char prio[2];
+ unsigned char addr[6];
+};
+
+struct bridge_info
+{
+ struct bridge_id designated_root;
+ struct bridge_id bridge_id;
+ unsigned root_path_cost;
+ struct timeval max_age;
+ struct timeval hello_time;
+ struct timeval forward_delay;
+ struct timeval bridge_max_age;
+ struct timeval bridge_hello_time;
+ struct timeval bridge_forward_delay;
+ u_int16_t root_port;
+ unsigned char stp_enabled;
+ unsigned char topology_change;
+ unsigned char topology_change_detected;
+ struct timeval ageing_time;
+ struct timeval hello_timer_value;
+ struct timeval tcn_timer_value;
+ struct timeval topology_change_timer_value;
+ struct timeval gc_timer_value;
+};
+
+struct fdb_entry
+{
+ u_int8_t mac_addr[6];
+ u_int16_t port_no;
+ unsigned char is_local;
+ struct timeval ageing_timer_value;
+};
+
+struct port_info
+{
+ unsigned port_no;
+ struct bridge_id designated_root;
+ struct bridge_id designated_bridge;
+ u_int16_t port_id;
+ u_int16_t designated_port;
+ u_int8_t priority;
+ unsigned char top_change_ack;
+ unsigned char config_pending;
+ unsigned char state;
+ unsigned path_cost;
+ unsigned designated_cost;
+ struct timeval message_age_timer_value;
+ struct timeval forward_delay_timer_value;
+ struct timeval hold_timer_value;
+};
+
+#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..36d0eb9b8e
--- /dev/null
+++ b/package/network/services/ead/src/libbridge_init.c
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+#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 "libbridge.h"
+#include "libbridge_private.h"
+
+int br_socket_fd = -1;
+
+static int br_init(void)
+{
+ if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+ return errno;
+ return 0;
+}
+
+static 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;
+}
+
+/*
+ * Old interface uses ioctl
+ */
+static int old_foreach_bridge(int (*iterator)(const char *, void *),
+ void *iarg)
+{
+ int i, ret=0, num;
+ char ifname[IFNAMSIZ];
+ int ifindices[MAX_BRIDGES];
+ unsigned long args[3] = { BRCTL_GET_BRIDGES,
+ (unsigned long)ifindices, MAX_BRIDGES };
+
+ num = ioctl(br_socket_fd, SIOCGIFBR, args);
+ if (num < 0) {
+ dprintf("Get bridge indices failed: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (!if_indextoname(ifindices[i], ifname)) {
+ dprintf("get find name for ifindex %d\n",
+ ifindices[i]);
+ return -errno;
+ }
+
+ ++ret;
+ if(iterator(ifname, iarg))
+ break;
+ }
+
+ return ret;
+
+}
+
+/*
+ * Go over all bridges and call iterator function.
+ * if iterator returns non-zero then stop.
+ */
+static int br_foreach_bridge(int (*iterator)(const char *, void *),
+ void *arg)
+{
+ int ret;
+
+ ret = new_foreach_bridge(iterator, arg);
+ if (ret <= 0)
+ ret = old_foreach_bridge(iterator, arg);
+
+ return ret;
+}
+
+/*
+ * Only used if sysfs is not available.
+ */
+static int old_foreach_port(const char *brname,
+ int (*iterator)(const char *br, const char *port,
+ void *arg),
+ void *arg)
+{
+ int i, err, count;
+ struct ifreq ifr;
+ char ifname[IFNAMSIZ];
+ int ifindices[MAX_PORTS];
+ unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+ (unsigned long)ifindices, MAX_PORTS, 0 };
+
+ memset(ifindices, 0, sizeof(ifindices));
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ if (err < 0) {
+ dprintf("list ports for bridge:'%s' failed: %s\n",
+ brname, strerror(errno));
+ return -errno;
+ }
+
+ count = 0;
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (!ifindices[i])
+ continue;
+
+ if (!if_indextoname(ifindices[i], ifname)) {
+ dprintf("can't find name for ifindex:%d\n",
+ ifindices[i]);
+ continue;
+ }
+
+ ++count;
+ if (iterator(brname, ifname, arg))
+ break;
+ }
+
+ return count;
+}
+
+/*
+ * Iterate over all ports in bridge (using sysfs).
+ */
+static 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);
+ if (count < 0)
+ return old_foreach_port(brname, iterator, arg);
+
+ 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;
+}
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..402e37f31d
--- /dev/null
+++ b/package/network/services/ead/src/pfc.c
@@ -0,0 +1,54 @@
+/*
+ * Small pcap precompiler
+ * Copyright (C) 2008 Felix Fietkau <nbd@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 <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..d2d9fc5571
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_mul.c
@@ -0,0 +1,176 @@
+/* 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_RECURSION
+ BIGNUM *t;
+ int j,k;
+#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..faaa5dd90d
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/clitest.c
@@ -0,0 +1,112 @@
+/*
+ * 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 n;
+ struct t_num g;
+ 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..ebdd203af5
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_client.c
@@ -0,0 +1,287 @@
+/*
+ * 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;
+
+ BigInteger nn, gg, n12, r;
+
+ 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..d3fe246c41
--- /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(a[j] == 0 && j <= size)
+ ++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..1aede0c832
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/tphrase.c
@@ -0,0 +1,348 @@
+/* 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_conf *tc;
+ 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);
+ fclose(bakfp);
+ 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)
+ return -1;
+ if(rename(bakfile2, pwname) < 0)
+ 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..810c5a09a9
--- /dev/null
+++ b/package/network/services/hostapd/Config.in
@@ -0,0 +1,47 @@
+# wpa_supplicant config
+config WPA_SUPPLICANT_NO_TIMESTAMP_CHECK
+ bool "Disable timestamp check"
+ depends PACKAGE_wpa-supplicant || PACKAGE_wpa-supplicant-mini || PACKAGE_wpad || PACKAGE_wpad-mini
+ 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 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 PACKAGE_wpa-supplicant || PACKAGE_wpa-supplicant-mini || PACKAGE_wpad || PACKAGE_wpad-mini
+ 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
diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile
new file mode 100644
index 0000000000..bc4384f5e7
--- /dev/null
+++ b/package/network/services/hostapd/Makefile
@@ -0,0 +1,342 @@
+#
+# 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:=hostapd
+PKG_VERSION:=20120910
+PKG_RELEASE:=1
+PKG_REV:=762b99db7a76803d1ad274e87caa6fe870d47441
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=git://w1.fi/srv/git/hostap.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_PROTO:=git
+PKG_MIRROR_MD5SUM:=fa3227c146cb50732fe8511ce6d1d862
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+PKG_BUILD_PARALLEL:=1
+
+PKG_BUILD_DEPENDS:= \
+ PACKAGE_kmod-madwifi:madwifi \
+
+PKG_CONFIG_DEPENDS:= \
+ CONFIG_WPA_SUPPLICANT_NO_TIMESTAMP_CHECK \
+ CONFIG_PACKAGE_kmod-ath9k \
+ CONFIG_PACKAGE_kmod-mac80211 \
+ CONFIG_PACKAGE_kmod-madwifi \
+ CONFIG_PACKAGE_hostapd \
+ CONFIG_PACKAGE_hostapd-mini \
+ CONFIG_PACKAGE_kmod-hostap \
+ 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)))
+
+ifeq ($(LOCAL_TYPE),supplicant)
+ 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_DRIVER_NL80211=$(CONFIG_PACKAGE_kmod-mac80211) \
+ CONFIG_DRIVER_MADWIFI=$(CONFIG_PACKAGE_kmod-madwifi) \
+ CONFIG_DRIVER_HOSTAP=$(CONFIG_PACKAGE_kmod-hostap) \
+ CONFIG_IEEE80211N=$(HOSTAPD_IEEE80211N) \
+ CONFIG_IEEE80211W=$(CONFIG_PACKAGE_kmod-ath9k) \
+ CONFIG_DRIVER_WEXT=$(CONFIG_DRIVER_WEXT_SUPPORT) \
+ $(if $(CONFIG_WPA_RFKILL_SUPPORT),NEED_RFKILL=y)
+
+ifneq ($(LOCAL_TYPE),hostapd)
+ ifdef CONFIG_WPA_SUPPLICANT_OPENSSL
+ ifeq ($(LOCAL_VARIANT),full)
+ DRIVER_MAKEOPTS += CONFIG_TLS=openssl
+ TARGET_LDFLAGS += -lcrypto -lssl
+ endif
+ endif
+ ifdef CONFIG_WPA_SUPPLICANT_NO_TIMESTAMP_CHECK
+ TARGET_CFLAGS += -DNO_TIMESTAMP_CHECK
+ endif
+ DRIVER_MAKEOPTS += \
+ CONFIG_DRIVER_ROBOSWITCH=$(CONFIG_PACKAGE_kmod-switch)
+endif
+
+DRV_DEPENDS:=+PACKAGE_kmod-mac80211:libnl-tiny @(!(TARGET_avr32||TARGET_etrax)||BROKEN)
+
+define Package/hostapd/Default
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=IEEE 802.1x Authenticator
+ URL:=http://hostap.epitest.fi/
+ DEPENDS:=$(DRV_DEPENDS)
+ MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+endef
+
+define Package/hostapd
+$(call Package/hostapd/Default)
+ TITLE+= (full)
+ VARIANT:=full
+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
+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-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
+ URL:=http://hostap.epitest.fi/
+ MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+endef
+
+define Package/wpad
+$(call Package/wpad/Default)
+ TITLE+= (full)
+ DEPENDS:=$(DRV_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)
+ DEPENDS:=$(DRV_DEPENDS)
+ 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/wpa-supplicant
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=WPA Supplicant
+ URL:=http://hostap.epitest.fi/wpa_supplicant/
+ DEPENDS:=$(DRV_DEPENDS) +WPA_SUPPLICANT_OPENSSL:libopenssl
+ VARIANT:=supplicant-full
+ MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+endef
+
+define Package/wpa-supplicant/Description
+ WPA Supplicant
+endef
+
+define Package/wpa-supplicant/config
+ source "$(SOURCE)/Config.in"
+endef
+
+define Package/wpa-supplicant-mini
+ $(Package/wpa-supplicant)
+ TITLE:=WPA Supplicant (minimal version)
+ DEPENDS:=$(DRV_DEPENDS)
+ 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_wpad-mini||PACKAGE_wpad
+ TITLE:=WPA Supplicant command line interface
+ MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+endef
+
+define Package/wpa-cli/Description
+ WPA Supplicant control utility
+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)
+ $(CP) ./files/hostapd-$(LOCAL_VARIANT).config $(PKG_BUILD_DIR)/hostapd/.config
+ $(CP) ./files/wpa_supplicant-$(LOCAL_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) \
+ -I$(STAGING_DIR)/usr/include/madwifi \
+ -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
+
+ifdef CONFIG_PACKAGE_kmod-mac80211
+ 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)" \
+ 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
+ $(Build/Compile/$(LOCAL_TYPE))
+endef
+
+define Install/hostapd
+ $(INSTALL_DIR) $(1)/lib/wifi
+ $(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/wifi/hostapd.sh
+ $(INSTALL_DIR) $(1)/usr/sbin
+endef
+
+define Install/supplicant
+ $(INSTALL_DIR) $(1)/lib/wifi
+ $(INSTALL_DATA) ./files/wpa_supplicant.sh $(1)/lib/wifi/wpa_supplicant.sh
+ $(INSTALL_DIR) $(1)/usr/sbin
+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/hotplug.d/button
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/hostapd/hostapd_cli $(1)/usr/sbin/
+ $(INSTALL_DATA) ./files/wps-hotplug.sh $(1)/etc/hotplug.d/button/50-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 -sf wpad $(1)/usr/sbin/hostapd
+ ln -sf wpad $(1)/usr/sbin/wpa_supplicant
+endef
+Package/wpad-mini/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)
+
+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
+
+$(eval $(call BuildPackage,hostapd))
+$(eval $(call BuildPackage,hostapd-mini))
+$(eval $(call BuildPackage,wpad))
+$(eval $(call BuildPackage,wpad-mini))
+$(eval $(call BuildPackage,wpa-supplicant))
+$(eval $(call BuildPackage,wpa-supplicant-mini))
+$(eval $(call BuildPackage,wpa-cli))
+$(eval $(call BuildPackage,hostapd-utils))
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..3a0ce12fc4
--- /dev/null
+++ b/package/network/services/hostapd/files/hostapd-full.config
@@ -0,0 +1,164 @@
+# 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 madwifi driver
+CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# 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., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=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_DUMP_STATE=y
+
+CONFIG_WPS=y
+CONFIG_FULL_DYNAMIC_VLAN=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..3e94a645b5
--- /dev/null
+++ b/package/network/services/hostapd/files/hostapd-mini.config
@@ -0,0 +1,157 @@
+# 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 madwifi driver
+CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# 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., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=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_DUMP_STATE=y
diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh
new file mode 100644
index 0000000000..d60c26f3c6
--- /dev/null
+++ b/package/network/services/hostapd/files/hostapd.sh
@@ -0,0 +1,276 @@
+hostapd_set_bss_options() {
+ local var="$1"
+ local vif="$2"
+ local enc wep_rekey wpa_group_rekey wpa_pair_rekey wpa_master_rekey wps_possible
+
+ config_get enc "$vif" encryption
+ config_get wep_rekey "$vif" wep_rekey # 300
+ config_get wpa_group_rekey "$vif" wpa_group_rekey # 300
+ config_get wpa_pair_rekey "$vif" wpa_pair_rekey # 300
+ config_get wpa_master_rekey "$vif" wpa_master_rekey # 640
+ config_get_bool ap_isolate "$vif" isolate 0
+ config_get_bool disassoc_low_ack "$vif" disassoc_low_ack 1
+ config_get max_num_sta "$vif" max_num_sta 0
+ config_get max_inactivity "$vif" max_inactivity 0
+
+ config_get device "$vif" device
+ config_get hwmode "$device" hwmode
+ config_get phy "$device" phy
+
+ append "$var" "ctrl_interface=/var/run/hostapd-$phy" "$N"
+
+ if [ "$ap_isolate" -gt 0 ]; then
+ append "$var" "ap_isolate=$ap_isolate" "$N"
+ fi
+ if [ "$max_num_sta" -gt 0 ]; then
+ append "$var" "max_num_sta=$max_num_sta" "$N"
+ fi
+ if [ "$max_inactivity" -gt 0 ]; then
+ append "$var" "ap_max_inactivity=$max_inactivity" "$N"
+ fi
+ append "$var" "disassoc_low_ack=$disassoc_low_ack" "$N"
+
+ # Examples:
+ # psk-mixed/tkip => WPA1+2 PSK, TKIP
+ # wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
+ # wpa2/tkip+aes => WPA2 RADIUS, CCMP+TKIP
+ # ...
+
+ # TODO: move this parsing function somewhere generic, so that
+ # later it can be reused by drivers that don't use hostapd
+
+ # crypto defaults: WPA2 vs WPA1
+ case "$enc" in
+ wpa2*|*psk2*)
+ wpa=2
+ crypto="CCMP"
+ ;;
+ *mixed*)
+ wpa=3
+ crypto="CCMP TKIP"
+ ;;
+ *)
+ wpa=1
+ crypto="TKIP"
+ ;;
+ esac
+
+ # explicit override for crypto setting
+ case "$enc" in
+ *tkip+aes|*tkip+ccmp|*aes+tkip|*ccmp+tkip) crypto="CCMP TKIP";;
+ *aes|*ccmp) crypto="CCMP";;
+ *tkip) crypto="TKIP";;
+ esac
+
+ # enforce CCMP for 11ng and 11na
+ case "$hwmode:$crypto" in
+ *ng:TKIP|*na:TKIP) crypto="CCMP TKIP";;
+ esac
+
+ # use crypto/auth settings for building the hostapd config
+ case "$enc" in
+ *psk*)
+ config_get psk "$vif" key
+ if [ ${#psk} -eq 64 ]; then
+ append "$var" "wpa_psk=$psk" "$N"
+ else
+ append "$var" "wpa_passphrase=$psk" "$N"
+ fi
+ wps_possible=1
+ [ -n "$wpa_group_rekey" ] && append "$var" "wpa_group_rekey=$wpa_group_rekey" "$N"
+ [ -n "$wpa_pair_rekey" ] && append "$var" "wpa_ptk_rekey=$wpa_pair_rekey" "$N"
+ [ -n "$wpa_master_rekey" ] && append "$var" "wpa_gmk_rekey=$wpa_master_rekey" "$N"
+ ;;
+ *wpa*)
+ # required fields? formats?
+ # hostapd is particular, maybe a default configuration for failures
+ config_get auth_server "$vif" auth_server
+ [ -z "$auth_server" ] && config_get auth_server "$vif" server
+ append "$var" "auth_server_addr=$auth_server" "$N"
+ config_get auth_port "$vif" auth_port
+ [ -z "$auth_port" ] && config_get auth_port "$vif" port
+ auth_port=${auth_port:-1812}
+ append "$var" "auth_server_port=$auth_port" "$N"
+ config_get auth_secret "$vif" auth_secret
+ [ -z "$auth_secret" ] && config_get auth_secret "$vif" key
+ append "$var" "auth_server_shared_secret=$auth_secret" "$N"
+ config_get_bool auth_cache "$vif" auth_cache 0
+ [ "$auth_cache" -gt 0 ] || append "$var" "disable_pmksa_caching=1" "$N"
+ [ "$auth_cache" -gt 0 ] || append "$var" "okc=0" "$N"
+ config_get acct_server "$vif" acct_server
+ [ -n "$acct_server" ] && append "$var" "acct_server_addr=$acct_server" "$N"
+ config_get acct_port "$vif" acct_port
+ [ -n "$acct_port" ] && acct_port=${acct_port:-1813}
+ [ -n "$acct_port" ] && append "$var" "acct_server_port=$acct_port" "$N"
+ config_get acct_secret "$vif" acct_secret
+ [ -n "$acct_secret" ] && append "$var" "acct_server_shared_secret=$acct_secret" "$N"
+ config_get nasid "$vif" nasid
+ append "$var" "nas_identifier=$nasid" "$N"
+ append "$var" "eapol_key_index_workaround=1" "$N"
+ append "$var" "ieee8021x=1" "$N"
+ append "$var" "wpa_key_mgmt=WPA-EAP" "$N"
+ [ -n "$wpa_group_rekey" ] && append "$var" "wpa_group_rekey=$wpa_group_rekey" "$N"
+ [ -n "$wpa_pair_rekey" ] && append "$var" "wpa_ptk_rekey=$wpa_pair_rekey" "$N"
+ [ -n "$wpa_master_rekey" ] && append "$var" "wpa_gmk_rekey=$wpa_master_rekey" "$N"
+ ;;
+ *wep*)
+ config_get key "$vif" key
+ key="${key:-1}"
+ case "$key" in
+ [1234])
+ for idx in 1 2 3 4; do
+ local zidx
+ zidx=$(($idx - 1))
+ config_get ckey "$vif" "key${idx}"
+ [ -n "$ckey" ] && \
+ append "$var" "wep_key${zidx}=$(prepare_key_wep "$ckey")" "$N"
+ done
+ append "$var" "wep_default_key=$((key - 1))" "$N"
+ ;;
+ *)
+ append "$var" "wep_key0=$(prepare_key_wep "$key")" "$N"
+ append "$var" "wep_default_key=0" "$N"
+ [ -n "$wep_rekey" ] && append "$var" "wep_rekey_period=$wep_rekey" "$N"
+ ;;
+ esac
+ case "$enc" in
+ *shared*)
+ auth_algs=2
+ ;;
+ *mixed*)
+ auth_algs=3
+ ;;
+ esac
+ wpa=0
+ crypto=
+ ;;
+ *)
+ wpa=0
+ crypto=
+ ;;
+ esac
+ append "$var" "auth_algs=${auth_algs:-1}" "$N"
+ append "$var" "wpa=$wpa" "$N"
+ [ -n "$crypto" ] && append "$var" "wpa_pairwise=$crypto" "$N"
+ [ -n "$wpa_group_rekey" ] && append "$var" "wpa_group_rekey=$wpa_group_rekey" "$N"
+
+ config_get ssid "$vif" ssid
+ config_get bridge "$vif" bridge
+ config_get ieee80211d "$vif" ieee80211d
+ config_get iapp_interface "$vif" iapp_interface
+
+ config_get_bool wps_pbc "$vif" wps_pushbutton 0
+ config_get_bool wps_label "$vif" wps_label 0
+
+ config_get config_methods "$vif" wps_config
+ [ "$wps_pbc" -gt 0 ] && append config_methods push_button
+
+ [ -n "$wps_possible" -a -n "$config_methods" ] && {
+ config_get device_type "$vif" wps_device_type "6-0050F204-1"
+ config_get device_name "$vif" wps_device_name "OpenWrt AP"
+ config_get manufacturer "$vif" wps_manufacturer "openwrt.org"
+
+ append "$var" "eap_server=1" "$N"
+ append "$var" "wps_state=2" "$N"
+ append "$var" "ap_setup_locked=1" "$N"
+ append "$var" "device_type=$device_type" "$N"
+ append "$var" "device_name=$device_name" "$N"
+ append "$var" "manufacturer=$manufacturer" "$N"
+ append "$var" "config_methods=$config_methods" "$N"
+ }
+
+ append "$var" "ssid=$ssid" "$N"
+ [ -n "$bridge" ] && append "$var" "bridge=$bridge" "$N"
+ [ -n "$ieee80211d" ] && append "$var" "ieee80211d=$ieee80211d" "$N"
+ [ -n "$iapp_interface" ] && append "$var" iapp_interface=$(uci_get_state network "$iapp_interface" ifname "$iapp_interface") "$N"
+
+ if [ "$wpa" -ge "2" ]
+ then
+ # RSN -> allow preauthentication
+ config_get_bool rsn_preauth "$vif" rsn_preauth "$auth_cache"
+ if [ -n "$bridge" -a "$rsn_preauth" = 1 ]
+ then
+ append "$var" "rsn_preauth=1" "$N"
+ append "$var" "rsn_preauth_interfaces=$bridge" "$N"
+ fi
+
+ # RSN -> allow management frame protection
+ config_get ieee80211w "$vif" ieee80211w
+ case "$ieee80211w" in
+ [012])
+ append "$var" "ieee80211w=$ieee80211w" "$N"
+ [ "$ieee80211w" -gt "0" ] && {
+ config_get ieee80211w_max_timeout "$vif" ieee80211w_max_timeout
+ config_get ieee80211w_retry_timeout "$vif" ieee80211w_retry_timeout
+ [ -n "$ieee80211w_max_timeout" ] && \
+ append "$var" "assoc_sa_query_max_timeout=$ieee80211w_max_timeout" "$N"
+ [ -n "$ieee80211w_retry_timeout" ] && \
+ append "$var" "assoc_sa_query_retry_timeout=$ieee80211w_retry_timeout" "$N"
+ }
+ ;;
+ esac
+ fi
+}
+
+hostapd_set_log_options() {
+ local var="$1"
+ local cfg="$2"
+ local log_level log_80211 log_8021x log_radius log_wpa log_driver log_iapp log_mlme
+
+ config_get log_level "$cfg" log_level 2
+
+ config_get_bool log_80211 "$cfg" log_80211 1
+ config_get_bool log_8021x "$cfg" log_8021x 1
+ config_get_bool log_radius "$cfg" log_radius 1
+ config_get_bool log_wpa "$cfg" log_wpa 1
+ config_get_bool log_driver "$cfg" log_driver 1
+ config_get_bool log_iapp "$cfg" log_iapp 1
+ config_get_bool log_mlme "$cfg" 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"
+}
+
+hostapd_setup_vif() {
+ local vif="$1"
+ local driver="$2"
+ local ifname device channel hwmode
+
+ hostapd_cfg=
+
+ config_get ifname "$vif" ifname
+ config_get device "$vif" device
+ config_get channel "$device" channel
+ config_get hwmode "$device" hwmode
+
+ hostapd_set_log_options hostapd_cfg "$device"
+ hostapd_set_bss_options hostapd_cfg "$vif"
+
+ case "$hwmode" in
+ *bg|*gdt|*gst|*fh) hwmode=g;;
+ *adt|*ast) hwmode=a;;
+ esac
+ [ "$channel" = auto ] && channel=
+ [ -n "$channel" -a -z "$hwmode" ] && wifi_fixup_hwmode "$device"
+ cat > /var/run/hostapd-$ifname.conf <<EOF
+driver=$driver
+interface=$ifname
+${hwmode:+hw_mode=${hwmode#11}}
+${channel:+channel=$channel}
+$hostapd_cfg
+EOF
+ hostapd -P /var/run/wifi-$ifname.pid -B /var/run/hostapd-$ifname.conf
+}
+
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/wpa_supplicant-full.config b/package/network/services/hostapd/files/wpa_supplicant-full.config
new file mode 100644
index 0000000000..f5abbad94f
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant-full.config
@@ -0,0 +1,408 @@
+# 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 madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_MADWIFI=y
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
+
+# 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
+
+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..772e1d9809
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant-mini.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 madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_MADWIFI=y
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
+
+# 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
+
+NEED_80211_COMMON=y
diff --git a/package/network/services/hostapd/files/wpa_supplicant.sh b/package/network/services/hostapd/files/wpa_supplicant.sh
new file mode 100644
index 0000000000..928243e425
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant.sh
@@ -0,0 +1,199 @@
+wpa_supplicant_setup_vif() {
+ local vif="$1"
+ local driver="$2"
+ local key="$key"
+ local options="$3"
+ local freq=""
+ local ht="$5"
+ local ap_scan=""
+ local scan_ssid="1"
+ [ -n "$4" ] && freq="frequency=$4"
+
+ # make sure we have the encryption type and the psk
+ [ -n "$enc" ] || {
+ config_get enc "$vif" encryption
+ }
+ [ -n "$key" ] || {
+ config_get key "$vif" key
+ }
+
+ local net_cfg bridge
+ config_get bridge "$vif" bridge
+ [ -z "$bridge" ] && {
+ net_cfg="$(find_net_config "$vif")"
+ [ -z "$net_cfg" ] || bridge="$(bridge_interface "$net_cfg")"
+ config_set "$vif" bridge "$bridge"
+ }
+
+ local mode ifname wds modestr=""
+ config_get mode "$vif" mode
+ config_get ifname "$vif" ifname
+ config_get_bool wds "$vif" wds 0
+ [ -z "$bridge" ] || [ "$mode" = ap ] || [ "$mode" = sta -a $wds -eq 1 ] || {
+ echo "wpa_supplicant_setup_vif($ifname): Refusing to bridge $mode mode interface"
+ return 1
+ }
+ [ "$mode" = "adhoc" ] && {
+ modestr="mode=1"
+ scan_ssid="0"
+ ap_scan="ap_scan=2"
+ }
+
+ key_mgmt='NONE'
+ case "$enc" in
+ *none*) ;;
+ *wep*)
+ config_get key "$vif" key
+ key="${key:-1}"
+ case "$key" in
+ [1234])
+ for idx in 1 2 3 4; do
+ local zidx
+ zidx=$(($idx - 1))
+ config_get ckey "$vif" "key${idx}"
+ [ -n "$ckey" ] && \
+ append "wep_key${zidx}" "wep_key${zidx}=$(prepare_key_wep "$ckey")"
+ done
+ wep_tx_keyidx="wep_tx_keyidx=$((key - 1))"
+ ;;
+ *)
+ wep_key0="wep_key0=$(prepare_key_wep "$key")"
+ wep_tx_keyidx="wep_tx_keyidx=0"
+ ;;
+ esac
+ ;;
+ *psk*)
+ key_mgmt='WPA-PSK'
+ # if you want to use PSK with a non-nl80211 driver you
+ # have to use WPA-NONE and wext driver for wpa_s
+ [ "$mode" = "adhoc" -a "$driver" != "nl80211" ] && {
+ key_mgmt='WPA-NONE'
+ driver='wext'
+ }
+ if [ ${#key} -eq 64 ]; then
+ passphrase="psk=${key}"
+ else
+ passphrase="psk=\"${key}\""
+ fi
+ case "$enc" in
+ *psk2*)
+ proto='proto=RSN'
+ config_get ieee80211w "$vif" ieee80211w
+ ;;
+ *psk*)
+ proto='proto=WPA'
+ ;;
+ esac
+ ;;
+ *wpa*|*8021x*)
+ proto='proto=WPA2'
+ key_mgmt='WPA-EAP'
+ config_get ieee80211w "$vif" ieee80211w
+ config_get ca_cert "$vif" ca_cert
+ config_get eap_type "$vif" eap_type
+ ca_cert=${ca_cert:+"ca_cert=\"$ca_cert\""}
+ case "$eap_type" in
+ tls)
+ pairwise='pairwise=CCMP'
+ group='group=CCMP'
+ config_get identity "$vif" identity
+ config_get client_cert "$vif" client_cert
+ config_get priv_key "$vif" priv_key
+ config_get priv_key_pwd "$vif" priv_key_pwd
+ identity="identity=\"$identity\""
+ client_cert="client_cert=\"$client_cert\""
+ priv_key="private_key=\"$priv_key\""
+ priv_key_pwd="private_key_passwd=\"$priv_key_pwd\""
+ ;;
+ peap|ttls)
+ config_get auth "$vif" auth
+ config_get identity "$vif" identity
+ config_get password "$vif" password
+ phase2="phase2=\"auth=${auth:-MSCHAPV2}\""
+ identity="identity=\"$identity\""
+ password="password=\"$password\""
+ ;;
+ esac
+ eap_type="eap=$(echo $eap_type | tr 'a-z' 'A-Z')"
+ ;;
+ esac
+
+ case "$ieee80211w" in
+ [012])
+ ieee80211w="ieee80211w=$ieee80211w"
+ ;;
+ esac
+
+ local fixed_freq bssid1 beacon_interval brates mrate
+ config_get ifname "$vif" ifname
+ config_get bridge "$vif" bridge
+ config_get ssid "$vif" ssid
+ config_get bssid "$vif" bssid
+ bssid1=${bssid:+"bssid=$bssid"}
+ beacon_interval=${beacon_int:+"beacon_interval=$beacon_int"}
+
+ local br brval brsub brstr
+ [ -n "$basic_rate_list" ] && {
+ for br in $basic_rate_list; do
+ brval="$(($br / 1000))"
+ brsub="$((($br / 100) % 10))"
+ [ "$brsub" -gt 0 ] && brval="$brval.$brsub"
+ [ -n "$brstr" ] && brstr="$brstr,"
+ brstr="$brstr$brval"
+ done
+ brates=${basic_rate_list:+"rates=$brstr"}
+ }
+
+ local mcval=""
+ [ -n "$mcast_rate" ] && {
+ mcval="$(($mcast_rate / 1000))"
+ mcsub="$(( ($mcast_rate / 100) % 10 ))"
+ [ "$mcsub" -gt 0 ] && mcval="$mcval.$mcsub"
+ mrate=${mcast_rate:+"mcast_rate=$mcval"}
+ }
+
+ local ht_str
+ [ -n "$ht" ] && ht_str="htmode=$ht"
+
+ rm -rf /var/run/wpa_supplicant-$ifname
+ cat > /var/run/wpa_supplicant-$ifname.conf <<EOF
+ctrl_interface=/var/run/wpa_supplicant-$ifname
+$ap_scan
+network={
+ $modestr
+ scan_ssid=$scan_ssid
+ ssid="$ssid"
+ $bssid1
+ key_mgmt=$key_mgmt
+ $proto
+ $freq
+ ${fixed:+"fixed_freq=1"}
+ $beacon_interval
+ $brates
+ $mrate
+ $ht_str
+ $ieee80211w
+ $passphrase
+ $pairwise
+ $group
+ $eap_type
+ $ca_cert
+ $client_cert
+ $priv_key
+ $priv_key_pwd
+ $phase2
+ $identity
+ $password
+ $wep_key0
+ $wep_key1
+ $wep_key2
+ $wep_key3
+ $wep_tx_keyidx
+}
+EOF
+ if [ -n "$proto" -o "$key_mgmt" == "NONE" ]; then
+ wpa_supplicant ${bridge:+ -b $bridge} -B -P "/var/run/wifi-${ifname}.pid" -D ${driver:-wext} -i "$ifname" -c /var/run/wpa_supplicant-$ifname.conf $options
+ else
+ return 0
+ fi
+}
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..b5376cc55b
--- /dev/null
+++ b/package/network/services/hostapd/files/wps-hotplug.sh
@@ -0,0 +1,6 @@
+if [ "$ACTION" = "pressed" -a "$BUTTON" = "wps" ]; then
+ for dir in /var/run/hostapd-*; do
+ [ -d "$dir" ] || continue
+ hostapd_cli -p "$dir" wps_pbc
+ done
+fi
diff --git a/package/network/services/hostapd/patches/100-pending_work.patch b/package/network/services/hostapd/patches/100-pending_work.patch
new file mode 100644
index 0000000000..1c97a64caa
--- /dev/null
+++ b/package/network/services/hostapd/patches/100-pending_work.patch
@@ -0,0 +1,123 @@
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -1506,13 +1506,6 @@ static void handle_assoc_cb(struct hosta
+ int new_assoc = 1;
+ struct ieee80211_ht_capabilities ht_cap;
+
+- if (!ok) {
+- hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+- HOSTAPD_LEVEL_DEBUG,
+- "did not acknowledge association response");
+- return;
+- }
+-
+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+ sizeof(mgmt->u.assoc_resp))) {
+ printf("handle_assoc_cb(reassoc=%d) - too short payload "
+@@ -1520,11 +1513,6 @@ static void handle_assoc_cb(struct hosta
+ return;
+ }
+
+- if (reassoc)
+- status = le_to_host16(mgmt->u.reassoc_resp.status_code);
+- else
+- status = le_to_host16(mgmt->u.assoc_resp.status_code);
+-
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ printf("handle_assoc_cb: STA " MACSTR " not found\n",
+@@ -1532,6 +1520,19 @@ static void handle_assoc_cb(struct hosta
+ return;
+ }
+
++ if (!ok) {
++ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
++ HOSTAPD_LEVEL_DEBUG,
++ "did not acknowledge association response");
++ sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
++ return;
++ }
++
++ if (reassoc)
++ status = le_to_host16(mgmt->u.reassoc_resp.status_code);
++ else
++ status = le_to_host16(mgmt->u.assoc_resp.status_code);
++
+ if (status != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+@@ -1830,6 +1831,9 @@ void ieee802_11_rx_from_unknown(struct h
+
+ sta = ap_get_sta(hapd, src);
+ if (sta && (sta->flags & WLAN_STA_ASSOC)) {
++ if (!hapd->conf->wds_sta)
++ return;
++
+ if (wds && !(sta->flags & WLAN_STA_WDS)) {
+ wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
+ "STA " MACSTR " (aid %u)",
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -2661,10 +2661,10 @@ static int wpa_driver_nl80211_capa(struc
+ drv->data_tx_status = info.data_tx_status;
+
+ /*
+- * If poll command is supported mac80211 is new enough to
+- * have everything we need to not need monitor interfaces.
++ * If poll command and tx status are supported, mac80211 is new enough
++ * to have everything we need to not need monitor interfaces.
+ */
+- drv->use_monitor = !info.poll_command_supported;
++ drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
+
+ if (drv->device_ap_sme && drv->use_monitor) {
+ /*
+@@ -6392,8 +6392,8 @@ static int wpa_driver_nl80211_hapd_send_
+ pos = (u8 *) (hdr + 1);
+
+ if (qos) {
+- /* add an empty QoS header if needed */
+- pos[0] = 0;
++ /* Set highest priority in QoS header */
++ pos[0] = 7;
+ pos[1] = 0;
+ pos += 2;
+ }
+@@ -7698,6 +7698,10 @@ static int i802_set_wds_sta(void *priv,
+ }
+ return i802_set_sta_vlan(priv, addr, name, 0);
+ } else {
++ if (bridge_ifname)
++ linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
++ name);
++
+ i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+ return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+ name);
+@@ -8065,7 +8069,12 @@ static int wpa_driver_nl80211_if_remove(
+ if (ifindex <= 0)
+ return -1;
+
++ nl80211_remove_iface(drv, ifindex);
++
+ #ifdef HOSTAPD
++ if (type != WPA_IF_AP_BSS)
++ return 0;
++
+ if (bss->added_if_into_bridge) {
+ if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+ bss->ifname) < 0)
+@@ -8079,13 +8088,6 @@ static int wpa_driver_nl80211_if_remove(
+ "bridge %s: %s",
+ bss->brname, strerror(errno));
+ }
+-#endif /* HOSTAPD */
+-
+- nl80211_remove_iface(drv, ifindex);
+-
+-#ifdef HOSTAPD
+- if (type != WPA_IF_AP_BSS)
+- return 0;
+
+ if (bss != &drv->first_bss) {
+ struct i802_bss *tbss;
diff --git a/package/network/services/hostapd/patches/300-nl80211_multicall_fixes.patch b/package/network/services/hostapd/patches/300-nl80211_multicall_fixes.patch
new file mode 100644
index 0000000000..1d2519a937
--- /dev/null
+++ b/package/network/services/hostapd/patches/300-nl80211_multicall_fixes.patch
@@ -0,0 +1,60 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -2988,6 +2988,7 @@ static void * wpa_driver_nl80211_init(vo
+ drv->monitor_sock = -1;
+ drv->eapol_tx_sock = -1;
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
++ drv->nlmode = NL80211_IFTYPE_STATION;
+
+ if (wpa_driver_nl80211_init_nl(drv)) {
+ os_free(drv);
+@@ -3302,17 +3303,12 @@ static void wpa_driver_nl80211_send_rfki
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+ }
+
+-
+ static int
+-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
++wpa_driver_nl80211_finish_drv_init_sta(struct wpa_driver_nl80211_data *drv,
++ int *send_rfkill_event)
+ {
+ struct i802_bss *bss = &drv->first_bss;
+- int send_rfkill_event = 0;
+
+- drv->ifindex = if_nametoindex(bss->ifname);
+- drv->first_bss.ifindex = drv->ifindex;
+-
+-#ifndef HOSTAPD
+ /*
+ * Make sure the interface starts up in station mode unless this is a
+ * dynamically added interface (e.g., P2P) that was already configured
+@@ -3331,7 +3327,7 @@ wpa_driver_nl80211_finish_drv_init(struc
+ "interface '%s' due to rfkill",
+ bss->ifname);
+ drv->if_disabled = 1;
+- send_rfkill_event = 1;
++ *send_rfkill_event = 1;
+ } else {
+ wpa_printf(MSG_ERROR, "nl80211: Could not set "
+ "interface '%s' UP", bss->ifname);
+@@ -3341,7 +3337,19 @@ wpa_driver_nl80211_finish_drv_init(struc
+
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
+-#endif /* HOSTAPD */
++}
++
++static int
++wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
++{
++ struct i802_bss *bss = &drv->first_bss;
++ int send_rfkill_event = 0;
++
++ drv->ifindex = if_nametoindex(bss->ifname);
++ drv->first_bss.ifindex = drv->ifindex;
++
++ if (drv->nlmode == NL80211_IFTYPE_STATION)
++ wpa_driver_nl80211_finish_drv_init_sta(drv, &send_rfkill_event);
+
+ if (wpa_driver_nl80211_capa(drv))
+ return -1;
diff --git a/package/network/services/hostapd/patches/310-multicall_bridge_fix.patch b/package/network/services/hostapd/patches/310-multicall_bridge_fix.patch
new file mode 100644
index 0000000000..59bfe5177a
--- /dev/null
+++ b/package/network/services/hostapd/patches/310-multicall_bridge_fix.patch
@@ -0,0 +1,45 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -893,6 +893,10 @@ static void wpa_driver_nl80211_event_rtm
+ return;
+ }
+
++ if (ifi->ifi_family == AF_BRIDGE &&
++ drv->nlmode != NL80211_IFTYPE_AP)
++ return;
++
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+@@ -1000,6 +1004,10 @@ static void wpa_driver_nl80211_event_rtm
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
++ if (ifi->ifi_family == AF_BRIDGE &&
++ drv->nlmode != NL80211_IFTYPE_AP)
++ return;
++
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+@@ -2990,6 +2998,11 @@ static void * wpa_driver_nl80211_init(vo
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ drv->nlmode = NL80211_IFTYPE_STATION;
+
++#ifdef HOSTAPD
++ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
++ drv->if_indices = drv->default_if_indices;
++#endif
++
+ if (wpa_driver_nl80211_init_nl(drv)) {
+ os_free(drv);
+ return NULL;
+@@ -7819,8 +7832,6 @@ static void *i802_init(struct hostapd_da
+ br_ifindex = 0;
+ }
+
+- drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+- drv->if_indices = drv->default_if_indices;
+ for (i = 0; i < params->num_bridge; i++) {
+ if (params->bridge[i]) {
+ ifindex = if_nametoindex(params->bridge[i]);
diff --git a/package/network/services/hostapd/patches/320-madwifi_key_fixes.patch b/package/network/services/hostapd/patches/320-madwifi_key_fixes.patch
new file mode 100644
index 0000000000..45a7ac6c83
--- /dev/null
+++ b/package/network/services/hostapd/patches/320-madwifi_key_fixes.patch
@@ -0,0 +1,34 @@
+--- a/src/drivers/driver_madwifi.c
++++ b/src/drivers/driver_madwifi.c
+@@ -453,7 +453,9 @@ wpa_driver_madwifi_set_key(const char *i
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+- wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
++ wk.ik_flags = IEEE80211_KEY_RECV;
++ if (set_tx)
++ wk.ik_flags |= IEEE80211_KEY_XMIT;
+ if (addr == NULL || is_broadcast_ether_addr(addr)) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+@@ -465,6 +467,20 @@ wpa_driver_madwifi_set_key(const char *i
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
++#ifdef WORDS_BIGENDIAN
++#define WPA_KEY_RSC_LEN 8
++ {
++ size_t i;
++ u8 tmp[WPA_KEY_RSC_LEN];
++ os_memset(tmp, 0, sizeof(tmp));
++ for (i = 0; i < seq_len; i++)
++ tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
++ os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
++ }
++#else /* WORDS_BIGENDIAN */
++ os_memcpy(&wk.ik_keyrsc, seq, seq_len);
++#endif /* WORDS_BIGENDIAN */
++
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
diff --git a/package/network/services/hostapd/patches/400-noscan.patch b/package/network/services/hostapd/patches/400-noscan.patch
new file mode 100644
index 0000000000..69d026b3da
--- /dev/null
+++ b/package/network/services/hostapd/patches/400-noscan.patch
@@ -0,0 +1,32 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2485,6 +2485,8 @@ 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, "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
+@@ -497,6 +497,7 @@ struct hostapd_config {
+
+ int ht_op_mode_fixed;
+ u16 ht_capab;
++ int noscan;
+ int ieee80211n;
+ int secondary_channel;
+ int require_ht;
+--- a/src/ap/hw_features.c
++++ b/src/ap/hw_features.c
+@@ -493,7 +493,7 @@ static int ieee80211n_check_40mhz(struct
+ {
+ struct wpa_driver_scan_params params;
+
+- if (!iface->conf->secondary_channel)
++ if (!iface->conf->secondary_channel || iface->conf->noscan)
+ return 0; /* HT40 not used */
+
+ wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
diff --git a/package/network/services/hostapd/patches/410-multicall.patch b/package/network/services/hostapd/patches/410-multicall.patch
new file mode 100644
index 0000000000..7900428aea
--- /dev/null
+++ b/package/network/services/hostapd/patches/410-multicall.patch
@@ -0,0 +1,246 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -14,6 +14,7 @@ CFLAGS += -I../src/utils
+ # CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
+
+ -include .config
++-include $(if $(MULTICALL), ../wpa_supplicant/.config)
+
+ ifndef CONFIG_OS
+ ifdef CONFIG_NATIVE_WINDOWS
+@@ -188,10 +189,14 @@ ifdef CONFIG_IEEE80211AC
+ CFLAGS += -DCONFIG_IEEE80211AC
+ 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
+@@ -867,6 +872,12 @@ install: all
+
+ 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 " $@
+@@ -905,6 +916,12 @@ HOBJS += ../src/crypto/aes-internal.o
+ HOBJS += ../src/crypto/aes-internal-enc.o
+ endif
+
++dump_cflags:
++ @echo -n $(CFLAGS) " "
++
++dump_ldflags:
++ @echo -n $(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
+@@ -14,6 +14,7 @@ CFLAGS += -I../src
+ CFLAGS += -I../src/utils
+
+ -include .config
++-include $(if $(MULTICALL),../hostapd/.config)
+
+ BINALL=wpa_supplicant wpa_cli
+
+@@ -705,6 +706,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_AP
+@@ -713,9 +718,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
+@@ -770,10 +777,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
+@@ -1515,6 +1530,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 " $@
+@@ -1585,6 +1606,12 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2.
+ %@.service: %.service.arg.in
+ sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
++dump_cflags:
++ @echo -n $(CFLAGS) " "
++
++dump_ldflags:
++ @echo -n $(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
+@@ -3686,8 +3686,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);
+
+
+ /*
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -685,8 +685,8 @@ static void hostapd_event_eapol_rx(struc
+ }
+
+
+-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
+--- a/wpa_supplicant/wpa_priv.c
++++ b/wpa_supplicant/wpa_priv.c
+@@ -819,8 +819,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;
+
+@@ -962,6 +962,7 @@ int main(int argc, char *argv[])
+ if (os_program_init())
+ return -1;
+
++ wpa_supplicant_event = supplicant_event;
+ wpa_priv_fd_workaround();
+
+ for (;;) {
+--- a/wpa_supplicant/events.c
++++ b/wpa_supplicant/events.c
+@@ -2258,8 +2258,8 @@ static void wnm_action_rx(struct wpa_sup
+ }
+
+
+-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;
+ u16 reason_code = 0;
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -2921,6 +2921,9 @@ static void wpa_supplicant_deinit_iface(
+ }
+ }
+
++extern void supplicant_event(void *ctx, enum wpa_event_type event,
++ union wpa_event_data *data);
++
+
+ /**
+ * wpa_supplicant_add_iface - Add a new network interface
+@@ -3113,6 +3116,7 @@ struct wpa_global * wpa_supplicant_init(
+ wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
+ #endif /* CONFIG_NO_WPA_MSG */
+
++ wpa_supplicant_event = supplicant_event;
+ wpa_debug_open_file(params->wpa_debug_file_path);
+ if (params->wpa_debug_syslog)
+ wpa_debug_open_syslog();
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -530,6 +530,9 @@ static int hostapd_get_global_ctrl_iface
+ return 0;
+ }
+
++void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
++ union wpa_event_data *data);
++
+
+ int main(int argc, char *argv[])
+ {
+@@ -555,6 +558,7 @@ int main(int argc, char *argv[])
+ interfaces.global_iface_name = NULL;
+ interfaces.global_ctrl_sock = -1;
+
++ wpa_supplicant_event = hostapd_wpa_event;
+ for (;;) {
+ c = getopt(argc, argv, "Bde:f:hKP:tvg:");
+ if (c < 0)
+--- a/src/drivers/drivers.c
++++ b/src/drivers/drivers.c
+@@ -7,7 +7,11 @@
+ */
+
+ #include "includes.h"
++#include "common.h"
++#include "driver.h"
+
++void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event,
++ union wpa_event_data *data);
+
+ #ifdef CONFIG_DRIVER_WEXT
+ extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
diff --git a/package/network/services/hostapd/patches/420-timestamp_check.patch b/package/network/services/hostapd/patches/420-timestamp_check.patch
new file mode 100644
index 0000000000..b2d4a05115
--- /dev/null
+++ b/package/network/services/hostapd/patches/420-timestamp_check.patch
@@ -0,0 +1,12 @@
+--- a/src/tls/x509v3.c
++++ b/src/tls/x509v3.c
+@@ -1848,6 +1848,9 @@ int x509_certificate_chain_validate(stru
+ if (chain_trusted)
+ continue;
+
++#ifdef NO_TIMESTAMP_CHECK
++ disable_time_checks = 1;
++#endif
+ if (!disable_time_checks &&
+ ((unsigned long) now.sec <
+ (unsigned long) cert->not_before ||
diff --git a/package/network/services/hostapd/patches/430-rescan_immediately.patch b/package/network/services/hostapd/patches/430-rescan_immediately.patch
new file mode 100644
index 0000000000..51d41f8001
--- /dev/null
+++ b/package/network/services/hostapd/patches/430-rescan_immediately.patch
@@ -0,0 +1,11 @@
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -2388,7 +2388,7 @@ static struct wpa_supplicant * wpa_suppl
+ if (wpa_s == NULL)
+ return NULL;
+ wpa_s->scan_req = 1;
+- wpa_s->scan_interval = 5;
++ wpa_s->scan_interval = 1;
+ wpa_s->new_connection = 1;
+ wpa_s->parent = wpa_s;
+ wpa_s->sched_scanning = 0;
diff --git a/package/network/services/hostapd/patches/440-optional_rfkill.patch b/package/network/services/hostapd/patches/440-optional_rfkill.patch
new file mode 100644
index 0000000000..be18458b24
--- /dev/null
+++ b/package/network/services/hostapd/patches/440-optional_rfkill.patch
@@ -0,0 +1,261 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -218,7 +218,9 @@ struct wpa_driver_nl80211_data {
+ int if_removed;
+ int if_disabled;
+ int ignore_if_down_event;
++#ifdef CONFIG_RFKILL
+ struct rfkill_data *rfkill;
++#endif
+ struct wpa_driver_capa capa;
+ int has_capability;
+
+@@ -2828,7 +2830,7 @@ static int wpa_driver_nl80211_init_nl(st
+ return 0;
+ }
+
+-
++#ifdef CONFIG_RFKILL
+ static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
+ {
+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
+@@ -2851,6 +2853,7 @@ static void wpa_driver_nl80211_rfkill_un
+ }
+ /* rtnetlink ifup handler will report interface as enabled */
+ }
++#endif /* CONFIG_RFKILL */
+
+
+ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
+@@ -2979,7 +2982,9 @@ static void * wpa_driver_nl80211_init(vo
+ void *global_priv)
+ {
+ struct wpa_driver_nl80211_data *drv;
++#ifdef CONFIG_RFKILL
+ struct rfkill_config *rcfg;
++#endif
+ struct i802_bss *bss;
+
+ if (global_priv == NULL)
+@@ -3013,6 +3018,7 @@ static void * wpa_driver_nl80211_init(vo
+
+ nl80211_get_phy_name(drv);
+
++#ifdef CONFIG_RFKILL
+ rcfg = os_zalloc(sizeof(*rcfg));
+ if (rcfg == NULL)
+ goto failed;
+@@ -3025,6 +3031,7 @@ static void * wpa_driver_nl80211_init(vo
+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
+ os_free(rcfg);
+ }
++#endif /* CONFIG_RFKILL */
+
+ if (wpa_driver_nl80211_finish_drv_init(drv))
+ goto failed;
+@@ -3311,10 +3318,12 @@ static void nl80211_mgmt_unsubscribe(str
+ }
+
+
++#ifdef CONFIG_RFKILL
+ static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+ {
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+ }
++#endif /* CONFIG_RFKILL */
+
+ static int
+ wpa_driver_nl80211_finish_drv_init_sta(struct wpa_driver_nl80211_data *drv,
+@@ -3335,13 +3344,16 @@ wpa_driver_nl80211_finish_drv_init_sta(s
+ }
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
++#ifdef CONFIG_RFKILL
+ if (rfkill_is_blocked(drv->rfkill)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
+ "interface '%s' due to rfkill",
+ bss->ifname);
+ drv->if_disabled = 1;
+ *send_rfkill_event = 1;
+- } else {
++ } else
++#endif
++ {
+ wpa_printf(MSG_ERROR, "nl80211: Could not set "
+ "interface '%s' UP", bss->ifname);
+ return -1;
+@@ -3372,8 +3384,10 @@ wpa_driver_nl80211_finish_drv_init(struc
+ return -1;
+
+ if (send_rfkill_event) {
++#ifdef CONFIG_RFKILL
+ eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
+ drv, drv->ctx);
++#endif
+ }
+
+ return 0;
+@@ -3460,7 +3474,9 @@ static void wpa_driver_nl80211_deinit(vo
+
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+ IF_OPER_UP);
++#ifdef CONFIG_RFKILL
+ rfkill_deinit(drv->rfkill);
++#endif
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+--- a/src/drivers/driver_wext.c
++++ b/src/drivers/driver_wext.c
+@@ -742,7 +742,7 @@ static void wpa_driver_wext_event_rtm_de
+ }
+ }
+
+-
++#ifdef CONFIG_RFKILL
+ static void wpa_driver_wext_rfkill_blocked(void *ctx)
+ {
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
+@@ -764,7 +764,7 @@ static void wpa_driver_wext_rfkill_unblo
+ }
+ /* rtnetlink ifup handler will report interface as enabled */
+ }
+-
++#endif /* CONFIG_RFKILL */
+
+ static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
+ {
+@@ -810,7 +810,9 @@ void * wpa_driver_wext_init(void *ctx, c
+ {
+ struct wpa_driver_wext_data *drv;
+ struct netlink_config *cfg;
++#ifdef CONFIG_RFKILL
+ struct rfkill_config *rcfg;
++#endif
+ char path[128];
+ struct stat buf;
+
+@@ -845,6 +847,7 @@ void * wpa_driver_wext_init(void *ctx, c
+ goto err2;
+ }
+
++#ifdef CONFIG_RFKILL
+ rcfg = os_zalloc(sizeof(*rcfg));
+ if (rcfg == NULL)
+ goto err3;
+@@ -857,6 +860,7 @@ void * wpa_driver_wext_init(void *ctx, c
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
+ os_free(rcfg);
+ }
++#endif /* CONFIG_RFKILL */
+
+ drv->mlme_sock = -1;
+
+@@ -874,7 +878,9 @@ void * wpa_driver_wext_init(void *ctx, c
+ return drv;
+
+ err3:
++#ifdef CONFIG_RFKILL
+ rfkill_deinit(drv->rfkill);
++#endif
+ netlink_deinit(drv->netlink);
+ err2:
+ close(drv->ioctl_sock);
+@@ -884,10 +890,12 @@ err1:
+ }
+
+
++#ifdef CONFIG_RFKILL
+ static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+ {
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+ }
++#endif /* CONFIG_RFKILL */
+
+
+ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+@@ -895,13 +903,16 @@ static int wpa_driver_wext_finish_drv_in
+ int send_rfkill_event = 0;
+
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) {
++#ifdef CONFIG_RFKILL
+ if (rfkill_is_blocked(drv->rfkill)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable "
+ "interface '%s' due to rfkill",
+ drv->ifname);
+ drv->if_disabled = 1;
+ send_rfkill_event = 1;
+- } else {
++ } else
++#endif
++ {
+ wpa_printf(MSG_ERROR, "WEXT: Could not set "
+ "interface '%s' UP", drv->ifname);
+ return -1;
+@@ -949,8 +960,10 @@ static int wpa_driver_wext_finish_drv_in
+ 1, IF_OPER_DORMANT);
+
+ if (send_rfkill_event) {
++#ifdef CONFIG_RFKILL
+ eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill,
+ drv, drv->ctx);
++#endif
+ }
+
+ return 0;
+@@ -980,7 +993,9 @@ void wpa_driver_wext_deinit(void *priv)
+
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+ netlink_deinit(drv->netlink);
++#ifdef CONFIG_RFKILL
+ rfkill_deinit(drv->rfkill);
++#endif
+
+ if (drv->mlme_sock >= 0)
+ eloop_unregister_read_sock(drv->mlme_sock);
+--- a/src/drivers/drivers.mak
++++ b/src/drivers/drivers.mak
+@@ -25,7 +25,6 @@ NEED_SME=y
+ NEED_AP_MLME=y
+ NEED_NETLINK=y
+ NEED_LINUX_IOCTL=y
+-NEED_RFKILL=y
+
+ ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+@@ -101,7 +100,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
+@@ -127,7 +125,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
+@@ -140,6 +137,7 @@ endif
+
+ ifdef NEED_RFKILL
+ DRV_OBJS += ../src/drivers/rfkill.o
++DRV_WPA_CFLAGS += -DCONFIG_RFKILL
+ endif
+
+ ifdef CONFIG_VLAN_NETLINK
+--- a/src/drivers/driver_wext.h
++++ b/src/drivers/driver_wext.h
+@@ -22,7 +22,9 @@ struct wpa_driver_wext_data {
+ int ifindex2;
+ int if_removed;
+ int if_disabled;
++#ifdef CONFIG_RFKILL
+ struct rfkill_data *rfkill;
++#endif
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
diff --git a/package/network/services/hostapd/patches/450-reload_freq_change.patch b/package/network/services/hostapd/patches/450-reload_freq_change.patch
new file mode 100644
index 0000000000..f11593fcd5
--- /dev/null
+++ b/package/network/services/hostapd/patches/450-reload_freq_change.patch
@@ -0,0 +1,23 @@
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -140,6 +140,20 @@ int hostapd_reload_config(struct hostapd
+ oldconf = hapd->iconf;
+ iface->conf = newconf;
+
++ hostapd_select_hw_mode(iface);
++ iface->freq = hostapd_hw_get_freq(hapd, newconf->channel);
++
++ if (hostapd_set_freq(hapd, newconf->hw_mode, iface->freq,
++ newconf->channel,
++ newconf->ieee80211n,
++ newconf->secondary_channel)) {
++ wpa_printf(MSG_ERROR, "Could not set channel for "
++ "kernel driver");
++ }
++
++ if (iface->current_mode)
++ hostapd_prepare_rates(iface, iface->current_mode);
++
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ hapd->iconf = newconf;
diff --git a/package/network/services/hostapd/patches/451-nl80211_del_beacon_bss.patch b/package/network/services/hostapd/patches/451-nl80211_del_beacon_bss.patch
new file mode 100644
index 0000000000..801b78b124
--- /dev/null
+++ b/package/network/services/hostapd/patches/451-nl80211_del_beacon_bss.patch
@@ -0,0 +1,63 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -3394,16 +3394,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_bss_beacon(struct i802_bss *bss)
+ {
++ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
++ bss->beacon_set = 0;
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
+- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+@@ -3411,6 +3413,21 @@ static int wpa_driver_nl80211_del_beacon
+ return -ENOBUFS;
+ }
+
++static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
++{
++ struct i802_bss *bss;
++
++ for (bss = &drv->first_bss; bss; bss = bss->next)
++ wpa_driver_nl80211_del_bss_beacon(bss);
++
++ return 0;
++}
++
++static int wpa_driver_nl80211_stop_ap(void *priv)
++{
++ struct i802_bss *bss = priv;
++ return wpa_driver_nl80211_del_beacon(bss->drv);
++}
+
+ /**
+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
+@@ -9238,4 +9255,5 @@ const struct wpa_driver_ops wpa_driver_n
+ .send_tdls_mgmt = nl80211_send_tdls_mgmt,
+ .tdls_oper = nl80211_tdls_oper,
+ #endif /* CONFIG_TDLS */
++ .stop_ap = wpa_driver_nl80211_stop_ap,
+ };
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -2053,6 +2053,9 @@ struct wpa_driver_ops {
+ */
+ int (*probe_req_report)(void *priv, int report);
+
++
++ int (*stop_ap)(void *priv);
++
+ /**
+ * deinit_ap - Deinitialize AP mode
+ * @priv: Private driver interface data
diff --git a/package/network/services/hostapd/patches/452-ctrl_iface_reload.patch b/package/network/services/hostapd/patches/452-ctrl_iface_reload.patch
new file mode 100644
index 0000000000..81dcfedde5
--- /dev/null
+++ b/package/network/services/hostapd/patches/452-ctrl_iface_reload.patch
@@ -0,0 +1,98 @@
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -33,6 +33,7 @@
+ #include "wps/wps.h"
+ #include "config_file.h"
+ #include "ctrl_iface.h"
++#include "config_file.h"
+
+
+ struct wpa_ctrl_dst {
+@@ -43,6 +44,7 @@ struct wpa_ctrl_dst {
+ int errors;
+ };
+
++static char *reload_opts = NULL;
+
+ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ const char *buf, size_t len);
+@@ -152,6 +154,68 @@ static int hostapd_ctrl_iface_new_sta(st
+ return 0;
+ }
+
++static int hostapd_ctrl_iface_set_down(struct hostapd_data *hapd)
++{
++ if (hapd->driver->stop_ap)
++ hapd->driver->stop_ap(hapd->drv_priv);
++ 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
+@@ -864,6 +928,10 @@ static void hostapd_ctrl_iface_receive(i
+ reply_len += res;
+ }
+ #endif /* CONFIG_NO_RADIUS */
++ } else if (os_strcmp(buf, "DOWN") == 0) {
++ hostapd_ctrl_iface_set_down(hapd);
++ } else if (os_strncmp(buf, "UPDATE ", 7) == 0) {
++ hostapd_ctrl_iface_update(hapd, buf + 7);
+ } else if (os_strcmp(buf, "STA-FIRST") == 0) {
+ reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+ reply_size);
diff --git a/package/network/services/hostapd/patches/453-ap_sta_support.patch b/package/network/services/hostapd/patches/453-ap_sta_support.patch
new file mode 100644
index 0000000000..4b6c0f1646
--- /dev/null
+++ b/package/network/services/hostapd/patches/453-ap_sta_support.patch
@@ -0,0 +1,221 @@
+--- a/wpa_supplicant/wpa_supplicant_i.h
++++ b/wpa_supplicant/wpa_supplicant_i.h
+@@ -95,6 +95,8 @@ struct wpa_interface {
+ * receiving of EAPOL frames from an additional interface.
+ */
+ const char *bridge_ifname;
++
++ const char *hostapd_ctrl;
+ };
+
+ /**
+@@ -294,6 +296,8 @@ struct wpa_supplicant {
+ #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+ char bridge_ifname[16];
+
++ struct wpa_ctrl *hostapd;
++
+ char *confname;
+ struct wpa_config *conf;
+ int countermeasures;
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -13,6 +13,10 @@ PKG_CONFIG ?= pkg-config
+ CFLAGS += -I../src
+ CFLAGS += -I../src/utils
+
++ifdef MULTICALL
++CFLAGS += -DMULTICALL
++endif
++
+ -include .config
+ -include $(if $(MULTICALL),../hostapd/.config)
+
+@@ -76,6 +80,10 @@ OBJS_c = wpa_cli.o ../src/common/wpa_ctr
+ OBJS_c += ../src/utils/wpa_debug.o
+ OBJS_c += ../src/utils/common.o
+
++ifdef MULTICALL
++OBJS += ../src/common/wpa_ctrl.o
++endif
++
+ ifndef CONFIG_OS
+ ifdef CONFIG_NATIVE_WINDOWS
+ CONFIG_OS=win32
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -107,6 +107,55 @@ extern int wpa_debug_show_keys;
+ extern int wpa_debug_timestamp;
+ extern struct wpa_driver_ops *wpa_drivers[];
+
++#ifdef MULTICALL
++static int hostapd_stop(struct wpa_supplicant *wpa_s)
++{
++ const char *cmd = "DOWN";
++ char buf[256];
++ int 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];
++ int len = sizeof(buf);
++ int channel, hw_mode;
++ int ret;
++
++ if (!bss)
++ return;
++
++ if (bss->freq < 4000) {
++ hw_mode = HOSTAPD_MODE_IEEE80211G;
++ channel = (bss->freq - 2407) / 5;
++ } else {
++ hw_mode = HOSTAPD_MODE_IEEE80211A;
++ channel = (bss->freq - 5000) / 5;
++ }
++
++ if (asprintf(&cmd, "UPDATE channel=%d sec_chan=0 hw_mode=%d ieee80211n=%d",
++ channel, hw_mode, !!bss->ht_capab) < 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;
++}
++#endif
++
+ /* Configure default/group WEP keys for static WEP */
+ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+ {
+@@ -672,8 +721,16 @@ void wpa_supplicant_set_state(struct wpa
+ #endif /* CONFIG_P2P */
+
+ sme_sched_obss_scan(wpa_s, 1);
++#ifdef MULTICALL
++ if (wpa_s->hostapd)
++ hostapd_reload(wpa_s, wpa_s->current_bss);
++#endif
+ } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
+ state == WPA_ASSOCIATED) {
++#ifdef MULTICALL
++ if (wpa_s->hostapd)
++ hostapd_stop(wpa_s);
++#endif
+ wpa_s->new_connection = 1;
+ wpa_drv_set_operstate(wpa_s, 0);
+ #ifndef IEEE8021X_EAPOL
+@@ -2727,6 +2784,21 @@ static int wpa_supplicant_init_iface(str
+ os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
+ sizeof(wpa_s->bridge_ifname));
+ }
++#ifdef MULTICALL
++ if (iface->hostapd_ctrl) {
++ char *cmd = "DOWN";
++ 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;
++ }
++#endif
+
+ /* RSNA Supplicant Key Management - INITIALIZE */
+ eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+--- 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 "wpa_supplicant_i.h"
+ #include "config.h"
+@@ -139,6 +140,8 @@ struct wpa_bss * wpa_bss_get(struct wpa_
+
+ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+ {
++ struct ieee80211_ht_capabilities *capab;
++ struct ieee802_11_elems elems;
+ os_time_t usec;
+
+ dst->flags = src->flags;
+@@ -151,6 +154,12 @@ static void wpa_bss_copy_res(struct wpa_
+ dst->level = src->level;
+ dst->tsf = src->tsf;
+
++ 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;
++ if (capab)
++ dst->ht_capab = le_to_host16(capab->ht_capabilities_info);
++
+ os_get_time(&dst->last_update);
+ dst->last_update.sec -= src->age / 1000;
+ usec = (src->age % 1000) * 1000;
+--- a/wpa_supplicant/bss.h
++++ b/wpa_supplicant/bss.h
+@@ -72,6 +72,7 @@ struct wpa_bss {
+ u8 bssid[ETH_ALEN];
+ u8 hessid[ETH_ALEN];
+ u8 ssid[32];
++ u16 ht_capab;
+ size_t ssid_len;
+ int freq;
+ u16 beacon_int;
+--- a/wpa_supplicant/main.c
++++ b/wpa_supplicant/main.c
+@@ -25,7 +25,7 @@ static void usage(void)
+ "usage:\n"
+ " wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
+ "[-g<global ctrl>] \\\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>] [-f<debug file>] [-e<entropy file>] "
+ "\\\n"
+@@ -67,6 +67,7 @@ static void usage(void)
+ #endif /* CONFIG_DEBUG_LINUX_TRACING */
+ printf(" -t = include timestamp in debug messages\n"
+ " -h = show this help text\n"
++ " -H = connect to a hostapd instance to manage state changes\n"
+ " -L = show license (BSD)\n"
+ " -o = override driver parameter for new interfaces\n"
+ " -O = override ctrl_interface parameter for new interfaces\n"
+@@ -155,7 +156,7 @@ int main(int argc, char *argv[])
+
+ for (;;) {
+ c = getopt(argc, argv,
+- "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
++ "b:Bc:C:D:de:f:g:hH:i:KLNo:O:p:P:qsTtuvW");
+ if (c < 0)
+ break;
+ switch (c) {
+@@ -199,6 +200,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;
diff --git a/package/network/services/hostapd/patches/460-disable_ctrl_iface_mib.patch b/package/network/services/hostapd/patches/460-disable_ctrl_iface_mib.patch
new file mode 100644
index 0000000000..2f03179a0a
--- /dev/null
+++ b/package/network/services/hostapd/patches/460-disable_ctrl_iface_mib.patch
@@ -0,0 +1,168 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -135,6 +135,9 @@ endif
+ ifdef CONFIG_NO_CTRL_IFACE
+ CFLAGS += -DCONFIG_NO_CTRL_IFACE
+ else
++ifdef CONFIG_CTRL_IFACE_MIB
++CFLAGS += -DCONFIG_CTRL_IFACE_MIB
++endif
+ OBJS += ctrl_iface.o
+ OBJS += ../src/ap/ctrl_iface_ap.o
+ endif
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -899,6 +899,7 @@ static void hostapd_ctrl_iface_receive(i
+ } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+ if (wpa_debug_reopen_file() < 0)
+ reply_len = -1;
++#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) {
+@@ -928,10 +929,12 @@ static void hostapd_ctrl_iface_receive(i
+ reply_len += res;
+ }
+ #endif /* CONFIG_NO_RADIUS */
++#endif
+ } else if (os_strcmp(buf, "DOWN") == 0) {
+ hostapd_ctrl_iface_set_down(hapd);
+ } else if (os_strncmp(buf, "UPDATE ", 7) == 0) {
+ hostapd_ctrl_iface_update(hapd, buf + 7);
++#ifdef CONFIG_CTRL_IFACE_MIB
+ } else if (os_strcmp(buf, "STA-FIRST") == 0) {
+ reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+ reply_size);
+@@ -941,6 +944,7 @@ static void hostapd_ctrl_iface_receive(i
+ } 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
+@@ -751,6 +751,9 @@ ifdef CONFIG_IEEE80211N
+ OBJS += ../src/ap/ieee802_11_ht.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
+@@ -4382,6 +4382,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) {
+@@ -4393,6 +4394,7 @@ char * wpa_supplicant_ctrl_iface_process
+ else
+ reply_len += res;
+ }
++#endif
+ } else if (os_strncmp(buf, "STATUS", 6) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_status(
+ wpa_s, buf + 6, reply, reply_size);
+@@ -4792,6 +4794,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) {
+@@ -4800,6 +4803,7 @@ 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
+ } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+ if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+ reply_len = -1;
+--- a/src/ap/ctrl_iface_ap.c
++++ b/src/ap/ctrl_iface_ap.c
+@@ -20,6 +20,7 @@
+ #include "ctrl_iface_ap.h"
+ #include "ap_drv_ops.h"
+
++#ifdef CONFIG_CTRL_IFACE_MIB
+
+ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
+ struct sta_info *sta,
+@@ -103,6 +104,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,
+@@ -269,3 +271,4 @@ int hostapd_ctrl_iface_disassociate(stru
+
+ return 0;
+ }
++
+--- a/src/ap/ieee802_1x.c
++++ b/src/ap/ieee802_1x.c
+@@ -2034,6 +2034,7 @@ static const char * bool_txt(Boolean boo
+ return bool ? "TRUE" : "FALSE";
+ }
+
++#ifdef CONFIG_CTRL_IFACE_MIB
+
+ int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+ {
+@@ -2186,6 +2187,7 @@ int ieee802_1x_get_mib_sta(struct hostap
+ return len;
+ }
+
++#endif
+
+ static void ieee802_1x_finished(struct hostapd_data *hapd,
+ struct sta_info *sta, int success)
+--- a/src/ap/wpa_auth.c
++++ b/src/ap/wpa_auth.c
+@@ -2729,6 +2729,7 @@ static const char * wpa_bool_txt(int boo
+ return bool ? "TRUE" : "FALSE";
+ }
+
++#ifdef CONFIG_CTRL_IFACE_MIB
+
+ #define RSN_SUITE "%02x-%02x-%02x-%d"
+ #define RSN_SUITE_ARG(s) \
+@@ -2873,7 +2874,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
+@@ -1844,6 +1844,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
+@@ -1927,6 +1929,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch
+
+ return (int) len;
+ }
++#endif
+ #endif /* CONFIG_CTRL_IFACE */
+
+
diff --git a/package/network/services/hostapd/patches/470-wpa_ie_cap_workaround.patch b/package/network/services/hostapd/patches/470-wpa_ie_cap_workaround.patch
new file mode 100644
index 0000000000..00a32229d4
--- /dev/null
+++ b/package/network/services/hostapd/patches/470-wpa_ie_cap_workaround.patch
@@ -0,0 +1,56 @@
+--- a/src/common/wpa_common.c
++++ b/src/common/wpa_common.c
+@@ -959,6 +959,31 @@ const char * wpa_key_mgmt_txt(int key_mg
+ }
+
+
++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)
+@@ -966,8 +991,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/480-terminate_on_setup_failure.patch b/package/network/services/hostapd/patches/480-terminate_on_setup_failure.patch
new file mode 100644
index 0000000000..6168a5cfc3
--- /dev/null
+++ b/package/network/services/hostapd/patches/480-terminate_on_setup_failure.patch
@@ -0,0 +1,81 @@
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -886,11 +886,8 @@ int hostapd_setup_interface_complete(str
+ size_t j;
+ u8 *prev_addr;
+
+- if (err) {
+- wpa_printf(MSG_ERROR, "Interface initialization failed");
+- eloop_terminate();
+- return -1;
+- }
++ if (err)
++ goto error;
+
+ wpa_printf(MSG_DEBUG, "Completing interface initialization");
+ if (hapd->iconf->channel) {
+@@ -906,7 +903,7 @@ int hostapd_setup_interface_complete(str
+ hapd->iconf->secondary_channel)) {
+ wpa_printf(MSG_ERROR, "Could not set channel for "
+ "kernel driver");
+- return -1;
++ goto error;
+ }
+ }
+
+@@ -917,7 +914,7 @@ int hostapd_setup_interface_complete(str
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Failed to prepare rates table.");
+- return -1;
++ goto error;
+ }
+ }
+
+@@ -925,14 +922,14 @@ int hostapd_setup_interface_complete(str
+ hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+ wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
+ "kernel driver");
+- return -1;
++ goto error;
+ }
+
+ if (hapd->iconf->fragm_threshold > -1 &&
+ hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+ wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
+ "for kernel driver");
+- return -1;
++ goto error;
+ }
+
+ prev_addr = hapd->own_addr;
+@@ -942,7 +939,7 @@ int hostapd_setup_interface_complete(str
+ if (j)
+ os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+ if (hostapd_setup_bss(hapd, j == 0))
+- return -1;
++ goto error;
+ if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+ prev_addr = hapd->own_addr;
+ }
+@@ -954,7 +951,7 @@ int hostapd_setup_interface_complete(str
+ if (hostapd_driver_commit(hapd) < 0) {
+ wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
+ "configuration", __func__);
+- return -1;
++ goto error;
+ }
+
+ /*
+@@ -975,6 +972,11 @@ int hostapd_setup_interface_complete(str
+ iface->bss[0]->conf->iface);
+
+ return 0;
++
++error:
++ wpa_printf(MSG_ERROR, "Interface initialization failed");
++ eloop_terminate();
++ return -1;
+ }
+
+
diff --git a/package/network/services/hostapd/patches/500-random_pool_add_kernel.patch b/package/network/services/hostapd/patches/500-random_pool_add_kernel.patch
new file mode 100644
index 0000000000..e54e881d8e
--- /dev/null
+++ b/package/network/services/hostapd/patches/500-random_pool_add_kernel.patch
@@ -0,0 +1,168 @@
+--- a/src/crypto/random.c
++++ b/src/crypto/random.c
+@@ -33,6 +33,8 @@
+ #include "sha1.h"
+ #include "random.h"
+
++#define RANDOM_STAMPFILE "/var/run/.random_available"
++
+ #define POOL_WORDS 32
+ #define POOL_WORDS_MASK (POOL_WORDS - 1)
+ #define POOL_TAP1 26
+@@ -43,6 +45,8 @@
+ #define EXTRACT_LEN 16
+ #define MIN_READY_MARK 2
+
++#ifndef CONFIG_NO_RANDOM_POOL
++
+ static u32 pool[POOL_WORDS];
+ static unsigned int input_rotate = 0;
+ static unsigned int pool_pos = 0;
+@@ -123,7 +127,7 @@ static void random_extract(u8 *out)
+ }
+
+
+-void random_add_randomness(const void *buf, size_t len)
++static void random_pool_add_randomness(const void *buf, size_t len)
+ {
+ struct os_time t;
+ static unsigned int count = 0;
+@@ -213,16 +217,22 @@ int random_get_bytes(void *buf, size_t l
+ int random_pool_ready(void)
+ {
+ #ifdef __linux__
++ struct stat st;
+ int fd;
+ ssize_t res;
+
++ if (stat(RANDOM_STAMPFILE, &st) == 0)
++ return 1;
++
+ /*
+ * Make sure that there is reasonable entropy available before allowing
+ * some key derivation operations to proceed.
+ */
+
+- if (dummy_key_avail == sizeof(dummy_key))
++ if (dummy_key_avail == sizeof(dummy_key)) {
++ random_mark_pool_ready();
+ return 1; /* Already initialized - good to continue */
++ }
+
+ /*
+ * Try to fetch some more data from the kernel high quality
+@@ -257,6 +267,7 @@ int random_pool_ready(void)
+ if (dummy_key_avail == sizeof(dummy_key)) {
+ if (own_pool_ready < MIN_READY_MARK)
+ own_pool_ready = MIN_READY_MARK;
++ random_mark_pool_ready();
+ random_write_entropy();
+ return 1;
+ }
+@@ -269,6 +280,7 @@ int random_pool_ready(void)
+ total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
+ wpa_printf(MSG_INFO, "random: Allow operation to proceed "
+ "based on internal entropy");
++ random_mark_pool_ready();
+ return 1;
+ }
+
+@@ -284,10 +296,16 @@ int random_pool_ready(void)
+
+ void random_mark_pool_ready(void)
+ {
++ int fd;
++
+ own_pool_ready++;
+ wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
+ "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+ random_write_entropy();
++
++ fd = open(RANDOM_STAMPFILE, O_CREAT | O_WRONLY | O_EXCL | O_NOFOLLOW, 0600);
++ if (fd >= 0)
++ close(fd);
+ }
+
+
+@@ -444,3 +462,22 @@ void random_deinit(void)
+ os_free(random_entropy_file);
+ random_entropy_file = NULL;
+ }
++
++#endif /* CONFIG_NO_RANDOM_POOL */
++
++
++void random_add_randomness(const void *buf, size_t len)
++{
++#ifdef __linux__
++ int fd;
++
++ fd = open("/dev/random", O_RDWR);
++ if (fd >= 0) {
++ write(fd, buf, len);
++ close(fd);
++ }
++#endif
++#ifndef CONFIG_NO_RANDOM_POOL
++ random_pool_add_randomness(buf, len);
++#endif
++}
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -1217,9 +1217,8 @@ endif
+
+ ifdef CONFIG_NO_RANDOM_POOL
+ CFLAGS += -DCONFIG_NO_RANDOM_POOL
+-else
+-OBJS += ../src/crypto/random.o
+ endif
++OBJS += ../src/crypto/random.o
+
+ ifdef CONFIG_CTRL_IFACE
+ ifeq ($(CONFIG_CTRL_IFACE), y)
+--- a/wpa_supplicant/Android.mk
++++ b/wpa_supplicant/Android.mk
+@@ -1161,9 +1161,8 @@ endif
+
+ ifdef CONFIG_NO_RANDOM_POOL
+ L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+-else
+-OBJS += src/crypto/random.c
+ endif
++OBJS += src/crypto/random.c
+
+ ifdef CONFIG_CTRL_IFACE
+ ifeq ($(CONFIG_CTRL_IFACE), y)
+--- a/hostapd/Android.mk
++++ b/hostapd/Android.mk
+@@ -748,11 +748,11 @@ endif
+ ifdef CONFIG_NO_RANDOM_POOL
+ L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+ else
+-OBJS += src/crypto/random.c
+-HOBJS += src/crypto/random.c
+ HOBJS += $(SHA1OBJS)
+ HOBJS += src/crypto/md5.c
+ endif
++OBJS += src/crypto/random.c
++HOBJS += src/crypto/random.c
+
+ ifdef CONFIG_RADIUS_SERVER
+ L_CFLAGS += -DRADIUS_SERVER
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -755,12 +755,12 @@ endif
+ ifdef CONFIG_NO_RANDOM_POOL
+ CFLAGS += -DCONFIG_NO_RANDOM_POOL
+ else
+-OBJS += ../src/crypto/random.o
+-HOBJS += ../src/crypto/random.o
+ HOBJS += ../src/utils/eloop.o
+ HOBJS += $(SHA1OBJS)
+ HOBJS += ../src/crypto/md5.o
+ endif
++OBJS += ../src/crypto/random.o
++HOBJS += ../src/crypto/random.o
+
+ ifdef CONFIG_RADIUS_SERVER
+ CFLAGS += -DRADIUS_SERVER
diff --git a/package/network/services/hostapd/patches/510-bring_down_interface.patch b/package/network/services/hostapd/patches/510-bring_down_interface.patch
new file mode 100644
index 0000000000..7481eb152a
--- /dev/null
+++ b/package/network/services/hostapd/patches/510-bring_down_interface.patch
@@ -0,0 +1,19 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -7144,8 +7144,6 @@ static int wpa_driver_nl80211_set_mode(s
+ ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (ret == -EACCES)
+ break;
+- res = linux_set_iface_flags(drv->global->ioctl_sock,
+- bss->ifname, 1);
+ if (res && !ret)
+ ret = -1;
+ else if (ret != -EBUSY)
+@@ -7161,6 +7159,7 @@ static int wpa_driver_nl80211_set_mode(s
+ "interface is down");
+ drv->nlmode = nlmode;
+ drv->ignore_if_down_event = 1;
++ linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+ }
+
+ done:
diff --git a/package/network/services/hostapd/patches/520-fix_wps_pin_crash.patch b/package/network/services/hostapd/patches/520-fix_wps_pin_crash.patch
new file mode 100644
index 0000000000..29d154cef3
--- /dev/null
+++ b/package/network/services/hostapd/patches/520-fix_wps_pin_crash.patch
@@ -0,0 +1,12 @@
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -450,6 +450,9 @@ static int hostapd_ctrl_iface_wps_ap_pin
+ char *pos;
+ const char *pin_txt;
+
++ if (!hapd->wps)
++ return -1;
++
+ pos = os_strchr(txt, ' ');
+ if (pos)
+ *pos++ = '\0';
diff --git a/package/network/services/hostapd/patches/530-wps_single_auth_enc_type.patch b/package/network/services/hostapd/patches/530-wps_single_auth_enc_type.patch
new file mode 100644
index 0000000000..f05ea35cf9
--- /dev/null
+++ b/package/network/services/hostapd/patches/530-wps_single_auth_enc_type.patch
@@ -0,0 +1,25 @@
+--- a/src/ap/wps_hostapd.c
++++ b/src/ap/wps_hostapd.c
+@@ -873,11 +873,9 @@ int hostapd_init_wps(struct hostapd_data
+
+ if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
+ wps->encr_types |= WPS_ENCR_AES;
+- if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
++ else if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
+ wps->encr_types |= WPS_ENCR_TKIP;
+- }
+-
+- if (conf->wpa & WPA_PROTO_WPA) {
++ } else if (conf->wpa & WPA_PROTO_WPA) {
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+ wps->auth_types |= WPS_AUTH_WPAPSK;
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+@@ -885,7 +883,7 @@ int hostapd_init_wps(struct hostapd_data
+
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ wps->encr_types |= WPS_ENCR_AES;
+- if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
++ else if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ wps->encr_types |= WPS_ENCR_TKIP;
+ }
+
diff --git a/package/network/services/hostapd/patches/540-dynamic_20_40_mhz.patch b/package/network/services/hostapd/patches/540-dynamic_20_40_mhz.patch
new file mode 100644
index 0000000000..d58358c083
--- /dev/null
+++ b/package/network/services/hostapd/patches/540-dynamic_20_40_mhz.patch
@@ -0,0 +1,202 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2495,6 +2495,10 @@ static int hostapd_config_fill(struct ho
+ "ht_capab", line);
+ errors++;
+ }
++ } else if (os_strcmp(buf, "dynamic_ht40") == 0) {
++ conf->dynamic_ht40 = atoi(pos);
++ if (conf->dynamic_ht40 == 1)
++ conf->dynamic_ht40 = 1500;
+ } else if (os_strcmp(buf, "require_ht") == 0) {
+ conf->require_ht = atoi(pos);
+ #endif /* CONFIG_IEEE80211N */
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -501,6 +501,7 @@ struct hostapd_config {
+ int ieee80211n;
+ int secondary_channel;
+ int require_ht;
++ int dynamic_ht40;
+ u32 vht_capab;
+ int ieee80211ac;
+ int require_vht;
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -22,6 +22,7 @@
+ #include "beacon.h"
+ #include "iapp.h"
+ #include "ieee802_1x.h"
++#include "ieee802_11.h"
+ #include "ieee802_11_auth.h"
+ #include "vlan_init.h"
+ #include "wpa_auth.h"
+@@ -323,6 +324,7 @@ static void hostapd_cleanup_iface_pre(st
+
+ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+ {
++ hostapd_deinit_ht(iface);
+ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+ iface->hw_features = NULL;
+ os_free(iface->current_rates);
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -251,6 +251,9 @@ struct hostapd_iface {
+ /* Overlapping BSS information */
+ int olbc_ht;
+
++ int force_20mhz;
++ struct os_time last_20mhz_trigger;
++
+ u16 ht_op_mode;
+ void (*scan_cb)(struct hostapd_iface *iface);
+ };
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -1220,6 +1220,9 @@ static void handle_beacon(struct hostapd
+ sizeof(mgmt->u.beacon)), &elems,
+ 0);
+
++ if (!elems.ht_capabilities)
++ hostapd_trigger_20mhz(hapd->iface);
++
+ ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
+ }
+
+--- a/src/ap/ieee802_11.h
++++ b/src/ap/ieee802_11.h
+@@ -78,4 +78,17 @@ int hostapd_update_time_adv(struct hosta
+ void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+
++#ifdef CONFIG_IEEE80211N
++void hostapd_trigger_20mhz(struct hostapd_iface *iface);
++void hostapd_deinit_ht(struct hostapd_iface *iface);
++
++#else
++static inline void hostapd_deinit_ht(struct hostapd_iface *iface)
++{
++}
++static inline void hostapd_trigger_20mhz(struct hostapd_iface *iface)
++{
++}
++#endif /* CONFIG_IEEE80211N */
++
+ #endif /* IEEE802_11_H */
+--- a/src/ap/ieee802_11_ht.c
++++ b/src/ap/ieee802_11_ht.c
+@@ -20,9 +20,11 @@
+ #include "drivers/driver.h"
+ #include "hostapd.h"
+ #include "ap_config.h"
++#include "ap_drv_ops.h"
+ #include "sta_info.h"
+ #include "beacon.h"
+ #include "ieee802_11.h"
++#include "utils/eloop.h"
+
+
+ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
+@@ -70,12 +72,15 @@ u8 * hostapd_eid_ht_operation(struct hos
+
+ oper->control_chan = hapd->iconf->channel;
+ oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
+- if (hapd->iconf->secondary_channel == 1)
+- oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
+- HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+- if (hapd->iconf->secondary_channel == -1)
+- oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+- HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
++
++ if (!hapd->iface->force_20mhz) {
++ if (hapd->iconf->secondary_channel == 1)
++ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
++ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
++ if (hapd->iconf->secondary_channel == -1)
++ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
++ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
++ }
+
+ pos += sizeof(*oper);
+
+@@ -271,3 +276,80 @@ void hostapd_get_ht_capab(struct hostapd
+
+ neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
+ }
++
++static void hostapd_set_force_20mhz(struct hostapd_iface *iface);
++
++static void hostapd_restore_40mhz(void *eloop_data, void *user_ctx)
++{
++ struct hostapd_iface *iface = eloop_data;
++ struct os_time time;
++ int timeout;
++
++ if (!iface->last_20mhz_trigger.sec)
++ return;
++
++ os_get_time(&time);
++ timeout = iface->last_20mhz_trigger.sec + iface->conf->dynamic_ht40 -
++ time.sec;
++
++ if (timeout > 0) {
++ eloop_register_timeout(timeout, 0, hostapd_restore_40mhz,
++ iface, NULL);
++ return;
++ }
++
++ iface->last_20mhz_trigger.sec = 0;
++ iface->last_20mhz_trigger.usec = 0;
++
++ iface->force_20mhz = 0;
++ hostapd_set_force_20mhz(iface);
++}
++
++static void hostapd_set_force_20mhz(struct hostapd_iface *iface)
++{
++ int secondary_channel;
++ int i;
++
++ ieee802_11_set_beacons(iface);
++
++ for (i = 0; i < iface->num_bss; i++) {
++ struct hostapd_data *hapd = iface->bss[i];
++
++ if (iface->force_20mhz)
++ secondary_channel = 0;
++ else
++ secondary_channel = hapd->iconf->secondary_channel;
++
++ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
++ hapd->iconf->channel,
++ hapd->iconf->ieee80211n,
++ secondary_channel)) {
++ wpa_printf(MSG_ERROR, "Could not set channel for "
++ "kernel driver");
++ }
++ }
++}
++
++void hostapd_deinit_ht(struct hostapd_iface *iface)
++{
++ eloop_cancel_timeout(hostapd_restore_40mhz, iface, NULL);
++}
++
++void hostapd_trigger_20mhz(struct hostapd_iface *iface)
++{
++ if (!iface->conf->dynamic_ht40)
++ return;
++
++ if (!iface->force_20mhz) {
++ iface->force_20mhz = 1;
++ hostapd_set_force_20mhz(iface);
++ }
++
++ if (!iface->last_20mhz_trigger.sec) {
++ eloop_cancel_timeout(hostapd_restore_40mhz, iface, NULL);
++ eloop_register_timeout(iface->conf->dynamic_ht40, 0,
++ hostapd_restore_40mhz, iface, NULL);
++ }
++
++ os_get_time(&iface->last_20mhz_trigger);
++}
diff --git a/package/network/services/hostapd/patches/550-limit_debug_messages.patch b/package/network/services/hostapd/patches/550-limit_debug_messages.patch
new file mode 100644
index 0000000000..659e980112
--- /dev/null
+++ b/package/network/services/hostapd/patches/550-limit_debug_messages.patch
@@ -0,0 +1,213 @@
+--- 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,9 @@ static void _wpa_hexdump(int level, cons
+ #endif /* CONFIG_ANDROID_LOG */
+ }
+
+-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
+-{
+- _wpa_hexdump(level, title, buf, len, 1);
+-}
+-
+-
+-void wpa_hexdump_key(int level, const char *title, const u8 *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 u8 *buf,
+- size_t len, int show)
++void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
++ size_t len, int show)
+ {
+ size_t i, llen;
+ const u8 *pos = buf;
+@@ -495,19 +484,6 @@ static void _wpa_hexdump_ascii(int level
+ }
+
+
+-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
+-{
+- _wpa_hexdump_ascii(level, title, buf, len, 1);
+-}
+-
+-
+-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *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 */
+@@ -591,7 +567,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;
+@@ -625,7 +601,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
+@@ -43,6 +43,17 @@ int wpa_debug_open_file(const char *path
+ int wpa_debug_reopen_file(void);
+ void wpa_debug_close_file(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 u8 *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
+ *
+@@ -63,9 +74,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
+@@ -77,7 +94,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 u8 *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)
+@@ -99,7 +122,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 u8 *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)
+@@ -121,8 +150,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 u8 *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
+@@ -138,8 +173,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 u8 *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
+@@ -172,7 +213,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
+@@ -186,8 +232,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)
+
+ typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
+ size_t len);
diff --git a/package/network/services/hostapd/patches/560-indicate-features.patch b/package/network/services/hostapd/patches/560-indicate-features.patch
new file mode 100644
index 0000000000..d01e18b862
--- /dev/null
+++ b/package/network/services/hostapd/patches/560-indicate-features.patch
@@ -0,0 +1,82 @@
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -13,6 +13,7 @@
+
+ #include "utils/common.h"
+ #include "utils/eloop.h"
++#include "utils/build_features.h"
+ #include "crypto/random.h"
+ #include "crypto/tls.h"
+ #include "common/version.h"
+@@ -560,7 +561,7 @@ int main(int argc, char *argv[])
+
+ wpa_supplicant_event = hostapd_wpa_event;
+ for (;;) {
+- c = getopt(argc, argv, "Bde:f:hKP:tvg:");
++ c = getopt(argc, argv, "Bde:f:hKP:tg:v::");
+ if (c < 0)
+ break;
+ switch (c) {
+@@ -592,6 +593,8 @@ int main(int argc, char *argv[])
+ wpa_debug_timestamp++;
+ break;
+ 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 "wpa_supplicant_i.h"
+ #include "driver_i.h"
+
+@@ -156,7 +157,7 @@ int main(int argc, char *argv[])
+
+ for (;;) {
+ c = getopt(argc, argv,
+- "b:Bc:C:D:de:f:g:hH:i:KLNo:O:p:P:qsTtuvW");
++ "b:Bc:C:D:de:f:g:hH:i:KLNo:O:p:P:qsTtuv::W");
+ if (c < 0)
+ break;
+ switch (c) {
+@@ -248,8 +249,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++;
+--- /dev/null
++++ b/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/hostapd/patches/570-genl_connect_debug.patch b/package/network/services/hostapd/patches/570-genl_connect_debug.patch
new file mode 100644
index 0000000000..5f140489b0
--- /dev/null
+++ b/package/network/services/hostapd/patches/570-genl_connect_debug.patch
@@ -0,0 +1,11 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -127,7 +127,7 @@ static struct nl_handle * nl_create_hand
+ }
+
+ if (genl_connect(handle)) {
+- wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
++ wpa_printf(MSG_DEBUG, "nl80211: Failed to connect to generic "
+ "netlink (%s)", dbg);
+ nl80211_handle_destroy(handle);
+ return NULL;
diff --git a/package/network/services/hostapd/patches/580-fix_bss_addr.patch b/package/network/services/hostapd/patches/580-fix_bss_addr.patch
new file mode 100644
index 0000000000..3a76668c14
--- /dev/null
+++ b/package/network/services/hostapd/patches/580-fix_bss_addr.patch
@@ -0,0 +1,11 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -7738,7 +7738,7 @@ static int i802_set_wds_sta(void *priv,
+ if (!if_nametoindex(name)) {
+ if (nl80211_create_iface(drv, name,
+ NL80211_IFTYPE_AP_VLAN,
+- NULL, 1) < 0)
++ bss->addr, 1) < 0)
+ return -1;
+ if (bridge_ifname &&
+ linux_br_add_if(drv->global->ioctl_sock,
diff --git a/package/network/services/hostapd/patches/590-hostapd_cli_ifdef.patch b/package/network/services/hostapd/patches/590-hostapd_cli_ifdef.patch
new file mode 100644
index 0000000000..705cef13d5
--- /dev/null
+++ b/package/network/services/hostapd/patches/590-hostapd_cli_ifdef.patch
@@ -0,0 +1,50 @@
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -67,7 +67,6 @@ static const char *commands_help =
+ #ifdef CONFIG_IEEE80211W
+ " sa_query <addr> send SA Query to a station\n"
+ #endif /* CONFIG_IEEE80211W */
+-#ifdef CONFIG_WPS
+ " wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
+ " wps_check_pin <PIN> verify PIN checksum\n"
+ " wps_pbc indicate button pushed to initiate PBC\n"
+@@ -82,7 +81,6 @@ static const char *commands_help =
+ #endif /* CONFIG_WPS_NFC */
+ " wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
+ " wps_config <SSID> <auth> <encr> <key> configure AP\n"
+-#endif /* CONFIG_WPS */
+ " get_config show current configuration\n"
+ " help show this usage help\n"
+ " interface [ifname] show interfaces/select interface\n"
+@@ -343,7 +341,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[])
+ {
+@@ -573,7 +570,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_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+@@ -799,7 +795,6 @@ static struct hostapd_cli_cmd hostapd_cl
+ #ifdef CONFIG_IEEE80211W
+ { "sa_query", hostapd_cli_cmd_sa_query },
+ #endif /* CONFIG_IEEE80211W */
+-#ifdef CONFIG_WPS
+ { "wps_pin", hostapd_cli_cmd_wps_pin },
+ { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
+ { "wps_pbc", hostapd_cli_cmd_wps_pbc },
+@@ -814,7 +809,6 @@ static struct hostapd_cli_cmd hostapd_cl
+ #endif /* CONFIG_WPS_NFC */
+ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
+ { "wps_config", hostapd_cli_cmd_wps_config },
+-#endif /* CONFIG_WPS */
+ { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
+ { "get_config", hostapd_cli_cmd_get_config },
+ { "help", hostapd_cli_cmd_help },
diff --git a/package/network/services/hostapd/patches/601-wpa_supplicant-add-new-config-params-to-be-used-with.patch b/package/network/services/hostapd/patches/601-wpa_supplicant-add-new-config-params-to-be-used-with.patch
new file mode 100644
index 0000000000..ac0d247d76
--- /dev/null
+++ b/package/network/services/hostapd/patches/601-wpa_supplicant-add-new-config-params-to-be-used-with.patch
@@ -0,0 +1,211 @@
+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 "drivers/nl80211_copy.h"
+ #include "common/defs.h"
+
+ #define HOSTAPD_CHAN_DISABLED 0x00000001
+@@ -351,6 +352,11 @@ struct wpa_driver_associate_params {
+ */
+ int freq;
+
++ int beacon_interval;
++ int fixed_freq;
++ unsigned char rates[NL80211_MAX_SUPP_RATES];
++ int mcast_rate;
++
+ /**
+ * bg_scan_period - Background scan period in seconds, 0 to disable
+ * background scan, or -1 to indicate no change to default driver
+--- a/wpa_supplicant/config.c
++++ b/wpa_supplicant/config.c
+@@ -14,6 +14,7 @@
+ #include "rsn_supp/wpa.h"
+ #include "eap_peer/eap.h"
+ #include "p2p/p2p.h"
++#include "drivers/nl80211_copy.h"
+ #include "config.h"
+
+
+@@ -1463,6 +1464,97 @@ static char * wpa_config_write_p2p_clien
+
+ #endif /* CONFIG_P2P */
+
++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 < NL80211_MAX_SUPP_RATES) {
++ 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 * NL80211_MAX_SUPP_RATES + 1);
++ if (value == NULL)
++ return NULL;
++ pos = value;
++ for (i = 0; i < NL80211_MAX_SUPP_RATES - 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[NL80211_MAX_SUPP_RATES - 1] / 2);
++ if (res < 0) {
++ os_free(value);
++ return NULL;
++ }
++
++ value[6 * NL80211_MAX_SUPP_RATES] = '\0';
++ return value;
++}
++#endif /* NO_CONFIG_WRITE */
++
+ /* Helper macros for network block parser */
+
+ #ifdef OFFSET
+@@ -1638,6 +1730,10 @@ static const struct parse_data ssid_fiel
+ #endif /* CONFIG_HT_OVERRIDES */
+ { INT(ap_max_inactivity) },
+ { INT(dtim_period) },
++ { INT_RANGE(fixed_freq, 0, 1) },
++ { INT_RANGE(beacon_interval, 0, 1000) },
++ { FUNC(rates) },
++ { FUNC(mcast_rate) },
+ };
+
+ #undef OFFSET
+--- a/wpa_supplicant/config_ssid.h
++++ b/wpa_supplicant/config_ssid.h
+@@ -11,6 +11,7 @@
+
+ #include "common/defs.h"
+ #include "eap_peer/eap_config.h"
++#include "drivers/nl80211_copy.h"
+
+ #define MAX_SSID_LEN 32
+
+@@ -529,6 +530,11 @@ struct wpa_ssid {
+ * disabled_until - Network block disabled until this time if non-zero
+ */
+ struct os_time disabled_until;
++
++ int fixed_freq;
++ int beacon_interval;
++ unsigned char rates[NL80211_MAX_SUPP_RATES];
++ double mcast_rate;
+ };
+
+ #endif /* CONFIG_SSID_H */
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -1561,15 +1561,24 @@ void wpa_supplicant_associate(struct wpa
+ params.ssid_len = ssid->ssid_len;
+ }
+
+- if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
+- wpa_s->conf->ap_scan == 2) {
+- params.bssid = ssid->bssid;
+- params.fixed_bssid = 1;
++ if (ssid->mode == WPAS_MODE_IBSS) {
++ if (ssid->bssid_set && wpa_s->conf->ap_scan == 2) {
++ params.bssid = ssid->bssid;
++ params.fixed_bssid = 1;
++ }
++ if (ssid->frequency > 0 && params.freq == 0)
++ /* Initial channel for IBSS */
++ params.freq = ssid->frequency;
++ params.fixed_freq = ssid->fixed_freq;
++ params.beacon_interval = ssid->beacon_interval;
++ i = 0;
++ while (i < NL80211_MAX_SUPP_RATES) {
++ params.rates[i] = ssid->rates[i];
++ i++;
++ }
++ params.mcast_rate = ssid->mcast_rate;
+ }
+
+- if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
+- params.freq == 0)
+- params.freq = ssid->frequency; /* Initial channel for IBSS */
+ params.wpa_ie = wpa_ie;
+ params.wpa_ie_len = wpa_ie_len;
+ params.pairwise_suite = cipher_pairwise;
diff --git a/package/network/services/hostapd/patches/602-driver_nl80211-use-new-parameters-during-ibss-join.patch b/package/network/services/hostapd/patches/602-driver_nl80211-use-new-parameters-during-ibss-join.patch
new file mode 100644
index 0000000000..c426a0bb2d
--- /dev/null
+++ b/package/network/services/hostapd/patches/602-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
+@@ -6587,7 +6587,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);
+@@ -6620,6 +6620,37 @@ retry:
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+
++ if (params->fixed_freq) {
++ wpa_printf(MSG_DEBUG, " * fixed_freq");
++ NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED);
++ }
++
++ if (params->beacon_interval > 0) {
++ wpa_printf(MSG_DEBUG, " * beacon_interval=%d",
++ params->beacon_interval);
++ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL,
++ params->beacon_interval);
++ }
++
++ 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_rates=%.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 nla_put_failure;
diff --git a/package/network/services/hostapd/patches/604-wpa_s-support-htmode-param.patch b/package/network/services/hostapd/patches/604-wpa_s-support-htmode-param.patch
new file mode 100644
index 0000000000..44931f2f3b
--- /dev/null
+++ b/package/network/services/hostapd/patches/604-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
+@@ -356,6 +356,8 @@ struct wpa_driver_associate_params {
+ int fixed_freq;
+ unsigned char rates[NL80211_MAX_SUPP_RATES];
+ int mcast_rate;
++ int ht_set;
++ unsigned int htmode;
+
+ /**
+ * bg_scan_period - Background scan period in seconds, 0 to disable
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -6651,6 +6651,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 nla_put_failure;
+--- a/wpa_supplicant/config.c
++++ b/wpa_supplicant/config.c
+@@ -1495,6 +1495,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)
+@@ -1734,6 +1799,7 @@ static const struct parse_data ssid_fiel
+ { INT_RANGE(beacon_interval, 0, 1000) },
+ { FUNC(rates) },
+ { FUNC(mcast_rate) },
++ { FUNC(htmode) },
+ };
+
+ #undef OFFSET
+--- a/wpa_supplicant/config_ssid.h
++++ b/wpa_supplicant/config_ssid.h
+@@ -535,6 +535,8 @@ struct wpa_ssid {
+ int beacon_interval;
+ unsigned char rates[NL80211_MAX_SUPP_RATES];
+ double mcast_rate;
++ int ht_set;
++ unsigned int htmode;
+ };
+
+ #endif /* CONFIG_SSID_H */
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -1577,6 +1577,8 @@ void wpa_supplicant_associate(struct wpa
+ 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/610-max_num_sta_probe.patch b/package/network/services/hostapd/patches/610-max_num_sta_probe.patch
new file mode 100644
index 0000000000..e22348c896
--- /dev/null
+++ b/package/network/services/hostapd/patches/610-max_num_sta_probe.patch
@@ -0,0 +1,13 @@
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -413,6 +413,10 @@ void handle_probe_req(struct hostapd_dat
+ return;
+ }
+
++ if (!sta && hapd->num_sta >= hapd->conf->max_num_sta)
++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " ignored,"
++ " too many connected stations.", MAC2STR(mgmt->sa));
++
+ #ifdef CONFIG_INTERWORKING
+ if (elems.interworking && elems.interworking_len >= 1) {
+ u8 ant = elems.interworking[0] & 0x0f;
diff --git a/package/network/services/ppp/Makefile b/package/network/services/ppp/Makefile
new file mode 100644
index 0000000000..fc4ccd4ba2
--- /dev/null
+++ b/package/network/services/ppp/Makefile
@@ -0,0 +1,263 @@
+#
+# 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:=ppp
+PKG_VERSION:=2.4.5
+PKG_RELEASE:=6
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=ftp://ftp.samba.org/pub/ppp/
+PKG_MD5SUM:=4621bc56167b6953ec4071043fe0ec57
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+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
+ MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+ 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/chat
+$(call Package/ppp/Default)
+ DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink)
+ 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/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
+
+
+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 -sf /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/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/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,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..8ab8c9dd19
--- /dev/null
+++ b/package/network/services/ppp/files/lib/netifd/ppp-up
@@ -0,0 +1,22 @@
+#!/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
+ [ -n "$IPREMOTE" ] && proto_add_ipv4_route 0.0.0.0 0 "$IPREMOTE"
+ [ -n "$LLLOCAL" ] && proto_add_ipv6_address "$LLLOCAL" 128
+ [ -n "$LLREMOTE" ] && proto_add_ipv6_route "::0" 0 "$LLREMOTE"
+ [ -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/ppp.sh b/package/network/services/ppp/files/ppp.sh
new file mode 100755
index 0000000000..7e9b8dd856
--- /dev/null
+++ b/package/network/services/ppp/files/ppp.sh
@@ -0,0 +1,222 @@
+#!/bin/sh
+
+[ -x /usr/sbin/pppd ] || exit 0
+
+[ -n "$INCLUDE_ONLY" ] || {
+ . /lib/functions.sh
+ . ../netifd-proto.sh
+ init_proto "$@"
+}
+
+ppp_generic_init_config() {
+ proto_config_add_string "username"
+ proto_config_add_string "password"
+ proto_config_add_string "keepalive"
+ proto_config_add_int "demand"
+ proto_config_add_string "pppd_options"
+ proto_config_add_string "connect"
+ proto_config_add_string "disconnect"
+ proto_config_add_boolean "defaultroute"
+ proto_config_add_boolean "peerdns"
+ proto_config_add_boolean "ipv6"
+ proto_config_add_boolean "authfail"
+ proto_config_add_int "mtu"
+}
+
+ppp_generic_setup() {
+ local config="$1"; shift
+
+ json_get_vars ipv6 peerdns defaultroute demand keepalive username password pppd_options
+ [ "$ipv6" = 1 ] || ipv6=""
+ [ "$peerdns" = 0 ] && peerdns="" || peerdns="1"
+ if [ "$defaultroute" = 1 ]; then
+ defaultroute="defaultroute replacedefaultroute";
+ else
+ defaultroute="nodefaultroute"
+ fi
+ if [ "${demand:-0}" -gt 0 ]; then
+ demand="precompiled-active-filter /etc/ppp/filter demand idle $demand"
+ else
+ demand="persist"
+ fi
+
+ [ -n "$mtu" ] || json_get_var mtu mtu
+
+ local interval="${keepalive##*[, ]}"
+ [ "$interval" != "$keepalive" ] || interval=5
+ [ -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 "${proto:-ppp}-$config" \
+ ${keepalive:+lcp-echo-interval $interval lcp-echo-failure ${keepalive%%[, ]*}} \
+ ${ipv6:++ipv6} $defaultroute \
+ ${peerdns:+usepeerdns} \
+ $demand maxfail 1 \
+ ${username:+user "$username" password "$password"} \
+ ${connect:+connect "$connect"} \
+ ${disconnect:+disconnect "$disconnect"} \
+ ip-up-script /lib/netifd/ppp-up \
+ ipv6-up-script /lib/netifd/ppp-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"
+
+ case "$ERROR" in
+ 11|19)
+ proto_notify_error "$interface" AUTH_FAILED
+ json_get_var authfail authfail
+ if [ "${authfail:-0}" -gt 0 ]; then
+ proto_block_restart "$interface"
+ fi
+ ;;
+ 2)
+ proto_notify_error "$interface" INVALID_OPTIONS
+ proto_block_restart "$interface"
+ ;;
+ 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
+}
+
+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_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
+
+ ppp_generic_setup "$config" \
+ plugin rp-pppoe.so \
+ ${ac:+rp_pppoe_ac "$ac"} \
+ ${service:+rp_pppoe_service "$service"} \
+ "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
+}
+
+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"
+ available=1
+ no_device=1
+}
+
+proto_pptp_setup() {
+ local config="$1"
+ local iface="$2"
+
+ local ip serv_addr server
+ json_get_var server server && {
+ for ip in $(resolveip -t 5 "$server"); do
+ ( proto_add_host_dependency "$config" "$ip" )
+ 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/010-use_target_for_configure.patch b/package/network/services/ppp/patches/010-use_target_for_configure.patch
new file mode 100644
index 0000000000..aff0df67f8
--- /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 <jow@openwrt.org>
+
+--- 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..ca43cb2780
--- /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 <jow@openwrt.org>
+
+--- a/pppd/ipcp.c
++++ b/pppd/ipcp.c
+@@ -1939,7 +1939,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);
+ }
+ }
+
+@@ -1989,7 +1989,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);
+ }
+ }
+
+@@ -2043,13 +2043,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
+@@ -113,6 +113,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 */
+@@ -281,6 +283,13 @@ option_t general_options[] = {
+ "Number of seconds to wait for child processes at exit",
+ OPT_PRIO },
+
++ { "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
+@@ -313,6 +313,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..232b10b521
--- /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 <jow@openwrt.org>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -453,6 +453,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..c8a23edd6a
--- /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 <jow@openwrt.org>
+
+--- 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..c278656987
--- /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
+@@ -1864,7 +1864,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
+@@ -566,7 +566,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..86af1ef412
--- /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 <jow@openwrt.org>
+
+--- 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..eaad2cdaae
--- /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 <jow@openwrt.org>
+
+--- 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..41d28909be
--- /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 <jow@openwrt.org>
+
+--- 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 *));
+
+@@ -1742,7 +1750,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))
+@@ -1830,7 +1839,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);
+@@ -1855,7 +1865,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. */
+@@ -1905,7 +1916,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. */
+@@ -1983,7 +1995,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 */
+@@ -1999,16 +2011,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
+@@ -717,7 +722,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
+@@ -645,7 +645,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
+@@ -206,6 +206,8 @@ static unsigned char inbuf[512]; /* buff
+
+ static int if_is_up; /* Interface has been marked up */
+ 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 */
+@@ -1544,6 +1546,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);
+@@ -1613,20 +1618,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));
+@@ -1641,10 +1677,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;
+@@ -1675,11 +1717,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
+@@ -2036,12 +2036,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..c5457fa515
--- /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 <jow@openwrt.org>
+
+--- 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
+@@ -115,6 +115,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 */
+@@ -290,6 +292,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
+@@ -1288,7 +1288,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);
+ }
+ }
+
+@@ -1339,7 +1339,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);
+ }
+ }
+
+@@ -1382,13 +1382,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
+@@ -315,6 +315,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/200-makefile.patch b/package/network/services/ppp/patches/200-makefile.patch
new file mode 100644
index 0000000000..9db908de8d
--- /dev/null
+++ b/package/network/services/ppp/patches/200-makefile.patch
@@ -0,0 +1,55 @@
+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 <jow@openwrt.org>
+
+--- 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,11 +58,11 @@ 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
++#HAS_SHADOW=y
+ #USE_PAM=y
+-#HAVE_INET6=y
++HAVE_INET6=y
+
+ # Enable plugins
+ PLUGIN=y
+@@ -77,7 +77,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@"'
+
+@@ -117,10 +117,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 NEEDDES
+ ifndef USE_CRYPT
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..3edd11e7f6
--- /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 <jow@openwrt.org>
+
+--- 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
+@@ -898,13 +898,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..87c76ad0e7
--- /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 <jow@openwrt.org>
+
+--- 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
+@@ -99,7 +99,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
+@@ -200,7 +200,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..a369163527
--- /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 <jow@openwrt.org>
+
+--- 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..7119fb83f2
--- /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 <jow@openwrt.org>
+
+--- a/pppd/plugins/rp-pppoe/discovery.c
++++ b/pppd/plugins/rp-pppoe/discovery.c
+@@ -548,7 +548,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;
+@@ -563,7 +565,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);
+
+ /* We're done. */
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..fb6c65679e
--- /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 <jow@openwrt.org>
+
+--- 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..1ebcf412fc
--- /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 <jow@openwrt.org>
+
+--- a/pppd/lcp.c
++++ b/pppd/lcp.c
+@@ -1904,12 +1904,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..25e2a10b85
--- /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 <jow@openwrt.org>
+
+--- 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..d8dcc64c8b
--- /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 <jow@openwrt.org>
+
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -170,8 +170,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..87b9687ef7
--- /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 <jow@openwrt.org>
+
+--- 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!
+@@ -175,6 +178,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...
+@@ -162,6 +163,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 **));
+@@ -326,6 +334,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",
+@@ -1472,6 +1488,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..a95f4f8c81
--- /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 <jow@openwrt.org>
+
+--- 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
+@@ -111,6 +111,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 */
+@@ -266,6 +267,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
+@@ -71,6 +71,10 @@
+ #include "eui64.h"
+ #endif
+
++#ifndef IFNAMSIZ
++#define IFNAMSIZ 16
++#endif
++
+ /*
+ * Limits.
+ */
+@@ -309,6 +313,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
+@@ -168,6 +168,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 */
+@@ -622,7 +626,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?");
+@@ -645,6 +650,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/330-retain_foreign_default_routes.patch b/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
new file mode 100644
index 0000000000..0d7fff9b4b
--- /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 <jow@openwrt.org>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -1743,6 +1743,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..9a0284eb23
--- /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 <jow@openwrt.org>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -1697,6 +1697,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)) {
+@@ -1704,7 +1707,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..ec82576cbc
--- /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 <jow@openwrt.org>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -203,7 +203,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 */
+@@ -220,8 +220,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
+
+@@ -1438,11 +1438,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;
+
+@@ -1464,6 +1465,7 @@ static char *path_to_procfs(const char *
+ fclose (fp);
+ }
+ }
++#endif
+
+ strlcpy(proc_path + proc_path_len, tail,
+ sizeof(proc_path) - proc_path_len);
+@@ -2116,15 +2118,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;
+@@ -2185,6 +2191,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
+@@ -2678,6 +2685,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) {
+@@ -2696,6 +2704,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
+@@ -170,14 +170,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
+@@ -60,9 +60,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;
+@@ -340,10 +337,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
+@@ -500,12 +500,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..94c0263eaa
--- /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 <jow@openwrt.org>
+
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -309,7 +309,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
+@@ -145,7 +145,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 */
+@@ -201,8 +201,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..71233200e7
--- /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 <jow@openwrt.org>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -2254,6 +2254,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
+@@ -2319,6 +2320,7 @@ void logwtmp (const char *line, const ch
+ close (wtmp);
+ }
+ #endif
++#endif
+ }
+
+
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..edbca7603c
--- /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 <jow@openwrt.org>
+
+--- 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..97a79c474a
--- /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 <jow@openwrt.org>
+
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -318,13 +318,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/430-pppol2tpv3-struct.patch b/package/network/services/ppp/patches/430-pppol2tpv3-struct.patch
new file mode 100644
index 0000000000..4f517df764
--- /dev/null
+++ b/package/network/services/ppp/patches/430-pppol2tpv3-struct.patch
@@ -0,0 +1,30 @@
+pppol2tp: Provide struct pppol2tpv3_addr to align with Linux
+
+The struct pppol2tpv3_addr is referenced in the current Linux kernel sources
+but not provided by the shipped kernel headers, add it.
+
+Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
+
+--- a/include/linux/if_pppol2tp.h
++++ b/include/linux/if_pppol2tp.h
+@@ -32,6 +32,20 @@ struct pppol2tp_addr
+ __u16 d_tunnel, d_session; /* For sending outgoing packets */
+ };
+
++/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
++ * bits. So we need a different sockaddr structure.
++ */
++struct pppol2tpv3_addr {
++ pid_t pid; /* pid that owns the fd.
++ * 0 => current */
++ int fd; /* FD of UDP or IP socket to use */
++
++ struct sockaddr_in addr; /* IP address and port to send to */
++
++ __u32 s_tunnel, s_session; /* For matching incoming packets */
++ __u32 d_tunnel, d_session; /* For sending outgoing packets */
++};
++
+ /* Socket options:
+ * DEBUG - bitmask of debug message categories
+ * SENDSEQ - 0 => don't send packets with sequence numbers
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/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..db957bdf66
--- /dev/null
+++ b/package/network/services/relayd/Makefile
@@ -0,0 +1,44 @@
+#
+# 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:=2011-10-24
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL:=git://nbd.name/relayd.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=4e8f1fa4ca2b176500362843a9e57ea5abd4b7a3
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+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..43ba6e10f4
--- /dev/null
+++ b/package/network/services/relayd/files/relay.init
@@ -0,0 +1,97 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2011-2012 OpenWrt.org
+START=80
+
+resolve_ifname() {
+ grep -qs "^ *$1:" /proc/net/dev && {
+ append args "-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
+
+ 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
+ }
+
+ 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" ] && append args "-L $ipaddr"
+
+ local gateway
+ config_get gateway "$cfg" gateway
+ [ -n "$gateway" ] && append args "-G $gateway"
+
+ local expiry # = 30
+ config_get expiry "$cfg" expiry
+ [ -n "$expiry" ] && append args "-t $expiry"
+
+ local retry # = 5
+ config_get retry "$cfg" retry
+ [ -n "$retry" ] && append args "-p $retry"
+
+ local table # = 16800
+ config_get table "$cfg" table
+ [ -n "$table" ] && append args "-T $table"
+
+ local fwd_bcast # = 1
+ config_get_bool fwd_bcast "$cfg" forward_bcast 1
+ [ $fwd_bcast -eq 1 ] && append args "-B"
+
+ local fwd_dhcp # = 1
+ config_get_bool fwd_dhcp "$cfg" forward_dhcp 1
+ [ $fwd_dhcp -eq 1 ] && append args "-D"
+
+ service_start /usr/sbin/relayd $args
+}
+
+stop() {
+ for pid in /var/run/relay-*.pid; do
+ SERVICE_PID_FILE="$pid"
+ service_stop /usr/sbin/relayd
+ rm -f "$SERVICE_PID_FILE"
+ done
+}
+
+start() {
+ include /lib/network
+ config_load network
+ config_foreach start_relay interface
+}
diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile
new file mode 100644
index 0000000000..245426b4e2
--- /dev/null
+++ b/package/network/services/uhttpd/Makefile
@@ -0,0 +1,164 @@
+#
+# Copyright (C) 2010-2012 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:=uhttpd
+PKG_RELEASE:=40
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+PKG_CONFIG_DEPENDS := \
+ CONFIG_PACKAGE_uhttpd_debug \
+ CONFIG_PACKAGE_uhttpd-mod-lua \
+ CONFIG_PACKAGE_uhttpd-mod-tls \
+ CONFIG_PACKAGE_uhttpd-mod-tls_cyassl \
+ CONFIG_PACKAGE_uhttpd-mod-tls_openssl \
+ CONFIG_PACKAGE_uhttpd-mod-ubus
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/uhttpd/default
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Web Servers/Proxies
+ TITLE:=uHTTPd - tiny, single threaded HTTP server
+ MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+endef
+
+define Package/uhttpd
+ $(Package/uhttpd/default)
+ DEPENDS:=+libubox
+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_cyassl:libcyassl +PACKAGE_uhttpd-mod-tls_openssl:libopenssl
+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_cyassl
+
+ config PACKAGE_uhttpd-mod-tls_cyassl
+ bool "CyaSSL"
+
+ config PACKAGE_uhttpd-mod-tls_openssl
+ bool "OpenSSL"
+ endchoice
+endef
+
+UHTTPD_TLS:=
+TLS_CFLAGS:=
+TLS_LDFLAGS:=
+
+ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_cyassl),)
+ UHTTPD_TLS:=cyassl
+ TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl -DTLS_IS_CYASSL
+ TLS_LDFLAGS:=-lcyassl -lm
+endif
+
+ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
+ UHTTPD_TLS:=openssl
+ TLS_CFLAGS:=-DTLS_IS_OPENSSL
+ TLS_LDFLAGS:=-lssl
+endif
+
+
+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
+
+
+TARGET_CFLAGS += $(TLS_CFLAGS) $(if $(CONFIG_PACKAGE_uhttpd_debug),-DDEBUG) -ggdb3
+TARGET_LDFLAGS += -lubox -Wl,-rpath-link=$(STAGING_DIR)/usr/lib
+MAKE_VARS += \
+ FPIC="$(FPIC)" \
+ LUA_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-lua),1)" \
+ TLS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-tls),1)" \
+ UBUS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-ubus),1)" \
+ UHTTPD_TLS="$(UHTTPD_TLS)" \
+ TLS_CFLAGS="$(TLS_CFLAGS)" \
+ TLS_LDFLAGS="$(TLS_LDFLAGS)"
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Package/uhttpd/conffiles
+/etc/config/uhttpd
+/etc/uhttpd.crt
+/etc/uhttpd.key
+endef
+
+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
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd $(1)/usr/sbin/uhttpd
+endef
+
+define Package/uhttpd-mod-tls/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_tls.so $(1)/usr/lib/
+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
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_ubus.so $(1)/usr/lib/
+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/uhttpd.config b/package/network/services/uhttpd/files/uhttpd.config
new file mode 100644
index 0000000000..b33411e970
--- /dev/null
+++ b/package/network/services/uhttpd/files/uhttpd.config
@@ -0,0 +1,89 @@
+# 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
+
+ # 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
+
+ # 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
+
+ # 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
+
+ # 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 OpenWrt
+
+ # Configuration file in busybox httpd format
+# option config /etc/httpd.conf
+
+
+# Certificate defaults for px5g key generator
+config cert px5g
+
+ # Validity time
+ option days 730
+
+ # RSA key size
+ option bits 1024
+
+ # Location
+ option country DE
+ option state Berlin
+ option location Berlin
+
+ # Common name
+ option commonname OpenWrt
diff --git a/package/network/services/uhttpd/files/uhttpd.init b/package/network/services/uhttpd/files/uhttpd.init
new file mode 100755
index 0000000000..379a9f5b5f
--- /dev/null
+++ b/package/network/services/uhttpd/files/uhttpd.init
@@ -0,0 +1,135 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010 Jo-Philipp Wich
+
+START=50
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+UHTTPD_BIN="/usr/sbin/uhttpd"
+PX5G_BIN="/usr/sbin/px5g"
+
+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" ] && append UHTTPD_ARGS "$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 ] && append UHTTPD_ARGS "$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
+
+ [ -x "$PX5G_BIN" ] && {
+ $PX5G_BIN selfsigned -der \
+ -days ${days:-730} -newkey rsa:${bits:-1024} -keyout "$UHTTPD_KEY" -out "$UHTTPD_CERT" \
+ -subj /C="${country:-DE}"/ST="${state:-Saxony}"/L="${location:-Leipzig}"/CN="${commonname:-OpenWrt}"
+ }
+}
+
+start_instance()
+{
+ UHTTPD_ARGS=""
+ UHTTPD_CERT=""
+ UHTTPD_KEY=""
+
+ local cfg="$1"
+ local realm="$(uci_get system.@system[0].hostname)"
+ local listen http https interpreter path
+
+ append_arg "$cfg" home "-h"
+ append_arg "$cfg" realm "-r" "${realm:-OpenWrt}"
+ append_arg "$cfg" config "-c"
+ append_arg "$cfg" cgi_prefix "-x"
+ append_arg "$cfg" lua_prefix "-l"
+ append_arg "$cfg" lua_handler "-L"
+ append_arg "$cfg" script_timeout "-t"
+ append_arg "$cfg" network_timeout "-T"
+ append_arg "$cfg" tcp_keepalive "-A"
+ append_arg "$cfg" error_page "-E"
+ append_arg "$cfg" index_page "-I"
+ append_arg "$cfg" max_requests "-n" 3
+
+ append_bool "$cfg" no_symlinks "-S" 0
+ append_bool "$cfg" no_dirlists "-D" 0
+ append_bool "$cfg" rfc1918_filter "-R" 0
+
+ config_get http "$cfg" listen_http
+ for listen in $http; do
+ append UHTTPD_ARGS "-p $listen"
+ done
+
+ config_get interpreter "$cfg" interpreter
+ for path in $interpreter; do
+ append UHTTPD_ARGS "-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
+
+ [ -n "$https" ] && {
+ [ -f "$UHTTPD_CERT" -a -f "$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
+ append UHTTPD_ARGS "-s $listen"
+ done
+ }
+ }
+
+ SERVICE_PID_FILE=/var/run/uhttpd_${cfg}.pid
+ service_start $UHTTPD_BIN -f $UHTTPD_ARGS
+
+ # Check if daemon is running, if not then
+ # re-execute in foreground to display error.
+ sleep 1 && service_check $UHTTPD_BIN || \
+ $UHTTPD_BIN -f $UHTTPD_ARGS
+}
+
+stop_instance()
+{
+ local cfg="$1"
+
+ SERVICE_PID_FILE=/var/run/uhttpd_${cfg}.pid
+ service_stop $UHTTPD_BIN
+}
+
+start() {
+ config_load uhttpd
+ config_foreach start_instance uhttpd
+}
+
+stop() {
+ config_load uhttpd
+ config_foreach stop_instance uhttpd
+}
diff --git a/package/network/services/uhttpd/src/Makefile b/package/network/services/uhttpd/src/Makefile
new file mode 100644
index 0000000000..98226ed206
--- /dev/null
+++ b/package/network/services/uhttpd/src/Makefile
@@ -0,0 +1,89 @@
+CGI_SUPPORT ?= 1
+LUA_SUPPORT ?= 1
+TLS_SUPPORT ?= 1
+UHTTPD_TLS ?= cyassl
+
+CFLAGS ?= -I./lua-5.1.4/src $(TLS_CFLAGS) -O0 -ggdb3
+LDFLAGS ?= -L./lua-5.1.4/src
+
+CFLAGS += -Wall --std=gnu99
+
+ifeq ($(UHTTPD_TLS),openssl)
+ TLS_LDFLAGS ?= -L./openssl-0.9.8m -lssl
+ TLS_CFLAGS ?= -I./openssl-0.9.8m/include -DTLS_IS_OPENSSL
+else
+ TLS_LDFLAGS ?= -L./cyassl-1.4.0/src/.libs -lcyassl
+ TLS_CFLAGS ?= -I./cyassl-1.4.0/include -DTLS_IS_CYASSL
+endif
+
+OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
+LIB := -Wl,--export-dynamic -lcrypt -ldl
+
+TLSLIB :=
+LUALIB :=
+
+HAVE_SHADOW=$(shell echo 'int main(void){ return !getspnam("root"); }' | \
+ $(CC) -include shadow.h -xc -o/dev/null - 2>/dev/null && echo yes)
+
+ifeq ($(HAVE_SHADOW),yes)
+ CFLAGS += -DHAVE_SHADOW
+endif
+
+ifeq ($(TLS_SUPPORT),1)
+ CFLAGS += -DHAVE_TLS
+endif
+
+ifeq ($(CGI_SUPPORT),1)
+ CFLAGS += -DHAVE_CGI
+endif
+
+ifeq ($(LUA_SUPPORT),1)
+ CFLAGS += -DHAVE_LUA
+endif
+
+ifeq ($(UBUS_SUPPORT),1)
+ CFLAGS += -DHAVE_UBUS
+endif
+
+
+world: compile
+
+ifeq ($(CGI_SUPPORT),1)
+ OBJ += uhttpd-cgi.o
+endif
+
+ifeq ($(LUA_SUPPORT),1)
+ LUALIB := uhttpd_lua.so
+
+ $(LUALIB): uhttpd-lua.c
+ $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
+ -shared -lm -llua -ldl \
+ -o $(LUALIB) uhttpd-lua.c
+endif
+
+ifeq ($(TLS_SUPPORT),1)
+ TLSLIB := uhttpd_tls.so
+
+ $(TLSLIB): uhttpd-tls.c
+ $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
+ -shared $(TLS_LDFLAGS) \
+ -o $(TLSLIB) uhttpd-tls.c
+endif
+
+ifeq ($(UBUS_SUPPORT),1)
+ UBUSLIB := uhttpd_ubus.so
+
+ $(UBUSLIB): uhttpd-ubus.c
+ $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
+ -shared -lubus -ljson -lblobmsg_json \
+ -o $(UBUSLIB) uhttpd-ubus.c
+endif
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+compile: $(OBJ) $(TLSLIB) $(LUALIB) $(UBUSLIB)
+ $(CC) -o uhttpd $(LDFLAGS) $(OBJ) $(LIB)
+
+clean:
+ rm -f *.o *.so uhttpd
diff --git a/package/network/services/uhttpd/src/uhttpd-cgi.c b/package/network/services/uhttpd/src/uhttpd-cgi.c
new file mode 100644
index 0000000000..69af90db45
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-cgi.c
@@ -0,0 +1,556 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - CGI handler
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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 "uhttpd.h"
+#include "uhttpd-utils.h"
+#include "uhttpd-cgi.h"
+
+
+static bool
+uh_cgi_header_parse(struct http_response *res, char *buf, int len, int *off)
+{
+ char *bufptr = NULL;
+ char *hdrname = NULL;
+ int hdrcount = 0;
+ int pos = 0;
+
+ if (((bufptr = strfind(buf, len, "\r\n\r\n", 4)) != NULL) ||
+ ((bufptr = strfind(buf, len, "\n\n", 2)) != NULL))
+ {
+ *off = (int)(bufptr - buf) + ((bufptr[0] == '\r') ? 4 : 2);
+
+ memset(res, 0, sizeof(*res));
+
+ res->statuscode = 200;
+ res->statusmsg = "OK";
+
+ bufptr = &buf[0];
+
+ for (pos = 0; pos < *off; pos++)
+ {
+ if (!hdrname && (buf[pos] == ':'))
+ {
+ buf[pos++] = 0;
+
+ if ((pos < len) && (buf[pos] == ' '))
+ pos++;
+
+ if (pos < len)
+ {
+ hdrname = bufptr;
+ bufptr = &buf[pos];
+ }
+ }
+
+ else if ((buf[pos] == '\r') || (buf[pos] == '\n'))
+ {
+ if (! hdrname)
+ break;
+
+ buf[pos++] = 0;
+
+ if ((pos < len) && (buf[pos] == '\n'))
+ pos++;
+
+ if (pos <= len)
+ {
+ if ((hdrcount+1) < array_size(res->headers))
+ {
+ if (!strcasecmp(hdrname, "Status"))
+ {
+ res->statuscode = atoi(bufptr);
+
+ if (res->statuscode < 100)
+ res->statuscode = 200;
+
+ if (((bufptr = strchr(bufptr, ' ')) != NULL) &&
+ (&bufptr[1] != 0))
+ {
+ res->statusmsg = &bufptr[1];
+ }
+
+ D("CGI: HTTP/1.x %03d %s\n",
+ res->statuscode, res->statusmsg);
+ }
+ else
+ {
+ D("CGI: HTTP: %s: %s\n", hdrname, bufptr);
+
+ res->headers[hdrcount++] = hdrname;
+ res->headers[hdrcount++] = bufptr;
+ }
+
+ bufptr = &buf[pos];
+ hdrname = NULL;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static char * uh_cgi_header_lookup(struct http_response *res,
+ const char *hdrname)
+{
+ int i;
+
+ foreach_header(i, res->headers)
+ {
+ if (!strcasecmp(res->headers[i], hdrname))
+ return res->headers[i+1];
+ }
+
+ return NULL;
+}
+
+static void uh_cgi_shutdown(struct uh_cgi_state *state)
+{
+ free(state);
+}
+
+static bool uh_cgi_socket_cb(struct client *cl)
+{
+ int i, len, blen, hdroff;
+ char buf[UH_LIMIT_MSGHEAD];
+
+ struct uh_cgi_state *state = (struct uh_cgi_state *)cl->priv;
+ struct http_response *res = &cl->response;
+ struct http_request *req = &cl->request;
+
+ /* there is unread post data waiting */
+ while (state->content_length > 0)
+ {
+ /* remaining data in http head buffer ... */
+ if (cl->httpbuf.len > 0)
+ {
+ len = min(state->content_length, cl->httpbuf.len);
+
+ D("CGI: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
+
+ memcpy(buf, cl->httpbuf.ptr, len);
+
+ cl->httpbuf.len -= len;
+ cl->httpbuf.ptr +=len;
+ }
+
+ /* read it from socket ... */
+ else
+ {
+ len = uh_tcp_recv(cl, buf,
+ min(state->content_length, sizeof(buf)));
+
+ if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+ break;
+
+ D("CGI: Child(%d) feed %d/%d TCP socket bytes\n",
+ cl->proc.pid, len, min(state->content_length, sizeof(buf)));
+ }
+
+ if (len)
+ state->content_length -= len;
+ else
+ state->content_length = 0;
+
+ /* ... write to CGI process */
+ len = uh_raw_send(cl->wpipe.fd, buf, len,
+ cl->server->conf->script_timeout);
+
+ /* explicit EOF notification for the child */
+ if (state->content_length <= 0)
+ uh_ufd_remove(&cl->wpipe);
+ }
+
+ /* try to read data from child */
+ while ((len = uh_raw_recv(cl->rpipe.fd, buf, state->header_sent
+ ? sizeof(buf) : state->httpbuf.len, -1)) > 0)
+ {
+ /* we have not pushed out headers yet, parse input */
+ if (!state->header_sent)
+ {
+ /* try to parse header ... */
+ memcpy(state->httpbuf.ptr, buf, len);
+ state->httpbuf.len -= len;
+ state->httpbuf.ptr += len;
+
+ blen = state->httpbuf.ptr - state->httpbuf.buf;
+
+ if (uh_cgi_header_parse(res, state->httpbuf.buf, blen, &hdroff))
+ {
+ /* write status */
+ ensure_out(uh_http_sendf(cl, NULL,
+ "%s %03d %s\r\n"
+ "Connection: close\r\n",
+ http_versions[req->version],
+ res->statuscode, res->statusmsg));
+
+ /* add Content-Type if no Location or Content-Type */
+ if (!uh_cgi_header_lookup(res, "Location") &&
+ !uh_cgi_header_lookup(res, "Content-Type"))
+ {
+ ensure_out(uh_http_send(cl, NULL,
+ "Content-Type: text/plain\r\n", -1));
+ }
+
+ /* if request was HTTP 1.1 we'll respond chunked */
+ if ((req->version > UH_HTTP_VER_1_0) &&
+ !uh_cgi_header_lookup(res, "Transfer-Encoding"))
+ {
+ ensure_out(uh_http_send(cl, NULL,
+ "Transfer-Encoding: chunked\r\n", -1));
+ }
+
+ /* write headers from CGI program */
+ foreach_header(i, res->headers)
+ {
+ ensure_out(uh_http_sendf(cl, NULL, "%s: %s\r\n",
+ res->headers[i], res->headers[i+1]));
+ }
+
+ /* terminate header */
+ ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
+
+ state->header_sent = true;
+
+ /* push out remaining head buffer */
+ if (hdroff < blen)
+ {
+ D("CGI: Child(%d) relaying %d rest bytes\n",
+ cl->proc.pid, blen - hdroff);
+
+ ensure_out(uh_http_send(cl, req,
+ state->httpbuf.buf + hdroff,
+ blen - hdroff));
+ }
+ }
+
+ /* ... failed and head buffer exceeded */
+ else if (!state->httpbuf.len)
+ {
+ /* I would do this ...
+ *
+ * uh_cgi_error_500(cl, req,
+ * "The CGI program generated an "
+ * "invalid response:\n\n");
+ *
+ * ... but in order to stay as compatible as possible,
+ * treat whatever we got as text/plain response and
+ * build the required headers here.
+ */
+
+ ensure_out(uh_http_sendf(cl, NULL,
+ "%s 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "%s\r\n",
+ http_versions[req->version],
+ (req->version > UH_HTTP_VER_1_0)
+ ? "Transfer-Encoding: chunked\r\n" : ""
+ ));
+
+ state->header_sent = true;
+
+ D("CGI: Child(%d) relaying %d invalid bytes\n",
+ cl->proc.pid, len);
+
+ ensure_out(uh_http_send(cl, req, buf, len));
+ }
+ }
+ else
+ {
+ /* headers complete, pass through buffer to socket */
+ D("CGI: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
+ ensure_out(uh_http_send(cl, req, buf, len));
+ }
+ }
+
+ /* got EOF or read error from child */
+ if ((len == 0) ||
+ ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
+ {
+ D("CGI: Child(%d) presumed dead [%s]\n", cl->proc.pid, strerror(errno));
+
+ goto out;
+ }
+
+ return true;
+
+out:
+ if (!state->header_sent)
+ {
+ if (cl->timeout.pending)
+ uh_http_sendhf(cl, 502, "Bad Gateway",
+ "The CGI process did not produce any response\n");
+ else
+ uh_http_sendhf(cl, 504, "Gateway Timeout",
+ "The CGI process took too long to produce a "
+ "response\n");
+ }
+ else
+ {
+ uh_http_send(cl, req, "", 0);
+ }
+
+ uh_cgi_shutdown(state);
+ return false;
+}
+
+bool uh_cgi_request(struct client *cl, struct path_info *pi,
+ struct interpreter *ip)
+{
+ int i;
+
+ int rfd[2] = { 0, 0 };
+ int wfd[2] = { 0, 0 };
+
+ pid_t child;
+
+ struct uh_cgi_state *state;
+ struct http_request *req = &cl->request;
+
+ /* allocate state */
+ if (!(state = malloc(sizeof(*state))))
+ {
+ uh_http_sendhf(cl, 500, "Internal Server Error", "Out of memory");
+ return false;
+ }
+
+ /* spawn pipes for me->child, child->me */
+ if ((pipe(rfd) < 0) || (pipe(wfd) < 0))
+ {
+ if (rfd[0] > 0) close(rfd[0]);
+ if (rfd[1] > 0) close(rfd[1]);
+ if (wfd[0] > 0) close(wfd[0]);
+ if (wfd[1] > 0) close(wfd[1]);
+
+ uh_http_sendhf(cl, 500, "Internal Server Error",
+ "Failed to create pipe: %s\n", strerror(errno));
+
+ return false;
+ }
+
+ /* fork off child process */
+ switch ((child = fork()))
+ {
+ /* oops */
+ case -1:
+ uh_http_sendhf(cl, 500, "Internal Server Error",
+ "Failed to fork child: %s\n", strerror(errno));
+
+ return false;
+
+ /* exec child */
+ case 0:
+#ifdef DEBUG
+ sleep(atoi(getenv("UHTTPD_SLEEP_ON_FORK") ?: "0"));
+#endif
+
+ /* do not leak parent epoll descriptor */
+ uloop_done();
+
+ /* close loose pipe ends */
+ close(rfd[0]);
+ close(wfd[1]);
+
+ /* patch stdout and stdin to pipes */
+ dup2(rfd[1], 1);
+ dup2(wfd[0], 0);
+
+ /* avoid leaking our pipe into child-child processes */
+ fd_cloexec(rfd[1]);
+ fd_cloexec(wfd[0]);
+
+ /* check for regular, world-executable file _or_ interpreter */
+ if (((pi->stat.st_mode & S_IFREG) &&
+ (pi->stat.st_mode & S_IXOTH)) || (ip != NULL))
+ {
+ /* build environment */
+ clearenv();
+
+ /* common information */
+ setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
+ setenv("SERVER_SOFTWARE", "uHTTPd", 1);
+ setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
+
+#ifdef HAVE_TLS
+ /* https? */
+ if (cl->tls)
+ setenv("HTTPS", "on", 1);
+#endif
+
+ /* addresses */
+ setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1);
+ setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1);
+ setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1);
+ setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1);
+ setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1);
+ setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1);
+
+ /* path information */
+ setenv("SCRIPT_NAME", pi->name, 1);
+ setenv("SCRIPT_FILENAME", pi->phys, 1);
+ setenv("DOCUMENT_ROOT", pi->root, 1);
+ setenv("QUERY_STRING", pi->query ? pi->query : "", 1);
+
+ if (pi->info)
+ setenv("PATH_INFO", pi->info, 1);
+
+ /* REDIRECT_STATUS, php-cgi wants it */
+ switch (req->redirect_status)
+ {
+ case 404:
+ setenv("REDIRECT_STATUS", "404", 1);
+ break;
+
+ default:
+ setenv("REDIRECT_STATUS", "200", 1);
+ break;
+ }
+
+ /* http version */
+ setenv("SERVER_PROTOCOL", http_versions[req->version], 1);
+
+ /* request method */
+ setenv("REQUEST_METHOD", http_methods[req->method], 1);
+
+ /* request url */
+ setenv("REQUEST_URI", req->url, 1);
+
+ /* remote user */
+ if (req->realm)
+ setenv("REMOTE_USER", req->realm->user, 1);
+
+ /* request message headers */
+ foreach_header(i, req->headers)
+ {
+ if (!strcasecmp(req->headers[i], "Accept"))
+ setenv("HTTP_ACCEPT", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Accept-Charset"))
+ setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Accept-Encoding"))
+ setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Accept-Language"))
+ setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Authorization"))
+ setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Connection"))
+ setenv("HTTP_CONNECTION", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Cookie"))
+ setenv("HTTP_COOKIE", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Host"))
+ setenv("HTTP_HOST", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Referer"))
+ setenv("HTTP_REFERER", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "User-Agent"))
+ setenv("HTTP_USER_AGENT", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Content-Type"))
+ setenv("CONTENT_TYPE", req->headers[i+1], 1);
+
+ else if (!strcasecmp(req->headers[i], "Content-Length"))
+ setenv("CONTENT_LENGTH", req->headers[i+1], 1);
+ }
+
+
+ /* execute child code ... */
+ if (chdir(pi->root))
+ perror("chdir()");
+
+ if (ip != NULL)
+ execl(ip->path, ip->path, pi->phys, NULL);
+ else
+ execl(pi->phys, pi->phys, NULL);
+
+ /* in case it fails ... */
+ printf("Status: 500 Internal Server Error\r\n\r\n"
+ "Unable to launch the requested CGI program:\n"
+ " %s: %s\n", ip ? ip->path : pi->phys, strerror(errno));
+ }
+
+ /* 403 */
+ else
+ {
+ printf("Status: 403 Forbidden\r\n\r\n"
+ "Access to this resource is forbidden\n");
+ }
+
+ close(wfd[0]);
+ close(rfd[1]);
+ exit(0);
+
+ break;
+
+ /* parent; handle I/O relaying */
+ default:
+ memset(state, 0, sizeof(*state));
+
+ cl->rpipe.fd = rfd[0];
+ cl->wpipe.fd = wfd[1];
+ cl->proc.pid = child;
+
+ /* make pipe non-blocking */
+ fd_nonblock(cl->rpipe.fd);
+ fd_nonblock(cl->wpipe.fd);
+
+ /* close unneeded pipe ends */
+ close(rfd[1]);
+ close(wfd[0]);
+
+ D("CGI: Child(%d) created: rfd(%d) wfd(%d)\n", child, rfd[0], wfd[1]);
+
+ state->httpbuf.ptr = state->httpbuf.buf;
+ state->httpbuf.len = sizeof(state->httpbuf.buf);
+
+ state->content_length = cl->httpbuf.len;
+
+ /* find content length */
+ if (req->method == UH_HTTP_MSG_POST)
+ {
+ foreach_header(i, req->headers)
+ {
+ if (!strcasecmp(req->headers[i], "Content-Length"))
+ {
+ state->content_length = atoi(req->headers[i+1]);
+ break;
+ }
+ }
+ }
+
+ cl->cb = uh_cgi_socket_cb;
+ cl->priv = state;
+
+ break;
+ }
+
+ return true;
+}
diff --git a/package/network/services/uhttpd/src/uhttpd-cgi.h b/package/network/services/uhttpd/src/uhttpd-cgi.h
new file mode 100644
index 0000000000..c7094da424
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-cgi.h
@@ -0,0 +1,43 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - CGI header
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_CGI_
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/limits.h>
+
+#include <time.h>
+
+
+struct uh_cgi_state {
+ struct {
+ char buf[UH_LIMIT_MSGHEAD];
+ char *ptr;
+ int len;
+ } httpbuf;
+ int content_length;
+ bool header_sent;
+};
+
+bool uh_cgi_request(struct client *cl, struct path_info *pi,
+ struct interpreter *ip);
+
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd-file.c b/package/network/services/uhttpd/src/uhttpd-file.c
new file mode 100644
index 0000000000..0bafc2b38c
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-file.c
@@ -0,0 +1,438 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Static file handler
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#define _XOPEN_SOURCE 500 /* strptime() */
+#define _BSD_SOURCE /* scandir(), timegm() */
+
+#include "uhttpd.h"
+#include "uhttpd-utils.h"
+#include "uhttpd-file.h"
+
+#include "uhttpd-mimetypes.h"
+
+
+static const char * uh_file_mime_lookup(const char *path)
+{
+ struct mimetype *m = &uh_mime_types[0];
+ const char *e;
+
+ while (m->extn)
+ {
+ e = &path[strlen(path)-1];
+
+ while (e >= path)
+ {
+ if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
+ return m->mime;
+
+ e--;
+ }
+
+ m++;
+ }
+
+ return "application/octet-stream";
+}
+
+static const char * uh_file_mktag(struct stat *s)
+{
+ static char tag[128];
+
+ snprintf(tag, sizeof(tag), "\"%x-%x-%x\"",
+ (unsigned int) s->st_ino,
+ (unsigned int) s->st_size,
+ (unsigned int) s->st_mtime);
+
+ return tag;
+}
+
+static time_t uh_file_date2unix(const char *date)
+{
+ struct tm t;
+
+ memset(&t, 0, sizeof(t));
+
+ if (strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL)
+ return timegm(&t);
+
+ return 0;
+}
+
+static char * uh_file_unix2date(time_t ts)
+{
+ static char str[128];
+ struct tm *t = gmtime(&ts);
+
+ strftime(str, sizeof(str), "%a, %d %b %Y %H:%M:%S GMT", t);
+
+ return str;
+}
+
+static char * uh_file_header_lookup(struct client *cl, const char *name)
+{
+ int i;
+
+ foreach_header(i, cl->request.headers)
+ {
+ if (!strcasecmp(cl->request.headers[i], name))
+ return cl->request.headers[i+1];
+ }
+
+ return NULL;
+}
+
+
+static int uh_file_response_ok_hdrs(struct client *cl, struct stat *s)
+{
+ ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n"));
+
+ if (s)
+ {
+ ensure_ret(uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s)));
+ ensure_ret(uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n",
+ uh_file_unix2date(s->st_mtime)));
+ }
+
+ return uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL)));
+}
+
+static int uh_file_response_200(struct client *cl, struct stat *s)
+{
+ ensure_ret(uh_http_sendf(cl, NULL, "%s 200 OK\r\n",
+ http_versions[cl->request.version]));
+
+ return uh_file_response_ok_hdrs(cl, s);
+}
+
+static int uh_file_response_304(struct client *cl, struct stat *s)
+{
+ ensure_ret(uh_http_sendf(cl, NULL, "%s 304 Not Modified\r\n",
+ http_versions[cl->request.version]));
+
+ return uh_file_response_ok_hdrs(cl, s);
+}
+
+static int uh_file_response_412(struct client *cl)
+{
+ return uh_http_sendf(cl, NULL,
+ "%s 412 Precondition Failed\r\n"
+ "Connection: close\r\n",
+ http_versions[cl->request.version]);
+}
+
+static int uh_file_if_match(struct client *cl, struct stat *s, int *ok)
+{
+ const char *tag = uh_file_mktag(s);
+ char *hdr = uh_file_header_lookup(cl, "If-Match");
+ char *p;
+ int i;
+
+ if (hdr)
+ {
+ p = &hdr[0];
+
+ for (i = 0; i < strlen(hdr); i++)
+ {
+ if ((hdr[i] == ' ') || (hdr[i] == ','))
+ {
+ hdr[i++] = 0;
+ p = &hdr[i];
+ }
+ else if (!strcmp(p, "*") || !strcmp(p, tag))
+ {
+ *ok = 1;
+ return *ok;
+ }
+ }
+
+ *ok = 0;
+ ensure_ret(uh_file_response_412(cl));
+ return *ok;
+ }
+
+ *ok = 1;
+ return *ok;
+}
+
+static int uh_file_if_modified_since(struct client *cl, struct stat *s, int *ok)
+{
+ char *hdr = uh_file_header_lookup(cl, "If-Modified-Since");
+ *ok = 1;
+
+ if (hdr)
+ {
+ if (uh_file_date2unix(hdr) >= s->st_mtime)
+ {
+ *ok = 0;
+ ensure_ret(uh_file_response_304(cl, s));
+ }
+ }
+
+ return *ok;
+}
+
+static int uh_file_if_none_match(struct client *cl, struct stat *s, int *ok)
+{
+ const char *tag = uh_file_mktag(s);
+ char *hdr = uh_file_header_lookup(cl, "If-None-Match");
+ char *p;
+ int i;
+ *ok = 1;
+
+ if (hdr)
+ {
+ p = &hdr[0];
+
+ for (i = 0; i < strlen(hdr); i++)
+ {
+ if ((hdr[i] == ' ') || (hdr[i] == ','))
+ {
+ hdr[i++] = 0;
+ p = &hdr[i];
+ }
+ else if (!strcmp(p, "*") || !strcmp(p, tag))
+ {
+ *ok = 0;
+
+ if ((cl->request.method == UH_HTTP_MSG_GET) ||
+ (cl->request.method == UH_HTTP_MSG_HEAD))
+ {
+ ensure_ret(uh_file_response_304(cl, s));
+ }
+ else
+ {
+ ensure_ret(uh_file_response_412(cl));
+ }
+
+ break;
+ }
+ }
+ }
+
+ return *ok;
+}
+
+static int uh_file_if_range(struct client *cl, struct stat *s, int *ok)
+{
+ char *hdr = uh_file_header_lookup(cl, "If-Range");
+ *ok = 1;
+
+ if (hdr)
+ {
+ *ok = 0;
+ ensure_ret(uh_file_response_412(cl));
+ }
+
+ return *ok;
+}
+
+static int uh_file_if_unmodified_since(struct client *cl, struct stat *s,
+ int *ok)
+{
+ char *hdr = uh_file_header_lookup(cl, "If-Unmodified-Since");
+ *ok = 1;
+
+ if (hdr)
+ {
+ if (uh_file_date2unix(hdr) <= s->st_mtime)
+ {
+ *ok = 0;
+ ensure_ret(uh_file_response_412(cl));
+ }
+ }
+
+ return *ok;
+}
+
+
+static int uh_file_scandir_filter_dir(const struct dirent *e)
+{
+ return strcmp(e->d_name, ".") ? 1 : 0;
+}
+
+static void uh_file_dirlist(struct client *cl, struct path_info *pi)
+{
+ int i;
+ int count = 0;
+ char filename[PATH_MAX];
+ char *pathptr;
+ struct dirent **files = NULL;
+ struct stat s;
+
+ ensure_out(uh_http_sendf(cl, &cl->request,
+ "<html><head><title>Index of %s</title></head>"
+ "<body><h1>Index of %s</h1><hr /><ol>",
+ pi->name, pi->name));
+
+ if ((count = scandir(pi->phys, &files, uh_file_scandir_filter_dir,
+ alphasort)) > 0)
+ {
+ memset(filename, 0, sizeof(filename));
+ memcpy(filename, pi->phys, sizeof(filename));
+ pathptr = &filename[strlen(filename)];
+
+ /* list subdirs */
+ for (i = 0; i < count; i++)
+ {
+ strncat(filename, files[i]->d_name,
+ sizeof(filename) - strlen(files[i]->d_name));
+
+ if (!stat(filename, &s) &&
+ (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH))
+ {
+ ensure_out(uh_http_sendf(cl, &cl->request,
+ "<li><strong><a href='%s%s'>%s</a>/"
+ "</strong><br /><small>modified: %s"
+ "<br />directory - %.02f kbyte<br />"
+ "<br /></small></li>",
+ pi->name, files[i]->d_name,
+ files[i]->d_name,
+ uh_file_unix2date(s.st_mtime),
+ s.st_size / 1024.0));
+ }
+
+ *pathptr = 0;
+ }
+
+ /* list files */
+ for (i = 0; i < count; i++)
+ {
+ strncat(filename, files[i]->d_name,
+ sizeof(filename) - strlen(files[i]->d_name));
+
+ if (!stat(filename, &s) &&
+ !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH))
+ {
+ ensure_out(uh_http_sendf(cl, &cl->request,
+ "<li><strong><a href='%s%s'>%s</a>"
+ "</strong><br /><small>modified: %s"
+ "<br />%s - %.02f kbyte<br />"
+ "<br /></small></li>",
+ pi->name, files[i]->d_name,
+ files[i]->d_name,
+ uh_file_unix2date(s.st_mtime),
+ uh_file_mime_lookup(filename),
+ s.st_size / 1024.0));
+ }
+
+ *pathptr = 0;
+ }
+ }
+
+ ensure_out(uh_http_sendf(cl, &cl->request, "</ol><hr /></body></html>"));
+ ensure_out(uh_http_sendf(cl, &cl->request, ""));
+
+out:
+ if (files)
+ {
+ for (i = 0; i < count; i++)
+ free(files[i]);
+
+ free(files);
+ }
+}
+
+
+bool uh_file_request(struct client *cl, struct path_info *pi)
+{
+ int rlen;
+ int ok = 1;
+ int fd = -1;
+ char buf[UH_LIMIT_MSGHEAD];
+
+ /* we have a file */
+ if ((pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0))
+ {
+ /* test preconditions */
+ if (ok) ensure_out(uh_file_if_modified_since(cl, &pi->stat, &ok));
+ if (ok) ensure_out(uh_file_if_match(cl, &pi->stat, &ok));
+ if (ok) ensure_out(uh_file_if_range(cl, &pi->stat, &ok));
+ if (ok) ensure_out(uh_file_if_unmodified_since(cl, &pi->stat, &ok));
+ if (ok) ensure_out(uh_file_if_none_match(cl, &pi->stat, &ok));
+
+ if (ok > 0)
+ {
+ /* write status */
+ ensure_out(uh_file_response_200(cl, &pi->stat));
+
+ ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n",
+ uh_file_mime_lookup(pi->name)));
+
+ ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n",
+ pi->stat.st_size));
+
+ /* if request was HTTP 1.1 we'll respond chunked */
+ if ((cl->request.version > 1.0) &&
+ (cl->request.method != UH_HTTP_MSG_HEAD))
+ {
+ ensure_out(uh_http_send(cl, NULL,
+ "Transfer-Encoding: chunked\r\n", -1));
+ }
+
+ /* close header */
+ ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
+
+ /* send body */
+ if (cl->request.method != UH_HTTP_MSG_HEAD)
+ {
+ /* pump file data */
+ while ((rlen = read(fd, buf, sizeof(buf))) > 0)
+ ensure_out(uh_http_send(cl, &cl->request, buf, rlen));
+
+ /* send trailer in chunked mode */
+ ensure_out(uh_http_send(cl, &cl->request, "", 0));
+ }
+ }
+
+ /* one of the preconditions failed, terminate opened header and exit */
+ else
+ {
+ ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
+ }
+ }
+
+ /* directory */
+ else if ((pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists)
+ {
+ /* write status */
+ ensure_out(uh_file_response_200(cl, NULL));
+
+ if (cl->request.version > 1.0)
+ ensure_out(uh_http_send(cl, NULL,
+ "Transfer-Encoding: chunked\r\n", -1));
+
+ ensure_out(uh_http_send(cl, NULL,
+ "Content-Type: text/html\r\n\r\n", -1));
+
+ /* content */
+ uh_file_dirlist(cl, pi);
+ }
+
+ /* 403 */
+ else
+ {
+ ensure_out(uh_http_sendhf(cl, 403, "Forbidden",
+ "Access to this resource is forbidden"));
+ }
+
+out:
+ if (fd > -1)
+ close(fd);
+
+ return false;
+}
diff --git a/package/network/services/uhttpd/src/uhttpd-file.h b/package/network/services/uhttpd/src/uhttpd-file.h
new file mode 100644
index 0000000000..08dbe2cf9a
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-file.h
@@ -0,0 +1,36 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Static file header
+ *
+ * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_FILE_
+
+#include <fcntl.h>
+#include <time.h>
+#include <strings.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/limits.h>
+
+struct mimetype {
+ const char *extn;
+ const char *mime;
+};
+
+bool uh_file_request(struct client *cl, struct path_info *pi);
+
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd-lua.c b/package/network/services/uhttpd/src/uhttpd-lua.c
new file mode 100644
index 0000000000..e113937399
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-lua.c
@@ -0,0 +1,579 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Lua handler
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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 "uhttpd.h"
+#include "uhttpd-utils.h"
+#include "uhttpd-lua.h"
+
+
+static int uh_lua_recv(lua_State *L)
+{
+ size_t length;
+
+ char buffer[UH_LIMIT_MSGHEAD];
+
+ int to = 1;
+ int fd = fileno(stdin);
+ int rlen = 0;
+
+ length = luaL_checknumber(L, 1);
+
+ if ((length > 0) && (length <= sizeof(buffer)))
+ {
+ /* receive data */
+ rlen = uh_raw_recv(fd, buffer, length, to);
+
+ /* data read */
+ if (rlen > 0)
+ {
+ lua_pushnumber(L, rlen);
+ lua_pushlstring(L, buffer, rlen);
+ return 2;
+ }
+
+ /* eof */
+ else if (rlen == 0)
+ {
+ lua_pushnumber(L, 0);
+ return 1;
+ }
+
+ /* no, timeout and actually no data */
+ else
+ {
+ lua_pushnumber(L, -1);
+ return 1;
+ }
+ }
+
+ /* parameter error */
+ lua_pushnumber(L, -2);
+ return 1;
+}
+
+static int uh_lua_send_common(lua_State *L, bool chunked)
+{
+ size_t length;
+
+ char chunk[16];
+ const char *buffer;
+
+ int rv;
+ int to = 1;
+ int fd = fileno(stdout);
+ int slen = 0;
+
+ buffer = luaL_checklstring(L, 1, &length);
+
+ if (chunked)
+ {
+ if (length > 0)
+ {
+ snprintf(chunk, sizeof(chunk), "%X\r\n", length);
+
+ ensure_out(rv = uh_raw_send(fd, chunk, strlen(chunk), to));
+ slen += rv;
+
+ ensure_out(rv = uh_raw_send(fd, buffer, length, to));
+ slen += rv;
+
+ ensure_out(rv = uh_raw_send(fd, "\r\n", 2, to));
+ slen += rv;
+ }
+ else
+ {
+ slen = uh_raw_send(fd, "0\r\n\r\n", 5, to);
+ }
+ }
+ else
+ {
+ slen = uh_raw_send(fd, buffer, length, to);
+ }
+
+out:
+ lua_pushnumber(L, slen);
+ return 1;
+}
+
+static int uh_lua_send(lua_State *L)
+{
+ return uh_lua_send_common(L, false);
+}
+
+static int uh_lua_sendc(lua_State *L)
+{
+ return uh_lua_send_common(L, true);
+}
+
+static int uh_lua_str2str(lua_State *L, int (*xlate_func) (char *, int, const char *, int))
+{
+ size_t inlen;
+ int outlen;
+ const char *inbuf;
+ char outbuf[UH_LIMIT_MSGHEAD];
+
+ inbuf = luaL_checklstring(L, 1, &inlen);
+ outlen = (* xlate_func)(outbuf, sizeof(outbuf), inbuf, inlen);
+ if (outlen < 0)
+ luaL_error(L, "%s on URL-encode codec",
+ (outlen==-1) ? "buffer overflow" : "malformed string");
+
+ lua_pushlstring(L, outbuf, outlen);
+ return 1;
+}
+
+static int uh_lua_urldecode(lua_State *L)
+{
+ return uh_lua_str2str( L, uh_urldecode );
+}
+
+
+static int uh_lua_urlencode(lua_State *L)
+{
+ return uh_lua_str2str( L, uh_urlencode );
+}
+
+
+lua_State * uh_lua_init(const struct config *conf)
+{
+ lua_State *L = lua_open();
+ const char *err_str = NULL;
+
+ /* Load standard libaries */
+ luaL_openlibs(L);
+
+ /* build uhttpd api table */
+ lua_newtable(L);
+
+ /* register global send and receive functions */
+ lua_pushcfunction(L, uh_lua_recv);
+ lua_setfield(L, -2, "recv");
+
+ lua_pushcfunction(L, uh_lua_send);
+ lua_setfield(L, -2, "send");
+
+ lua_pushcfunction(L, uh_lua_sendc);
+ lua_setfield(L, -2, "sendc");
+
+ lua_pushcfunction(L, uh_lua_urldecode);
+ lua_setfield(L, -2, "urldecode");
+
+ lua_pushcfunction(L, uh_lua_urlencode);
+ lua_setfield(L, -2, "urlencode");
+
+ /* Pass the document-root to the Lua handler by placing it in
+ ** uhttpd.docroot. It could alternatively be placed in env.DOCUMENT_ROOT
+ ** which would more closely resemble the CGI protocol; but would mean that
+ ** it is not available at the time when the handler-chunk is loaded but
+ ** rather not until the handler is called, without any code savings. */
+ lua_pushstring(L, conf->docroot);
+ lua_setfield(L, -2, "docroot");
+
+ /* _G.uhttpd = { ... } */
+ lua_setfield(L, LUA_GLOBALSINDEX, "uhttpd");
+
+
+ /* load Lua handler */
+ switch (luaL_loadfile(L, conf->lua_handler))
+ {
+ case LUA_ERRSYNTAX:
+ fprintf(stderr,
+ "Lua handler contains syntax errors, unable to continue\n");
+ exit(1);
+
+ case LUA_ERRMEM:
+ fprintf(stderr,
+ "Lua handler ran out of memory, unable to continue\n");
+ exit(1);
+
+ case LUA_ERRFILE:
+ fprintf(stderr,
+ "Lua cannot open the handler script, unable to continue\n");
+ exit(1);
+
+ default:
+ /* compile Lua handler */
+ switch (lua_pcall(L, 0, 0, 0))
+ {
+ case LUA_ERRRUN:
+ err_str = luaL_checkstring(L, -1);
+ fprintf(stderr,
+ "Lua handler had runtime error, "
+ "unable to continue\n"
+ "Error: %s\n", err_str);
+ exit(1);
+
+ case LUA_ERRMEM:
+ err_str = luaL_checkstring(L, -1);
+ fprintf(stderr,
+ "Lua handler ran out of memory, "
+ "unable to continue\n"
+ "Error: %s\n", err_str);
+ exit(1);
+
+ default:
+ /* test handler function */
+ lua_getglobal(L, UH_LUA_CALLBACK);
+
+ if (! lua_isfunction(L, -1))
+ {
+ fprintf(stderr,
+ "Lua handler provides no "UH_LUA_CALLBACK"(), "
+ "unable to continue\n");
+ exit(1);
+ }
+
+ lua_pop(L, 1);
+ break;
+ }
+
+ break;
+ }
+
+ return L;
+}
+
+static void uh_lua_shutdown(struct uh_lua_state *state)
+{
+ free(state);
+}
+
+static bool uh_lua_socket_cb(struct client *cl)
+{
+ int len;
+ char buf[UH_LIMIT_MSGHEAD];
+
+ struct uh_lua_state *state = (struct uh_lua_state *)cl->priv;
+
+ /* there is unread post data waiting */
+ while (state->content_length > 0)
+ {
+ /* remaining data in http head buffer ... */
+ if (cl->httpbuf.len > 0)
+ {
+ len = min(state->content_length, cl->httpbuf.len);
+
+ D("Lua: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
+
+ memcpy(buf, cl->httpbuf.ptr, len);
+
+ cl->httpbuf.len -= len;
+ cl->httpbuf.ptr += len;
+ }
+
+ /* read it from socket ... */
+ else
+ {
+ len = uh_tcp_recv(cl, buf, min(state->content_length, sizeof(buf)));
+
+ if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+ break;
+
+ D("Lua: Child(%d) feed %d/%d TCP socket bytes\n",
+ cl->proc.pid, len, min(state->content_length, sizeof(buf)));
+ }
+
+ if (len)
+ state->content_length -= len;
+ else
+ state->content_length = 0;
+
+ /* ... write to Lua process */
+ len = uh_raw_send(cl->wpipe.fd, buf, len,
+ cl->server->conf->script_timeout);
+
+ /* explicit EOF notification for the child */
+ if (state->content_length <= 0)
+ uh_ufd_remove(&cl->wpipe);
+ }
+
+ /* try to read data from child */
+ while ((len = uh_raw_recv(cl->rpipe.fd, buf, sizeof(buf), -1)) > 0)
+ {
+ /* pass through buffer to socket */
+ D("Lua: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
+ ensure_out(uh_tcp_send(cl, buf, len));
+ state->data_sent = true;
+ }
+
+ /* got EOF or read error from child */
+ if ((len == 0) ||
+ ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
+ {
+ D("Lua: Child(%d) presumed dead [%s]\n",
+ cl->proc.pid, strerror(errno));
+
+ goto out;
+ }
+
+ return true;
+
+out:
+ if (!state->data_sent)
+ {
+ if (cl->timeout.pending)
+ uh_http_sendhf(cl, 502, "Bad Gateway",
+ "The Lua process did not produce any response\n");
+ else
+ uh_http_sendhf(cl, 504, "Gateway Timeout",
+ "The Lua process took too long to produce a "
+ "response\n");
+ }
+
+ uh_lua_shutdown(state);
+ return false;
+}
+
+bool uh_lua_request(struct client *cl, lua_State *L)
+{
+ int i;
+ char *query_string;
+ const char *prefix = cl->server->conf->lua_prefix;
+ const char *err_str = NULL;
+
+ int rfd[2] = { 0, 0 };
+ int wfd[2] = { 0, 0 };
+
+ pid_t child;
+
+ struct uh_lua_state *state;
+ struct http_request *req = &cl->request;
+
+ int content_length = cl->httpbuf.len;
+
+
+ /* allocate state */
+ if (!(state = malloc(sizeof(*state))))
+ {
+ uh_client_error(cl, 500, "Internal Server Error", "Out of memory");
+ return false;
+ }
+
+ /* spawn pipes for me->child, child->me */
+ if ((pipe(rfd) < 0) || (pipe(wfd) < 0))
+ {
+ if (rfd[0] > 0) close(rfd[0]);
+ if (rfd[1] > 0) close(rfd[1]);
+ if (wfd[0] > 0) close(wfd[0]);
+ if (wfd[1] > 0) close(wfd[1]);
+
+ uh_client_error(cl, 500, "Internal Server Error",
+ "Failed to create pipe: %s", strerror(errno));
+
+ return false;
+ }
+
+
+ switch ((child = fork()))
+ {
+ case -1:
+ uh_client_error(cl, 500, "Internal Server Error",
+ "Failed to fork child: %s", strerror(errno));
+
+ return false;
+
+ case 0:
+#ifdef DEBUG
+ sleep(atoi(getenv("UHTTPD_SLEEP_ON_FORK") ?: "0"));
+#endif
+
+ /* do not leak parent epoll descriptor */
+ uloop_done();
+
+ /* close loose pipe ends */
+ close(rfd[0]);
+ close(wfd[1]);
+
+ /* patch stdout and stdin to pipes */
+ dup2(rfd[1], 1);
+ dup2(wfd[0], 0);
+
+ /* avoid leaking our pipe into child-child processes */
+ fd_cloexec(rfd[1]);
+ fd_cloexec(wfd[0]);
+
+ /* put handler callback on stack */
+ lua_getglobal(L, UH_LUA_CALLBACK);
+
+ /* build env table */
+ lua_newtable(L);
+
+ /* request method */
+ lua_pushstring(L, http_methods[req->method]);
+ lua_setfield(L, -2, "REQUEST_METHOD");
+
+ /* request url */
+ lua_pushstring(L, req->url);
+ lua_setfield(L, -2, "REQUEST_URI");
+
+ /* script name */
+ lua_pushstring(L, cl->server->conf->lua_prefix);
+ lua_setfield(L, -2, "SCRIPT_NAME");
+
+ /* query string, path info */
+ if ((query_string = strchr(req->url, '?')) != NULL)
+ {
+ lua_pushstring(L, query_string + 1);
+ lua_setfield(L, -2, "QUERY_STRING");
+
+ if ((int)(query_string - req->url) > strlen(prefix))
+ {
+ lua_pushlstring(L,
+ &req->url[strlen(prefix)],
+ (int)(query_string - req->url) - strlen(prefix)
+ );
+
+ lua_setfield(L, -2, "PATH_INFO");
+ }
+ }
+ else if (strlen(req->url) > strlen(prefix))
+ {
+ lua_pushstring(L, &req->url[strlen(prefix)]);
+ lua_setfield(L, -2, "PATH_INFO");
+ }
+
+ /* http protcol version */
+ lua_pushnumber(L, 0.9 + (req->version / 10.0));
+ lua_setfield(L, -2, "HTTP_VERSION");
+
+ lua_pushstring(L, http_versions[req->version]);
+ lua_setfield(L, -2, "SERVER_PROTOCOL");
+
+
+ /* address information */
+ lua_pushstring(L, sa_straddr(&cl->peeraddr));
+ lua_setfield(L, -2, "REMOTE_ADDR");
+
+ lua_pushinteger(L, sa_port(&cl->peeraddr));
+ lua_setfield(L, -2, "REMOTE_PORT");
+
+ lua_pushstring(L, sa_straddr(&cl->servaddr));
+ lua_setfield(L, -2, "SERVER_ADDR");
+
+ lua_pushinteger(L, sa_port(&cl->servaddr));
+ lua_setfield(L, -2, "SERVER_PORT");
+
+ /* essential env vars */
+ foreach_header(i, req->headers)
+ {
+ if (!strcasecmp(req->headers[i], "Content-Length"))
+ {
+ content_length = atoi(req->headers[i+1]);
+ }
+ else if (!strcasecmp(req->headers[i], "Content-Type"))
+ {
+ lua_pushstring(L, req->headers[i+1]);
+ lua_setfield(L, -2, "CONTENT_TYPE");
+ }
+ }
+
+ lua_pushnumber(L, content_length);
+ lua_setfield(L, -2, "CONTENT_LENGTH");
+
+ /* misc. headers */
+ lua_newtable(L);
+
+ foreach_header(i, req->headers)
+ {
+ if( strcasecmp(req->headers[i], "Content-Length") &&
+ strcasecmp(req->headers[i], "Content-Type"))
+ {
+ lua_pushstring(L, req->headers[i+1]);
+ lua_setfield(L, -2, req->headers[i]);
+ }
+ }
+
+ lua_setfield(L, -2, "headers");
+
+
+ /* call */
+ switch (lua_pcall(L, 1, 0, 0))
+ {
+ case LUA_ERRMEM:
+ case LUA_ERRRUN:
+ err_str = luaL_checkstring(L, -1);
+
+ if (! err_str)
+ err_str = "Unknown error";
+
+ printf("%s 500 Internal Server Error\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: %i\r\n\r\n"
+ "Lua raised a runtime error:\n %s\n",
+ http_versions[req->version],
+ 31 + strlen(err_str), err_str);
+
+ break;
+
+ default:
+ break;
+ }
+
+ close(wfd[0]);
+ close(rfd[1]);
+ exit(0);
+
+ break;
+
+ /* parent; handle I/O relaying */
+ default:
+ memset(state, 0, sizeof(*state));
+
+ cl->rpipe.fd = rfd[0];
+ cl->wpipe.fd = wfd[1];
+ cl->proc.pid = child;
+
+ /* make pipe non-blocking */
+ fd_nonblock(cl->rpipe.fd);
+ fd_nonblock(cl->wpipe.fd);
+
+ /* close unneeded pipe ends */
+ close(rfd[1]);
+ close(wfd[0]);
+
+ D("Lua: Child(%d) created: rfd(%d) wfd(%d)\n", child, rfd[0], wfd[1]);
+
+ state->content_length = cl->httpbuf.len;
+
+ /* find content length */
+ if (req->method == UH_HTTP_MSG_POST)
+ {
+ foreach_header(i, req->headers)
+ {
+ if (!strcasecmp(req->headers[i], "Content-Length"))
+ {
+ state->content_length = atoi(req->headers[i+1]);
+ break;
+ }
+ }
+ }
+
+ cl->cb = uh_lua_socket_cb;
+ cl->priv = state;
+
+ break;
+ }
+
+ return true;
+}
+
+void uh_lua_close(lua_State *L)
+{
+ lua_close(L);
+}
diff --git a/package/network/services/uhttpd/src/uhttpd-lua.h b/package/network/services/uhttpd/src/uhttpd-lua.h
new file mode 100644
index 0000000000..780d845d87
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-lua.h
@@ -0,0 +1,44 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Lua header
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_LUA_
+
+#include <math.h> /* floor() */
+#include <errno.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define UH_LUA_CALLBACK "handle_request"
+
+#define UH_LUA_ERR_TIMEOUT -1
+#define UH_LUA_ERR_TOOBIG -2
+#define UH_LUA_ERR_PARAM -3
+
+
+struct uh_lua_state {
+ int content_length;
+ bool data_sent;
+};
+
+lua_State * uh_lua_init(const struct config *conf);
+bool uh_lua_request(struct client *cl, lua_State *L);
+void uh_lua_close(lua_State *L);
+
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd-mimetypes.h b/package/network/services/uhttpd/src/uhttpd-mimetypes.h
new file mode 100644
index 0000000000..21717c0003
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-mimetypes.h
@@ -0,0 +1,86 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - MIME type definitions
+ *
+ * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_MIMETYPES_
+
+static struct mimetype uh_mime_types[] = {
+
+ { "txt", "text/plain" },
+ { "log", "text/plain" },
+ { "js", "text/javascript" },
+ { "css", "text/css" },
+ { "htm", "text/html" },
+ { "html", "text/html" },
+ { "diff", "text/x-patch" },
+ { "patch", "text/x-patch" },
+ { "c", "text/x-csrc" },
+ { "h", "text/x-chdr" },
+ { "o", "text/x-object" },
+ { "ko", "text/x-object" },
+
+ { "bmp", "image/bmp" },
+ { "gif", "image/gif" },
+ { "png", "image/png" },
+ { "jpg", "image/jpeg" },
+ { "jpeg", "image/jpeg" },
+ { "svg", "image/svg+xml" },
+
+ { "zip", "application/zip" },
+ { "pdf", "application/pdf" },
+ { "xml", "application/xml" },
+ { "xsl", "application/xml" },
+ { "doc", "application/msword" },
+ { "ppt", "application/vnd.ms-powerpoint" },
+ { "xls", "application/vnd.ms-excel" },
+ { "odt", "application/vnd.oasis.opendocument.text" },
+ { "odp", "application/vnd.oasis.opendocument.presentation" },
+ { "pl", "application/x-perl" },
+ { "sh", "application/x-shellscript" },
+ { "php", "application/x-php" },
+ { "deb", "application/x-deb" },
+ { "iso", "application/x-cd-image" },
+ { "tar.gz", "application/x-compressed-tar" },
+ { "tgz", "application/x-compressed-tar" },
+ { "gz", "application/x-gzip" },
+ { "tar.bz2", "application/x-bzip-compressed-tar" },
+ { "tbz", "application/x-bzip-compressed-tar" },
+ { "bz2", "application/x-bzip" },
+ { "tar", "application/x-tar" },
+ { "rar", "application/x-rar-compressed" },
+
+ { "mp3", "audio/mpeg" },
+ { "ogg", "audio/x-vorbis+ogg" },
+ { "wav", "audio/x-wav" },
+
+ { "mpg", "video/mpeg" },
+ { "mpeg", "video/mpeg" },
+ { "avi", "video/x-msvideo" },
+
+ { "README", "text/plain" },
+ { "log", "text/plain" },
+ { "cfg", "text/plain" },
+ { "conf", "text/plain" },
+
+ { "pac", "application/x-ns-proxy-autoconfig" },
+ { "wpad.dat", "application/x-ns-proxy-autoconfig" },
+
+ { NULL, NULL }
+};
+
+#endif
+
diff --git a/package/network/services/uhttpd/src/uhttpd-tls.c b/package/network/services/uhttpd/src/uhttpd-tls.c
new file mode 100644
index 0000000000..9c6eb81db3
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-tls.c
@@ -0,0 +1,170 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - TLS helper
+ *
+ * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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 "uhttpd.h"
+#include "uhttpd-tls.h"
+#include "uhttpd-utils.h"
+
+#include <syslog.h>
+#define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
+
+SSL_CTX * uh_tls_ctx_init(void)
+{
+ SSL_CTX *c;
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+#if TLS_IS_OPENSSL
+ if ((c = SSL_CTX_new(SSLv23_server_method())) != NULL)
+#else
+ if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
+#endif
+ SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
+
+ return c;
+}
+
+int uh_tls_ctx_cert(SSL_CTX *c, const char *file)
+{
+ int rv;
+
+ if( (rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_PEM)) < 1 )
+ rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_ASN1);
+
+ return rv;
+}
+
+int uh_tls_ctx_key(SSL_CTX *c, const char *file)
+{
+ int rv;
+
+ if( (rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_PEM)) < 1 )
+ rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_ASN1);
+
+ return rv;
+}
+
+void uh_tls_ctx_free(struct listener *l)
+{
+ SSL_CTX_free(l->tls);
+}
+
+
+int uh_tls_client_accept(struct client *c)
+{
+ int rv, err;
+ int fd = c->fd.fd;
+
+ if (!c->server || !c->server->tls)
+ {
+ c->tls = NULL;
+ return 1;
+ }
+
+ if ((c->tls = SSL_new(c->server->tls)))
+ {
+ if ((rv = SSL_set_fd(c->tls, fd)) < 1)
+ {
+ SSL_free(c->tls);
+ c->tls = NULL;
+ }
+ else
+ {
+ while (true)
+ {
+ rv = SSL_accept(c->tls);
+ err = SSL_get_error(c->tls, rv);
+
+ if ((rv != 1) &&
+ (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE))
+ {
+ if (uh_socket_wait(fd, c->server->conf->network_timeout,
+ (err == SSL_ERROR_WANT_WRITE)))
+ {
+ D("TLS: accept(%d) = retry\n", fd);
+ continue;
+ }
+
+ D("TLS: accept(%d) = timeout\n", fd);
+ }
+ else if (rv == 1)
+ {
+ D("TLS: accept(%d) = %p\n", fd, c->tls);
+ return 1;
+ }
+
+#ifdef TLS_IS_OPENSSL
+ D("TLS: accept(%d) = failed: %s\n",
+ fd, ERR_error_string(ERR_get_error(), NULL));
+#endif
+
+ SSL_free(c->tls);
+ c->tls = NULL;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int uh_tls_client_recv(struct client *c, char *buf, int len)
+{
+ int rv = SSL_read(c->tls, buf, len);
+ int err = SSL_get_error(c->tls, 0);
+
+ if ((rv == -1) && (err == SSL_ERROR_WANT_READ))
+ {
+ D("TLS: recv(%d, %d) = retry\n", c->fd.fd, len);
+ errno = EAGAIN;
+ return -1;
+ }
+
+ D("TLS: recv(%d, %d) = %d\n", c->fd.fd, len, rv);
+ return rv;
+}
+
+int uh_tls_client_send(struct client *c, const char *buf, int len)
+{
+ int rv = SSL_write(c->tls, buf, len);
+ int err = SSL_get_error(c->tls, 0);
+
+ if ((rv == -1) && (err == SSL_ERROR_WANT_WRITE))
+ {
+ D("TLS: send(%d, %d) = retry\n", c->fd.fd, len);
+ errno = EAGAIN;
+ return -1;
+ }
+
+ D("TLS: send(%d, %d) = %d\n", c->fd.fd, len, rv);
+ return rv;
+}
+
+void uh_tls_client_close(struct client *c)
+{
+ if (c->tls)
+ {
+ D("TLS: close(%d)\n", c->fd.fd);
+
+ SSL_shutdown(c->tls);
+ SSL_free(c->tls);
+
+ c->tls = NULL;
+ }
+}
diff --git a/package/network/services/uhttpd/src/uhttpd-tls.h b/package/network/services/uhttpd/src/uhttpd-tls.h
new file mode 100644
index 0000000000..8644c2ac5d
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-tls.h
@@ -0,0 +1,36 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - TLS header
+ *
+ * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_TLS_
+
+#include <openssl/ssl.h>
+#ifdef TLS_IS_OPENSSL
+#include <openssl/err.h>
+#endif
+
+SSL_CTX * uh_tls_ctx_init();
+int uh_tls_ctx_cert(SSL_CTX *c, const char *file);
+int uh_tls_ctx_key(SSL_CTX *c, const char *file);
+void uh_tls_ctx_free(struct listener *l);
+
+int uh_tls_client_accept(struct client *c);
+int uh_tls_client_recv(struct client *c, char *buf, int len);
+int uh_tls_client_send(struct client *c, const char *buf, int len);
+void uh_tls_client_close(struct client *c);
+
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd-ubus.c b/package/network/services/uhttpd/src/uhttpd-ubus.c
new file mode 100644
index 0000000000..20781629ba
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-ubus.c
@@ -0,0 +1,957 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - ubus handler
+ *
+ * Copyright (C) 2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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 "uhttpd.h"
+#include "uhttpd-utils.h"
+#include "uhttpd-ubus.h"
+
+
+enum {
+ UH_UBUS_SN_TIMEOUT,
+ __UH_UBUS_SN_MAX,
+};
+
+static const struct blobmsg_policy new_policy[__UH_UBUS_SN_MAX] = {
+ [UH_UBUS_SN_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
+};
+
+
+enum {
+ UH_UBUS_SI_SID,
+ __UH_UBUS_SI_MAX,
+};
+
+static const struct blobmsg_policy sid_policy[__UH_UBUS_SI_MAX] = {
+ [UH_UBUS_SI_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
+};
+
+
+enum {
+ UH_UBUS_SS_SID,
+ UH_UBUS_SS_VALUES,
+ __UH_UBUS_SS_MAX,
+};
+
+static const struct blobmsg_policy set_policy[__UH_UBUS_SS_MAX] = {
+ [UH_UBUS_SS_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
+ [UH_UBUS_SS_VALUES] = { .name = "values", .type = BLOBMSG_TYPE_TABLE },
+};
+
+
+enum {
+ UH_UBUS_SG_SID,
+ UH_UBUS_SG_KEYS,
+ __UH_UBUS_SG_MAX,
+};
+
+static const struct blobmsg_policy get_policy[__UH_UBUS_SG_MAX] = {
+ [UH_UBUS_SG_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
+ [UH_UBUS_SG_KEYS] = { .name = "keys", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+
+enum {
+ UH_UBUS_SA_SID,
+ UH_UBUS_SA_OBJECTS,
+ __UH_UBUS_SA_MAX,
+};
+
+static const struct blobmsg_policy acl_policy[__UH_UBUS_SA_MAX] = {
+ [UH_UBUS_SA_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
+ [UH_UBUS_SA_OBJECTS] = { .name = "objects", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+
+static bool
+uh_ubus_strmatch(const char *str, const char *pat)
+{
+ while (*pat)
+ {
+ if (*pat == '?')
+ {
+ if (!*str)
+ return false;
+
+ str++;
+ pat++;
+ }
+ else if (*pat == '*')
+ {
+ if (uh_ubus_strmatch(str, pat+1))
+ return true;
+
+ if (*str && uh_ubus_strmatch(str+1, pat))
+ return true;
+
+ return false;
+ }
+ else if (*str++ != *pat++)
+ {
+ return false;
+ }
+ }
+
+ return (!*str && !*pat);
+}
+
+static int
+uh_ubus_avlcmp(const void *k1, const void *k2, void *ptr)
+{
+ return strcmp((char *)k1, (char *)k2);
+}
+
+static void
+uh_ubus_random(char *dest)
+{
+ int i;
+ unsigned char buf[16] = { 0 };
+ FILE *f;
+
+ if ((f = fopen("/dev/urandom", "r")) != NULL)
+ {
+ fread(buf, 1, sizeof(buf), f);
+ fclose(f);
+ }
+
+ for (i = 0; i < sizeof(buf); i++)
+ sprintf(dest + (i<<1), "%02x", buf[i]);
+}
+
+static void
+uh_ubus_session_dump_data(struct uh_ubus_session *ses, struct blob_buf *b)
+{
+ struct uh_ubus_session_data *d;
+
+ avl_for_each_element(&ses->data, d, avl)
+ {
+ blobmsg_add_field(b, blobmsg_type(d->attr), blobmsg_name(d->attr),
+ blobmsg_data(d->attr), blobmsg_data_len(d->attr));
+ }
+}
+
+static void
+uh_ubus_session_dump_acls(struct uh_ubus_session *ses, struct blob_buf *b)
+{
+ struct uh_ubus_session_acl *acl;
+ const char *lastobj = NULL;
+ void *c = NULL;
+
+ avl_for_each_element(&ses->acls, acl, avl)
+ {
+ if (!lastobj || strcmp(acl->object, lastobj))
+ {
+ if (c) blobmsg_close_array(b, c);
+ c = blobmsg_open_array(b, acl->object);
+ }
+
+ blobmsg_add_string(b, NULL, acl->function);
+ lastobj = acl->object;
+ }
+
+ if (c) blobmsg_close_array(b, c);
+}
+
+static void
+uh_ubus_session_dump(struct uh_ubus_session *ses,
+ struct ubus_context *ctx,
+ struct ubus_request_data *req)
+{
+ void *c;
+ struct blob_buf b;
+
+ memset(&b, 0, sizeof(b));
+ blob_buf_init(&b, 0);
+
+ blobmsg_add_string(&b, "sid", ses->id);
+ blobmsg_add_u32(&b, "timeout", ses->timeout);
+ blobmsg_add_u32(&b, "touched", ses->touched.tv_sec);
+
+ c = blobmsg_open_table(&b, "acls");
+ uh_ubus_session_dump_acls(ses, &b);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "data");
+ uh_ubus_session_dump_data(ses, &b);
+ blobmsg_close_table(&b, c);
+
+ ubus_send_reply(ctx, req, b.head);
+ blob_buf_free(&b);
+}
+
+static struct uh_ubus_session *
+uh_ubus_session_create(struct uh_ubus_state *state, int timeout)
+{
+ struct uh_ubus_session *ses;
+
+ ses = malloc(sizeof(*ses));
+
+ /* failed to allocate memory... */
+ if (!ses)
+ return NULL;
+
+ memset(ses, 0, sizeof(*ses));
+
+ uh_ubus_random(ses->id);
+
+ ses->timeout = timeout;
+ ses->avl.key = ses->id;
+
+ avl_insert(&state->sessions, &ses->avl);
+ avl_init(&ses->acls, uh_ubus_avlcmp, true, NULL);
+ avl_init(&ses->data, uh_ubus_avlcmp, false, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &ses->touched);
+
+ return ses;
+}
+
+
+static struct uh_ubus_session *
+uh_ubus_session_get(struct uh_ubus_state *state, const char *id)
+{
+ struct uh_ubus_session *ses;
+
+ ses = avl_find_element(&state->sessions, id, ses, avl);
+
+ if (ses)
+ clock_gettime(CLOCK_MONOTONIC, &ses->touched);
+
+ return ses;
+}
+
+static void
+uh_ubus_session_destroy(struct uh_ubus_state *state,
+ struct uh_ubus_session *ses)
+{
+ struct uh_ubus_session_acl *acl, *nacl;
+ struct uh_ubus_session_data *data, *ndata;
+
+ avl_remove_all_elements(&ses->acls, acl, avl, nacl)
+ free(acl);
+
+ avl_remove_all_elements(&ses->data, data, avl, ndata)
+ free(data);
+
+ avl_delete(&state->sessions, &ses->avl);
+ free(ses);
+}
+
+static void
+uh_ubus_session_cleanup(struct uh_ubus_state *state)
+{
+ struct timespec now;
+ struct uh_ubus_session *ses, *nses;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ avl_for_each_element_safe(&state->sessions, ses, avl, nses)
+ {
+ if ((now.tv_sec - ses->touched.tv_sec) >= ses->timeout)
+ uh_ubus_session_destroy(state, ses);
+ }
+}
+
+
+static int
+uh_ubus_handle_create(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct blob_attr *tb[__UH_UBUS_SN_MAX];
+
+ int timeout = state->timeout;
+
+ blobmsg_parse(new_policy, __UH_UBUS_SN_MAX, tb, blob_data(msg), blob_len(msg));
+
+ /* TODO: make this a uloop timeout */
+ uh_ubus_session_cleanup(state);
+
+ if (tb[UH_UBUS_SN_TIMEOUT])
+ timeout = *(uint32_t *)blobmsg_data(tb[UH_UBUS_SN_TIMEOUT]);
+
+ ses = uh_ubus_session_create(state, timeout);
+
+ if (ses)
+ uh_ubus_session_dump(ses, ctx, req);
+
+ return 0;
+}
+
+static int
+uh_ubus_handle_list(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct blob_attr *tb[__UH_UBUS_SI_MAX];
+
+ blobmsg_parse(sid_policy, __UH_UBUS_SI_MAX, tb, blob_data(msg), blob_len(msg));
+
+ /* TODO: make this a uloop timeout */
+ uh_ubus_session_cleanup(state);
+
+ if (!tb[UH_UBUS_SI_SID])
+ {
+ avl_for_each_element(&state->sessions, ses, avl)
+ uh_ubus_session_dump(ses, ctx, req);
+ }
+ else
+ {
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SI_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ uh_ubus_session_dump(ses, ctx, req);
+ }
+
+ return 0;
+}
+
+
+static int
+uh_ubus_session_grant(struct uh_ubus_session *ses, struct ubus_context *ctx,
+ const char *object, const char *function)
+{
+ struct uh_ubus_session_acl *acl, *nacl;
+
+ acl = avl_find_element(&ses->acls, object, acl, avl);
+
+ if (acl)
+ {
+ avl_for_element_to_last(&ses->acls, acl, acl, avl)
+ {
+ if (!strcmp(acl->function, function))
+ return 1;
+ }
+ }
+
+ nacl = malloc(sizeof(*nacl) + strlen(object) + strlen(function) + 2);
+
+ if (nacl)
+ {
+ memset(nacl, 0, sizeof(*nacl));
+ nacl->function = nacl->object + 1;
+ nacl->function += sprintf(nacl->object, "%s", object);
+ sprintf(nacl->function, "%s", function);
+
+ nacl->avl.key = nacl->object;
+ avl_insert(&ses->acls, &nacl->avl);
+ }
+
+ return 0;
+}
+
+static int
+uh_ubus_session_revoke(struct uh_ubus_session *ses, struct ubus_context *ctx,
+ const char *object, const char *function)
+{
+ struct uh_ubus_session_acl *acl, *nacl;
+
+ if (!object && !function)
+ {
+ avl_remove_all_elements(&ses->acls, acl, avl, nacl)
+ free(acl);
+ }
+ else
+ {
+ avl_for_each_element_safe(&ses->acls, acl, avl, nacl)
+ {
+ if (uh_ubus_strmatch(acl->object, object) &&
+ uh_ubus_strmatch(acl->function, function))
+ {
+ avl_delete(&ses->acls, &acl->avl);
+ free(acl);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+uh_ubus_handle_grant(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct blob_attr *tb[__UH_UBUS_SA_MAX];
+ struct blob_attr *attr, *sattr;
+ const char *object, *function;
+ int rem1, rem2;
+
+ blobmsg_parse(acl_policy, __UH_UBUS_SA_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UH_UBUS_SA_SID] || !tb[UH_UBUS_SA_OBJECTS])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SA_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ blobmsg_for_each_attr(attr, tb[UH_UBUS_SA_OBJECTS], rem1)
+ {
+ if (blob_id(attr) != BLOBMSG_TYPE_ARRAY)
+ continue;
+
+ object = NULL;
+ function = NULL;
+
+ blobmsg_for_each_attr(sattr, attr, rem2)
+ {
+ if (blob_id(sattr) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ if (!object)
+ object = blobmsg_data(sattr);
+ else if (!function)
+ function = blobmsg_data(sattr);
+ else
+ break;
+ }
+
+ if (object && function)
+ uh_ubus_session_grant(ses, ctx, object, function);
+ }
+
+ return 0;
+}
+
+static int
+uh_ubus_handle_revoke(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct blob_attr *tb[__UH_UBUS_SA_MAX];
+ struct blob_attr *attr, *sattr;
+ const char *object, *function;
+ int rem1, rem2;
+
+ blobmsg_parse(acl_policy, __UH_UBUS_SA_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UH_UBUS_SA_SID])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SA_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ if (!tb[UH_UBUS_SA_OBJECTS])
+ {
+ uh_ubus_session_revoke(ses, ctx, NULL, NULL);
+ }
+ else
+ {
+ blobmsg_for_each_attr(attr, tb[UH_UBUS_SA_OBJECTS], rem1)
+ {
+ if (blob_id(attr) != BLOBMSG_TYPE_ARRAY)
+ continue;
+
+ object = NULL;
+ function = NULL;
+
+ blobmsg_for_each_attr(sattr, attr, rem2)
+ {
+ if (blob_id(sattr) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ if (!object)
+ object = blobmsg_data(sattr);
+ else if (!function)
+ function = blobmsg_data(sattr);
+ else
+ break;
+ }
+
+ if (object && function)
+ uh_ubus_session_revoke(ses, ctx, object, function);
+ }
+ }
+
+ return 0;
+}
+
+static int
+uh_ubus_handle_set(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct uh_ubus_session_data *data;
+ struct blob_attr *tb[__UH_UBUS_SA_MAX];
+ struct blob_attr *attr;
+ int rem;
+
+ blobmsg_parse(set_policy, __UH_UBUS_SS_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UH_UBUS_SS_SID] || !tb[UH_UBUS_SS_VALUES])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SS_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ blobmsg_for_each_attr(attr, tb[UH_UBUS_SS_VALUES], rem)
+ {
+ if (!blobmsg_name(attr)[0])
+ continue;
+
+ data = avl_find_element(&ses->data, blobmsg_name(attr), data, avl);
+
+ if (data)
+ {
+ avl_delete(&ses->data, &data->avl);
+ free(data);
+ }
+
+ data = malloc(sizeof(*data) + blob_pad_len(attr));
+
+ if (!data)
+ break;
+
+ memset(data, 0, sizeof(*data) + blob_pad_len(attr));
+ memcpy(data->attr, attr, blob_pad_len(attr));
+
+ data->avl.key = blobmsg_name(data->attr);
+ avl_insert(&ses->data, &data->avl);
+ }
+
+ return 0;
+}
+
+static int
+uh_ubus_handle_get(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct uh_ubus_session_data *data;
+ struct blob_attr *tb[__UH_UBUS_SA_MAX];
+ struct blob_attr *attr;
+ struct blob_buf b;
+ void *c;
+ int rem;
+
+ blobmsg_parse(get_policy, __UH_UBUS_SG_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UH_UBUS_SG_SID])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SG_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ memset(&b, 0, sizeof(b));
+ blob_buf_init(&b, 0);
+ c = blobmsg_open_table(&b, "values");
+
+ if (!tb[UH_UBUS_SG_KEYS])
+ {
+ uh_ubus_session_dump_data(ses, &b);
+ }
+ else
+ {
+ blobmsg_for_each_attr(attr, tb[UH_UBUS_SG_KEYS], rem)
+ {
+ if (blob_id(attr) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ data = avl_find_element(&ses->data, blobmsg_data(attr), data, avl);
+
+ if (!data)
+ continue;
+
+ blobmsg_add_field(&b, blobmsg_type(data->attr),
+ blobmsg_name(data->attr),
+ blobmsg_data(data->attr),
+ blobmsg_data_len(data->attr));
+ }
+ }
+
+ blobmsg_close_table(&b, c);
+ ubus_send_reply(ctx, req, b.head);
+ blob_buf_free(&b);
+
+ return 0;
+}
+
+static int
+uh_ubus_handle_unset(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct uh_ubus_session_data *data, *ndata;
+ struct blob_attr *tb[__UH_UBUS_SA_MAX];
+ struct blob_attr *attr;
+ int rem;
+
+ blobmsg_parse(get_policy, __UH_UBUS_SG_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UH_UBUS_SG_SID])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SG_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ if (!tb[UH_UBUS_SG_KEYS])
+ {
+ avl_remove_all_elements(&ses->data, data, avl, ndata)
+ free(data);
+ }
+ else
+ {
+ blobmsg_for_each_attr(attr, tb[UH_UBUS_SG_KEYS], rem)
+ {
+ if (blob_id(attr) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ data = avl_find_element(&ses->data, blobmsg_data(attr), data, avl);
+
+ if (!data)
+ continue;
+
+ avl_delete(&ses->data, &data->avl);
+ free(data);
+ }
+ }
+
+ return 0;
+}
+
+static int
+uh_ubus_handle_destroy(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
+ struct uh_ubus_session *ses;
+ struct blob_attr *tb[__UH_UBUS_SA_MAX];
+
+ blobmsg_parse(sid_policy, __UH_UBUS_SI_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UH_UBUS_SI_SID])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SI_SID]));
+
+ if (!ses)
+ return UBUS_STATUS_NOT_FOUND;
+
+ uh_ubus_session_destroy(state, ses);
+
+ return 0;
+}
+
+
+struct uh_ubus_state *
+uh_ubus_init(const struct config *conf)
+{
+ int rv;
+ struct uh_ubus_state *state;
+ struct ubus_object *session_object;
+
+ static struct ubus_method session_methods[] = {
+ UBUS_METHOD("create", uh_ubus_handle_create, new_policy),
+ UBUS_METHOD("list", uh_ubus_handle_list, sid_policy),
+ UBUS_METHOD("grant", uh_ubus_handle_grant, acl_policy),
+ UBUS_METHOD("revoke", uh_ubus_handle_revoke, acl_policy),
+ UBUS_METHOD("set", uh_ubus_handle_set, set_policy),
+ UBUS_METHOD("get", uh_ubus_handle_get, get_policy),
+ UBUS_METHOD("unset", uh_ubus_handle_unset, get_policy),
+ UBUS_METHOD("destroy", uh_ubus_handle_destroy, sid_policy),
+ };
+
+ static struct ubus_object_type session_type =
+ UBUS_OBJECT_TYPE("uhttpd", session_methods);
+
+ state = malloc(sizeof(*state));
+
+ if (!state)
+ {
+ fprintf(stderr, "Unable to allocate memory for ubus state\n");
+ exit(1);
+ }
+
+ memset(state, 0, sizeof(*state));
+ state->ctx = ubus_connect(conf->ubus_socket);
+ state->timeout = conf->script_timeout;
+
+ if (!state->ctx)
+ {
+ fprintf(stderr, "Unable to connect to ubus socket\n");
+ exit(1);
+ }
+
+ ubus_add_uloop(state->ctx);
+
+ session_object = &state->ubus;
+ session_object->name = "session";
+ session_object->type = &session_type;
+ session_object->methods = session_methods;
+ session_object->n_methods = ARRAY_SIZE(session_methods);
+
+ rv = ubus_add_object(state->ctx, &state->ubus);
+
+ if (rv)
+ {
+ fprintf(stderr, "Unable to publish ubus object: %s\n",
+ ubus_strerror(rv));
+ exit(1);
+ }
+
+ blob_buf_init(&state->buf, 0);
+ avl_init(&state->sessions, uh_ubus_avlcmp, false, NULL);
+
+ return state;
+}
+
+
+static bool
+uh_ubus_request_parse_url(struct client *cl, char **sid, char **obj, char **fun)
+{
+ char *url = cl->request.url + strlen(cl->server->conf->ubus_prefix);
+
+ for (; url && *url == '/'; *url++ = 0);
+ *sid = url;
+
+ for (url = url ? strchr(url, '/') : NULL; url && *url == '/'; *url++ = 0);
+ *obj = url;
+
+ for (url = url ? strchr(url, '/') : NULL; url && *url == '/'; *url++ = 0);
+ *fun = url;
+
+ for (url = url ? strchr(url, '/') : NULL; url && *url == '/'; *url++ = 0);
+ return (*sid && *obj && *fun);
+}
+
+static bool
+uh_ubus_request_parse_post(struct client *cl, int len, struct blob_buf *b)
+{
+ int rlen;
+ bool rv = false;
+ char buf[UH_LIMIT_MSGHEAD];
+
+ struct json_object *obj = NULL;
+ struct json_tokener *tok = NULL;
+
+ if (!len)
+ return NULL;
+
+ memset(b, 0, sizeof(*b));
+ blob_buf_init(b, 0);
+
+ tok = json_tokener_new();
+
+ while (len > 0)
+ {
+ /* remaining data in http head buffer ... */
+ if (cl->httpbuf.len > 0)
+ {
+ rlen = min(len, cl->httpbuf.len);
+
+ D("ubus: feed %d HTTP buffer bytes\n", rlen);
+
+ memcpy(buf, cl->httpbuf.ptr, rlen);
+
+ cl->httpbuf.len -= rlen;
+ cl->httpbuf.ptr += rlen;
+ }
+
+ /* read it from socket ... */
+ else
+ {
+ ensure_out(rlen = uh_tcp_recv(cl, buf, min(len, sizeof(buf))));
+
+ if ((rlen < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+ break;
+
+ D("ubus: feed %d/%d TCP socket bytes\n",
+ rlen, min(len, sizeof(buf)));
+ }
+
+ obj = json_tokener_parse_ex(tok, buf, rlen);
+ len -= rlen;
+
+ if (tok->err != json_tokener_continue && !is_error(obj))
+ break;
+ }
+
+out:
+ if (!is_error(obj))
+ {
+ if (json_object_get_type(obj) == json_type_object)
+ {
+ rv = true;
+ json_object_object_foreach(obj, key, val)
+ {
+ if (!blobmsg_add_json_element(b, key, val))
+ {
+ rv = false;
+ break;
+ }
+ }
+ }
+
+ json_object_put(obj);
+ }
+
+ json_tokener_free(tok);
+
+ if (!rv)
+ blob_buf_free(b);
+
+ return rv;
+}
+
+static void
+uh_ubus_request_cb(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ int len;
+ char *str;
+ struct client *cl = (struct client *)req->priv;
+
+ if (!msg)
+ {
+ uh_http_sendhf(cl, 204, "No content", "Function did not return data\n");
+ return;
+ }
+
+ str = blobmsg_format_json_indent(msg, true, 0);
+ len = strlen(str);
+
+ ensure_out(uh_http_sendf(cl, NULL, "HTTP/1.0 200 OK\r\n"));
+ ensure_out(uh_http_sendf(cl, NULL, "Content-Type: application/json\r\n"));
+ ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n\r\n", len));
+ ensure_out(uh_http_send(cl, NULL, str, len));
+
+out:
+ free(str);
+}
+
+bool
+uh_ubus_request(struct client *cl, struct uh_ubus_state *state)
+{
+ int i, len = 0;
+ bool access = false;
+ char *sid, *obj, *fun;
+
+ struct blob_buf buf;
+ struct uh_ubus_session *ses;
+ struct uh_ubus_session_acl *acl;
+
+ uint32_t obj_id;
+
+
+ memset(&buf, 0, sizeof(buf));
+ blob_buf_init(&buf, 0);
+
+ if (!uh_ubus_request_parse_url(cl, &sid, &obj, &fun))
+ {
+ uh_http_sendhf(cl, 400, "Bad Request", "Invalid Request\n");
+ goto out;
+ }
+
+ if (!(ses = uh_ubus_session_get(state, sid)))
+ {
+ uh_http_sendhf(cl, 404, "Not Found", "No such session\n");
+ goto out;
+ }
+
+ avl_for_each_element(&ses->acls, acl, avl)
+ {
+ if (uh_ubus_strmatch(obj, acl->object) &&
+ uh_ubus_strmatch(fun, acl->function))
+ {
+ access = true;
+ break;
+ }
+ }
+
+ if (!access)
+ {
+ uh_http_sendhf(cl, 403, "Denied", "Access to object denied\n");
+ goto out;
+ }
+
+ /* find content length */
+ if (cl->request.method == UH_HTTP_MSG_POST)
+ {
+ foreach_header(i, cl->request.headers)
+ {
+ if (!strcasecmp(cl->request.headers[i], "Content-Length"))
+ {
+ len = atoi(cl->request.headers[i+1]);
+ break;
+ }
+ }
+ }
+
+ if (len > UH_UBUS_MAX_POST_SIZE)
+ {
+ uh_http_sendhf(cl, 413, "Too Large", "Message too big\n");
+ goto out;
+ }
+
+ if (len && !uh_ubus_request_parse_post(cl, len, &buf))
+ {
+ uh_http_sendhf(cl, 400, "Bad Request", "Invalid JSON data\n");
+ goto out;
+ }
+
+ if (ubus_lookup_id(state->ctx, obj, &obj_id))
+ {
+ uh_http_sendhf(cl, 500, "Internal Error", "Unable to lookup object\n");
+ goto out;
+ }
+
+ if (ubus_invoke(state->ctx, obj_id, fun, buf.head,
+ uh_ubus_request_cb, cl, state->timeout * 1000))
+ {
+ uh_http_sendhf(cl, 500, "Internal Error", "Unable to invoke function\n");
+ goto out;
+ }
+
+out:
+ blob_buf_free(&buf);
+ return false;
+}
+
+void
+uh_ubus_close(struct uh_ubus_state *state)
+{
+ if (state->ctx)
+ ubus_free(state->ctx);
+
+ free(state);
+}
diff --git a/package/network/services/uhttpd/src/uhttpd-ubus.h b/package/network/services/uhttpd/src/uhttpd-ubus.h
new file mode 100644
index 0000000000..777ce27fd3
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-ubus.h
@@ -0,0 +1,70 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - ubus header
+ *
+ * Copyright (C) 2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_UBUS_
+
+#include <time.h>
+
+#include <libubus.h>
+#include <libubox/avl.h>
+#include <libubox/blobmsg_json.h>
+#include <json/json.h>
+
+
+#define UH_UBUS_MAX_POST_SIZE 4096
+
+
+struct uh_ubus_state {
+ struct ubus_context *ctx;
+ struct ubus_object ubus;
+ struct blob_buf buf;
+ struct avl_tree sessions;
+ int timeout;
+};
+
+struct uh_ubus_request_data {
+ const char *sid;
+ const char *object;
+ const char *function;
+};
+
+struct uh_ubus_session {
+ char id[33];
+ int timeout;
+ struct avl_node avl;
+ struct avl_tree data;
+ struct avl_tree acls;
+ struct timespec touched;
+};
+
+struct uh_ubus_session_data {
+ struct avl_node avl;
+ struct blob_attr attr[];
+};
+
+struct uh_ubus_session_acl {
+ struct avl_node avl;
+ char *function;
+ char object[];
+};
+
+struct uh_ubus_state * uh_ubus_init(const struct config *conf);
+bool uh_ubus_request(struct client *cl, struct uh_ubus_state *state);
+void uh_ubus_close(struct uh_ubus_state *state);
+
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd-utils.c b/package/network/services/uhttpd/src/uhttpd-utils.c
new file mode 100644
index 0000000000..c8d3bb40f4
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-utils.c
@@ -0,0 +1,1081 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Utility functions
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#define _XOPEN_SOURCE 500 /* crypt() */
+#define _BSD_SOURCE /* strcasecmp(), strncasecmp() */
+
+#include "uhttpd.h"
+#include "uhttpd-utils.h"
+
+#ifdef HAVE_TLS
+#include "uhttpd-tls.h"
+#endif
+
+
+static char *uh_index_files[] = {
+ "index.html",
+ "index.htm",
+ "default.html",
+ "default.htm"
+};
+
+
+const char * sa_straddr(void *sa)
+{
+ static char str[INET6_ADDRSTRLEN];
+ struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
+ struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)sa;
+
+ if (v4->sin_family == AF_INET)
+ return inet_ntop(AF_INET, &(v4->sin_addr), str, sizeof(str));
+ else
+ return inet_ntop(AF_INET6, &(v6->sin6_addr), str, sizeof(str));
+}
+
+const char * sa_strport(void *sa)
+{
+ static char str[6];
+ snprintf(str, sizeof(str), "%i", sa_port(sa));
+ return str;
+}
+
+int sa_port(void *sa)
+{
+ return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+}
+
+int sa_rfc1918(void *sa)
+{
+ struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
+ unsigned long a = htonl(v4->sin_addr.s_addr);
+
+ if (v4->sin_family == AF_INET)
+ {
+ return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
+ ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
+ ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
+ }
+
+ return 0;
+}
+
+/* Simple strstr() like function that takes len arguments for both haystack and needle. */
+char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
+{
+ int match = 0;
+ int i, j;
+
+ for (i = 0; i < hslen; i++)
+ {
+ if (haystack[i] == needle[0])
+ {
+ match = ((ndlen == 1) || ((i + ndlen) <= hslen));
+
+ for (j = 1; (j < ndlen) && ((i + j) < hslen); j++)
+ {
+ if (haystack[i+j] != needle[j])
+ {
+ match = 0;
+ break;
+ }
+ }
+
+ if (match)
+ return &haystack[i];
+ }
+ }
+
+ return NULL;
+}
+
+bool uh_socket_wait(int fd, int sec, bool write)
+{
+ int rv;
+ struct timeval timeout;
+
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ timeout.tv_sec = sec;
+ timeout.tv_usec = 0;
+
+ while (((rv = select(fd+1, write ? NULL : &fds, write ? &fds : NULL,
+ NULL, &timeout)) < 0) && (errno == EINTR))
+ {
+ D("IO: FD(%d) select interrupted: %s\n",
+ fd, strerror(errno));
+
+ continue;
+ }
+
+ if (rv <= 0)
+ {
+ D("IO: FD(%d) appears dead (rv=%d)\n", fd, rv);
+ return false;
+ }
+
+ return true;
+}
+
+static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec,
+ int (*wfn) (struct client *, const char *, int))
+{
+ ssize_t rv;
+ int fd = cl->fd.fd;
+
+ while (true)
+ {
+ if ((rv = wfn(cl, buf, len)) < 0)
+ {
+ if (errno == EINTR)
+ {
+ D("IO: FD(%d) interrupted\n", cl->fd.fd);
+ continue;
+ }
+ else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
+ {
+ if (!uh_socket_wait(fd, sec, true))
+ return -1;
+ }
+ else
+ {
+ D("IO: FD(%d) write error: %s\n", fd, strerror(errno));
+ return -1;
+ }
+ }
+ /*
+ * It is not entirely clear whether rv = 0 on nonblocking sockets
+ * is an error. In real world fuzzing tests, not handling it as close
+ * led to tight infinite loops in this send procedure, so treat it as
+ * closed and break out.
+ */
+ else if (rv == 0)
+ {
+ D("IO: FD(%d) appears closed\n", fd);
+ return 0;
+ }
+ else if (rv < len)
+ {
+ D("IO: FD(%d) short write %d/%d bytes\n", fd, rv, len);
+ len -= rv;
+ buf += rv;
+ continue;
+ }
+ else
+ {
+ D("IO: FD(%d) sent %d/%d bytes\n", fd, rv, len);
+ return rv;
+ }
+ }
+}
+
+int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len)
+{
+ return write(cl->fd.fd, buf, len);
+}
+
+int uh_raw_send(int fd, const char *buf, int len, int sec)
+{
+ struct client_light cl = { .fd = { .fd = fd } };
+ return __uh_raw_send((struct client *)&cl, buf, len, sec,
+ uh_tcp_send_lowlevel);
+}
+
+int uh_tcp_send(struct client *cl, const char *buf, int len)
+{
+ int seconds = cl->server->conf->network_timeout;
+#ifdef HAVE_TLS
+ if (cl->tls)
+ return __uh_raw_send(cl, buf, len, seconds,
+ cl->server->conf->tls_send);
+#endif
+ return __uh_raw_send(cl, buf, len, seconds, uh_tcp_send_lowlevel);
+}
+
+static int __uh_raw_recv(struct client *cl, char *buf, int len, int sec,
+ int (*rfn) (struct client *, char *, int))
+{
+ ssize_t rv;
+ int fd = cl->fd.fd;
+
+ while (true)
+ {
+ if ((rv = rfn(cl, buf, len)) < 0)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
+ {
+ if (!uh_socket_wait(fd, sec, false))
+ return -1;
+ }
+ else
+ {
+ D("IO: FD(%d) read error: %s\n", fd, strerror(errno));
+ return -1;
+ }
+ }
+ else if (rv == 0)
+ {
+ D("IO: FD(%d) appears closed\n", fd);
+ return 0;
+ }
+ else
+ {
+ D("IO: FD(%d) read %d bytes\n", fd, rv);
+ return rv;
+ }
+ }
+}
+
+int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
+{
+ return read(cl->fd.fd, buf, len);
+}
+
+int uh_raw_recv(int fd, char *buf, int len, int sec)
+{
+ struct client_light cl = { .fd = { .fd = fd } };
+ return __uh_raw_recv((struct client *)&cl, buf, len, sec,
+ uh_tcp_recv_lowlevel);
+}
+
+int uh_tcp_recv(struct client *cl, char *buf, int len)
+{
+ int seconds = cl->server->conf->network_timeout;
+#ifdef HAVE_TLS
+ if (cl->tls)
+ return __uh_raw_recv(cl, buf, len, seconds,
+ cl->server->conf->tls_recv);
+#endif
+ return __uh_raw_recv(cl, buf, len, seconds, uh_tcp_recv_lowlevel);
+}
+
+
+int uh_http_sendhf(struct client *cl, int code, const char *summary,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ char buffer[UH_LIMIT_MSGHEAD];
+ int len;
+
+ len = snprintf(buffer, sizeof(buffer),
+ "HTTP/1.1 %03i %s\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/plain\r\n"
+ "Transfer-Encoding: chunked\r\n\r\n",
+ code, summary
+ );
+
+ ensure_ret(uh_tcp_send(cl, buffer, len));
+
+ va_start(ap, fmt);
+ len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ ensure_ret(uh_http_sendc(cl, buffer, len));
+ ensure_ret(uh_http_sendc(cl, NULL, 0));
+
+ return 0;
+}
+
+
+int uh_http_sendc(struct client *cl, const char *data, int len)
+{
+ char chunk[8];
+ int clen;
+
+ if (len == -1)
+ len = strlen(data);
+
+ if (len > 0)
+ {
+ clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
+ ensure_ret(uh_tcp_send(cl, chunk, clen));
+ ensure_ret(uh_tcp_send(cl, data, len));
+ ensure_ret(uh_tcp_send(cl, "\r\n", 2));
+ }
+ else
+ {
+ ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5));
+ }
+
+ return 0;
+}
+
+int uh_http_sendf(struct client *cl, struct http_request *req,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[UH_LIMIT_MSGHEAD];
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ if ((req != NULL) && (req->version > UH_HTTP_VER_1_0))
+ ensure_ret(uh_http_sendc(cl, buffer, len));
+ else if (len > 0)
+ ensure_ret(uh_tcp_send(cl, buffer, len));
+
+ return 0;
+}
+
+int uh_http_send(struct client *cl, struct http_request *req,
+ const char *buf, int len)
+{
+ if (len < 0)
+ len = strlen(buf);
+
+ if ((req != NULL) && (req->version > UH_HTTP_VER_1_0))
+ ensure_ret(uh_http_sendc(cl, buf, len));
+ else if (len > 0)
+ ensure_ret(uh_tcp_send(cl, buf, len));
+
+ return 0;
+}
+
+
+/* blen is the size of buf; slen is the length of src. The input-string need
+** not be, and the output string will not be, null-terminated. Returns the
+** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
+int uh_urldecode(char *buf, int blen, const char *src, int slen)
+{
+ int i;
+ int len = 0;
+
+#define hex(x) \
+ (((x) <= '9') ? ((x) - '0') : \
+ (((x) <= 'F') ? ((x) - 'A' + 10) : \
+ ((x) - 'a' + 10)))
+
+ for (i = 0; (i < slen) && (len < blen); i++)
+ {
+ if (src[i] == '%')
+ {
+ if (((i+2) < slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]))
+ {
+ buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
+ i += 2;
+ }
+ else
+ {
+ /* Encoding error: it's hard to think of a
+ ** scenario in which returning an incorrect
+ ** 'decoding' of the malformed string is
+ ** preferable to signaling an error condition. */
+ #if 0 /* WORSE_IS_BETTER */
+ buf[len++] = '%';
+ #else
+ return -2;
+ #endif
+ }
+ }
+ else
+ {
+ buf[len++] = src[i];
+ }
+ }
+
+ return (i == slen) ? len : -1;
+}
+
+/* blen is the size of buf; slen is the length of src. The input-string need
+** not be, and the output string will not be, null-terminated. Returns the
+** length of the encoded string, or -1 on error (buffer overflow) */
+int uh_urlencode(char *buf, int blen, const char *src, int slen)
+{
+ int i;
+ int len = 0;
+ const char hex[] = "0123456789abcdef";
+
+ for (i = 0; (i < slen) && (len < blen); i++)
+ {
+ if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
+ (src[i] == '.') || (src[i] == '~') )
+ {
+ buf[len++] = src[i];
+ }
+ else if ((len+3) <= blen)
+ {
+ buf[len++] = '%';
+ buf[len++] = hex[(src[i] >> 4) & 15];
+ buf[len++] = hex[ src[i] & 15];
+ }
+ else
+ {
+ len = -1;
+ break;
+ }
+ }
+
+ return (i == slen) ? len : -1;
+}
+
+int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
+{
+ int i = 0;
+ int len = 0;
+
+ unsigned int cin = 0;
+ unsigned int cout = 0;
+
+
+ for (i = 0; (i <= slen) && (src[i] != 0); i++)
+ {
+ cin = src[i];
+
+ if ((cin >= '0') && (cin <= '9'))
+ cin = cin - '0' + 52;
+ else if ((cin >= 'A') && (cin <= 'Z'))
+ cin = cin - 'A';
+ else if ((cin >= 'a') && (cin <= 'z'))
+ cin = cin - 'a' + 26;
+ else if (cin == '+')
+ cin = 62;
+ else if (cin == '/')
+ cin = 63;
+ else if (cin == '=')
+ cin = 0;
+ else
+ continue;
+
+ cout = (cout << 6) | cin;
+
+ if ((i % 4) == 3)
+ {
+ if ((len + 3) < blen)
+ {
+ buf[len++] = (char)(cout >> 16);
+ buf[len++] = (char)(cout >> 8);
+ buf[len++] = (char)(cout);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ buf[len++] = 0;
+ return len;
+}
+
+static char * canonpath(const char *path, char *path_resolved)
+{
+ char path_copy[PATH_MAX];
+ char *path_cpy = path_copy;
+ char *path_res = path_resolved;
+
+ struct stat s;
+
+
+ /* relative -> absolute */
+ if (*path != '/')
+ {
+ getcwd(path_copy, PATH_MAX);
+ strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
+ strncat(path_copy, path, PATH_MAX - strlen(path_copy));
+ }
+ else
+ {
+ strncpy(path_copy, path, PATH_MAX);
+ }
+
+ /* normalize */
+ while ((*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)))
+ {
+ if (*path_cpy == '/')
+ {
+ /* skip repeating / */
+ if (path_cpy[1] == '/')
+ {
+ path_cpy++;
+ continue;
+ }
+
+ /* /./ or /../ */
+ else if (path_cpy[1] == '.')
+ {
+ /* skip /./ */
+ if ((path_cpy[2] == '/') || (path_cpy[2] == '\0'))
+ {
+ path_cpy += 2;
+ continue;
+ }
+
+ /* collapse /x/../ */
+ else if ((path_cpy[2] == '.') &&
+ ((path_cpy[3] == '/') || (path_cpy[3] == '\0')))
+ {
+ while ((path_res > path_resolved) && (*--path_res != '/'))
+ ;
+
+ path_cpy += 3;
+ continue;
+ }
+ }
+ }
+
+ *path_res++ = *path_cpy++;
+ }
+
+ /* remove trailing slash if not root / */
+ if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
+ path_res--;
+ else if (path_res == path_resolved)
+ *path_res++ = '/';
+
+ *path_res = '\0';
+
+ /* test access */
+ if (!stat(path_resolved, &s) && (s.st_mode & S_IROTH))
+ return path_resolved;
+
+ return NULL;
+}
+
+/* Returns NULL on error.
+** NB: improperly encoded URL should give client 400 [Bad Syntax]; returning
+** NULL here causes 404 [Not Found], but that's not too unreasonable. */
+struct path_info * uh_path_lookup(struct client *cl, const char *url)
+{
+ static char path_phys[PATH_MAX];
+ static char path_info[PATH_MAX];
+ static struct path_info p;
+
+ char buffer[UH_LIMIT_MSGHEAD];
+ char *docroot = cl->server->conf->docroot;
+ char *pathptr = NULL;
+
+ int slash = 0;
+ int no_sym = cl->server->conf->no_symlinks;
+ int i = 0;
+ struct stat s;
+
+ /* back out early if url is undefined */
+ if (url == NULL)
+ return NULL;
+
+ memset(path_phys, 0, sizeof(path_phys));
+ memset(path_info, 0, sizeof(path_info));
+ memset(buffer, 0, sizeof(buffer));
+ memset(&p, 0, sizeof(p));
+
+ /* copy docroot */
+ memcpy(buffer, docroot,
+ min(strlen(docroot), sizeof(buffer) - 1));
+
+ /* separate query string from url */
+ if ((pathptr = strchr(url, '?')) != NULL)
+ {
+ p.query = pathptr[1] ? pathptr + 1 : NULL;
+
+ /* urldecode component w/o query */
+ if (pathptr > url)
+ {
+ if (uh_urldecode(&buffer[strlen(docroot)],
+ sizeof(buffer) - strlen(docroot) - 1,
+ url, pathptr - url ) < 0)
+ {
+ return NULL; /* bad URL */
+ }
+ }
+ }
+
+ /* no query string, decode all of url */
+ else
+ {
+ if (uh_urldecode(&buffer[strlen(docroot)],
+ sizeof(buffer) - strlen(docroot) - 1,
+ url, strlen(url) ) < 0)
+ {
+ return NULL; /* bad URL */
+ }
+ }
+
+ /* create canon path */
+ for (i = strlen(buffer), slash = (buffer[max(0, i-1)] == '/'); i >= 0; i--)
+ {
+ if ((buffer[i] == 0) || (buffer[i] == '/'))
+ {
+ memset(path_info, 0, sizeof(path_info));
+ memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
+
+ if (no_sym ? realpath(path_info, path_phys)
+ : canonpath(path_info, path_phys))
+ {
+ memset(path_info, 0, sizeof(path_info));
+ memcpy(path_info, &buffer[i],
+ min(strlen(buffer) - i, sizeof(path_info) - 1));
+
+ break;
+ }
+ }
+ }
+
+ /* check whether found path is within docroot */
+ if (strncmp(path_phys, docroot, strlen(docroot)) ||
+ ((path_phys[strlen(docroot)] != 0) &&
+ (path_phys[strlen(docroot)] != '/')))
+ {
+ return NULL;
+ }
+
+ /* test current path */
+ if (!stat(path_phys, &p.stat))
+ {
+ /* is a regular file */
+ if (p.stat.st_mode & S_IFREG)
+ {
+ p.root = docroot;
+ p.phys = path_phys;
+ p.name = &path_phys[strlen(docroot)];
+ p.info = path_info[0] ? path_info : NULL;
+ }
+
+ /* is a directory */
+ else if ((p.stat.st_mode & S_IFDIR) && !strlen(path_info))
+ {
+ /* ensure trailing slash */
+ if (path_phys[strlen(path_phys)-1] != '/')
+ path_phys[strlen(path_phys)] = '/';
+
+ /* try to locate index file */
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, path_phys, sizeof(buffer));
+ pathptr = &buffer[strlen(buffer)];
+
+ /* if requested url resolves to a directory and a trailing slash
+ is missing in the request url, redirect the client to the same
+ url with trailing slash appended */
+ if (!slash)
+ {
+ uh_http_sendf(cl, NULL,
+ "HTTP/1.1 302 Found\r\n"
+ "Location: %s%s%s\r\n"
+ "Connection: close\r\n\r\n",
+ &path_phys[strlen(docroot)],
+ p.query ? "?" : "",
+ p.query ? p.query : ""
+ );
+
+ p.redirected = 1;
+ }
+ else if (cl->server->conf->index_file)
+ {
+ strncat(buffer, cl->server->conf->index_file, sizeof(buffer));
+
+ if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
+ {
+ memcpy(path_phys, buffer, sizeof(path_phys));
+ memcpy(&p.stat, &s, sizeof(p.stat));
+ }
+ }
+ else
+ {
+ for (i = 0; i < array_size(uh_index_files); i++)
+ {
+ strncat(buffer, uh_index_files[i], sizeof(buffer));
+
+ if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
+ {
+ memcpy(path_phys, buffer, sizeof(path_phys));
+ memcpy(&p.stat, &s, sizeof(p.stat));
+ break;
+ }
+
+ *pathptr = 0;
+ }
+ }
+
+ p.root = docroot;
+ p.phys = path_phys;
+ p.name = &path_phys[strlen(docroot)];
+ }
+ }
+
+ return p.phys ? &p : NULL;
+}
+
+
+static struct auth_realm *uh_realms = NULL;
+
+struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
+{
+ struct auth_realm *new = NULL;
+ struct passwd *pwd;
+
+#ifdef HAVE_SHADOW
+ struct spwd *spwd;
+#endif
+
+ if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)
+ {
+ memset(new, 0, sizeof(struct auth_realm));
+
+ memcpy(new->path, path,
+ min(strlen(path), sizeof(new->path) - 1));
+
+ memcpy(new->user, user,
+ min(strlen(user), sizeof(new->user) - 1));
+
+ /* given password refers to a passwd entry */
+ if ((strlen(pass) > 3) && !strncmp(pass, "$p$", 3))
+ {
+#ifdef HAVE_SHADOW
+ /* try to resolve shadow entry */
+ if (((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp)
+ {
+ memcpy(new->pass, spwd->sp_pwdp,
+ min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1));
+ }
+
+ else
+#endif
+
+ /* try to resolve passwd entry */
+ if (((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd &&
+ (pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0))
+ {
+ memcpy(new->pass, pwd->pw_passwd,
+ min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
+ }
+ }
+
+ /* ordinary pwd */
+ else
+ {
+ memcpy(new->pass, pass,
+ min(strlen(pass), sizeof(new->pass) - 1));
+ }
+
+ if (new->pass[0])
+ {
+ new->next = uh_realms;
+ uh_realms = new;
+
+ return new;
+ }
+
+ free(new);
+ }
+
+ return NULL;
+}
+
+int uh_auth_check(struct client *cl, struct http_request *req,
+ struct path_info *pi)
+{
+ int i, plen, rlen, protected;
+ char buffer[UH_LIMIT_MSGHEAD];
+ char *user = NULL;
+ char *pass = NULL;
+
+ struct auth_realm *realm = NULL;
+
+ plen = strlen(pi->name);
+ protected = 0;
+
+ /* check whether at least one realm covers the requested url */
+ for (realm = uh_realms; realm; realm = realm->next)
+ {
+ rlen = strlen(realm->path);
+
+ if ((plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen))
+ {
+ req->realm = realm;
+ protected = 1;
+ break;
+ }
+ }
+
+ /* requested resource is covered by a realm */
+ if (protected)
+ {
+ /* try to get client auth info */
+ foreach_header(i, req->headers)
+ {
+ if (!strcasecmp(req->headers[i], "Authorization") &&
+ (strlen(req->headers[i+1]) > 6) &&
+ !strncasecmp(req->headers[i+1], "Basic ", 6))
+ {
+ memset(buffer, 0, sizeof(buffer));
+ uh_b64decode(buffer, sizeof(buffer) - 1,
+ (unsigned char *) &req->headers[i+1][6],
+ strlen(req->headers[i+1]) - 6);
+
+ if ((pass = strchr(buffer, ':')) != NULL)
+ {
+ user = buffer;
+ *pass++ = 0;
+ }
+
+ break;
+ }
+ }
+
+ /* have client auth */
+ if (user && pass)
+ {
+ /* find matching realm */
+ for (realm = uh_realms; realm; realm = realm->next)
+ {
+ rlen = strlen(realm->path);
+
+ if ((plen >= rlen) &&
+ !strncasecmp(pi->name, realm->path, rlen) &&
+ !strcmp(user, realm->user))
+ {
+ req->realm = realm;
+ break;
+ }
+ }
+
+ /* found a realm matching the username */
+ if (realm)
+ {
+ /* check user pass */
+ if (!strcmp(pass, realm->pass) ||
+ !strcmp(crypt(pass, realm->pass), realm->pass))
+ return 1;
+ }
+ }
+
+ /* 401 */
+ uh_http_sendf(cl, NULL,
+ "%s 401 Authorization Required\r\n"
+ "WWW-Authenticate: Basic realm=\"%s\"\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: 23\r\n\r\n"
+ "Authorization Required\n",
+ http_versions[req->version],
+ cl->server->conf->realm);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static struct listener *uh_listeners = NULL;
+static struct client *uh_clients = NULL;
+
+struct listener * uh_listener_add(int sock, struct config *conf)
+{
+ struct listener *new = NULL;
+ socklen_t sl;
+
+ if ((new = (struct listener *)malloc(sizeof(struct listener))) != NULL)
+ {
+ memset(new, 0, sizeof(struct listener));
+
+ new->fd.fd = sock;
+ new->conf = conf;
+
+
+ /* get local endpoint addr */
+ sl = sizeof(struct sockaddr_in6);
+ memset(&(new->addr), 0, sl);
+ getsockname(sock, (struct sockaddr *) &(new->addr), &sl);
+
+ new->next = uh_listeners;
+ uh_listeners = new;
+
+ return new;
+ }
+
+ return NULL;
+}
+
+struct listener * uh_listener_lookup(int sock)
+{
+ struct listener *cur = NULL;
+
+ for (cur = uh_listeners; cur; cur = cur->next)
+ if (cur->fd.fd == sock)
+ return cur;
+
+ return NULL;
+}
+
+
+struct client * uh_client_add(int sock, struct listener *serv,
+ struct sockaddr_in6 *peer)
+{
+ struct client *new = NULL;
+ socklen_t sl;
+
+ if ((new = (struct client *)malloc(sizeof(struct client))) != NULL)
+ {
+ memset(new, 0, sizeof(struct client));
+ memcpy(&new->peeraddr, peer, sizeof(new->peeraddr));
+
+ new->fd.fd = sock;
+ new->server = serv;
+
+ new->rpipe.fd = -1;
+ new->wpipe.fd = -1;
+
+ /* get local endpoint addr */
+ sl = sizeof(struct sockaddr_in6);
+ getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
+
+ new->next = uh_clients;
+ uh_clients = new;
+
+ serv->n_clients++;
+
+ D("IO: Client(%d) allocated\n", new->fd.fd);
+ }
+
+ return new;
+}
+
+struct client * uh_client_lookup(int sock)
+{
+ struct client *cur = NULL;
+
+ for (cur = uh_clients; cur; cur = cur->next)
+ if (cur->fd.fd == sock)
+ return cur;
+
+ return NULL;
+}
+
+void uh_client_shutdown(struct client *cl)
+{
+#ifdef HAVE_TLS
+ /* free client tls context */
+ if (cl->server && cl->server->conf->tls)
+ cl->server->conf->tls_close(cl);
+#endif
+
+ /* remove from global client list */
+ uh_client_remove(cl);
+}
+
+void uh_client_remove(struct client *cl)
+{
+ struct client *cur = NULL;
+ struct client *prv = NULL;
+
+ for (cur = uh_clients; cur; prv = cur, cur = cur->next)
+ {
+ if (cur == cl)
+ {
+ if (prv)
+ prv->next = cur->next;
+ else
+ uh_clients = cur->next;
+
+ if (cur->timeout.pending)
+ uloop_timeout_cancel(&cur->timeout);
+
+ if (cur->proc.pid)
+ uloop_process_delete(&cur->proc);
+
+ D("IO: Client(%d) freeing\n", cur->fd.fd);
+
+ uh_ufd_remove(&cur->rpipe);
+ uh_ufd_remove(&cur->wpipe);
+ uh_ufd_remove(&cur->fd);
+
+ cur->server->n_clients--;
+
+ free(cur);
+ break;
+ }
+ }
+}
+
+
+void uh_ufd_add(struct uloop_fd *u, uloop_fd_handler h, unsigned int ev)
+{
+ if (h != NULL)
+ {
+ u->cb = h;
+ uloop_fd_add(u, ev);
+ D("IO: FD(%d) added to uloop\n", u->fd);
+ }
+}
+
+void uh_ufd_remove(struct uloop_fd *u)
+{
+ if (u->cb != NULL)
+ {
+ uloop_fd_delete(u);
+ D("IO: FD(%d) removed from uloop\n", u->fd);
+ u->cb = NULL;
+ }
+
+ if (u->fd > -1)
+ {
+ close(u->fd);
+ D("IO: FD(%d) closed\n", u->fd);
+ u->fd = -1;
+ }
+}
+
+
+#ifdef HAVE_CGI
+static struct interpreter *uh_interpreters = NULL;
+
+struct interpreter * uh_interpreter_add(const char *extn, const char *path)
+{
+ struct interpreter *new = NULL;
+
+ if ((new = (struct interpreter *)malloc(sizeof(struct interpreter))) != NULL)
+ {
+ memset(new, 0, sizeof(struct interpreter));
+
+ memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1));
+ memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1));
+
+ new->next = uh_interpreters;
+ uh_interpreters = new;
+
+ return new;
+ }
+
+ return NULL;
+}
+
+struct interpreter * uh_interpreter_lookup(const char *path)
+{
+ struct interpreter *cur = NULL;
+ const char *e;
+
+ for (cur = uh_interpreters; cur; cur = cur->next)
+ {
+ e = &path[max(strlen(path) - strlen(cur->extn), 0)];
+
+ if (!strcmp(e, cur->extn))
+ return cur;
+ }
+
+ return NULL;
+}
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd-utils.h b/package/network/services/uhttpd/src/uhttpd-utils.h
new file mode 100644
index 0000000000..9de9191948
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd-utils.h
@@ -0,0 +1,140 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Utility header
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_UTILS_
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sys/stat.h>
+
+#include <libubox/uloop.h>
+
+
+#ifdef HAVE_SHADOW
+#include <shadow.h>
+#endif
+
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+
+#define array_size(x) \
+ (sizeof(x) / sizeof(x[0]))
+
+#define foreach_header(i, h) \
+ for( i = 0; (i + 1) < (sizeof(h) / sizeof(h[0])) && h[i]; i += 2 )
+
+#define fd_cloexec(fd) \
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)
+
+#define fd_nonblock(fd) \
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
+
+#define ensure_out(x) \
+ do { if((x) < 0) goto out; } while(0)
+
+#define ensure_ret(x) \
+ do { if((x) < 0) return -1; } while(0)
+
+
+struct path_info {
+ char *root;
+ char *phys;
+ char *name;
+ char *info;
+ char *query;
+ int redirected;
+ struct stat stat;
+};
+
+
+const char * sa_straddr(void *sa);
+const char * sa_strport(void *sa);
+int sa_port(void *sa);
+int sa_rfc1918(void *sa);
+
+char *strfind(char *haystack, int hslen, const char *needle, int ndlen);
+
+bool uh_socket_wait(int fd, int sec, bool write);
+
+int uh_raw_send(int fd, const char *buf, int len, int seconds);
+int uh_raw_recv(int fd, char *buf, int len, int seconds);
+int uh_tcp_send(struct client *cl, const char *buf, int len);
+int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len);
+int uh_tcp_recv(struct client *cl, char *buf, int len);
+int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len);
+
+int uh_http_sendhf(struct client *cl, int code, const char *summary,
+ const char *fmt, ...);
+
+#define uh_http_response(cl, code, message) \
+ uh_http_sendhf(cl, code, message, message)
+
+int uh_http_sendc(struct client *cl, const char *data, int len);
+
+int uh_http_sendf(
+ struct client *cl, struct http_request *req,
+ const char *fmt, ...
+);
+
+int uh_http_send(
+ struct client *cl, struct http_request *req,
+ const char *buf, int len
+);
+
+
+int uh_urldecode(char *buf, int blen, const char *src, int slen);
+int uh_urlencode(char *buf, int blen, const char *src, int slen);
+int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen);
+
+
+struct auth_realm * uh_auth_add(char *path, char *user, char *pass);
+
+int uh_auth_check(
+ struct client *cl, struct http_request *req, struct path_info *pi
+);
+
+
+struct path_info * uh_path_lookup(struct client *cl, const char *url);
+
+struct listener * uh_listener_add(int sock, struct config *conf);
+struct listener * uh_listener_lookup(int sock);
+
+struct client * uh_client_add(int sock, struct listener *serv,
+ struct sockaddr_in6 *peer);
+
+struct client * uh_client_lookup(int sock);
+
+#define uh_client_error(cl, code, status, ...) do { \
+ uh_http_sendhf(cl, code, status, __VA_ARGS__); \
+ uh_client_shutdown(cl); \
+} while(0)
+
+void uh_client_shutdown(struct client *cl);
+void uh_client_remove(struct client *cl);
+
+void uh_ufd_add(struct uloop_fd *u, uloop_fd_handler h, unsigned int ev);
+void uh_ufd_remove(struct uloop_fd *u);
+
+
+#ifdef HAVE_CGI
+struct interpreter * uh_interpreter_add(const char *extn, const char *path);
+struct interpreter * uh_interpreter_lookup(const char *path);
+#endif
+
+#endif
diff --git a/package/network/services/uhttpd/src/uhttpd.c b/package/network/services/uhttpd/src/uhttpd.c
new file mode 100644
index 0000000000..1efcbf0f51
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd.c
@@ -0,0 +1,1288 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Main component
+ *
+ * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#define _XOPEN_SOURCE 500 /* crypt() */
+
+#include "uhttpd.h"
+#include "uhttpd-utils.h"
+#include "uhttpd-file.h"
+
+#ifdef HAVE_CGI
+#include "uhttpd-cgi.h"
+#endif
+
+#ifdef HAVE_LUA
+#include "uhttpd-lua.h"
+#endif
+
+#ifdef HAVE_TLS
+#include "uhttpd-tls.h"
+#endif
+
+
+const char * http_methods[] = { "GET", "POST", "HEAD", };
+const char * http_versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", };
+
+static int run = 1;
+
+static void uh_sigterm(int sig)
+{
+ run = 0;
+}
+
+static void uh_config_parse(struct config *conf)
+{
+ FILE *c;
+ char line[512];
+ char *col1 = NULL;
+ char *col2 = NULL;
+ char *eol = NULL;
+
+ const char *path = conf->file ? conf->file : "/etc/httpd.conf";
+
+
+ if ((c = fopen(path, "r")) != NULL)
+ {
+ memset(line, 0, sizeof(line));
+
+ while (fgets(line, sizeof(line) - 1, c))
+ {
+ if ((line[0] == '/') && (strchr(line, ':') != NULL))
+ {
+ if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
+ !(eol = strchr(col2, '\n')) || (*eol++ = 0))
+ {
+ continue;
+ }
+
+ if (!uh_auth_add(line, col1, col2))
+ {
+ fprintf(stderr,
+ "Notice: No password set for user %s, ignoring "
+ "authentication on %s\n", col1, line
+ );
+ }
+ }
+ else if (!strncmp(line, "I:", 2))
+ {
+ if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(eol = strchr(col1, '\n')) || (*eol++ = 0))
+ {
+ continue;
+ }
+
+ conf->index_file = strdup(col1);
+ }
+ else if (!strncmp(line, "E404:", 5))
+ {
+ if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(eol = strchr(col1, '\n')) || (*eol++ = 0))
+ {
+ continue;
+ }
+
+ conf->error_handler = strdup(col1);
+ }
+#ifdef HAVE_CGI
+ else if ((line[0] == '*') && (strchr(line, ':') != NULL))
+ {
+ if (!(col1 = strchr(line, '*')) || (*col1++ = 0) ||
+ !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
+ !(eol = strchr(col2, '\n')) || (*eol++ = 0))
+ {
+ continue;
+ }
+
+ if (!uh_interpreter_add(col1, col2))
+ {
+ fprintf(stderr,
+ "Unable to add interpreter %s for extension %s: "
+ "Out of memory\n", col2, col1
+ );
+ }
+ }
+#endif
+ }
+
+ fclose(c);
+ }
+}
+
+static void uh_listener_cb(struct uloop_fd *u, unsigned int events);
+
+static int uh_socket_bind(const char *host, const char *port,
+ struct addrinfo *hints, int do_tls,
+ struct config *conf)
+{
+ int sock = -1;
+ int yes = 1;
+ int status;
+ int bound = 0;
+
+ int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt;
+
+ struct listener *l = NULL;
+ struct addrinfo *addrs = NULL, *p = NULL;
+
+ if ((status = getaddrinfo(host, port, hints, &addrs)) != 0)
+ {
+ fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
+ }
+
+ /* try to bind a new socket to each found address */
+ for (p = addrs; p; p = p->ai_next)
+ {
+ /* get the socket */
+ if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
+ {
+ perror("socket()");
+ goto error;
+ }
+
+ /* "address already in use" */
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
+ {
+ perror("setsockopt()");
+ goto error;
+ }
+
+ /* TCP keep-alive */
+ if (conf->tcp_keepalive > 0)
+ {
+ tcp_ka_idl = 1;
+ tcp_ka_cnt = 3;
+ tcp_ka_int = conf->tcp_keepalive;
+
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
+ setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
+ setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
+ setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)))
+ {
+ fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
+ strerror(errno));
+ }
+ }
+
+ /* required to get parallel v4 + v6 working */
+ if (p->ai_family == AF_INET6)
+ {
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1)
+ {
+ perror("setsockopt()");
+ goto error;
+ }
+ }
+
+ /* bind */
+ if (bind(sock, p->ai_addr, p->ai_addrlen) == -1)
+ {
+ perror("bind()");
+ goto error;
+ }
+
+ /* listen */
+ if (listen(sock, UH_LIMIT_CLIENTS) == -1)
+ {
+ perror("listen()");
+ goto error;
+ }
+
+ /* add listener to global list */
+ if (!(l = uh_listener_add(sock, conf)))
+ {
+ fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");
+ goto error;
+ }
+
+#ifdef HAVE_TLS
+ /* init TLS */
+ l->tls = do_tls ? conf->tls : NULL;
+#endif
+
+ /* add socket to uloop */
+ fd_cloexec(sock);
+ uh_ufd_add(&l->fd, uh_listener_cb, ULOOP_READ);
+
+ bound++;
+ continue;
+
+ error:
+ if (sock > 0)
+ close(sock);
+ }
+
+ freeaddrinfo(addrs);
+
+ return bound;
+}
+
+static struct http_request * uh_http_header_parse(struct client *cl,
+ char *buffer, int buflen)
+{
+ char *method = buffer;
+ char *path = NULL;
+ char *version = NULL;
+
+ char *headers = NULL;
+ char *hdrname = NULL;
+ char *hdrdata = NULL;
+
+ int i;
+ int hdrcount = 0;
+
+ struct http_request *req = &cl->request;
+
+
+ /* terminate initial header line */
+ if ((headers = strfind(buffer, buflen, "\r\n", 2)) != NULL)
+ {
+ buffer[buflen-1] = 0;
+
+ *headers++ = 0;
+ *headers++ = 0;
+
+ /* find request path */
+ if ((path = strchr(buffer, ' ')) != NULL)
+ *path++ = 0;
+
+ /* find http version */
+ if ((path != NULL) && ((version = strchr(path, ' ')) != NULL))
+ *version++ = 0;
+
+
+ /* check method */
+ if (method && !strcmp(method, "GET"))
+ req->method = UH_HTTP_MSG_GET;
+ else if (method && !strcmp(method, "POST"))
+ req->method = UH_HTTP_MSG_POST;
+ else if (method && !strcmp(method, "HEAD"))
+ req->method = UH_HTTP_MSG_HEAD;
+ else
+ {
+ /* invalid method */
+ uh_http_response(cl, 405, "Method Not Allowed");
+ return NULL;
+ }
+
+ /* check path */
+ if (!path || !strlen(path))
+ {
+ /* malformed request */
+ uh_http_response(cl, 400, "Bad Request");
+ return NULL;
+ }
+ else
+ {
+ req->url = path;
+ }
+
+ /* check version */
+ if (version && !strcmp(version, "HTTP/0.9"))
+ req->version = UH_HTTP_VER_0_9;
+ else if (version && !strcmp(version, "HTTP/1.0"))
+ req->version = UH_HTTP_VER_1_0;
+ else if (version && !strcmp(version, "HTTP/1.1"))
+ req->version = UH_HTTP_VER_1_1;
+ else
+ {
+ /* unsupported version */
+ uh_http_response(cl, 400, "Bad Request");
+ return NULL;
+ }
+
+ D("SRV: %s %s %s\n",
+ http_methods[req->method], req->url, http_versions[req->version]);
+
+ /* process header fields */
+ for (i = (int)(headers - buffer); i < buflen; i++)
+ {
+ /* found eol and have name + value, push out header tuple */
+ if (hdrname && hdrdata && (buffer[i] == '\r' || buffer[i] == '\n'))
+ {
+ buffer[i] = 0;
+
+ /* store */
+ if ((hdrcount + 1) < array_size(req->headers))
+ {
+ D("SRV: HTTP: %s: %s\n", hdrname, hdrdata);
+
+ req->headers[hdrcount++] = hdrname;
+ req->headers[hdrcount++] = hdrdata;
+
+ hdrname = hdrdata = NULL;
+ }
+
+ /* too large */
+ else
+ {
+ D("SRV: HTTP: header too big (too many headers)\n");
+ uh_http_response(cl, 413, "Request Entity Too Large");
+ return NULL;
+ }
+ }
+
+ /* have name but no value and found a colon, start of value */
+ else if (hdrname && !hdrdata &&
+ ((i+1) < buflen) && (buffer[i] == ':'))
+ {
+ buffer[i] = 0;
+ hdrdata = &buffer[i+1];
+
+ while ((hdrdata + 1) < (buffer + buflen) && *hdrdata == ' ')
+ hdrdata++;
+ }
+
+ /* have no name and found [A-Za-z], start of name */
+ else if (!hdrname && isalpha(buffer[i]))
+ {
+ hdrname = &buffer[i];
+ }
+ }
+
+ /* valid enough */
+ req->redirect_status = 200;
+ return req;
+ }
+
+ /* Malformed request */
+ uh_http_response(cl, 400, "Bad Request");
+ return NULL;
+}
+
+
+static struct http_request * uh_http_header_recv(struct client *cl)
+{
+ char *bufptr = cl->httpbuf.buf;
+ char *idxptr = NULL;
+
+ ssize_t blen = sizeof(cl->httpbuf.buf)-1;
+ ssize_t rlen = 0;
+
+ memset(bufptr, 0, sizeof(cl->httpbuf.buf));
+
+ while (blen > 0)
+ {
+ /* receive data */
+ ensure_out(rlen = uh_tcp_recv(cl, bufptr, blen));
+ D("SRV: Client(%d) peek(%d) = %d\n", cl->fd.fd, blen, rlen);
+
+ if (rlen <= 0)
+ {
+ D("SRV: Client(%d) dead [%s]\n", cl->fd.fd, strerror(errno));
+ return NULL;
+ }
+
+ blen -= rlen;
+ bufptr += rlen;
+
+ if ((idxptr = strfind(cl->httpbuf.buf, sizeof(cl->httpbuf.buf),
+ "\r\n\r\n", 4)))
+ {
+ /* header read complete ... */
+ cl->httpbuf.ptr = idxptr + 4;
+ cl->httpbuf.len = bufptr - cl->httpbuf.ptr;
+
+ return uh_http_header_parse(cl, cl->httpbuf.buf,
+ (cl->httpbuf.ptr - cl->httpbuf.buf));
+ }
+ }
+
+ /* request entity too large */
+ D("SRV: HTTP: header too big (buffer exceeded)\n");
+ uh_http_response(cl, 413, "Request Entity Too Large");
+
+out:
+ return NULL;
+}
+
+#if defined(HAVE_LUA) || defined(HAVE_CGI)
+static int uh_path_match(const char *prefix, const char *url)
+{
+ if ((strstr(url, prefix) == url) &&
+ ((prefix[strlen(prefix)-1] == '/') ||
+ (strlen(url) == strlen(prefix)) ||
+ (url[strlen(prefix)] == '/')))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static bool uh_dispatch_request(struct client *cl, struct http_request *req)
+{
+ struct path_info *pin;
+ struct interpreter *ipr = NULL;
+ struct config *conf = cl->server->conf;
+
+#ifdef HAVE_LUA
+ /* Lua request? */
+ if (conf->lua_state &&
+ uh_path_match(conf->lua_prefix, req->url))
+ {
+ return conf->lua_request(cl, conf->lua_state);
+ }
+ else
+#endif
+
+#ifdef HAVE_UBUS
+ /* ubus request? */
+ if (conf->ubus_state &&
+ uh_path_match(conf->ubus_prefix, req->url))
+ {
+ return conf->ubus_request(cl, conf->ubus_state);
+ }
+ else
+#endif
+
+ /* dispatch request */
+ if ((pin = uh_path_lookup(cl, req->url)) != NULL)
+ {
+ /* auth ok? */
+ if (!pin->redirected && uh_auth_check(cl, req, pin))
+ {
+#ifdef HAVE_CGI
+ if (uh_path_match(conf->cgi_prefix, pin->name) ||
+ (ipr = uh_interpreter_lookup(pin->phys)) != NULL)
+ {
+ return uh_cgi_request(cl, pin, ipr);
+ }
+#endif
+ return uh_file_request(cl, pin);
+ }
+ }
+
+ /* 404 - pass 1 */
+ else
+ {
+ /* Try to invoke an error handler */
+ if ((pin = uh_path_lookup(cl, conf->error_handler)) != NULL)
+ {
+ /* auth ok? */
+ if (uh_auth_check(cl, req, pin))
+ {
+ req->redirect_status = 404;
+#ifdef HAVE_CGI
+ if (uh_path_match(conf->cgi_prefix, pin->name) ||
+ (ipr = uh_interpreter_lookup(pin->phys)) != NULL)
+ {
+ return uh_cgi_request(cl, pin, ipr);
+ }
+#endif
+ return uh_file_request(cl, pin);
+ }
+ }
+
+ /* 404 - pass 2 */
+ else
+ {
+ uh_http_sendhf(cl, 404, "Not Found", "No such file or directory");
+ }
+ }
+
+ return false;
+}
+
+static void uh_socket_cb(struct uloop_fd *u, unsigned int events);
+
+static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
+{
+ int new_fd;
+ struct listener *serv;
+ struct client *cl;
+ struct config *conf;
+
+ struct sockaddr_in6 sa;
+ socklen_t sl = sizeof(sa);
+
+ serv = container_of(u, struct listener, fd);
+ conf = serv->conf;
+
+ /* defer client if maximum number of requests is exceeded */
+ if (serv->n_clients >= conf->max_requests)
+ return;
+
+ /* handle new connections */
+ if ((new_fd = accept(u->fd, (struct sockaddr *)&sa, &sl)) != -1)
+ {
+ D("SRV: Server(%d) accept => Client(%d)\n", u->fd, new_fd);
+
+ /* add to global client list */
+ if ((cl = uh_client_add(new_fd, serv, &sa)) != NULL)
+ {
+ /* add client socket to global fdset */
+ uh_ufd_add(&cl->fd, uh_socket_cb, ULOOP_READ);
+ fd_cloexec(cl->fd.fd);
+
+#ifdef HAVE_TLS
+ /* setup client tls context */
+ if (conf->tls)
+ {
+ if (conf->tls_accept(cl) < 1)
+ {
+ D("SRV: Client(%d) SSL handshake failed, drop\n", new_fd);
+
+ /* remove from global client list */
+ uh_client_remove(cl);
+ return;
+ }
+ }
+#endif
+ }
+
+ /* insufficient resources */
+ else
+ {
+ fprintf(stderr, "uh_client_add(): Cannot allocate memory\n");
+ close(new_fd);
+ }
+ }
+}
+
+static void uh_client_cb(struct client *cl, unsigned int events);
+
+static void uh_rpipe_cb(struct uloop_fd *u, unsigned int events)
+{
+ struct client *cl = container_of(u, struct client, rpipe);
+
+ D("SRV: Client(%d) rpipe readable\n", cl->fd.fd);
+
+ uh_client_cb(cl, ULOOP_WRITE);
+}
+
+static void uh_socket_cb(struct uloop_fd *u, unsigned int events)
+{
+ struct client *cl = container_of(u, struct client, fd);
+
+ D("SRV: Client(%d) socket readable\n", cl->fd.fd);
+
+ uh_client_cb(cl, ULOOP_READ);
+}
+
+static void uh_child_cb(struct uloop_process *p, int rv)
+{
+ struct client *cl = container_of(p, struct client, proc);
+
+ D("SRV: Client(%d) child(%d) dead\n", cl->fd.fd, cl->proc.pid);
+
+ uh_client_cb(cl, ULOOP_READ | ULOOP_WRITE);
+}
+
+static void uh_kill9_cb(struct uloop_timeout *t)
+{
+ struct client *cl = container_of(t, struct client, timeout);
+
+ if (!kill(cl->proc.pid, 0))
+ {
+ D("SRV: Client(%d) child(%d) kill(SIGKILL)...\n",
+ cl->fd.fd, cl->proc.pid);
+
+ kill(cl->proc.pid, SIGKILL);
+ }
+}
+
+static void uh_timeout_cb(struct uloop_timeout *t)
+{
+ struct client *cl = container_of(t, struct client, timeout);
+
+ D("SRV: Client(%d) child(%d) timed out\n", cl->fd.fd, cl->proc.pid);
+
+ if (!kill(cl->proc.pid, 0))
+ {
+ D("SRV: Client(%d) child(%d) kill(SIGTERM)...\n",
+ cl->fd.fd, cl->proc.pid);
+
+ kill(cl->proc.pid, SIGTERM);
+
+ cl->timeout.cb = uh_kill9_cb;
+ uloop_timeout_set(&cl->timeout, 1000);
+ }
+}
+
+static void uh_client_cb(struct client *cl, unsigned int events)
+{
+ int i;
+ struct config *conf;
+ struct http_request *req;
+
+ conf = cl->server->conf;
+
+ D("SRV: Client(%d) enter callback\n", cl->fd.fd);
+
+ /* undispatched yet */
+ if (!cl->dispatched)
+ {
+ /* we have no headers yet and this was a write event, ignore... */
+ if (!(events & ULOOP_READ))
+ {
+ D("SRV: Client(%d) ignoring write event before headers\n", cl->fd.fd);
+ return;
+ }
+
+ /* attempt to receive and parse headers */
+ if (!(req = uh_http_header_recv(cl)))
+ {
+ D("SRV: Client(%d) failed to receive header\n", cl->fd.fd);
+ uh_client_shutdown(cl);
+ return;
+ }
+
+ /* process expect headers */
+ foreach_header(i, req->headers)
+ {
+ if (strcasecmp(req->headers[i], "Expect"))
+ continue;
+
+ if (strcasecmp(req->headers[i+1], "100-continue"))
+ {
+ D("SRV: Client(%d) unknown expect header (%s)\n",
+ cl->fd.fd, req->headers[i+1]);
+
+ uh_http_response(cl, 417, "Precondition Failed");
+ uh_client_shutdown(cl);
+ return;
+ }
+ else
+ {
+ D("SRV: Client(%d) sending HTTP/1.1 100 Continue\n", cl->fd.fd);
+
+ uh_http_sendf(cl, NULL, "HTTP/1.1 100 Continue\r\n\r\n");
+ cl->httpbuf.len = 0; /* client will re-send the body */
+ break;
+ }
+ }
+
+ /* RFC1918 filtering */
+ if (conf->rfc1918_filter &&
+ sa_rfc1918(&cl->peeraddr) && !sa_rfc1918(&cl->servaddr))
+ {
+ uh_http_sendhf(cl, 403, "Forbidden",
+ "Rejected request from RFC1918 IP "
+ "to public server address");
+
+ uh_client_shutdown(cl);
+ return;
+ }
+
+ /* dispatch request */
+ if (!uh_dispatch_request(cl, req))
+ {
+ D("SRV: Client(%d) failed to dispach request\n", cl->fd.fd);
+ uh_client_shutdown(cl);
+ return;
+ }
+
+ /* request handler spawned a pipe, register handler */
+ if (cl->rpipe.fd > -1)
+ {
+ D("SRV: Client(%d) pipe(%d) spawned\n", cl->fd.fd, cl->rpipe.fd);
+
+ uh_ufd_add(&cl->rpipe, uh_rpipe_cb, ULOOP_READ);
+ }
+
+ /* request handler spawned a child, register handler */
+ if (cl->proc.pid)
+ {
+ D("SRV: Client(%d) child(%d) spawned\n", cl->fd.fd, cl->proc.pid);
+
+ cl->proc.cb = uh_child_cb;
+ uloop_process_add(&cl->proc);
+
+ cl->timeout.cb = uh_timeout_cb;
+ uloop_timeout_set(&cl->timeout, conf->script_timeout * 1000);
+ }
+
+ /* header processing complete */
+ D("SRV: Client(%d) dispatched\n", cl->fd.fd);
+ cl->dispatched = true;
+ }
+
+ if (!cl->cb(cl))
+ {
+ D("SRV: Client(%d) response callback signalized EOF\n", cl->fd.fd);
+ uh_client_shutdown(cl);
+ return;
+ }
+}
+
+#ifdef HAVE_TLS
+static inline int uh_inittls(struct config *conf)
+{
+ /* library handle */
+ void *lib;
+
+ /* already loaded */
+ if (conf->tls != NULL)
+ return 0;
+
+ /* load TLS plugin */
+ if (!(lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)))
+ {
+ fprintf(stderr,
+ "Notice: Unable to load TLS plugin - disabling SSL support! "
+ "(Reason: %s)\n", dlerror()
+ );
+
+ return 1;
+ }
+ else
+ {
+ /* resolve functions */
+ if (!(conf->tls_init = dlsym(lib, "uh_tls_ctx_init")) ||
+ !(conf->tls_cert = dlsym(lib, "uh_tls_ctx_cert")) ||
+ !(conf->tls_key = dlsym(lib, "uh_tls_ctx_key")) ||
+ !(conf->tls_free = dlsym(lib, "uh_tls_ctx_free")) ||
+ !(conf->tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
+ !(conf->tls_close = dlsym(lib, "uh_tls_client_close")) ||
+ !(conf->tls_recv = dlsym(lib, "uh_tls_client_recv")) ||
+ !(conf->tls_send = dlsym(lib, "uh_tls_client_send")))
+ {
+ fprintf(stderr,
+ "Error: Failed to lookup required symbols "
+ "in TLS plugin: %s\n", dlerror()
+ );
+ exit(1);
+ }
+
+ /* init SSL context */
+ if (!(conf->tls = conf->tls_init()))
+ {
+ fprintf(stderr, "Error: Failed to initalize SSL context\n");
+ exit(1);
+ }
+ }
+
+ return 0;
+}
+#endif
+
+int main (int argc, char **argv)
+{
+ /* working structs */
+ struct addrinfo hints;
+ struct sigaction sa;
+ struct config conf;
+
+ /* maximum file descriptor number */
+ int cur_fd = 0;
+
+#ifdef HAVE_TLS
+ int tls = 0;
+ int keys = 0;
+#endif
+
+ int bound = 0;
+ int nofork = 0;
+
+ /* args */
+ int opt;
+ char addr[128];
+ char *port = NULL;
+
+#if defined(HAVE_LUA) || defined(HAVE_TLS) || defined(HAVE_UBUS)
+ /* library handle */
+ void *lib;
+#endif
+
+ /* handle SIGPIPE, SIGINT, SIGTERM */
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = uh_sigterm;
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ /* prepare addrinfo hints */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ /* parse args */
+ memset(&conf, 0, sizeof(conf));
+
+ uloop_init();
+
+ while ((opt = getopt(argc, argv,
+ "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:n:x:i:t:T:A:u:U:")) > 0)
+ {
+ switch(opt)
+ {
+ /* [addr:]port */
+ case 'p':
+ case 's':
+ memset(addr, 0, sizeof(addr));
+
+ if ((port = strrchr(optarg, ':')) != NULL)
+ {
+ if ((optarg[0] == '[') && (port > optarg) && (port[-1] == ']'))
+ memcpy(addr, optarg + 1,
+ min(sizeof(addr), (int)(port - optarg) - 2));
+ else
+ memcpy(addr, optarg,
+ min(sizeof(addr), (int)(port - optarg)));
+
+ port++;
+ }
+ else
+ {
+ port = optarg;
+ }
+
+#ifdef HAVE_TLS
+ if (opt == 's')
+ {
+ if (uh_inittls(&conf))
+ {
+ fprintf(stderr,
+ "Notice: TLS support is disabled, "
+ "ignoring '-s %s'\n", optarg
+ );
+ continue;
+ }
+
+ tls = 1;
+ }
+#endif
+
+ /* bind sockets */
+ bound += uh_socket_bind(addr[0] ? addr : NULL, port, &hints,
+ (opt == 's'), &conf);
+ break;
+
+#ifdef HAVE_TLS
+ /* certificate */
+ case 'C':
+ if (!uh_inittls(&conf))
+ {
+ if (conf.tls_cert(conf.tls, optarg) < 1)
+ {
+ fprintf(stderr,
+ "Error: Invalid certificate file given\n");
+ exit(1);
+ }
+
+ keys++;
+ }
+
+ break;
+
+ /* key */
+ case 'K':
+ if (!uh_inittls(&conf))
+ {
+ if (conf.tls_key(conf.tls, optarg) < 1)
+ {
+ fprintf(stderr,
+ "Error: Invalid private key file given\n");
+ exit(1);
+ }
+
+ keys++;
+ }
+
+ break;
+#else
+ case 'C':
+ case 'K':
+ fprintf(stderr,
+ "Notice: TLS support not compiled, ignoring -%c\n",
+ opt);
+ break;
+#endif
+
+ /* docroot */
+ case 'h':
+ if (! realpath(optarg, conf.docroot))
+ {
+ fprintf(stderr, "Error: Invalid directory %s: %s\n",
+ optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+
+ /* error handler */
+ case 'E':
+ if ((strlen(optarg) == 0) || (optarg[0] != '/'))
+ {
+ fprintf(stderr, "Error: Invalid error handler: %s\n",
+ optarg);
+ exit(1);
+ }
+ conf.error_handler = optarg;
+ break;
+
+ /* index file */
+ case 'I':
+ if ((strlen(optarg) == 0) || (optarg[0] == '/'))
+ {
+ fprintf(stderr, "Error: Invalid index page: %s\n",
+ optarg);
+ exit(1);
+ }
+ conf.index_file = optarg;
+ break;
+
+ /* don't follow symlinks */
+ case 'S':
+ conf.no_symlinks = 1;
+ break;
+
+ /* don't list directories */
+ case 'D':
+ conf.no_dirlists = 1;
+ break;
+
+ case 'R':
+ conf.rfc1918_filter = 1;
+ break;
+
+ case 'n':
+ conf.max_requests = atoi(optarg);
+ break;
+
+#ifdef HAVE_CGI
+ /* cgi prefix */
+ case 'x':
+ conf.cgi_prefix = optarg;
+ break;
+
+ /* interpreter */
+ case 'i':
+ if ((optarg[0] == '.') && (port = strchr(optarg, '=')))
+ {
+ *port++ = 0;
+ uh_interpreter_add(optarg, port);
+ }
+ else
+ {
+ fprintf(stderr, "Error: Invalid interpreter: %s\n",
+ optarg);
+ exit(1);
+ }
+ break;
+#else
+ case 'x':
+ case 'i':
+ fprintf(stderr,
+ "Notice: CGI support not compiled, ignoring -%c\n",
+ opt);
+ break;
+#endif
+
+#ifdef HAVE_LUA
+ /* lua prefix */
+ case 'l':
+ conf.lua_prefix = optarg;
+ break;
+
+ /* lua handler */
+ case 'L':
+ conf.lua_handler = optarg;
+ break;
+#else
+ case 'l':
+ case 'L':
+ fprintf(stderr,
+ "Notice: Lua support not compiled, ignoring -%c\n",
+ opt);
+ break;
+#endif
+
+#ifdef HAVE_UBUS
+ /* ubus prefix */
+ case 'u':
+ conf.ubus_prefix = optarg;
+ break;
+
+ /* ubus socket */
+ case 'U':
+ conf.ubus_socket = optarg;
+ break;
+#else
+ case 'u':
+ case 'U':
+ fprintf(stderr,
+ "Notice: UBUS support not compiled, ignoring -%c\n",
+ opt);
+ break;
+#endif
+
+#if defined(HAVE_CGI) || defined(HAVE_LUA)
+ /* script timeout */
+ case 't':
+ conf.script_timeout = atoi(optarg);
+ break;
+#endif
+
+ /* network timeout */
+ case 'T':
+ conf.network_timeout = atoi(optarg);
+ break;
+
+ /* tcp keep-alive */
+ case 'A':
+ conf.tcp_keepalive = atoi(optarg);
+ break;
+
+ /* no fork */
+ case 'f':
+ nofork = 1;
+ break;
+
+ /* urldecode */
+ case 'd':
+ if ((port = malloc(strlen(optarg)+1)) != NULL)
+ {
+ /* "decode" plus to space to retain compat */
+ for (opt = 0; optarg[opt]; opt++)
+ if (optarg[opt] == '+')
+ optarg[opt] = ' ';
+ /* opt now contains strlen(optarg) -- no need to re-scan */
+ memset(port, 0, opt+1);
+ if (uh_urldecode(port, opt, optarg, opt) < 0)
+ fprintf(stderr, "uhttpd: invalid encoding\n");
+
+ printf("%s", port);
+ free(port);
+ exit(0);
+ }
+ break;
+
+ /* basic auth realm */
+ case 'r':
+ conf.realm = optarg;
+ break;
+
+ /* md5 crypt */
+ case 'm':
+ printf("%s\n", crypt(optarg, "$1$"));
+ exit(0);
+ break;
+
+ /* config file */
+ case 'c':
+ conf.file = optarg;
+ break;
+
+ default:
+ fprintf(stderr,
+ "Usage: %s -p [addr:]port [-h docroot]\n"
+ " -f Do not fork to background\n"
+ " -c file Configuration file, default is '/etc/httpd.conf'\n"
+ " -p [addr:]port Bind to specified address and port, multiple allowed\n"
+#ifdef HAVE_TLS
+ " -s [addr:]port Like -p but provide HTTPS on this port\n"
+ " -C file ASN.1 server certificate file\n"
+ " -K file ASN.1 server private key file\n"
+#endif
+ " -h directory Specify the document root, default is '.'\n"
+ " -E string Use given virtual URL as 404 error handler\n"
+ " -I string Use given filename as index page for directories\n"
+ " -S Do not follow symbolic links outside of the docroot\n"
+ " -D Do not allow directory listings, send 403 instead\n"
+ " -R Enable RFC1918 filter\n"
+ " -n count Maximum allowed number of concurrent requests\n"
+#ifdef HAVE_LUA
+ " -l string URL prefix for Lua handler, default is '/lua'\n"
+ " -L file Lua handler script, omit to disable Lua\n"
+#endif
+#ifdef HAVE_UBUS
+ " -u string URL prefix for HTTP/JSON handler\n"
+ " -U file Override ubus socket path\n"
+#endif
+#ifdef HAVE_CGI
+ " -x string URL prefix for CGI handler, default is '/cgi-bin'\n"
+ " -i .ext=path Use interpreter at path for files with the given extension\n"
+#endif
+#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS)
+ " -t seconds CGI, Lua and UBUS script timeout in seconds, default is 60\n"
+#endif
+ " -T seconds Network timeout in seconds, default is 30\n"
+ " -d string URL decode given string\n"
+ " -r string Specify basic auth realm\n"
+ " -m string MD5 crypt given string\n"
+ "\n", argv[0]
+ );
+
+ exit(1);
+ }
+ }
+
+#ifdef HAVE_TLS
+ if ((tls == 1) && (keys < 2))
+ {
+ fprintf(stderr, "Error: Missing private key or certificate file\n");
+ exit(1);
+ }
+#endif
+
+ if (bound < 1)
+ {
+ fprintf(stderr, "Error: No sockets bound, unable to continue\n");
+ exit(1);
+ }
+
+ /* default docroot */
+ if (!conf.docroot[0] && !realpath(".", conf.docroot))
+ {
+ fprintf(stderr, "Error: Can not determine default document root: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ /* default realm */
+ if (!conf.realm)
+ conf.realm = "Protected Area";
+
+ /* config file */
+ uh_config_parse(&conf);
+
+ /* default max requests */
+ if (conf.max_requests <= 0)
+ conf.max_requests = 3;
+
+ /* default network timeout */
+ if (conf.network_timeout <= 0)
+ conf.network_timeout = 30;
+
+#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS)
+ /* default script timeout */
+ if (conf.script_timeout <= 0)
+ conf.script_timeout = 60;
+#endif
+
+#ifdef HAVE_CGI
+ /* default cgi prefix */
+ if (!conf.cgi_prefix)
+ conf.cgi_prefix = "/cgi-bin";
+#endif
+
+#ifdef HAVE_LUA
+ /* load Lua plugin */
+ if (!(lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)))
+ {
+ fprintf(stderr,
+ "Notice: Unable to load Lua plugin - disabling Lua support! "
+ "(Reason: %s)\n", dlerror());
+ }
+ else
+ {
+ /* resolve functions */
+ if (!(conf.lua_init = dlsym(lib, "uh_lua_init")) ||
+ !(conf.lua_close = dlsym(lib, "uh_lua_close")) ||
+ !(conf.lua_request = dlsym(lib, "uh_lua_request")))
+ {
+ fprintf(stderr,
+ "Error: Failed to lookup required symbols "
+ "in Lua plugin: %s\n", dlerror()
+ );
+ exit(1);
+ }
+
+ /* init Lua runtime if handler is specified */
+ if (conf.lua_handler)
+ {
+ /* default lua prefix */
+ if (!conf.lua_prefix)
+ conf.lua_prefix = "/lua";
+
+ conf.lua_state = conf.lua_init(&conf);
+ }
+ }
+#endif
+
+#ifdef HAVE_UBUS
+ /* load ubus plugin */
+ if (!(lib = dlopen("uhttpd_ubus.so", RTLD_LAZY | RTLD_GLOBAL)))
+ {
+ fprintf(stderr,
+ "Notice: Unable to load ubus plugin - disabling ubus support! "
+ "(Reason: %s)\n", dlerror());
+ }
+ else if (conf.ubus_prefix)
+ {
+ /* resolve functions */
+ if (!(conf.ubus_init = dlsym(lib, "uh_ubus_init")) ||
+ !(conf.ubus_close = dlsym(lib, "uh_ubus_close")) ||
+ !(conf.ubus_request = dlsym(lib, "uh_ubus_request")))
+ {
+ fprintf(stderr,
+ "Error: Failed to lookup required symbols "
+ "in ubus plugin: %s\n", dlerror()
+ );
+ exit(1);
+ }
+
+ /* initialize ubus */
+ conf.ubus_state = conf.ubus_init(&conf);
+ }
+#endif
+
+ /* fork (if not disabled) */
+ if (!nofork)
+ {
+ switch (fork())
+ {
+ case -1:
+ perror("fork()");
+ exit(1);
+
+ case 0:
+ /* daemon setup */
+ if (chdir("/"))
+ perror("chdir()");
+
+ if ((cur_fd = open("/dev/null", O_WRONLY)) > -1)
+ dup2(cur_fd, 0);
+
+ if ((cur_fd = open("/dev/null", O_RDONLY)) > -1)
+ dup2(cur_fd, 1);
+
+ if ((cur_fd = open("/dev/null", O_RDONLY)) > -1)
+ dup2(cur_fd, 2);
+
+ break;
+
+ default:
+ exit(0);
+ }
+ }
+
+ /* server main loop */
+ uloop_run();
+
+#ifdef HAVE_LUA
+ /* destroy the Lua state */
+ if (conf.lua_state != NULL)
+ conf.lua_close(conf.lua_state);
+#endif
+
+#ifdef HAVE_UBUS
+ /* destroy the ubus state */
+ if (conf.ubus_state != NULL)
+ conf.ubus_close(conf.ubus_state);
+#endif
+
+ return 0;
+}
diff --git a/package/network/services/uhttpd/src/uhttpd.h b/package/network/services/uhttpd/src/uhttpd.h
new file mode 100644
index 0000000000..f6982db323
--- /dev/null
+++ b/package/network/services/uhttpd/src/uhttpd.h
@@ -0,0 +1,214 @@
+/*
+ * uhttpd - Tiny single-threaded httpd - Main header
+ *
+ * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * 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.
+ */
+
+#ifndef _UHTTPD_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <linux/limits.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <libubox/list.h>
+#include <libubox/uloop.h>
+
+
+#ifdef HAVE_LUA
+#include <lua.h>
+#endif
+
+#ifdef HAVE_TLS
+#include <openssl/ssl.h>
+#endif
+
+/* uClibc... */
+#ifndef SOL_TCP
+#define SOL_TCP 6
+#endif
+
+#ifdef DEBUG
+#define D(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define D(...)
+#endif
+
+
+#define UH_LIMIT_MSGHEAD 4096
+#define UH_LIMIT_HEADERS 64
+#define UH_LIMIT_CLIENTS 64
+
+
+struct listener;
+struct client;
+struct interpreter;
+struct http_request;
+struct uh_ubus_state;
+
+struct config {
+ char docroot[PATH_MAX];
+ char *realm;
+ char *file;
+ char *index_file;
+ char *error_handler;
+ int no_symlinks;
+ int no_dirlists;
+ int network_timeout;
+ int rfc1918_filter;
+ int tcp_keepalive;
+ int max_requests;
+#ifdef HAVE_CGI
+ char *cgi_prefix;
+#endif
+#ifdef HAVE_LUA
+ char *lua_prefix;
+ char *lua_handler;
+ lua_State *lua_state;
+ lua_State * (*lua_init) (const struct config *conf);
+ void (*lua_close) (lua_State *L);
+ bool (*lua_request) (struct client *cl, lua_State *L);
+#endif
+#ifdef HAVE_UBUS
+ char *ubus_prefix;
+ char *ubus_socket;
+ void *ubus_state;
+ struct uh_ubus_state * (*ubus_init) (const struct config *conf);
+ void (*ubus_close) (struct uh_ubus_state *state);
+ bool (*ubus_request) (struct client *cl, struct uh_ubus_state *state);
+#endif
+#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS)
+ int script_timeout;
+#endif
+#ifdef HAVE_TLS
+ char *cert;
+ char *key;
+ SSL_CTX *tls;
+ SSL_CTX * (*tls_init) (void);
+ int (*tls_cert) (SSL_CTX *c, const char *file);
+ int (*tls_key) (SSL_CTX *c, const char *file);
+ void (*tls_free) (struct listener *l);
+ int (*tls_accept) (struct client *c);
+ void (*tls_close) (struct client *c);
+ int (*tls_recv) (struct client *c, char *buf, int len);
+ int (*tls_send) (struct client *c, const char *buf, int len);
+#endif
+};
+
+enum http_method {
+ UH_HTTP_MSG_GET,
+ UH_HTTP_MSG_POST,
+ UH_HTTP_MSG_HEAD,
+};
+
+extern const char *http_methods[];
+
+enum http_version {
+ UH_HTTP_VER_0_9,
+ UH_HTTP_VER_1_0,
+ UH_HTTP_VER_1_1,
+};
+
+extern const char *http_versions[];
+
+struct http_request {
+ enum http_method method;
+ enum http_version version;
+ int redirect_status;
+ char *url;
+ char *headers[UH_LIMIT_HEADERS];
+ struct auth_realm *realm;
+};
+
+struct http_response {
+ int statuscode;
+ char *statusmsg;
+ char *headers[UH_LIMIT_HEADERS];
+};
+
+struct listener {
+ struct uloop_fd fd;
+ int socket;
+ int n_clients;
+ struct sockaddr_in6 addr;
+ struct config *conf;
+#ifdef HAVE_TLS
+ SSL_CTX *tls;
+#endif
+ struct listener *next;
+};
+
+struct client {
+#ifdef HAVE_TLS
+ SSL *tls;
+#endif
+ struct uloop_fd fd;
+ struct uloop_fd rpipe;
+ struct uloop_fd wpipe;
+ struct uloop_process proc;
+ struct uloop_timeout timeout;
+ bool (*cb)(struct client *);
+ void *priv;
+ bool dispatched;
+ struct {
+ char buf[UH_LIMIT_MSGHEAD];
+ char *ptr;
+ int len;
+ } httpbuf;
+ struct listener *server;
+ struct http_request request;
+ struct http_response response;
+ struct sockaddr_in6 servaddr;
+ struct sockaddr_in6 peeraddr;
+ struct client *next;
+};
+
+struct client_light {
+#ifdef HAVE_TLS
+ SSL *tls;
+#endif
+ struct uloop_fd fd;
+};
+
+struct auth_realm {
+ char path[PATH_MAX];
+ char user[32];
+ char pass[128];
+ struct auth_realm *next;
+};
+
+#ifdef HAVE_CGI
+struct interpreter {
+ char path[PATH_MAX];
+ char extn[32];
+ struct interpreter *next;
+};
+#endif
+
+#endif