2 Copyright 2005, Broadcom Corporation
5 THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
25 #include <sys/types.h>
29 #include <sys/ioctl.h>
31 // #include <net/ethernet.h>
41 * Concatenates NULL-terminated list of arguments into a single
42 * commmand and executes it
43 * @param argv argument list
44 * @param path NULL, ">output", or ">>output"
45 * @param timeout seconds to wait before timing out or 0 for no timeout
46 * @param ppid NULL to wait for child termination or pointer to pid
47 * @return return value of executed command or errno
49 * Ref: http://www.open-std.org/jtc1/sc22/WG15/docs/rr/9945-2/9945-2-28.html
51 int _eval(char *const argv
[], const char *path
, int timeout
, int *ppid
)
53 sigset_t set
, sigmask
;
54 sighandler_t chld
= SIG_IGN
;
67 sigaddset(&set
, SIGCHLD
);
68 sigprocmask(SIG_BLOCK
, &set
, &sigmask
);
69 // without this we cannot rely on waitpid() to tell what happened to our children
70 chld
= signal(SIGCHLD
, SIG_DFL
);
86 if ((w
= waitpid(pid
, &status
, 0)) == -1) {
91 } while (!WIFEXITED(status
) && !WIFSIGNALED(status
));
93 if (WIFEXITED(status
)) status
= WEXITSTATUS(status
);
97 sigprocmask(SIG_SETMASK
, &sigmask
, NULL
);
98 signal(SIGCHLD
, chld
);
107 // reset signal handlers
108 for (sig
= 0; sig
< (_NSIG
- 1); sig
++)
109 signal(sig
, SIG_DFL
);
111 // unblock signals if called from signal handler
113 sigprocmask(SIG_SETMASK
, &set
, NULL
);
118 close(STDOUT_FILENO
);
119 close(STDERR_FILENO
);
120 open("/dev/null", O_RDONLY
);
121 open("/dev/null", O_WRONLY
);
122 open("/dev/null", O_WRONLY
);
124 if (nvram_match("debug_logeval", "1")) {
127 cprintf("_eval +%ld pid=%d ", get_uptime(), pid
);
128 for (n
= 0; argv
[n
]; ++n
) cprintf("%s ", argv
[n
]);
131 if ((fd
= open("/dev/console", O_RDWR
)) >= 0) {
132 dup2(fd
, STDIN_FILENO
);
133 dup2(fd
, STDOUT_FILENO
);
134 dup2(fd
, STDERR_FILENO
);
137 sprintf(s
, "/tmp/eval.%d", pid
);
138 if ((fd
= open(s
, O_CREAT
|O_RDWR
, 0600)) >= 0) {
139 dup2(fd
, STDOUT_FILENO
);
140 dup2(fd
, STDERR_FILENO
);
143 if (fd
> STDERR_FILENO
) close(fd
);
146 // Redirect stdout & stderr to <path>
148 flags
= O_WRONLY
| O_CREAT
;
162 if ((fd
= open(path
, flags
, 0644)) < 0) {
166 dup2(fd
, STDOUT_FILENO
);
167 dup2(fd
, STDERR_FILENO
);
174 p
= nvram_safe_get("env_path");
175 snprintf(s
, sizeof(s
), "%s%s/sbin:/bin:/usr/sbin:/usr/bin:/opt/sbin:/opt/bin", *p
? p
: "", *p
? ":" : "");
176 setenv("PATH", s
, 1);
179 execvp(argv
[0], argv
);
186 * fread() with automatic retry on syscall interrupt
187 * @param ptr location to store to
188 * @param size size of each element of data
189 * @param nmemb number of elements
190 * @param stream file stream
191 * @return number of items successfully read
193 int safe_fread(void *ptr
, size_t size
, size_t nmemb
, FILE *stream
)
198 ret
+= fread((char *)ptr
+ (ret
* size
), size
, nmemb
- ret
, stream
);
199 } while (ret
< nmemb
&& ferror(stream
) && errno
== EINTR
);
204 * fwrite() with automatic retry on syscall interrupt
205 * @param ptr location to read from
206 * @param size size of each element of data
207 * @param nmemb number of elements
208 * @param stream file stream
209 * @return number of items successfully written
211 int safe_fwrite(const void *ptr
, size_t size
, size_t nmemb
, FILE *stream
)
216 ret
+= fwrite((char *)ptr
+ (ret
* size
), size
, nmemb
- ret
, stream
);
217 } while (ret
< nmemb
&& ferror(stream
) && errno
== EINTR
);
223 * Convert Ethernet address string representation to binary data
224 * @param a string in xx:xx:xx:xx:xx:xx notation
225 * @param e binary data
226 * @return TRUE if conversion was successful and FALSE otherwise
228 int ether_atoe(const char *a
, unsigned char *e
)
235 e
[i
++] = (unsigned char) strtoul(a
, &x
, 16);
237 if (i
== ETHER_ADDR_LEN
) return 1;
241 memset(e
, 0, sizeof(e
));
246 * Convert Ethernet address binary data to string representation
247 * @param e binary data
248 * @param a string in xx:xx:xx:xx:xx:xx notation
251 char *ether_etoa(const unsigned char *e
, char *a
)
253 sprintf(a
, "%02X:%02X:%02X:%02X:%02X:%02X", e
[0], e
[1], e
[2], e
[3], e
[4], e
[5]);
257 void cprintf(const char *format
, ...)
265 if (nvram_match("debug_cprintf", "1")) {
267 if ((f
= fopen("/dev/console", "w")) != NULL
) {
268 va_start(args
, format
);
269 vfprintf(f
, format
, args
);
275 if (nvram_match("debug_cprintf_file", "1")) {
277 // sprintf(s, "/tmp/cprintf.%d", getpid());
278 // if ((f = fopen(s, "a")) != NULL) {
279 if ((f
= fopen("/tmp/cprintf", "a")) != NULL
) {
280 va_start(args
, format
);
281 vfprintf(f
, format
, args
);
288 if (nvram_match("debug_cprintf_log", "1")) {
291 va_start(args
, format
);
292 vsnprintf(s
, sizeof(s
), format
, args
);
293 s
[sizeof(s
) - 1] = 0;
296 if ((s
[0] != '\n') || (s
[1] != 0)) syslog(LOG_DEBUG
, "%s", s
);
302 #ifndef WL_BSS_INFO_VERSION
303 #error WL_BSS_INFO_VERSION
306 #if WL_BSS_INFO_VERSION >= 108
307 // xref (all): nas, wlconf
310 #define MAX_NVPARSE 255
315 * Get the ip configuration index if it exists given the
318 * @param wl_ifname pointer to eth interface name
319 * @return index or -1 if not found
322 get_ipconfig_index(char *eth_ifname
)
327 char wl_ifname
[NVRAM_MAX_PARAM_LEN
];
330 /* Bail if we get a NULL or empty string */
332 if (!eth_ifname
) return -1;
333 if (!*eth_ifname
) return -1;
335 /* Look up wl name from the eth name */
336 if (osifname_to_nvifname(eth_ifname
, wl_ifname
, sizeof(wl_ifname
)) != 0)
339 snprintf(varname
, sizeof(varname
), "%s_ipconfig_index", wl_ifname
);
341 ptr
= nvram_get(varname
);
344 /* Check ipconfig_index pointer to see if it is still pointing
345 * the correct lan config block
353 snprintf(buf
, sizeof(buf
), "lan%d_ifname", index
);
355 ifname
= nvram_get(buf
);
358 if (!(strcmp(ifname
, wl_ifname
)))
361 nvram_unset(varname
);
365 /* The index pointer may not have been configured if the
366 * user enters the variables manually. Do a brute force search
367 * of the lanXX_ifname variables
369 for (index
= 0; index
< MAX_NVPARSE
; index
++) {
370 snprintf(varname
, sizeof(varname
), "lan%d_ifname", index
);
371 if (nvram_match(varname
, wl_ifname
)) {
372 /* if a match is found set up a corresponding index pointer for wlXX */
373 snprintf(varname
, sizeof(varname
), "%s_ipconfig_index", wl_ifname
);
374 snprintf(varval
, sizeof(varval
), "%d", index
);
375 nvram_set(varname
, varval
);
384 * Set the ip configuration index given the eth name
385 * Updates both wlXX_ipconfig_index and lanYY_ifname.
387 * @param eth_ifname pointer to eth interface name
388 * @return 0 if successful -1 if not.
391 set_ipconfig_index(char *eth_ifname
, int index
)
395 char wl_ifname
[NVRAM_MAX_PARAM_LEN
];
397 /* Bail if we get a NULL or empty string */
399 if (!eth_ifname
) return -1;
400 if (!*eth_ifname
) return -1;
402 if (index
>= MAX_NVPARSE
) return -1;
404 /* Look up wl name from the eth name only if the name contains
408 if (osifname_to_nvifname(eth_ifname
, wl_ifname
, sizeof(wl_ifname
)) != 0)
411 snprintf(varname
, sizeof(varname
), "%s_ipconfig_index", wl_ifname
);
412 snprintf(varval
, sizeof(varval
), "%d", index
);
413 nvram_set(varname
, varval
);
415 snprintf(varname
, sizeof(varname
), "lan%d_ifname", index
);
416 nvram_set(varname
, wl_ifname
);
424 * Get interfaces belonging to a specific bridge.
426 * @param bridge_name pointer to bridge interface name
427 * @return list of interfaces belonging to the bridge or NULL
431 get_bridged_interfaces(char *bridge_name
)
433 static char interfaces
[255];
434 char *ifnames
= NULL
;
437 if (!bridge_name
) return NULL
;
439 memset(interfaces
, 0, sizeof(interfaces
));
440 snprintf(bridge
, sizeof(bridge
), "%s_ifnames", bridge_name
);
442 ifnames
= nvram_get(bridge
);
445 strncpy(interfaces
, ifnames
, sizeof(interfaces
));
456 * Search a string backwards for a set of characters
457 * This is the reverse version of strspn()
459 * @param s string to search backwards
460 * @param accept set of chars for which to search
461 * @return number of characters in the trailing segment of s
462 * which consist only of characters from accept.
465 sh_strrspn(const char *s
, const char *accept
)
468 size_t accept_len
= strlen(accept
);
480 if (memchr(accept
, *p
, accept_len
) == NULL
)
489 * Parse the unit and subunit from an interface string such as wlXX or wlXX.YY
491 * @param ifname interface string to parse
492 * @param unit pointer to return the unit number, may pass NULL
493 * @param subunit pointer to return the subunit number, may pass NULL
494 * @return Returns 0 if the string ends with digits or digits.digits, -1 otherwise.
495 * If ifname ends in digits.digits, then unit and subuint are set
496 * to the first and second values respectively. If ifname ends
497 * in just digits, unit is set to the value, and subunit is set
498 * to -1. On error both unit and subunit are -1. NULL may be passed
499 * for unit and/or subuint to ignore the value.
502 get_ifname_unit(const char* ifname
, int *unit
, int *subunit
)
504 const char digits
[] = "0123456789";
507 size_t ifname_len
= strlen(ifname
);
516 if (ifname_len
+ 1 > sizeof(str
))
521 /* find the trailing digit chars */
522 len
= sh_strrspn(str
, digits
);
524 /* fail if there were no trailing digits */
528 /* point to the beginning of the last integer and convert */
529 p
= str
+ (ifname_len
- len
);
530 val
= strtoul(p
, NULL
, 10);
532 /* if we are at the beginning of the string, or the previous
533 * character is not a '.', then we have the unit number and
534 * we are done parsing
536 if (p
== str
|| p
[-1] != '.') {
545 /* chop off the '.NNN' and get the unit number */
549 /* find the trailing digit chars */
550 len
= sh_strrspn(str
, digits
);
552 /* fail if there were no trailing digits */
556 /* point to the beginning of the last integer and convert */
558 val
= strtoul(p
, NULL
, 10);
560 /* save the unit number */
567 /* In the space-separated/null-terminated list(haystack), try to
568 * locate the string "needle"
570 char *find_in_list(const char *haystack
, const char *needle
)
572 const char *ptr
= haystack
;
574 int haystack_len
= 0;
577 if (!haystack
|| !needle
|| !*haystack
|| !*needle
)
580 needle_len
= strlen(needle
);
581 haystack_len
= strlen(haystack
);
583 while (*ptr
!= 0 && ptr
< &haystack
[haystack_len
])
585 /* consume leading spaces */
586 ptr
+= strspn(ptr
, " ");
588 /* what's the length of the next word */
589 len
= strcspn(ptr
, " ");
591 if ((needle_len
== len
) && (!strncmp(needle
, ptr
, len
)))
602 * Remove the specified word from the list.
604 * @param name word to be removed from the list
605 * @param list Space separated list to modify
606 * @param listsize Max size the list can occupy
610 int remove_from_list(const char *name
, char *list
, int listsize
)
614 char *occurrence
= list
;
616 if (!list
|| !name
|| (listsize
<= 0))
619 listlen
= strlen(list
);
620 namelen
= strlen(name
);
622 occurrence
= find_in_list(occurrence
, name
);
627 /* last item in list? */
628 if (occurrence
[namelen
] == 0)
630 /* only item in list? */
631 if (occurrence
!= list
)
635 else if (occurrence
[namelen
] == ' ')
637 strncpy(occurrence
, &occurrence
[namelen
+1 /* space */],
638 strlen(&occurrence
[namelen
+1 /* space */]) +1 /* terminate */);
646 * Add the specified interface(string) to the list as long as
647 * it will fit in the space left in the list.
649 * NOTE: If item is already in list, it won't be added again.
651 * @param name Name of interface to be added to the list
652 * @param list List to modify
653 * @param listsize Max size the list can occupy
657 int add_to_list(const char *name
, char *list
, int listsize
)
662 if (!list
|| !name
|| (listsize
<= 0))
665 listlen
= strlen(list
);
666 namelen
= strlen(name
);
668 /* is the item already in the list? */
669 if (find_in_list(list
, name
))
672 if (listsize
<= listlen
+ namelen
+ 1 /* space */ + 1 /* NULL */)
675 /* add a space if the list isn't empty and it doesn't already have space */
676 if (list
[0] != 0 && list
[listlen
-1] != ' ')
678 list
[listlen
++] = 0x20;
681 strncpy(&list
[listlen
], name
, namelen
+ 1 /* terminate */);
686 /* Utility function to remove duplicate entries in a space separated list */
688 char *remove_dups(char *inlist
, int inlist_size
)
690 char name
[256], *next
= NULL
;
693 if (!inlist_size
) return NULL
;
694 if (!inlist
) return NULL
;
696 outlist
= (char *) malloc(inlist_size
);
697 if (!outlist
) return NULL
;
698 memset(outlist
, 0, inlist_size
);
700 foreach(name
, inlist
, next
) {
701 if (!find_in_list(outlist
, name
)) {
702 if (strlen(outlist
) == 0) {
703 snprintf(outlist
, inlist_size
, "%s", name
);
705 strncat(outlist
, " ", inlist_size
- strlen(outlist
));
706 strncat(outlist
, name
, inlist_size
- strlen(outlist
));
710 strncpy(inlist
, outlist
, inlist_size
);
716 char *find_smallest_in_list(char *haystack
) {
717 char *ptr
= haystack
;
718 char *smallest
= ptr
;
719 int haystack_len
= strlen(haystack
);
722 if (!haystack
|| !*haystack
|| !haystack_len
)
725 while (*ptr
!= 0 && ptr
< &haystack
[haystack_len
]) {
726 /* consume leading spaces */
727 ptr
+= strspn(ptr
, " ");
729 /* what's the length of the next word */
730 len
= strcspn(ptr
, " ");
732 /* if this item/word is 'smaller', update our pointer */
733 if ((strncmp(smallest
, ptr
, len
) > 0)) {
739 return (char*) smallest
;
742 char *sort_list(char *inlist
, int inlist_size
) {
746 if (!inlist_size
) return NULL
;
747 if (!inlist
) return NULL
;
749 tmplist
= (char *) malloc(inlist_size
);
750 if (!tmplist
) return NULL
;
751 memset(tmplist
, 0, inlist_size
);
755 while ((b
= find_smallest_in_list(inlist
)) != NULL
) {
756 len
= strcspn(b
, " ");
757 snprintf(tmp
, len
+ 1, "%s", b
);
759 add_to_list(tmp
, tmplist
, inlist_size
);
760 remove_from_list(tmp
, inlist
, inlist_size
);
763 strncpy(inlist
, tmplist
, inlist_size
);
770 return true/false if any wireless interface has URE enabled.
773 ure_any_enabled(void)
776 char nv_param
[NVRAM_MAX_PARAM_LEN
];
778 sprintf(nv_param
, "ure_disable");
779 temp
= nvram_safe_get(nv_param
);
780 if (temp
&& (strncmp(temp
, "0", 1) == 0))
786 #define WLMBSS_DEV_NAME "wlmbss"
787 #define WL_DEV_NAME "wl"
788 #define WDS_DEV_NAME "wds"
791 * nvifname_to_osifname()
792 * The intent here is to provide a conversion between the OS interface name
793 * and the device name that we keep in NVRAM.
794 * This should eventually be placed in a Linux specific file with other
795 * OS abstraction functions.
797 * @param nvifname pointer to ifname to be converted
798 * @param osifname_buf storage for the converted osifname
799 * @param osifname_buf_len length of storage for osifname_buf
802 nvifname_to_osifname(const char *nvifname
, char *osifname_buf
,
803 int osifname_buf_len
)
805 char varname
[NVRAM_MAX_PARAM_LEN
];
808 memset(osifname_buf
, 0, osifname_buf_len
);
810 /* Bail if we get a NULL or empty string */
811 if ((!nvifname
) || (!*nvifname
) || (!osifname_buf
)) {
815 if (strstr(nvifname
, "eth") || strstr(nvifname
, ".")) {
816 strncpy(osifname_buf
, nvifname
, osifname_buf_len
);
820 snprintf(varname
, sizeof(varname
), "%s_ifname", nvifname
);
821 ptr
= nvram_get(varname
);
823 /* Bail if the string is empty */
824 if (!*ptr
) return -1;
825 strncpy(osifname_buf
, ptr
, osifname_buf_len
);
832 /* osifname_to_nvifname()
833 * Convert the OS interface name to the name we use internally(NVRAM, GUI, etc.)
834 * This is the Linux version of this function
836 * @param osifname pointer to osifname to be converted
837 * @param nvifname_buf storage for the converted ifname
838 * @param nvifname_buf_len length of storage for nvifname_buf
841 osifname_to_nvifname(const char *osifname
, char *nvifname_buf
,
842 int nvifname_buf_len
)
844 char varname
[NVRAM_MAX_PARAM_LEN
];
847 /* Bail if we get a NULL or empty string */
849 if ((!osifname
) || (!*osifname
) || (!nvifname_buf
))
854 memset(nvifname_buf
, 0, nvifname_buf_len
);
856 if (strstr(osifname
, "wl") || strstr(osifname
, "br") ||
857 strstr(osifname
, "wds")) {
858 strncpy(nvifname_buf
, osifname
, nvifname_buf_len
);
862 /* look for interface name on the primary interfaces first */
863 for (pri
= 0; pri
< MAX_NVPARSE
; pri
++) {
864 snprintf(varname
, sizeof(varname
),
866 if (nvram_match(varname
, (char *)osifname
)) {
867 snprintf(nvifname_buf
, nvifname_buf_len
, "wl%d", pri
);
872 /* look for interface name on the multi-instance interfaces */
873 for (pri
= 0; pri
< MAX_NVPARSE
; pri
++)
874 for (sec
= 0; sec
< MAX_NVPARSE
; sec
++) {
875 snprintf(varname
, sizeof(varname
),
876 "wl%d.%d_ifname", pri
, sec
);
877 if (nvram_match(varname
, (char *)osifname
)) {
878 snprintf(nvifname_buf
, nvifname_buf_len
, "wl%d.%d", pri
, sec
);
886 #endif // #if WL_BSS_INFO_VERSION >= 108
892 // -----------------------------------------------------------------------------
899 * Reads file and returns contents
900 * @param fd file descriptor
901 * @return contents of file or NULL if an error occurred
909 buf
= realloc(buf
, count
+ 512);
910 n
= read(fd
, buf
+ count
, 512);
925 * Reads file and returns contents
926 * @param path path to file
927 * @return contents of file or NULL if an error occurred
929 char *file2str(const char *path
)
933 if ((fd
= open(path
, O_RDONLY
)) == -1) {
942 * Waits for a file descriptor to change status or unblocked signal
943 * @param fd file descriptor
944 * @param timeout seconds to wait before timing out or 0 for no timeout
945 * @return 1 if descriptor changed status or 0 if timed out or -1 on error
948 int waitfor(int fd
, int timeout
)
951 struct timeval tv
= { timeout
, 0 };
955 return select(fd
+ 1, &rfds
, NULL
, NULL
, (timeout
> 0) ? &tv
: NULL
);
959 * Kills process whose PID is stored in plaintext in pidfile
960 * @param pidfile PID file
961 * @return 0 on success and errno on failure
963 int kill_pidfile(char *pidfile
)
968 if ((fp
= fopen(pidfile
, "r")) != NULL
) {
969 if (fgets(buf
, sizeof(buf
), fp
)) {
970 pid_t pid
= strtoul(buf
, NULL
, 0);
972 return kill(pid
, SIGTERM
);