From 102ad2157b31642e029c8c176de1cc5b22c96599 Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Sun, 24 Jul 2005 19:58:14 +0000
Subject: move wificonf and nvram stuff back to package/, remove
 build_mipsel/root, run install part of package/ for every board/kernel -
 fixes dependency mess

git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@1540 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 package/nvram/Makefile            |  46 +++
 package/nvram/ipkg/nvram.control  |   7 +
 package/nvram/src/Makefile        |  22 ++
 package/nvram/src/bcmtimer.h      |  42 +++
 package/nvram/src/defaults.c      | 179 +++++++++
 package/nvram/src/linux_timer.c   | 738 ++++++++++++++++++++++++++++++++++++++
 package/nvram/src/main.c          |  78 ++++
 package/nvram/src/nvram_convert.c |  77 ++++
 package/nvram/src/nvram_convert.h |   7 +
 package/nvram/src/nvram_linux.c   | 320 +++++++++++++++++
 package/nvram/src/shutils.c       | 329 +++++++++++++++++
 package/nvram/src/wl.c            |  86 +++++
 package/nvram/src/wl_linux.c      |  77 ++++
 13 files changed, 2008 insertions(+)
 create mode 100644 package/nvram/Makefile
 create mode 100644 package/nvram/ipkg/nvram.control
 create mode 100644 package/nvram/src/Makefile
 create mode 100644 package/nvram/src/bcmtimer.h
 create mode 100644 package/nvram/src/defaults.c
 create mode 100644 package/nvram/src/linux_timer.c
 create mode 100644 package/nvram/src/main.c
 create mode 100644 package/nvram/src/nvram_convert.c
 create mode 100644 package/nvram/src/nvram_convert.h
 create mode 100644 package/nvram/src/nvram_linux.c
 create mode 100644 package/nvram/src/shutils.c
 create mode 100644 package/nvram/src/wl.c
 create mode 100644 package/nvram/src/wl_linux.c

(limited to 'package/nvram')

