diff options
Diffstat (limited to 'target/linux/package/nvram/src')
| -rw-r--r-- | target/linux/package/nvram/src/Makefile | 22 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/bcmtimer.h | 42 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/defaults.c | 179 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/linux_timer.c | 738 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/main.c | 78 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/nvram_convert.c | 77 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/nvram_convert.h | 7 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/nvram_linux.c | 320 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/shutils.c | 329 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/wl.c | 86 | ||||
| -rw-r--r-- | target/linux/package/nvram/src/wl_linux.c | 77 | 
11 files changed, 1955 insertions, 0 deletions
| diff --git a/target/linux/package/nvram/src/Makefile b/target/linux/package/nvram/src/Makefile new file mode 100644 index 000000000..376c2b7de --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/bcmtimer.h b/target/linux/package/nvram/src/bcmtimer.h new file mode 100644 index 000000000..3db9e624f --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/defaults.c b/target/linux/package/nvram/src/defaults.c new file mode 100644 index 000000000..119eaac72 --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/linux_timer.c b/target/linux/package/nvram/src/linux_timer.c new file mode 100644 index 000000000..0402e4437 --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/main.c b/target/linux/package/nvram/src/main.c new file mode 100644 index 000000000..a64430f7b --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/nvram_convert.c b/target/linux/package/nvram/src/nvram_convert.c new file mode 100644 index 000000000..485909026 --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/nvram_convert.h b/target/linux/package/nvram/src/nvram_convert.h new file mode 100644 index 000000000..70e12327d --- /dev/null +++ b/target/linux/package/nvram/src/nvram_convert.h @@ -0,0 +1,7 @@ + +struct nvram_convert { +        char *name; +	char *wl0_name; +        char *d11g_name; +}; + diff --git a/target/linux/package/nvram/src/nvram_linux.c b/target/linux/package/nvram/src/nvram_linux.c new file mode 100644 index 000000000..c41e32118 --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/shutils.c b/target/linux/package/nvram/src/shutils.c new file mode 100644 index 000000000..49ad41af8 --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/wl.c b/target/linux/package/nvram/src/wl.c new file mode 100644 index 000000000..f09317ad0 --- /dev/null +++ b/target/linux/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/target/linux/package/nvram/src/wl_linux.c b/target/linux/package/nvram/src/wl_linux.c new file mode 100644 index 000000000..126a40b4b --- /dev/null +++ b/target/linux/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; +}	 + | 
