From 0bc4109776d047ae999f11b3e329d10eb364d561 Mon Sep 17 00:00:00 2001 From: nbd Date: Mon, 7 Mar 2005 23:24:52 +0000 Subject: add libshared/libnvram and required includes under version control git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@344 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/openwrt/libshared/Makefile | 48 +++ package/openwrt/libshared/bcmtimer.h | 40 ++ package/openwrt/libshared/defaults.c | 179 ++++++++ package/openwrt/libshared/linux_timer.c | 707 ++++++++++++++++++++++++++++++++ package/openwrt/libshared/shutils.c | 329 +++++++++++++++ package/openwrt/libshared/wl.c | 86 ++++ package/openwrt/libshared/wl_linux.c | 77 ++++ 7 files changed, 1466 insertions(+) create mode 100644 package/openwrt/libshared/Makefile create mode 100644 package/openwrt/libshared/bcmtimer.h create mode 100644 package/openwrt/libshared/defaults.c create mode 100644 package/openwrt/libshared/linux_timer.c create mode 100644 package/openwrt/libshared/shutils.c create mode 100644 package/openwrt/libshared/wl.c create mode 100644 package/openwrt/libshared/wl_linux.c (limited to 'package/openwrt/libshared') diff --git a/package/openwrt/libshared/Makefile b/package/openwrt/libshared/Makefile new file mode 100644 index 000000000..ccdd8aeae --- /dev/null +++ b/package/openwrt/libshared/Makefile @@ -0,0 +1,48 @@ +# +# Linux router shared code Makefile +# +# Copyright 2001-2003, 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 $(TOPDIR)/rules.mk + +PKG_NAME:=libshared +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) + +EXTRA_CFLAGS := -c -I. -I../include + +all: compile + +LIBSHARED_OBJS:= +define OBJ_template +$(PKG_BUILD_DIR)/$(1): $(PKG_BUILD_DIR) + $(TARGET_CC) $(TARGET_CFLAGS) $(EXTRA_CFLAGS) -o $$@ $$(patsubst %.o,%.c,$(1)) +LIBSHARED_OBJS += $(PKG_BUILD_DIR)/$(1) +endef + +OBJS := shutils.o wl.o wl_linux.o defaults.o linux_timer.o +$(foreach obj,$(OBJS),$(eval $(call OBJ_template,$(obj)))) + + +$(PKG_BUILD_DIR): + mkdir -p $(PKG_BUILD_DIR) + +$(PKG_BUILD_DIR)/libshared.so: $(LIBSHARED_OBJS) + $(TARGET_CC) -shared -o $@ $^ + +$(TARGET_DIR)/usr/lib/libshared.so: $(PKG_BUILD_DIR)/libshared.so + install -m 644 $^ $@ + install -m 644 $^ $(STAGING_DIR)/lib/libshared.so + $(STRIP) $@ + +compile: $(PKG_BUILD_DIR)/libshared.so +install: $(TARGET_DIR)/usr/lib/libshared.so + +clean: + rm -rf $(PKG_BUILD_DIR) diff --git a/package/openwrt/libshared/bcmtimer.h b/package/openwrt/libshared/bcmtimer.h new file mode 100644 index 000000000..560957cbf --- /dev/null +++ b/package/openwrt/libshared/bcmtimer.h @@ -0,0 +1,40 @@ +/* + * 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 + +/* 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_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); + +#endif /* #ifndef __bcmtimer_h__ */ diff --git a/package/openwrt/libshared/defaults.c b/package/openwrt/libshared/defaults.c new file mode 100644 index 000000000..f75f1282a --- /dev/null +++ b/package/openwrt/libshared/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 +#include +#include +#include +#include + +#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", "linksys", 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", "1", 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/openwrt/libshared/linux_timer.c b/package/openwrt/libshared/linux_timer.c new file mode 100644 index 000000000..eece9f84e --- /dev/null +++ b/package/openwrt/libshared/linux_timer.c @@ -0,0 +1,707 @@ +/* + * 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 // for malloc, free, etc. +#include // for memset, strncasecmp, etc. +#include // for assert, of course. +#include // for sigemptyset, etc. +#include // for printf, etc. +#include +#include + +/* 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 + +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; +} + + +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; +} + +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; +} + diff --git a/package/openwrt/libshared/shutils.c b/package/openwrt/libshared/shutils.c new file mode 100644 index 000000000..49ad41af8 --- /dev/null +++ b/package/openwrt/libshared/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * 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 */ + if (path) { + flags = O_WRONLY | O_CREAT; + if (!strncmp(path, ">>", 2)) { + /* append to */ + flags |= O_APPEND; + path += 2; + } else if (!strncmp(path, ">", 1)) { + /* overwrite */ + 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/openwrt/libshared/wl.c b/package/openwrt/libshared/wl.c new file mode 100644 index 000000000..f09317ad0 --- /dev/null +++ b/package/openwrt/libshared/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 + +#include +#include + +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/openwrt/libshared/wl_linux.c b/package/openwrt/libshared/wl_linux.c new file mode 100644 index 000000000..126a40b4b --- /dev/null +++ b/package/openwrt/libshared/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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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