diff --git a/package/nvram/Makefile b/package/nvram/Makefile
new file mode 100644
index 000000000..9885f9908
--- /dev/null
+++ b/package/nvram/Makefile
@@ -0,0 +1,46 @@
+# $Id$
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=nvram
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(TOPDIR)/package/rules.mk
+
+# does not depend on menuconfig
+ifneq ($(BOARD),brcm)
+BR2_PACKAGE_NVRAM:=m
+else
+BR2_PACKAGE_NVRAM:=y
+endif
+
+$(eval $(call PKG_template,NVRAM,nvram,$(PKG_RELEASE),$(ARCH)))
+
+$(PKG_BUILD_DIR)/.prepared:
+	mkdir -p $(PKG_BUILD_DIR)
+	cp -a ./src/* $(PKG_BUILD_DIR)
+	touch $@
+
+$(PKG_BUILD_DIR)/.built:
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		CFLAGS="$(TARGET_CFLAGS) -I $(STAGING_DIR)/usr/include"
+	touch $@
+
+$(IPKG_NVRAM):
+	mkdir -p $(IDIR_NVRAM)/usr/lib
+	cp $(PKG_BUILD_DIR)/*.so $(IDIR_NVRAM)/usr/lib
+	mkdir -p $(IDIR_NVRAM)/usr/sbin
+	cp $(PKG_BUILD_DIR)/nvram $(IDIR_NVRAM)/usr/sbin
+	$(RSTRIP) $(IDIR_NVRAM)
+	$(IPKG_BUILD) $(IDIR_NVRAM) $(PACKAGE_DIR)
+
+
+compile: install-dev
+install-dev:
+	mkdir -p $(STAGING_DIR)/usr/lib
+	cp $(PKG_BUILD_DIR)/*.so $(STAGING_DIR)/usr/lib
+	
+
diff --git a/package/nvram/ipkg/nvram.control b/package/nvram/ipkg/nvram.control
new file mode 100644
index 000000000..bb2581303
--- /dev/null
+++ b/package/nvram/ipkg/nvram.control
@@ -0,0 +1,7 @@
+Package: nvram
+Priority: optional
+Section: sys
+Maintainer: Felix Fietkau <nbd@vd-s.ath.cx>
+Source: buildroot internal
+Description: NVRAM utility and libraries for Broadcom hardware
+
diff --git a/package/nvram/src/Makefile b/package/nvram/src/Makefile
new file mode 100644
index 000000000..376c2b7de
--- /dev/null
+++ b/package/nvram/src/Makefile
@@ -0,0 +1,22 @@
+# $Id$
+
+EXTRA_CFLAGS := -c -I. -I../include
+LIBSHARED_OBJS := shutils.o wl.o wl_linux.o defaults.o linux_timer.o
+LIBNVRAM_OBJS := nvram_linux.o nvram_convert.o
+
+all: libshared.so libnvram.so nvram
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $^
+
+libshared.so: $(LIBSHARED_OBJS)
+	$(CC) -shared -o $@ $^
+
+libnvram.so: $(LIBNVRAM_OBJS)
+	$(CC) -shared -o $@ $^
+
+nvram: main.o
+	$(CC) -o $@ $^ -L. -lnvram
+
+clean:
+	rm -f *.o *.so nvram
diff --git a/package/nvram/src/bcmtimer.h b/package/nvram/src/bcmtimer.h
new file mode 100644
index 000000000..3db9e624f
--- /dev/null
+++ b/package/nvram/src/bcmtimer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * Low resolution timer interface. Timer handlers may be called 
+ * in a deferred manner in a different task context after the 
+ * timer expires or in the task context from which the timer
+ * was created, depending on the implementation.
+ *
+ * $Id$
+ */
+#ifndef __bcmtimer_h__
+#define __bcmtimer_h__
+
+/* ANSI headers */
+#include <time.h>
+
+/* timer ID */
+typedef unsigned int bcm_timer_module_id;
+typedef unsigned int bcm_timer_id;
+
+/* timer callback */
+typedef void (*bcm_timer_cb)(bcm_timer_id id, int data);
+
+/* OS-independant interfaces, applications should call these functions only */
+int bcm_timer_module_init(int timer_entries, bcm_timer_module_id *module_id);
+int bcm_timer_module_cleanup(bcm_timer_module_id module_id);
+int bcm_timer_module_enable(bcm_timer_module_id module_id, int enable);
+int bcm_timer_create(bcm_timer_module_id module_id, bcm_timer_id *timer_id);
+int bcm_timer_delete(bcm_timer_id timer_id);
+int bcm_timer_gettime(bcm_timer_id timer_id, struct itimerspec *value);
+int bcm_timer_settime(bcm_timer_id timer_id, const struct itimerspec *value);
+int bcm_timer_connect(bcm_timer_id timer_id, bcm_timer_cb func, int data);
+int bcm_timer_cancel(bcm_timer_id timer_id);
+int bcm_timer_change_expirytime(bcm_timer_id timer_id, const struct itimerspec *timer_spec);
+
+#endif	/* #ifndef __bcmtimer_h__ */
diff --git a/package/nvram/src/defaults.c b/package/nvram/src/defaults.c
new file mode 100644
index 000000000..119eaac72
--- /dev/null
+++ b/package/nvram/src/defaults.c
@@ -0,0 +1,179 @@
+/*
+ * Router default NVRAM values
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <epivers.h>
+#include <string.h>
+#include <bcmnvram.h>
+#include <typedefs.h>
+#include <wlioctl.h>
+
+#define XSTR(s) STR(s)
+#define STR(s) #s
+
+struct nvram_tuple router_defaults[] = {
+	/* OS parameters */
+	{ "os_name", "", 0 },			/* OS name string */
+	{ "os_version", EPI_VERSION_STR, 0 },	/* OS revision */
+	{ "os_date", __DATE__, 0 },		/* OS date */
+
+	/* Miscellaneous parameters */
+	{ "timer_interval", "3600", 0 },	/* Timer interval in seconds */
+	{ "ntp_server", "192.5.41.40 192.5.41.41 133.100.9.2", 0 },		/* NTP server */
+	{ "time_zone", "PST8PDT", 0 },		/* Time zone (GNU TZ format) */
+	{ "log_level", "0", 0 },		/* Bitmask 0:off 1:denied 2:accepted */
+	{ "upnp_enable", "0", 0 },		/* Start UPnP */
+	{ "ezc_enable", "1", 0 },		/* Enable EZConfig updates */
+	{ "ezc_version", "1", 0 },		/* EZConfig version */
+	{ "is_default", "1", 0 },		/* is it default setting: 1:yes 0:no*/
+	{ "os_server", "", 0 },			/* URL for getting upgrades */
+	{ "stats_server", "", 0 },		/* URL for posting stats */
+	{ "console_loglevel", "1", 0 },		/* Kernel panics only */
+
+	/* Big switches */
+	{ "router_disable", "0", 0 },		/* lan_proto=static lan_stp=0 wan_proto=disabled */
+	{ "fw_disable", "0", 0 },		/* Disable firewall (allow new connections from the WAN) */
+
+	{ "log_ipaddr", "", 0 },		/* syslog recipient */
+	
+	/* LAN H/W parameters */
+	{ "lan_ifname", "", 0 },		/* LAN interface name */
+	{ "lan_ifnames", "", 0 },		/* Enslaved LAN interfaces */
+	{ "lan_hwnames", "", 0 },		/* LAN driver names (e.g. et0) */
+	{ "lan_hwaddr", "", 0 },		/* LAN interface MAC address */
+	
+	/* LAN TCP/IP parameters */
+	{ "lan_proto", "dhcp", 0 },		/* [static|dhcp] */
+	{ "lan_ipaddr", "192.168.1.1", 0 },	/* LAN IP address */
+	{ "lan_netmask", "255.255.255.0", 0 },	/* LAN netmask */
+	{ "lan_stp", "0", 0 },			/* LAN spanning tree protocol */
+	{ "lan_wins", "", 0 },			/* x.x.x.x x.x.x.x ... */
+	{ "lan_domain", "", 0 },		/* LAN domain name */
+	{ "lan_lease", "86400", 0 },		/* LAN lease time in seconds */
+
+	/* WAN H/W parameters */
+	{ "wan_ifname", "", 0 },		/* WAN interface name */
+	{ "wan_ifnames", "", 0 },		/* WAN interface names */
+	{ "wan_hwname", "", 0 },		/* WAN driver name (e.g. et1) */
+	{ "wan_hwaddr", "", 0 },		/* WAN interface MAC address */
+	
+	/* WAN TCP/IP parameters */
+	{ "wan_proto", "dhcp", 0 },		/* [static|dhcp|pppoe|disabled] */
+	{ "wan_ipaddr", "0.0.0.0", 0 },		/* WAN IP address */
+	{ "wan_netmask", "0.0.0.0", 0 },	/* WAN netmask */
+	{ "wan_gateway", "0.0.0.0", 0 },	/* WAN gateway */
+	{ "wan_dns", "", 0 },			/* x.x.x.x x.x.x.x ... */
+	{ "wan_wins", "", 0 },			/* x.x.x.x x.x.x.x ... */
+	{ "wan_hostname", "", 0 },		/* WAN hostname */
+	{ "wan_domain", "", 0 },		/* WAN domain name */
+	{ "wan_lease", "86400", 0 },		/* WAN lease time in seconds */
+	
+	/* PPPoE parameters */
+	{ "wan_pppoe_ifname", "", 0 },		/* PPPoE enslaved interface */
+	{ "wan_pppoe_username", "", 0 },	/* PPP username */
+	{ "wan_pppoe_passwd", "", 0 },		/* PPP password */
+	{ "wan_pppoe_idletime", "60", 0 },	/* Dial on demand max idle time (seconds) */
+	{ "wan_pppoe_keepalive", "0", 0 },	/* Restore link automatically */
+	{ "wan_pppoe_demand", "0", 0 },		/* Dial on demand */
+	{ "wan_pppoe_mru", "1492", 0 },		/* Negotiate MRU to this value */
+	{ "wan_pppoe_mtu", "1492", 0 },		/* Negotiate MTU to the smaller of this value or the peer MRU */
+	{ "wan_pppoe_service", "", 0 },		/* PPPoE service name */
+	{ "wan_pppoe_ac", "", 0 },		/* PPPoE access concentrator name */
+
+	/* Misc WAN parameters */
+	{ "wan_desc", "", 0 },			/* WAN connection description */
+	{ "wan_route", "", 0 },			/* Static routes (ipaddr:netmask:gateway:metric:ifname ...) */
+	{ "wan_primary", "0", 0 },		/* Primary wan connection */
+
+	{ "wan_unit", "0", 0 },			/* Last configured connection */
+	
+	/* Filters */
+	{ "filter_maclist", "", 0 },		/* xx:xx:xx:xx:xx:xx ... */
+	{ "filter_macmode", "deny", 0 },	/* "allow" only, "deny" only, or "disabled" (allow all) */
+	{ "filter_client0", "", 0 },		/* [lan_ipaddr0-lan_ipaddr1|*]:lan_port0-lan_port1,proto,enable,day_start-day_end,sec_start-sec_end,desc */
+
+	/* Port forwards */
+	{ "dmz_ipaddr", "", 0 },		/* x.x.x.x (equivalent to 0-60999>dmz_ipaddr:0-60999) */
+	{ "forward_port0", "", 0 },		/* wan_port0-wan_port1>lan_ipaddr:lan_port0-lan_port1[:,]proto[:,]enable[:,]desc */
+	{ "autofw_port0", "", 0 },		/* out_proto:out_port,in_proto:in_port0-in_port1>to_port0-to_port1,enable,desc */
+
+	/* DHCP server parameters */
+	{ "dhcp_start", "192.168.1.100", 0 },	/* First assignable DHCP address */
+	{ "dhcp_end", "192.168.1.150", 0 },	/* Last assignable DHCP address */
+	{ "dhcp_domain", "wan", 0 },		/* Use WAN domain name first if available (wan|lan) */
+	{ "dhcp_wins", "wan", 0 },		/* Use WAN WINS first if available (wan|lan) */
+
+	/* Web server parameters */
+	{ "http_username", "", 0 },		/* Username */
+	{ "http_passwd", "admin", 0 },		/* Password */
+	{ "http_wanport", "", 0 },		/* WAN port to listen on */
+	{ "http_lanport", "80", 0 },		/* LAN port to listen on */
+
+	/* Wireless parameters */
+	{ "wl_ifname", "", 0 },			/* Interface name */
+	{ "wl_hwaddr", "", 0 },			/* MAC address */
+	{ "wl_phytype", "g", 0 },		/* Current wireless band ("a" (5 GHz), "b" (2.4 GHz), or "g" (2.4 GHz)) */
+	{ "wl_corerev", "", 0 },		/* Current core revision */
+	{ "wl_phytypes", "", 0 },		/* List of supported wireless bands (e.g. "ga") */
+	{ "wl_radioids", "", 0 },		/* List of radio IDs */
+	{ "wl_ssid", "OpenWrt", 0 },		/* Service set ID (network name) */
+	{ "wl_country", "", 0 },		/* Country (default obtained from driver) */
+	{ "wl_radio", "1", 0 },			/* Enable (1) or disable (0) radio */
+	{ "wl_closed", "0", 0 },		/* Closed (hidden) network */
+        { "wl_ap_isolate", "0", 0 },            /* AP isolate mode */
+	{ "wl_mode", "ap", 0 },			/* AP mode (ap|sta|wds) */
+	{ "wl_lazywds", "0", 0 },		/* Enable "lazy" WDS mode (0|1) */
+	{ "wl_wds", "", 0 },			/* xx:xx:xx:xx:xx:xx ... */
+	{ "wl_wep", "disabled", 0 },		/* WEP data encryption (enabled|disabled) */
+	{ "wl_auth", "0", 0 },			/* Shared key authentication optional (0) or required (1) */
+	{ "wl_key", "1", 0 },			/* Current WEP key */
+	{ "wl_key1", "", 0 },			/* 5/13 char ASCII or 10/26 char hex */
+	{ "wl_key2", "", 0 },			/* 5/13 char ASCII or 10/26 char hex */
+	{ "wl_key3", "", 0 },			/* 5/13 char ASCII or 10/26 char hex */
+	{ "wl_key4", "", 0 },			/* 5/13 char ASCII or 10/26 char hex */
+	{ "wl_maclist", "", 0 },		/* xx:xx:xx:xx:xx:xx ... */
+	{ "wl_macmode", "disabled", 0 },	/* "allow" only, "deny" only, or "disabled" (allow all) */
+	{ "wl_channel", "11", 0 },		/* Channel number */
+	{ "wl_rate", "0", 0 },			/* Rate (bps, 0 for auto) */
+	{ "wl_rateset", "default", 0 },		/* "default" or "all" or "12" */
+	{ "wl_frag", "2346", 0 },		/* Fragmentation threshold */
+	{ "wl_rts", "2347", 0 },		/* RTS threshold */
+	{ "wl_dtim", "1", 0 },			/* DTIM period */
+	{ "wl_bcn", "100", 0 },			/* Beacon interval */
+	{ "wl_plcphdr", "long", 0 },		/* 802.11b PLCP preamble type */
+	{ "wl_net_mode", "mixed", 0 },		/* 54g mode */
+	{ "wl_gmode", "6", 0 },			/* 54g mode */
+	{ "wl_gmode_protection", "auto", 0 },	/* 802.11g RTS/CTS protection (off|auto) */
+	{ "wl_afterburner", "auto", 0 },	/* AfterBurner */
+	{ "wl_frameburst", "off", 0 },		/* BRCM Frambursting mode (off|on) */
+	{ "wl_antdiv", "-1", 0 },		/* Antenna Diversity (-1|0|1|3) */
+	{ "wl_infra", "1", 0 },			/* Network Type (BSS/IBSS) */
+
+	/* WPA parameters */
+	{ "security_mode", "open", 0 },
+	{ "wl_auth_mode", "open", 0 },		/* Network authentication mode (open|shared|radius|wpa|psk) */
+	{ "wl_wpa_psk", "", 0 },		/* WPA pre-shared key */
+	{ "wl_wpa_gtk_rekey", "3600", 0 },	/* GTK rotation interval */
+	{ "wl_radius_ipaddr", "", 0 },		/* RADIUS server IP address */
+	{ "wl_radius_key", "", 0 },		/* RADIUS shared secret */
+	{ "wl_radius_port", "1812", 0 },	/* RADIUS server UDP port */
+	{ "wl_crypto", "tkip", 0 },		/* WPA data encryption */
+
+
+	{ "wl_unit", "0", 0 },			/* Last configured interface */
+		
+	/* Restore defaults */
+	{ "restore_defaults", "0", 0 },		/* Set to 0 to not restore defaults on boot */
+
+	{ 0, 0, 0 }
+};
diff --git a/package/nvram/src/linux_timer.c b/package/nvram/src/linux_timer.c
new file mode 100644
index 000000000..0402e4437
--- /dev/null
+++ b/package/nvram/src/linux_timer.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * Low resolution timer interface linux specific implementation.
+ *
+ * $Id$
+ */
+
+/*
+* debug facilities
+*/
+#define TIMER_DEBUG	0
+#if TIMER_DEBUG
+#define TIMERDBG(fmt, args...) printf("%s: " fmt "\n" , __FUNCTION__ , ## args)
+#else
+#define TIMERDBG(fmt, args...)
+#endif
+
+
+/*
+ * POSIX timer support for Linux. Taken from linux_timer.c in upnp
+ */
+
+#define __USE_GNU
+
+
+#include <stdlib.h>	    // for malloc, free, etc.
+#include <string.h>	    // for memset, strncasecmp, etc.
+#include <assert.h>	    // for assert, of course.
+#include <signal.h>	    // for sigemptyset, etc.
+#include <stdio.h>	    // for printf, etc.
+#include <sys/time.h>
+#include <time.h>
+
+/* define TIMER_PROFILE to enable code which guages how accurate the timer functions are.
+   For each expiring timer the code will print the expected time interval and the actual time interval.
+#define TIMER_PROFILE
+*/
+#undef TIMER_PROFILE
+
+/*
+timer_cancel( ) - cancel a timer
+timer_connect( ) - connect a user routine to the timer signal
+timer_create( ) - allocate a timer using the specified clock for a timing base (POSIX)
+timer_delete( ) - remove a previously created timer (POSIX)
+timer_gettime( ) - get the remaining time before expiration and the reload value (POSIX)
+timer_getoverrun( ) - return the timer expiration overrun (POSIX)
+timer_settime( ) - set the time until the next expiration and arm timer (POSIX)
+nanosleep( ) - suspend the current task until the time interval elapses (POSIX)
+*/
+
+#define MS_PER_SEC 1000
+#define US_PER_SEC 1000000
+#define US_PER_MS  1000
+#define UCLOCKS_PER_SEC 1000000
+
+typedef void (*event_callback_t)(timer_t, int);
+
+#ifndef TIMESPEC_TO_TIMEVAL
+# define TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
+        (tv)->tv_sec = (ts)->tv_sec;                                    \
+        (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
+}
+#endif
+
+#ifndef TIMEVAL_TO_TIMESPEC
+# define TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
+        (ts)->tv_sec = (tv)->tv_sec;                                    \
+        (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
+}
+#endif
+
+#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
+
+#define timerroundup(t,g) \
+    do { \
+	if (!timerisset(t)) (t)->tv_usec=1; \
+	if ((t)->tv_sec == 0) (t)->tv_usec=ROUNDUP((t)->tv_usec, g); \
+    } while (0)
+
+typedef long uclock_t;
+
+#define TFLAG_NONE	0
+#define TFLAG_CANCELLED	(1<<0)
+#define TFLAG_DELETED	(1<<1)
+
+struct event {
+    struct timeval it_interval;
+    struct timeval it_value;
+    event_callback_t func;
+    int arg;
+    unsigned short flags;
+    struct event *next;
+#ifdef TIMER_PROFILE
+    uint expected_ms;
+    uclock_t start;
+#endif
+};
+
+void timer_cancel(timer_t timerid);
+
+static void alarm_handler(int i);
+static void check_event_queue();
+static void print_event_queue();
+static void check_timer();
+#if THIS_FINDS_USE
+static int count_queue(struct event *);
+#endif
+static int timer_change_settime(timer_t timer_id, const struct itimerspec *timer_spec);
+void block_timer();
+void unblock_timer();
+
+static struct event *event_queue = NULL;
+static struct event *event_freelist;
+static uint g_granularity;
+static int g_maxevents = 0;
+
+uclock_t uclock()
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return ((tv.tv_sec * US_PER_SEC) + tv.tv_usec);
+}
+
+
+void init_event_queue(int n)
+{
+    int i;
+    struct itimerval tv;
+    
+    g_maxevents = n;
+    event_freelist = (struct event *) malloc(n * sizeof(struct event));
+    memset(event_freelist, 0, n * sizeof(struct event));
+
+    for (i = 0; i < (n-1); i++) 
+	event_freelist[i].next = &event_freelist[i+1];
+
+    event_freelist[i].next = NULL;
+
+    tv.it_interval.tv_sec = 0;
+    tv.it_interval.tv_usec = 1;
+    tv.it_value.tv_sec = 0;
+    tv.it_value.tv_usec = 0;
+    setitimer (ITIMER_REAL, &tv, 0);
+    setitimer (ITIMER_REAL, 0, &tv);
+    g_granularity = tv.it_interval.tv_usec;
+
+    signal(SIGALRM, alarm_handler);
+}
+
+
+int clock_gettime(
+    clockid_t         clock_id, /* clock ID (always CLOCK_REALTIME) */
+    struct timespec * tp        /* where to store current time */
+)
+{
+    struct timeval tv;
+    int n;
+
+
+    n = gettimeofday(&tv, NULL);
+    TIMEVAL_TO_TIMESPEC(&tv, tp);
+    
+    return n;
+}
+
+
+int timer_create(
+    clockid_t         clock_id, /* clock ID (always CLOCK_REALTIME) */
+    struct sigevent * evp,      /* user event handler */
+    timer_t *         pTimer    /* ptr to return value */
+)
+{
+    struct event *event;
+
+    if (clock_id != CLOCK_REALTIME) {
+	TIMERDBG("timer_create can only support clock id CLOCK_REALTIME");
+	exit(1);
+    }
+
+    if (evp != NULL) {
+	if (evp->sigev_notify != SIGEV_SIGNAL || evp->sigev_signo != SIGALRM) {
+	    TIMERDBG("timer_create can only support signalled alarms using SIGALRM");
+	    exit(1);
+	}
+    }
+
+    event = event_freelist;
+    if (event == NULL) {
+	print_event_queue();
+    }
+    assert(event != NULL);
+
+    event->flags = TFLAG_NONE;
+    
+    event_freelist = event->next;
+    event->next = NULL;
+
+    check_event_queue();
+
+    *pTimer = (timer_t) event;
+
+    return 0;
+}
+
+int timer_delete(
+    timer_t timerid /* timer ID */
+)
+{
+    struct event *event = (struct event *) timerid;
+    
+    if (event->flags & TFLAG_DELETED) {
+	TIMERDBG("Cannot delete a deleted event");
+	return 1;
+    }
+
+    timer_cancel(timerid);
+    
+    event->flags |= TFLAG_DELETED;
+
+    event->next = event_freelist;
+    event_freelist = event;
+
+    return 0;
+}
+
+int timer_connect
+(
+    timer_t     timerid, /* timer ID */
+    void (*routine)(timer_t, int), /* user routine */
+    int         arg      /* user argument */
+)
+{
+    struct event *event = (struct event *) timerid;
+
+    assert(routine != NULL);
+    event->func = routine;
+    event->arg = arg;
+    
+    return 0;
+}    
+
+/* 
+ * Please Call this function only from the call back functions of the alarm_handler.
+ * This is just a hack 
+*/
+int timer_change_settime
+(
+    timer_t                   timerid, /* timer ID */
+    const struct itimerspec * value   /* time to be set */
+)
+{
+    struct event *event = (struct event *) timerid;
+
+    TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
+    TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
+
+    return 1; 	
+}
+
+int timer_settime
+(
+    timer_t                   timerid, /* timer ID */
+    int                       flags,   /* absolute or relative */
+    const struct itimerspec * value,   /* time to be set */
+    struct itimerspec *       ovalue   /* previous time set (NULL=no result) */
+)
+{
+    struct itimerval itimer;
+    struct event *event = (struct event *) timerid;
+    struct event **ppevent;
+
+    TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
+    TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
+
+    /* if .it_value is zero, the timer is disarmed */
+    if (!timerisset(&event->it_value)) {
+	timer_cancel(timerid);
+	return 0;
+    }
+
+    block_timer();
+
+#ifdef TIMER_PROFILE
+    event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) + (event->it_value.tv_usec / US_PER_MS);
+    event->start = uclock();
+#endif
+    if (event->next) {
+	TIMERDBG("calling timer_settime with a timer that is already on the queue.");
+    }
+
+
+    /* We always want to make sure that the event at the head of the
+       queue has a timeout greater than the itimer granularity.
+       Otherwise we end up with the situation that the time remaining
+       on an itimer is greater than the time at the head of the queue
+       in the first place. */
+    timerroundup(&event->it_value, g_granularity);
+
+    timerclear(&itimer.it_value);
+    getitimer(ITIMER_REAL, &itimer);
+    if (timerisset(&itimer.it_value)) {
+	// reset the top timer to have an interval equal to the remaining interval 
+	// when the timer was cancelled.
+	if (event_queue) {
+	    if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
+		// it is an error if the amount of time remaining is more than the amount of time 
+		// requested by the top event.
+		//
+		TIMERDBG("timer_settime: TIMER ERROR!");
+
+	    } else {
+		// some portion of the top event has already expired.
+		// Reset the interval of the top event to remaining
+		// time left in that interval.
+		//
+		event_queue->it_value = itimer.it_value;
+
+		// if we were the earliest timer before now, we are still the earliest timer now.
+		// we do not need to reorder the list.
+	    }
+	}
+    }
+
+    // Now, march down the list, decrementing the new timer by the
+    // current it_value of each event on the queue.
+    ppevent = &event_queue;
+    while (*ppevent) {
+	if ( timercmp(&(event->it_value), &((*ppevent)->it_value), <) ) {
+	    // if the proposed event will trigger sooner than the next event
+	    // in the queue, we will insert the new event just before the next one.
+	    //
+	    // we also need to adjust the delta value to the next event.
+	    timersub(&((*ppevent)->it_value), &(event->it_value), &((*ppevent)->it_value));
+	    break;
+	}
+	// subtract the interval of the next event from the proposed interval.
+	timersub(&(event->it_value), &((*ppevent)->it_value), &(event->it_value));
+
+	ppevent = &((*ppevent)->next);
+    }
+    
+    // we have found our proper place in the queue, 
+    // link our new event into the pending event queue.
+    event->next = *ppevent;
+    *ppevent = event;
+
+    check_event_queue();
+
+    // if our new event ended up at the front of the queue, reissue the timer.
+    if (event == event_queue) {
+	timerroundup(&event_queue->it_value, g_granularity);
+	timerclear(&itimer.it_interval);
+	itimer.it_value = event_queue->it_value;
+	
+	// we want to be sure to never turn off the timer completely, 
+	// so if the next interval is zero, set it to some small value.
+	if (!timerisset(&(itimer.it_value)))
+	    itimer.it_value = (struct timeval) { 0, 1 };
+	
+	assert(!timerisset(&itimer.it_interval));
+	assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >= g_granularity);
+	assert(event_queue->it_value.tv_sec > 0 || event_queue->it_value.tv_usec >= g_granularity);
+	setitimer(ITIMER_REAL, &itimer, NULL);
+	check_timer();
+    }
+
+    event->flags &= ~TFLAG_CANCELLED;
+    
+    unblock_timer();
+
+    return 0;
+}
+
+static void check_timer()
+{
+    struct itimerval itimer;
+    
+    getitimer(ITIMER_REAL, &itimer);
+    if (timerisset(&itimer.it_interval)) {
+	TIMERDBG("ERROR timer interval is set.");
+    }
+    if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
+	TIMERDBG("ERROR timer expires later than top event.");
+    }
+}
+
+
+static void check_event_queue()
+{
+    struct timeval sum;
+    struct event *event;
+    int i = 0;
+
+#ifdef notdef
+    int nfree = 0;
+    struct event *p;
+    for (p = event_freelist; p; p = p->next)
+	nfree++;
+    printf("%d free events\n", nfree);
+#endif
+    
+    timerclear(&sum);
+    for (event = event_queue; event; event = event->next) {
+	if (i > g_maxevents) {
+	    TIMERDBG("timer queue looks like it loops back on itself!");
+	    print_event_queue();
+	    exit(1);
+	}
+	i++;
+    }
+}
+
+#if THIS_FINDS_USE
+/* The original upnp version has this unused function, so I left it in
+   to maintain the resemblance. */
+static int count_queue(struct event *event_queue)
+{
+    struct event *event;
+    int i = 0;
+    for (event = event_queue; event; event = event->next) 
+	i++;
+    return i;
+}
+#endif
+
+static void print_event_queue()
+{
+    struct event *event;
+    int i = 0;
+
+    for (event = event_queue; event; event = event->next) {
+	printf("#%d (0x%x)->0x%x: \t%d sec %d usec\t%p\n", 
+	       i++, (unsigned int) event, (unsigned int) event->next, (int) event->it_value.tv_sec, (int) event->it_value.tv_usec, event->func);
+	if (i > g_maxevents) {
+	    printf("...(giving up)\n");
+	    break;
+	}
+    }
+}
+
+// The top element of the event queue must have expired.
+// Remove that element, run its function, and reset the timer.
+// if there is no interval, recycle the event structure.
+static void alarm_handler(int i)
+{
+    struct event *event, **ppevent;
+    struct itimerval itimer;
+    struct timeval small_interval = { 0, g_granularity/2 };
+#ifdef TIMER_PROFILE
+    uint junk;
+    uclock_t end;
+    uint actual;
+#endif
+
+    block_timer();
+
+    // Loop through the event queue and remove the first event plus any 
+    // subsequent events that will expire very soon thereafter (within 'small_interval'}.
+    //
+    do {
+	// remove the top event.
+	event = event_queue;
+	event_queue = event_queue->next;
+	event->next = NULL;
+
+#ifdef TIMER_PROFILE
+	end = uclock();
+	actual = ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000));
+	if (actual < 0)
+	    junk = end;
+	TIMERDBG("expected %d ms  actual %d ms", event->expected_ms, ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000)));
+#endif
+	
+	    // call the event callback function
+	    (*(event->func))((timer_t) event, (int)event->arg);
+
+	/* If the event has been cancelled, do NOT put it back on the queue. */
+	if ( !(event->flags & TFLAG_CANCELLED) ) {
+
+	    // if the event is a recurring event, reset the timer and
+	    // find its correct place in the sorted list of events.
+	    //
+	    if (timerisset(&event->it_interval)) {
+		// event is recurring...
+		//
+		event->it_value = event->it_interval;
+#ifdef TIMER_PROFILE
+		event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) + (event->it_value.tv_usec / US_PER_MS);
+		event->start = uclock();
+#endif
+		timerroundup(&event->it_value, g_granularity);
+
+		// Now, march down the list, decrementing the new timer by the
+		// current delta of each event on the queue.
+		ppevent = &event_queue;
+		while (*ppevent) {
+		    if ( timercmp(&(event->it_value), &((*ppevent)->it_value), <) ) {
+			// if the proposed event will trigger sooner than the next event
+			// in the queue, we will insert the new event just before the next one.
+			//
+			// we also need to adjust the delta value to the next event.
+			timersub(&((*ppevent)->it_value), &(event->it_value), &((*ppevent)->it_value));
+			break;
+		    }
+		    timersub(&(event->it_value), &((*ppevent)->it_value), &(event->it_value));
+		    ppevent = &((*ppevent)->next);
+		}
+
+		// we have found our proper place in the queue, 
+		// link our new event into the pending event queue.
+		event->next = *ppevent;
+		*ppevent = event;
+	    } else {
+		// there is no interval, so recycle the event structure.
+		//timer_delete((timer_t) event);
+	    }
+	}
+
+	check_event_queue();
+	
+    } while (event_queue && timercmp(&event_queue->it_value, &small_interval, <));
+    
+    // re-issue the timer...
+    if (event_queue) {
+	timerroundup(&event_queue->it_value, g_granularity);
+
+	timerclear(&itimer.it_interval);
+	itimer.it_value = event_queue->it_value;
+	// we want to be sure to never turn off the timer completely, 
+	// so if the next interval is zero, set it to some small value.
+	if (!timerisset(&(itimer.it_value)))
+	    itimer.it_value = (struct timeval) { 0, 1 };
+
+	setitimer(ITIMER_REAL, &itimer, NULL);
+	check_timer();
+    } else {
+	TIMERDBG("There are no events in the queue - timer not reset.");
+    }
+
+    unblock_timer();
+}
+
+static int block_count = 0;
+
+void block_timer()
+{
+    sigset_t set;
+
+    if (block_count++ == 0) {
+	sigemptyset(&set);
+	sigaddset(&set, SIGALRM);
+	sigprocmask(SIG_BLOCK, &set, NULL);
+    }
+}
+
+void unblock_timer()
+{
+    sigset_t set;
+
+    if (--block_count == 0) {
+	sigemptyset(&set);
+	sigaddset(&set, SIGALRM);
+	sigprocmask(SIG_UNBLOCK, &set, NULL);
+    }
+}
+
+void timer_cancel_all()
+{
+    struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
+    struct event *event;
+    struct event **ppevent;
+
+    setitimer(ITIMER_REAL, &timeroff, NULL);
+
+    ppevent = &event_queue;
+    while (*ppevent) {
+	event = *ppevent;
+	*ppevent = event->next;
+	event->next = NULL;
+    }
+}
+
+
+
+void timer_cancel(timer_t timerid)
+{
+    struct itimerval itimer;
+    struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
+    struct event *event = (struct event *) timerid;
+    struct event **ppevent;
+
+    if (event->flags & TFLAG_CANCELLED) {
+	TIMERDBG("Cannot cancel a cancelled event");
+    	return;
+    }
+
+    block_timer();
+    
+    ppevent = &event_queue;
+    while (*ppevent) {
+	if ( *ppevent == event ) {
+
+	    /* RACE CONDITION - if the alarm goes off while we are in
+	       this loop, and if the timer we want to cancel is the
+	       next to expire, the alarm will end up firing
+	       after this routine is complete, causing it to go off early. */
+
+	    /* If the cancelled timer is the next to expire, 
+	       we need to do something special to clean up correctly. */
+	    if (event == event_queue && event->next != NULL) {
+		timerclear(&itimer.it_value);
+		getitimer(ITIMER_REAL, &itimer);
+		
+		/* subtract the time that has already passed while waiting for this timer... */
+		timersub(&(event->it_value), &(itimer.it_value), &(event->it_value));
+
+		/* and add any remainder to the next timer in the list */
+		timeradd(&(event->next->it_value), &(event->it_value), &(event->next->it_value));
+	    }
+
+	    *ppevent = event->next;
+	    event->next = NULL;
+
+	    if (event_queue) {
+		timerroundup(&event_queue->it_value, g_granularity);
+		timerclear(&itimer.it_interval);
+		itimer.it_value = event_queue->it_value;
+		
+		/* We want to be sure to never turn off the timer
+		   completely if there are more events on the queue,
+		   so if the next interval is zero, set it to some
+		   small value.  */
+
+		if (!timerisset(&(itimer.it_value)))
+		    itimer.it_value = (struct timeval) { 0, 1 };
+		
+		assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >= g_granularity);
+		assert(event_queue->it_value.tv_sec > 0 || event_queue->it_value.tv_usec >= g_granularity);
+		setitimer(ITIMER_REAL, &itimer, NULL);
+		check_timer();
+	    } else {
+		setitimer(ITIMER_REAL, &timeroff, NULL);
+	    }
+	    break;
+	}
+	ppevent = &((*ppevent)->next);
+    }
+
+    event->flags |= TFLAG_CANCELLED;
+
+    unblock_timer();
+}
+
+/*
+* timer related headers
+*/
+#include "bcmtimer.h"
+
+/*
+* locally used global variables and constants
+*/
+
+/*
+* Initialize internal resources used in the timer module. It must be called
+* before any other timer function calls. The param 'timer_entries' is used
+* to pre-allocate fixed number of timer entries.
+*/
+int bcm_timer_module_init(int timer_entries, bcm_timer_module_id *module_id)
+{
+	init_event_queue(timer_entries);
+	*module_id = (bcm_timer_module_id)event_freelist;
+	return 0;
+}
+
+/*
+* Cleanup internal resources used by this timer module. It deletes all
+* pending timer entries from the backend timer system as well.
+*/
+int bcm_timer_module_cleanup(bcm_timer_module_id module_id)
+{
+	module_id = 0;
+	return 0;
+}
+
+/* Enable/Disable timer module */
+int bcm_timer_module_enable(bcm_timer_module_id module_id, int enable)
+{
+	if (enable)
+		unblock_timer();
+	else
+		block_timer();
+	return 0;
+}
+
+int bcm_timer_create(bcm_timer_module_id module_id, bcm_timer_id *timer_id)
+{
+	module_id = 0;
+	return timer_create(CLOCK_REALTIME, NULL, (timer_t *)timer_id);
+}
+
+int bcm_timer_delete(bcm_timer_id timer_id)
+{
+	return timer_delete((timer_t)timer_id);
+}
+
+int bcm_timer_gettime(bcm_timer_id timer_id, struct itimerspec *timer_spec)
+{
+	return -1;
+}
+
+int bcm_timer_settime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
+{
+	return timer_settime((timer_t)timer_id, 0, timer_spec, NULL);
+}
+
+int bcm_timer_connect(bcm_timer_id timer_id, bcm_timer_cb func, int data)
+{
+	return timer_connect((timer_t)timer_id, (void *)func, data);
+}
+
+int bcm_timer_cancel(bcm_timer_id timer_id)
+{
+	timer_cancel((timer_t)timer_id);
+	return 0;
+}
+int bcm_timer_change_expirytime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
+{
+	timer_change_settime((timer_t)timer_id, timer_spec);
+	return 1;
+}
diff --git a/package/nvram/src/main.c b/package/nvram/src/main.c
new file mode 100644
index 000000000..a64430f7b
--- /dev/null
+++ b/package/nvram/src/main.c
@@ -0,0 +1,78 @@
+/*
+ * Frontend command-line utility for Linux NVRAM layer
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <typedefs.h>
+#include <bcmnvram.h>
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: nvram [get name] [set name=value] [unset name] [show]\n");
+	exit(0);
+}
+
+/* NVRAM utility */
+int
+main(int argc, char **argv)
+{
+	char *name, *value, buf[NVRAM_SPACE];
+	int size;
+
+	/* Skip program name */
+	--argc;
+	++argv;
+
+	if (!*argv) 
+		usage();
+
+	/* Process the remaining arguments. */
+	for (; *argv; argv++) {
+		if (!strncmp(*argv, "get", 3)) {
+			if (*++argv) {
+				if ((value = nvram_get(*argv)))
+					puts(value);
+			}
+		}
+		else if (!strncmp(*argv, "set", 3)) {
+			if (*++argv) {
+				strncpy(value = buf, *argv, sizeof(buf));
+				name = strsep(&value, "=");
+				nvram_set(name, value);
+			}
+		}
+		else if (!strncmp(*argv, "unset", 5)) {
+			if (*++argv)
+				nvram_unset(*argv);
+		}
+		else if (!strncmp(*argv, "commit", 5)) {
+			nvram_commit();
+		}
+		else if (!strncmp(*argv, "show", 4) ||
+			   !strncmp(*argv, "getall", 6)) {
+			nvram_getall(buf, sizeof(buf));
+			for (name = buf; *name; name += strlen(name) + 1)
+				puts(name);
+			size = sizeof(struct nvram_header) + (int) name - (int) buf;
+			fprintf(stderr, "size: %d bytes (%d left)\n", size, NVRAM_SPACE - size);
+		}
+		if (!*argv)
+			break;
+	}
+
+	return 0;
+}	
diff --git a/package/nvram/src/nvram_convert.c b/package/nvram/src/nvram_convert.c
new file mode 100644
index 000000000..485909026
--- /dev/null
+++ b/package/nvram/src/nvram_convert.c
@@ -0,0 +1,77 @@
+
+#define WL(a)	"wl_"a	
+#define WL0(a)	"wl0_"a	
+#define D11G(a)	"d11g_"a
+
+#define PPP(a)		"ppp_"a
+#define PPPOE(a)	"pppoe_"a
+
+struct nvram_convert {
+        char *name;		// for WEB
+	char *wl0_name;		// for driver
+        char *d11g_name;	// for old nv name
+};
+
+struct nvram_convert nvram_converts[] = {
+	// Bellow change from 3.11.48.7
+	{ WL("ssid"),	 	WL0("ssid"),	""},
+	{ WL("radio"), 		WL0("mode"),	""},
+	{ WL("mode"), 		WL0("mode"),	""},
+	{ WL("wds"), 		WL0("wds"),	""},
+	{ WL("auth"), 		WL0("auth"),	""},
+	{ WL("key"), 		WL0("key"), 	""},
+	{ WL("key1"), 		WL0("key1"), 	""},
+	{ WL("key2"), 		WL0("key2"),	""},
+	{ WL("key3"), 		WL0("key3"),	""},
+	{ WL("key4"), 		WL0("key4"),	""},
+	{ WL("maclist"), 	WL0("maclist"),	""},
+	{ WL("channel"), 	WL0("channel"), D11G("channel")},
+	{ WL("rateset"), 	WL0("rateset"), D11G("rateset")},
+	{ WL("rts"), 		WL0("rts"), 	D11G("rts")},
+	{ WL("bcn"), 		WL0("bcn"),	D11G("bcn")},
+	{ WL("gmode"), 		WL0("gmode"), 	"d11g_mode"},
+	{ WL("unit"), 		WL0("unit"), 	""},
+	{ WL("ifname"), 	WL0("ifname"),	""},
+	{ WL("phytype"), 	WL0("phytype"),	""},
+	{ WL("country"), 	WL0("country"),	""},
+	{ WL("closed"), 	WL0("closed"),	""},
+	{ WL("lazywds"), 	WL0("lazywds"),	""},
+	{ WL("wep"), 		WL0("wep"),	""},
+	{ WL("macmode"), 	WL0("macmode"),	""},
+	{ WL("rate"), 		WL0("rate"), 	D11G("rate")},
+	{ WL("frag"), 		WL0("frag"),	D11G("frag")},
+	{ WL("dtim"), 		WL0("dtim"), 	D11G("dtim")},
+	{ WL("plcphdr"), 	WL0("plcphdr"),	""},
+	{ WL("gmode_protection"), 	WL0("gmode_protection"),	""},
+	{ WL("radio"), 		WL0("radio"),	""},
+	// Bellow change from 3.21.9.0
+	{ WL("auth_mode"), 	WL0("auth_mode"),	""},
+	{ WL("radius_ipaddr"), 	WL0("radius_ipaddr"),	""},
+	{ WL("radius_port"), 	WL0("radius_port"),	""},
+	{ WL("radius_key"), 	WL0("radius_key"),	""},
+	{ WL("wpa_psk"), 	WL0("wpa_psk"),		""},
+	{ WL("wpa_gtk_rekey"), 	WL0("wpa_gtk_rekey"),	""},
+	{ WL("frameburst"), 	WL0("frameburst"),	""},
+	{ WL("crypto"), 	WL0("crypto"),		""},
+	{ WL("ap_isolate"), 	WL0("ap_isolate"),	""},
+	{ WL("afterburner"), 	WL0("afterburner"),	""},
+	// for PPPoE
+	{ PPP("username"), 	PPPOE("username"),	""},
+	{ PPP("passwd"), 	PPPOE("passwd"),	""},
+	{ PPP("idletime"), 	PPPOE("idletime"),	""},
+	{ PPP("keepalive"), 	PPPOE("keepalive"),	""},
+	{ PPP("demand"), 	PPPOE("demand"),	""},
+	{ PPP("service"), 	PPPOE("service"),	""},
+	{ PPP("ac"), 		PPPOE("ac"),		""},
+	{ PPP("static"),	PPPOE("static"),	""},
+	{ PPP("static_ip"), 	PPPOE("static_ip"),	""},
+	{ PPP("username_1"), 	PPPOE("username_1"),	""},
+	{ PPP("passwd_1"), 	PPPOE("passwd_1"),	""},
+	{ PPP("idletime_1"), 	PPPOE("idletime_1"),	""},
+	{ PPP("keepalive_1"), 	PPPOE("keepalive_1"),	""},
+	{ PPP("demand_1"), 	PPPOE("demand_1"),	""},
+	{ PPP("service_1"), 	PPPOE("service_1"),	""},
+	{ PPP("ac_1"), 		PPPOE("ac_1"),		""},
+	
+	{ 0, 0, 0},
+};
diff --git a/package/nvram/src/nvram_convert.h b/package/nvram/src/nvram_convert.h
new file mode 100644
index 000000000..70e12327d
--- /dev/null
+++ b/package/nvram/src/nvram_convert.h
@@ -0,0 +1,7 @@
+
+struct nvram_convert {
+        char *name;
+	char *wl0_name;
+        char *d11g_name;
+};
+
diff --git a/package/nvram/src/nvram_linux.c b/package/nvram/src/nvram_linux.c
new file mode 100644
index 000000000..c41e32118
--- /dev/null
+++ b/package/nvram/src/nvram_linux.c
@@ -0,0 +1,320 @@
+/*
+ * NVRAM variable manipulation (Linux user mode half)
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <typedefs.h>
+#include <bcmnvram.h>
+#include <nvram_convert.h>
+#include <shutils.h>
+#include <utils.h>
+
+#define PATH_DEV_NVRAM "/dev/nvram"
+
+/* Globals */
+static int nvram_fd = -1;
+static char *nvram_buf = NULL;
+int check_action(void);
+int file_to_buf(char *path, char *buf, int len);
+
+int
+nvram_init(void *unused)
+{
+	if ((nvram_fd = open(PATH_DEV_NVRAM, O_RDWR)) < 0)
+		goto err;
+
+	/* Map kernel string buffer into user space */
+	if ((nvram_buf = mmap(NULL, NVRAM_SPACE, PROT_READ, MAP_SHARED, nvram_fd, 0)) == MAP_FAILED) {
+		close(nvram_fd);
+		nvram_fd = -1;
+		goto err;
+	}
+
+	return 0;
+
+ err:
+	perror(PATH_DEV_NVRAM);
+	return errno;
+}
+
+char *
+nvram_get(const char *name)
+{
+	size_t count = strlen(name) + 1;
+	char tmp[100], *value;
+	unsigned long *off = (unsigned long *) tmp;
+
+	if (nvram_fd < 0)
+		if (nvram_init(NULL))
+			return NULL;
+
+	if (count > sizeof(tmp)) {
+		if (!(off = malloc(count)))
+			return NULL;
+	}
+
+	/* Get offset into mmap() space */
+	strcpy((char *) off, name);
+
+	count = read(nvram_fd, off, count);
+
+	if (count == sizeof(unsigned long))
+		value = &nvram_buf[*off];
+	else
+		value = NULL;
+
+	if (count < 0)
+		perror(PATH_DEV_NVRAM);
+
+	if (off != (unsigned long *) tmp)
+		free(off);
+
+	return value;
+}
+
+int
+nvram_getall(char *buf, int count)
+{
+	int ret;
+
+	if (nvram_fd < 0)
+		if ((ret = nvram_init(NULL)))
+			return ret;
+
+	if (count == 0)
+		return 0;
+
+	/* Get all variables */
+	*buf = '\0';
+
+	ret = read(nvram_fd, buf, count);
+
+	if (ret < 0)
+		perror(PATH_DEV_NVRAM);
+
+	return (ret == count) ? 0 : ret;
+}
+
+static int
+_nvram_set(const char *name, const char *value)
+{
+	size_t count = strlen(name) + 1;
+	char tmp[100], *buf = tmp;
+	int ret;
+
+	if (nvram_fd < 0)
+		if ((ret = nvram_init(NULL)))
+			return ret;
+
+	/* Unset if value is NULL */
+	if (value)
+		count += strlen(value) + 1;
+
+	if (count > sizeof(tmp)) {
+		if (!(buf = malloc(count)))
+			return -ENOMEM;
+	}
+
+	if (value)
+		sprintf(buf, "%s=%s", name, value);
+	else
+		strcpy(buf, name);
+
+	ret = write(nvram_fd, buf, count);
+
+	if (ret < 0)
+		perror(PATH_DEV_NVRAM);
+
+	if (buf != tmp)
+		free(buf);
+
+	return (ret == count) ? 0 : ret;
+}
+
+int
+nvram_set(const char *name, const char *value)
+{
+	 extern struct nvram_convert nvram_converts[];
+         struct nvram_convert *v;
+         int ret;
+
+         ret = _nvram_set(name, value);
+
+         for(v = nvram_converts ; v->name ; v++) {
+                 if(!strcmp(v->name, name)){
+                         if(strcmp(v->wl0_name,""))      _nvram_set(v->wl0_name, value);
+                         if(strcmp(v->d11g_name,""))     _nvram_set(v->d11g_name, value);
+                 }
+         }
+
+         return ret;
+}
+
+int
+nvram_unset(const char *name)
+{
+	return _nvram_set(name, NULL);
+}
+
+int
+nvram_commit(void)
+{
+	int ret;
+	
+	cprintf("nvram_commit(): start\n");	
+	
+	if((check_action() == ACT_IDLE) || 
+	   (check_action() == ACT_SW_RESTORE) || 
+	   (check_action() == ACT_HW_RESTORE)){
+		if (nvram_fd < 0)
+			if ((ret = nvram_init(NULL)))
+				return ret;
+
+		ret = ioctl(nvram_fd, NVRAM_MAGIC, NULL);
+
+		if (ret < 0)
+			perror(PATH_DEV_NVRAM);
+	
+		cprintf("nvram_commit(): end\n");	
+	}
+	else
+		cprintf("nvram_commit():  nothing to do...\n");
+
+	return ret;
+}
+
+int file2nvram(char *filename, char *varname) {
+   FILE *fp;
+   int c,count;
+   int i=0,j=0;
+   char mem[10000],buf[30000];
+
+   if ( !(fp=fopen(filename,"rb") ))
+        return 0;
+
+   count=fread(mem,1,sizeof(mem),fp);
+   fclose(fp);
+   for (j=0;j<count;j++) {
+        if  (i > sizeof(buf)-3 )
+                break;
+        c=mem[j];
+        if (c >= 32 && c <= 126 && c != '\\' && c != '~')  {
+                buf[i++]=(unsigned char) c;
+        } else if (c==0) {
+		buf[i++]='~';
+        } else {
+                buf[i++]='\\';
+                sprintf(buf+i,"%02X",c);
+                i+=2;
+        }
+   }
+   if (i==0) return 0;
+   buf[i]=0;
+   //fprintf(stderr,"================ > file2nvram %s = [%s] \n",varname,buf); 
+   nvram_set(varname,buf);
+   //nvram_commit(); //Barry adds for test
+}
+
+int nvram2file(char *varname, char *filename) {
+   FILE *fp;
+   int c,tmp;
+   int i=0,j=0;
+   char *buf;
+   char mem[10000];
+   
+   if ( !(fp=fopen(filename,"wb") ))
+        return 0;
+        
+   buf=strdup(nvram_safe_get(varname));
+   //fprintf(stderr,"=================> nvram2file %s = [%s] \n",varname,buf);
+   while (  buf[i] && j < sizeof(mem)-3 ) {
+        if (buf[i] == '\\')  {
+                i++;
+                tmp=buf[i+2];
+                buf[i+2]=0;
+                sscanf(buf+i,"%02X",&c);
+                buf[i+2]=tmp;
+                i+=2;
+                mem[j]=c;j++;
+        } else if (buf[i] == '~') {
+		mem[j]=0;j++;
+		i++;
+        } else {
+                mem[j]=buf[i];j++;
+                i++;
+        }       
+   }
+   if (j<=0) return j;
+   j=fwrite(mem,1,j,fp);
+   fclose(fp);
+   free(buf);
+   return j;
+}  
+
+int
+check_action(void)
+{
+	char buf[80] = "";
+	
+	if(file_to_buf(ACTION_FILE, buf, sizeof(buf))){
+		if(!strcmp(buf, "ACT_TFTP_UPGRADE")){
+			cprintf("Upgrading from tftp now, quiet exit....\n");
+			return ACT_TFTP_UPGRADE;
+		}
+		else if(!strcmp(buf, "ACT_WEBS_UPGRADE")){
+			cprintf("Upgrading from web (https) now, quiet exit....\n");
+			return ACT_WEBS_UPGRADE;
+		}
+		else if(!strcmp(buf, "ACT_WEB_UPGRADE")){
+			cprintf("Upgrading from web (http) now, quiet exit....\n");
+			return ACT_WEB_UPGRADE;
+		}
+		else if(!strcmp(buf, "ACT_SW_RESTORE")){
+			cprintf("Receive restore command from web, quiet exit....\n");
+			return ACT_SW_RESTORE;
+		}
+		else if(!strcmp(buf, "ACT_HW_RESTORE")){
+			cprintf("Receive restore commond from resetbutton, quiet exit....\n");
+			return ACT_HW_RESTORE;
+		}
+	}
+	//fprintf(stderr, "Waiting for upgrading....\n");
+	return ACT_IDLE;
+}
+
+int
+file_to_buf(char *path, char *buf, int len)
+{
+	FILE *fp;
+
+	memset(buf, 0 , len);
+
+	if ((fp = fopen(path, "r"))) {
+		fgets(buf, len, fp);
+		fclose(fp);
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/package/nvram/src/shutils.c b/package/nvram/src/shutils.c
new file mode 100644
index 000000000..49ad41af8
--- /dev/null
+++ b/package/nvram/src/shutils.c
@@ -0,0 +1,329 @@
+/*
+ * Shell-like utility functions
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/ethernet.h>
+
+#include <shutils.h>
+
+/*
+ * Reads file and returns contents
+ * @param	fd	file descriptor
+ * @return	contents of file or NULL if an error occurred
+ */
+char *
+fd2str(int fd)
+{
+	char *buf = NULL;
+	size_t count = 0, n;
+
+	do {
+		buf = realloc(buf, count + 512);
+		n = read(fd, buf + count, 512);
+		if (n < 0) {
+			free(buf);
+			buf = NULL;
+		}
+		count += n;
+	} while (n == 512);
+
+	close(fd);
+	if (buf)
+		buf[count] = '\0';
+	return buf;
+}
+
+/*
+ * Reads file and returns contents
+ * @param	path	path to file
+ * @return	contents of file or NULL if an error occurred
+ */
+char *
+file2str(const char *path)
+{
+	int fd;
+
+	if ((fd = open(path, O_RDONLY)) == -1) {
+		perror(path);
+		return NULL;
+	}
+
+	return fd2str(fd);
+}
+
+/* 
+ * Waits for a file descriptor to change status or unblocked signal
+ * @param	fd	file descriptor
+ * @param	timeout	seconds to wait before timing out or 0 for no timeout
+ * @return	1 if descriptor changed status or 0 if timed out or -1 on error
+ */
+int
+waitfor(int fd, int timeout)
+{
+	fd_set rfds;
+	struct timeval tv = { timeout, 0 };
+
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+	return select(fd + 1, &rfds, NULL, NULL, (timeout > 0) ? &tv : NULL);
+}
+
+/* 
+ * Concatenates NULL-terminated list of arguments into a single
+ * commmand and executes it
+ * @param	argv	argument list
+ * @param	path	NULL, ">output", or ">>output"
+ * @param	timeout	seconds to wait before timing out or 0 for no timeout
+ * @param	ppid	NULL to wait for child termination or pointer to pid
+ * @return	return value of executed command or errno
+ */
+int
+_eval(char *const argv[], char *path, int timeout, int *ppid)
+{
+	pid_t pid;
+	int status;
+	int fd;
+	int flags;
+	int sig;
+	char buf[254]="";
+	int i;
+
+	switch (pid = fork()) {
+	case -1:	/* error */
+		perror("fork");
+		return errno;
+	case 0:		/* child */
+		/* Reset signal handlers set for parent process */
+		for (sig = 0; sig < (_NSIG-1); sig++)
+			signal(sig, SIG_DFL);
+
+		/* Clean up */
+		ioctl(0, TIOCNOTTY, 0);
+		close(STDIN_FILENO);
+		close(STDOUT_FILENO);
+		close(STDERR_FILENO);
+		setsid();
+
+		/* We want to check the board if exist UART? , add by honor 2003-12-04 */
+		if ((fd = open("/dev/console", O_RDWR)) < 0) {
+                        (void) open("/dev/null", O_RDONLY);
+                        (void) open("/dev/null", O_WRONLY);
+                        (void) open("/dev/null", O_WRONLY);
+		}
+		else{
+			close(fd);
+                        (void) open("/dev/console", O_RDONLY);
+                        (void) open("/dev/console", O_WRONLY);
+                        (void) open("/dev/console", O_WRONLY);
+		}
+
+		/* Redirect stdout to <path> */
+		if (path) {
+			flags = O_WRONLY | O_CREAT;
+			if (!strncmp(path, ">>", 2)) {
+				/* append to <path> */
+				flags |= O_APPEND;
+				path += 2;
+			} else if (!strncmp(path, ">", 1)) {
+				/* overwrite <path> */
+				flags |= O_TRUNC;
+				path += 1;
+			}
+			if ((fd = open(path, flags, 0644)) < 0)
+				perror(path);
+			else {
+				dup2(fd, STDOUT_FILENO);
+				close(fd);
+			}
+		}
+
+		/* execute command */
+		for(i=0 ; argv[i] ; i++)
+			snprintf(buf+strlen(buf), sizeof(buf), "%s ", argv[i]);
+		dprintf("cmd=[%s]\n", buf);
+		setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
+		alarm(timeout);
+		execvp(argv[0], argv);
+		perror(argv[0]);
+		exit(errno);
+	default:	/* parent */
+		if (ppid) {
+			*ppid = pid;
+			return 0;
+		} else {
+			waitpid(pid, &status, 0);
+			if (WIFEXITED(status))
+				return WEXITSTATUS(status);
+			else
+				return status;
+		}
+	}
+}
+
+/* 
+ * Concatenates NULL-terminated list of arguments into a single
+ * commmand and executes it
+ * @param	argv	argument list
+ * @return	stdout of executed command or NULL if an error occurred
+ */
+char *
+_backtick(char *const argv[])
+{
+	int filedes[2];
+	pid_t pid;
+	int status;
+	char *buf = NULL;
+
+	/* create pipe */
+	if (pipe(filedes) == -1) {
+		perror(argv[0]);
+		return NULL;
+	}
+
+	switch (pid = fork()) {
+	case -1:	/* error */
+		return NULL;
+	case 0:		/* child */
+		close(filedes[0]);	/* close read end of pipe */
+		dup2(filedes[1], 1);	/* redirect stdout to write end of pipe */
+		close(filedes[1]);	/* close write end of pipe */
+		execvp(argv[0], argv);
+		exit(errno);
+		break;
+	default:	/* parent */
+		close(filedes[1]);	/* close write end of pipe */
+		buf = fd2str(filedes[0]);
+		waitpid(pid, &status, 0);
+		break;
+	}
+	
+	return buf;
+}
+
+/* 
+ * Kills process whose PID is stored in plaintext in pidfile
+ * @param	pidfile	PID file
+ * @return	0 on success and errno on failure
+ */
+int
+kill_pidfile(char *pidfile)
+{
+	FILE *fp = fopen(pidfile, "r");
+	char buf[256];
+
+	if (fp && fgets(buf, sizeof(buf), fp)) {
+		pid_t pid = strtoul(buf, NULL, 0);
+		fclose(fp);
+		return kill(pid, SIGTERM);
+  	} else
+		return errno;
+}
+
+/*
+ * fread() with automatic retry on syscall interrupt
+ * @param	ptr	location to store to
+ * @param	size	size of each element of data
+ * @param	nmemb	number of elements
+ * @param	stream	file stream
+ * @return	number of items successfully read
+ */
+int
+safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+	size_t ret = 0;
+
+	do {
+		clearerr(stream);
+		ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
+	} while (ret < nmemb && ferror(stream) && errno == EINTR);
+
+	return ret;
+}
+
+/*
+ * fwrite() with automatic retry on syscall interrupt
+ * @param	ptr	location to read from
+ * @param	size	size of each element of data
+ * @param	nmemb	number of elements
+ * @param	stream	file stream
+ * @return	number of items successfully written
+ */
+int
+safe_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+	size_t ret = 0;
+
+	do {
+		clearerr(stream);
+		ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
+	} while (ret < nmemb && ferror(stream) && errno == EINTR);
+
+	return ret;
+}
+
+/*
+ * Convert Ethernet address string representation to binary data
+ * @param	a	string in xx:xx:xx:xx:xx:xx notation
+ * @param	e	binary data
+ * @return	TRUE if conversion was successful and FALSE otherwise
+ */
+int
+ether_atoe(const char *a, unsigned char *e)
+{
+	char *c = (char *) a;
+	int i = 0;
+
+	memset(e, 0, ETHER_ADDR_LEN);
+	for (;;) {
+		e[i++] = (unsigned char) strtoul(c, &c, 16);
+		if (!*c++ || i == ETHER_ADDR_LEN)
+			break;
+	}
+	return (i == ETHER_ADDR_LEN);
+}
+
+/*
+ * Convert Ethernet address binary data to string representation
+ * @param	e	binary data
+ * @param	a	string in xx:xx:xx:xx:xx:xx notation
+ * @return	a
+ */
+char *
+ether_etoa(const unsigned char *e, char *a)
+{
+	char *c = a;
+	int i;
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
+		if (i)
+			*c++ = ':';
+		c += sprintf(c, "%02X", e[i] & 0xff);
+	}
+	return a;
+}
diff --git a/package/nvram/src/wl.c b/package/nvram/src/wl.c
new file mode 100644
index 000000000..f09317ad0
--- /dev/null
+++ b/package/nvram/src/wl.c
@@ -0,0 +1,86 @@
+/*
+ * Wireless network adapter utilities
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+#include <string.h>
+
+#include <typedefs.h>
+#include <wlutils.h>
+
+int
+wl_probe(char *name)
+{
+	int ret, val;
+
+	/* Check interface */
+	if ((ret = wl_ioctl(name, WLC_GET_MAGIC, &val, sizeof(val))))
+		return ret;
+	if (val != WLC_IOCTL_MAGIC)
+		return -1;
+	if ((ret = wl_ioctl(name, WLC_GET_VERSION, &val, sizeof(val))))
+		return ret;
+	if (val > WLC_IOCTL_VERSION)
+		return -1;
+
+	return ret;
+}
+
+int
+wl_set_val(char *name, char *var, void *val, int len)
+{
+	char buf[128];
+	int buf_len;
+
+	/* check for overflow */
+	if ((buf_len = strlen(var)) + 1 + len > sizeof(buf))
+		return -1;
+	
+	strcpy(buf, var);
+	buf_len += 1;
+
+	/* append int value onto the end of the name string */
+	memcpy(&buf[buf_len], val, len);
+	buf_len += len;
+
+	return wl_ioctl(name, WLC_SET_VAR, buf, buf_len);
+}
+
+int
+wl_get_val(char *name, char *var, void *val, int len)
+{
+	char buf[128];
+	int ret;
+
+	/* check for overflow */
+	if (strlen(var) + 1 > sizeof(buf) || len > sizeof(buf))
+		return -1;
+	
+	strcpy(buf, var);
+	if ((ret = wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))))
+		return ret;
+
+	memcpy(val, buf, len);
+	return 0;
+}
+
+int
+wl_set_int(char *name, char *var, int val)
+{
+	return wl_set_val(name, var, &val, sizeof(val));
+}
+
+int
+wl_get_int(char *name, char *var, int *val)
+{
+	return wl_get_val(name, var, val, sizeof(*val));
+}
+
diff --git a/package/nvram/src/wl_linux.c b/package/nvram/src/wl_linux.c
new file mode 100644
index 000000000..126a40b4b
--- /dev/null
+++ b/package/nvram/src/wl_linux.c
@@ -0,0 +1,77 @@
+/*
+ * Wireless network adapter utilities (linux-specific)
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include <typedefs.h>
+#include <wlioctl.h>
+#include <wlutils.h>
+
+int
+wl_ioctl(char *name, int cmd, void *buf, int len)
+{
+	struct ifreq ifr;
+	wl_ioctl_t ioc;
+	int ret = 0;
+ 	int s;
+
+	/* open socket to kernel */
+	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		perror("socket");
+		return errno;
+	}
+
+	/* do it */
+	ioc.cmd = cmd;
+	ioc.buf = buf;
+	ioc.len = len;
+	strncpy(ifr.ifr_name, name, IFNAMSIZ);
+	ifr.ifr_data = (caddr_t) &ioc;
+	if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0)
+		if (cmd != WLC_GET_MAGIC)
+			perror(ifr.ifr_name);
+
+	/* cleanup */
+	close(s);
+	return ret;
+}
+
+int
+wl_hwaddr(char *name, unsigned char *hwaddr)
+{
+	struct ifreq ifr;
+	int ret = 0;
+ 	int s;
+
+	/* open socket to kernel */
+	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		perror("socket");
+		return errno;
+	}
+
+	/* do it */
+	strncpy(ifr.ifr_name, name, IFNAMSIZ);
+	if ((ret = ioctl(s, SIOCGIFHWADDR, &ifr)) == 0)
+		memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
+
+	/* cleanup */
+	close(s);
+	return ret;
+}	
+
-- 
cgit v1.2.3