Fix up wlan/wan/usb leds,now all leds works well wifi toggle
[tomato.git] / release / src-rt-6.x.4708 / router / shared / misc.c
blob426e9a7804ec24bcdbea3d97267c7ef56cea9845
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13 #include <stdarg.h>
14 #include <syslog.h>
15 #include <sys/ioctl.h>
16 #include <net/if.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #include <ifaddrs.h>
21 #include <sys/sysinfo.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
25 #include <bcmnvram.h>
26 #include <bcmdevs.h>
27 #include <wlutils.h>
29 #include "shutils.h"
30 #include "shared.h"
33 int get_wan_proto(void)
35 const char *names[] = { // order must be synced with def at shared.h
36 "static",
37 "dhcp",
38 "l2tp",
39 "pppoe",
40 "pptp",
41 "ppp3g",
42 "lte",
43 NULL
45 int i;
46 const char *p;
48 p = nvram_safe_get("wan_proto");
49 for (i = 0; names[i] != NULL; ++i) {
50 if (strcmp(p, names[i]) == 0) return i + 1;
52 return WP_DISABLED;
55 #ifdef TCONFIG_IPV6
56 int get_ipv6_service(void)
58 const char *names[] = { // order must be synced with def at shared.h
59 "native", // IPV6_NATIVE
60 "native-pd", // IPV6_NATIVE_DHCP
61 "6to4", // IPV6_ANYCAST_6TO4
62 "sit", // IPV6_6IN4
63 "other", // IPV6_MANUAL
64 "6rd", // IPV6_6RD
65 "6rd-pd", // IPV6_6RD_DHCP
66 NULL
68 int i;
69 const char *p;
71 p = nvram_safe_get("ipv6_service");
72 for (i = 0; names[i] != NULL; ++i) {
73 if (strcmp(p, names[i]) == 0) return i + 1;
75 return IPV6_DISABLED;
78 const char *ipv6_router_address(struct in6_addr *in6addr)
80 char *p;
81 struct in6_addr addr;
82 static char addr6[INET6_ADDRSTRLEN];
84 addr6[0] = '\0';
86 if ((p = nvram_get("ipv6_rtr_addr")) && *p) {
87 inet_pton(AF_INET6, p, &addr);
89 else if ((p = nvram_get("ipv6_prefix")) && *p) {
90 inet_pton(AF_INET6, p, &addr);
91 addr.s6_addr16[7] = htons(0x0001);
93 else {
94 return addr6;
97 inet_ntop(AF_INET6, &addr, addr6, sizeof(addr6));
98 if (in6addr)
99 memcpy(in6addr, &addr, sizeof(addr));
101 return addr6;
104 int calc_6rd_local_prefix(const struct in6_addr *prefix,
105 int prefix_len, int relay_prefix_len,
106 const struct in_addr *local_ip,
107 struct in6_addr *local_prefix, int *local_prefix_len)
109 // the following code is based on ipv6calc's code
110 uint32_t local_ip_bits, j;
111 int i;
113 if (!prefix || !local_ip || !local_prefix || !local_prefix_len) {
114 return 0;
117 *local_prefix_len = prefix_len + 32 - relay_prefix_len;
118 if (*local_prefix_len > 64) {
119 return 0;
122 local_ip_bits = ntohl(local_ip->s_addr) << relay_prefix_len;
124 for (i=0; i<4; i++) {
125 local_prefix->s6_addr32[i] = prefix->s6_addr32[i];
128 for (j = 0x80000000, i = prefix_len; i < *local_prefix_len; i++, j>>=1)
130 if (local_ip_bits & j)
131 local_prefix->s6_addr[i>>3] |= (0x80 >> (i & 0x7));
134 return 1;
136 #endif
138 int using_dhcpc(void)
140 switch (get_wan_proto()) {
141 case WP_DHCP:
142 case WP_LTE:
143 return 1;
144 case WP_L2TP:
145 case WP_PPTP:
146 return nvram_get_int("pptp_dhcp");
148 return 0;
151 int wl_client(int unit, int subunit)
153 char *mode = nvram_safe_get(wl_nvname("mode", unit, subunit));
155 return ((strcmp(mode, "sta") == 0) || (strcmp(mode, "wet") == 0));
158 int foreach_wif(int include_vifs, void *param,
159 int (*func)(int idx, int unit, int subunit, void *param))
161 char ifnames[256];
162 char name[64], ifname[64], *next = NULL;
163 int unit = -1, subunit = -1;
164 int i;
165 int ret = 0;
167 snprintf(ifnames, sizeof(ifnames), "%s %s %s %s %s %s %s %s %s %s",
168 nvram_safe_get("lan_ifnames"),
169 nvram_safe_get("lan1_ifnames"),
170 nvram_safe_get("lan2_ifnames"),
171 nvram_safe_get("lan3_ifnames"),
172 nvram_safe_get("wan_ifnames"),
173 nvram_safe_get("wl_ifname"),
174 nvram_safe_get("wl0_ifname"),
175 nvram_safe_get("wl0_vifs"),
176 nvram_safe_get("wl1_ifname"),
177 nvram_safe_get("wl1_vifs"));
178 remove_dups(ifnames, sizeof(ifnames));
179 sort_list(ifnames, sizeof(ifnames));
181 i = 0;
182 foreach(name, ifnames, next) {
183 if (nvifname_to_osifname(name, ifname, sizeof(ifname)) != 0)
184 continue;
186 if (wl_probe(ifname) || wl_ioctl(ifname, WLC_GET_INSTANCE, &unit, sizeof(unit)))
187 continue;
189 // Convert eth name to wl name
190 if (osifname_to_nvifname(name, ifname, sizeof(ifname)) != 0)
191 continue;
193 // Slave intefaces have a '.' in the name
194 if (strchr(ifname, '.') && !include_vifs)
195 continue;
197 if (get_ifname_unit(ifname, &unit, &subunit) < 0)
198 continue;
200 ret |= func(i++, unit, subunit, param);
202 return ret;
205 void notice_set(const char *path, const char *format, ...)
207 char p[256];
208 char buf[2048];
209 va_list args;
211 va_start(args, format);
212 vsnprintf(buf, sizeof(buf), format, args);
213 va_end(args);
215 mkdir("/var/notice", 0755);
216 snprintf(p, sizeof(p), "/var/notice/%s", path);
217 f_write_string(p, buf, 0, 0);
218 if (buf[0]) syslog(LOG_INFO, "notice[%s]: %s", path, buf);
222 // #define _x_dprintf(args...) syslog(LOG_DEBUG, args);
223 #define _x_dprintf(args...) do { } while (0);
225 int check_wanup(void)
227 int up = 0;
228 int proto;
229 char buf1[64];
230 char buf2[64];
231 const char *name;
232 int f;
233 struct ifreq ifr;
235 proto = get_wan_proto();
236 if (proto == WP_DISABLED)
238 if (nvram_match("boardrev", "0x11")) { // Ovislink 1600GL - led "connected" off
239 led(LED_WHITE,LED_OFF);
241 if (nvram_match("boardtype", "0x052b") && nvram_match("boardrev", "0x1204")) { //rt-n15u wan led off
242 led(LED_WHITE,LED_OFF);
244 if (nvram_match("model", "RT-N18U")) {
245 led(LED_WHITE,LED_OFF);
247 if (get_model() == MODEL_DIR868L) {
248 led(LED_WHITE,LED_OFF);
250 if (get_model() == MODEL_WS880) {
251 led(LED_WHITE,LED_OFF);
253 if (get_model() == MODEL_R6250) {
254 led(LED_WHITE,LED_OFF);
256 return 0;
259 if ((proto == WP_PPTP) || (proto == WP_L2TP) || (proto == WP_PPPOE) || (proto == WP_PPP3G)) {
260 if (f_read_string("/tmp/ppp/link", buf1, sizeof(buf1)) > 0) {
261 // contains the base name of a file in /var/run/ containing pid of a daemon
262 snprintf(buf2, sizeof(buf2), "/var/run/%s.pid", buf1);
263 if (f_read_string(buf2, buf1, sizeof(buf1)) > 0) {
264 name = psname(atoi(buf1), buf2, sizeof(buf2));
265 if (strcmp(name, "pppd") == 0) up = 1;
267 else {
268 _dprintf("%s: error reading %s\n", __FUNCTION__, buf2);
270 if (!up) {
271 unlink("/tmp/ppp/link");
272 _x_dprintf("required daemon not found, assuming link is dead\n");
275 else {
276 _x_dprintf("%s: error reading %s\n", __FUNCTION__, "/tmp/ppp/link");
279 else if (!nvram_match("wan_ipaddr", "0.0.0.0")) {
280 up = 1;
282 else {
283 _x_dprintf("%s: default !up\n", __FUNCTION__);
286 if ((up) && ((f = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)) {
287 strlcpy(ifr.ifr_name, nvram_safe_get("wan_iface"), sizeof(ifr.ifr_name));
288 if (ioctl(f, SIOCGIFFLAGS, &ifr) < 0) {
289 up = 0;
290 _x_dprintf("%s: SIOCGIFFLAGS\n", __FUNCTION__);
292 close(f);
293 if ((ifr.ifr_flags & IFF_UP) == 0) {
294 up = 0;
295 _x_dprintf("%s: !IFF_UP\n", __FUNCTION__);
298 if (nvram_match("boardrev", "0x11")) { // Ovislink 1600GL - led "connected" on
299 led(LED_WHITE,up);
301 if (nvram_match("boardtype", "0x052b") && nvram_match("boardrev", "0x1204")) { //rt-n15u wan led on
302 led(LED_WHITE,up);
304 if (nvram_match("model", "RT-N18U")) {
305 led(LED_WHITE,up);
307 if (get_model() == MODEL_DIR868L) {
308 led(LED_WHITE,up);
310 if (get_model() == MODEL_WS880) {
311 led(LED_WHITE,up);
313 if (get_model() == MODEL_R6250) {
314 led(LED_WHITE,up);
316 return up;
320 const dns_list_t *get_dns(void)
322 static dns_list_t dns;
323 char s[512];
324 int n;
325 int i, j;
326 struct in_addr ia;
327 char d[7][22];
328 unsigned short port;
329 char *c;
331 dns.count = 0;
333 strlcpy(s, nvram_safe_get("wan_dns"), sizeof(s));
334 if ((nvram_get_int("dns_addget")) || (s[0] == 0)) {
335 n = strlen(s);
336 snprintf(s + n, sizeof(s) - n, " %s", nvram_safe_get("wan_get_dns"));
339 n = sscanf(s, "%21s %21s %21s %21s %21s %21s %21s", d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
340 for (i = 0; i < n; ++i) {
341 port = 53;
343 if ((c = strchr(d[i], ':')) != NULL) {
344 *c++ = 0;
345 if (((j = atoi(c)) < 1) || (j > 0xFFFF)) continue;
346 port = j;
349 if (inet_pton(AF_INET, d[i], &ia) > 0) {
350 for (j = dns.count - 1; j >= 0; --j) {
351 if ((dns.dns[j].addr.s_addr == ia.s_addr) && (dns.dns[j].port == port)) break;
353 if (j < 0) {
354 dns.dns[dns.count].port = port;
355 dns.dns[dns.count++].addr.s_addr = ia.s_addr;
356 if (dns.count == 6) break;
361 return &dns;
364 // -----------------------------------------------------------------------------
366 void set_action(int a)
368 int r = 3;
369 while (f_write("/var/lock/action", &a, sizeof(a), 0, 0) != sizeof(a)) {
370 sleep(1);
371 if (--r == 0) return;
373 if (a != ACT_IDLE) sleep(2);
376 int check_action(void)
378 int a;
379 int r = 3;
381 while (f_read("/var/lock/action", &a, sizeof(a)) != sizeof(a)) {
382 sleep(1);
383 if (--r == 0) return ACT_UNKNOWN;
385 return a;
388 int wait_action_idle(int n)
390 while (n-- > 0) {
391 if (check_action() == ACT_IDLE) return 1;
392 sleep(1);
394 return 0;
397 // -----------------------------------------------------------------------------
399 const wanface_list_t *get_wanfaces(void)
401 static wanface_list_t wanfaces;
402 char *ip, *iface;
403 int proto;
405 wanfaces.count = 0;
407 switch ((proto = get_wan_proto())) {
408 case WP_PPTP:
409 case WP_L2TP:
410 while (wanfaces.count < 2) {
411 if (wanfaces.count == 0) {
412 ip = nvram_safe_get("ppp_get_ip");
413 iface = nvram_safe_get("wan_iface");
414 if (!(*iface)) iface = "ppp+";
416 else /* if (wanfaces.count == 1) */ {
417 ip = nvram_safe_get("wan_ipaddr");
418 if ((!(*ip) || strcmp(ip, "0.0.0.0") == 0) && (wanfaces.count > 0))
419 iface = "";
420 else
421 iface = nvram_safe_get("wan_ifname");
423 strlcpy(wanfaces.iface[wanfaces.count].ip, ip, sizeof(wanfaces.iface[0].ip));
424 strlcpy(wanfaces.iface[wanfaces.count].name, iface, IFNAMSIZ);
425 ++wanfaces.count;
427 break;
428 default:
429 ip = (proto == WP_DISABLED) ? "0.0.0.0" : nvram_safe_get("wan_ipaddr");
430 if ((proto == WP_PPPOE) || (proto == WP_PPP3G)) {
431 iface = nvram_safe_get("wan_iface");
432 if (!(*iface)) iface = "ppp+";
434 else if (proto == WP_LTE) {
435 iface = nvram_safe_get("wan_4g");
436 } else {
437 iface = nvram_safe_get("wan_ifname");
439 strlcpy(wanfaces.iface[wanfaces.count].ip, ip, sizeof(wanfaces.iface[0].ip));
440 strlcpy(wanfaces.iface[wanfaces.count++].name, iface, IFNAMSIZ);
441 break;
444 return &wanfaces;
447 const char *get_wanface(void)
449 return (*get_wanfaces()).iface[0].name;
452 #ifdef TCONFIG_IPV6
453 const char *get_wan6face(void)
455 switch (get_ipv6_service()) {
456 case IPV6_NATIVE:
457 case IPV6_NATIVE_DHCP:
458 return get_wanface();
459 case IPV6_ANYCAST_6TO4:
460 return "v6to4";
461 case IPV6_6IN4:
462 return "v6in4";
464 return nvram_safe_get("ipv6_ifname");
466 #endif
468 const char *get_wanip(void)
470 if (!check_wanup()) return "0.0.0.0";
472 return (*get_wanfaces()).iface[0].ip;
475 const char *getifaddr(char *ifname, int family, int linklocal)
477 static char buf[INET6_ADDRSTRLEN];
478 void *addr = NULL;
479 struct ifaddrs *ifap, *ifa;
481 if (getifaddrs(&ifap) != 0) {
482 _dprintf("getifaddrs failed: %s\n", strerror(errno));
483 return NULL;
486 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
487 if ((ifa->ifa_addr == NULL) ||
488 (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0) ||
489 (ifa->ifa_addr->sa_family != family))
490 continue;
492 #ifdef TCONFIG_IPV6
493 if (ifa->ifa_addr->sa_family == AF_INET6) {
494 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
495 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) ^ linklocal)
496 continue;
497 addr = (void *)&(s6->sin6_addr);
499 else
500 #endif
502 struct sockaddr_in *s = (struct sockaddr_in *)(ifa->ifa_addr);
503 addr = (void *)&(s->sin_addr);
506 if ((addr) && inet_ntop(ifa->ifa_addr->sa_family, addr, buf, sizeof(buf)) != NULL) {
507 freeifaddrs(ifap);
508 return buf;
512 freeifaddrs(ifap);
513 return NULL;
516 // -----------------------------------------------------------------------------
518 long get_uptime(void)
520 struct sysinfo si;
521 sysinfo(&si);
522 return si.uptime;
525 char *wl_nvname(const char *nv, int unit, int subunit)
527 static char tmp[128];
528 char prefix[] = "wlXXXXXXXXXX_";
530 if (unit < 0)
531 strcpy(prefix, "wl_");
532 else if (subunit > 0)
533 snprintf(prefix, sizeof(prefix), "wl%d.%d_", unit, subunit);
534 else
535 snprintf(prefix, sizeof(prefix), "wl%d_", unit);
536 return strcat_r(prefix, nv, tmp);
539 int get_radio(int unit)
541 uint32 n;
543 return (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_GET_RADIO, &n, sizeof(n)) == 0) &&
544 ((n & WL_RADIO_SW_DISABLE) == 0);
547 void set_radio(int on, int unit)
549 uint32 n;
551 #ifndef WL_BSS_INFO_VERSION
552 #error WL_BSS_INFO_VERSION
553 #endif
555 #if WL_BSS_INFO_VERSION >= 108
556 n = on ? (WL_RADIO_SW_DISABLE << 16) : ((WL_RADIO_SW_DISABLE << 16) | 1);
557 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_SET_RADIO, &n, sizeof(n));
558 if (!on) {
559 if (unit == 0) led(LED_WLAN, LED_OFF);
560 else led(LED_5G, LED_OFF);
561 } else {
562 if (unit == 0) led(LED_WLAN, LED_ON);
563 else led(LED_5G, LED_ON);
565 #else
566 n = on ? 0 : WL_RADIO_SW_DISABLE;
567 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_SET_RADIO, &n, sizeof(n));
568 if (!on) {
569 led(LED_WLAN, LED_OFF);
570 } else {
571 led(LED_WLAN, LED_ON);
573 #endif
576 // -----------------------------------------------------------------------------
578 int mtd_getinfo(const char *mtdname, int *part, int *size)
580 FILE *f;
581 char s[256];
582 char t[256];
583 int r;
585 r = 0;
586 if ((strlen(mtdname) < 128) && (strcmp(mtdname, "pmon") != 0)) {
587 sprintf(t, "\"%s\"", mtdname);
588 if ((f = fopen("/proc/mtd", "r")) != NULL) {
589 while (fgets(s, sizeof(s), f) != NULL) {
590 if ((sscanf(s, "mtd%d: %x", part, size) == 2) && (strstr(s, t) != NULL)) {
591 // don't accidentally mess with bl (0)
592 if (*part > 0) r = 1;
593 break;
596 fclose(f);
599 if (!r) {
600 *size = 0;
601 *part = -1;
603 return r;
606 // -----------------------------------------------------------------------------
608 int nvram_get_int(const char *key)
610 return atoi(nvram_safe_get(key));
614 long nvram_xget_long(const char *name, long min, long max, long def)
616 const char *p;
617 char *e;
618 long n;
620 p = nvram_get(name);
621 if ((p != NULL) && (*p != 0)) {
622 n = strtol(p, &e, 0);
623 if ((e != p) && ((*e == 0) || (*e == ' ')) && (n > min) && (n < max)) {
624 return n;
627 return def;
631 int nvram_get_file(const char *key, const char *fname, int max)
633 int n;
634 char *p;
635 char *b;
636 int r;
638 r = 0;
639 p = nvram_safe_get(key);
640 n = strlen(p);
641 if (n <= max) {
642 if ((b = malloc(base64_decoded_len(n) + 128)) != NULL) {
643 n = base64_decode(p, b, n);
644 if (n > 0) r = (f_write(fname, b, n, 0, 0644) == n);
645 free(b);
648 return r;
650 char b[2048];
651 int n;
652 char *p;
654 p = nvram_safe_get(key);
655 n = strlen(p);
656 if (n <= max) {
657 n = base64_decode(p, b, n);
658 if (n > 0) return (f_write(fname, b, n, 0, 0700) == n);
660 return 0;
664 int nvram_set_file(const char *key, const char *fname, int max)
666 char *in;
667 char *out;
668 long len;
669 int n;
670 int r;
672 if ((len = f_size(fname)) > max) return 0;
673 max = (int)len;
674 r = 0;
675 if (f_read_alloc(fname, &in, max) == max) {
676 if ((out = malloc(base64_encoded_len(max) + 128)) != NULL) {
677 n = base64_encode(in, out, max);
678 out[n] = 0;
679 nvram_set(key, out);
680 free(out);
681 r = 1;
683 free(in);
685 return r;
687 char a[2048];
688 char b[4096];
689 int n;
691 if (((n = f_read(fname, &a, sizeof(a))) > 0) && (n <= max)) {
692 n = base64_encode(a, b, n);
693 b[n] = 0;
694 nvram_set(key, b);
695 return 1;
697 return 0;
701 int nvram_contains_word(const char *key, const char *word)
703 return (find_word(nvram_safe_get(key), word) != NULL);
706 int nvram_is_empty(const char *key)
708 char *p;
709 return (((p = nvram_get(key)) == NULL) || (*p == 0));
712 void nvram_commit_x(void)
714 if (!nvram_get_int("debug_nocommit")) nvram_commit();
717 int connect_timeout(int fd, const struct sockaddr *addr, socklen_t len, int timeout)
719 fd_set fds;
720 struct timeval tv;
721 int flags;
722 int n;
723 int r;
725 if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
726 (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) {
727 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
728 return -1;
731 if (connect(fd, addr, len) < 0) {
732 // _dprintf("%s: connect %d = <0\n", __FUNCTION__, fd);
734 if (errno != EINPROGRESS) {
735 _dprintf("%s: error in connect %d errno=%d\n", __FUNCTION__, fd, errno);
736 return -1;
739 while (1) {
740 tv.tv_sec = timeout;
741 tv.tv_usec = 0;
742 FD_ZERO(&fds);
743 FD_SET(fd, &fds);
744 r = select(fd + 1, NULL, &fds, NULL, &tv);
745 if (r == 0) {
746 _dprintf("%s: timeout in select %d\n", __FUNCTION__, fd);
747 return -1;
749 else if (r < 0) {
750 if (errno != EINTR) {
751 _dprintf("%s: error in select %d\n", __FUNCTION__, fd);
752 return -1;
754 // loop
756 else {
757 r = 0;
758 n = sizeof(r);
759 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &n) < 0) || (r != 0)) {
760 _dprintf("%s: error in SO_ERROR %d\n", __FUNCTION__, fd);
761 return -1;
763 break;
768 if (fcntl(fd, F_SETFL, flags) < 0) {
769 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
770 return -1;
773 // _dprintf("%s: OK %d\n", __FUNCTION__, fd);
774 return 0;
777 void chld_reap(int sig)
779 while (waitpid(-1, NULL, WNOHANG) > 0) {}
783 int time_ok(void)
785 return time(0) > Y2K;