Ovislink 1600GL: Turn on/off "Connected" led when WAN connection is up/down
[tomato.git] / release / src / router / shared / misc.c
blob6420bfa7db719d33a7a6c4901384682f10bcf978
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 NULL
43 int i;
44 const char *p;
46 p = nvram_safe_get("wan_proto");
47 for (i = 0; names[i] != NULL; ++i) {
48 if (strcmp(p, names[i]) == 0) return i + 1;
50 return WP_DISABLED;
53 #ifdef TCONFIG_IPV6
54 int get_ipv6_service(void)
56 const char *names[] = { // order must be synced with def at shared.h
57 "native", // IPV6_NATIVE
58 "native-pd", // IPV6_NATIVE_DHCP
59 "6to4", // IPV6_ANYCAST_6TO4
60 "sit", // IPV6_6IN4
61 "other", // IPV6_MANUAL
62 NULL
64 int i;
65 const char *p;
67 p = nvram_safe_get("ipv6_service");
68 for (i = 0; names[i] != NULL; ++i) {
69 if (strcmp(p, names[i]) == 0) return i + 1;
71 return IPV6_DISABLED;
74 const char *ipv6_router_address(struct in6_addr *in6addr)
76 char *p;
77 struct in6_addr addr;
78 static char addr6[INET6_ADDRSTRLEN];
80 addr6[0] = '\0';
82 if ((p = nvram_get("ipv6_rtr_addr")) && *p) {
83 inet_pton(AF_INET6, p, &addr);
85 else if ((p = nvram_get("ipv6_prefix")) && *p) {
86 inet_pton(AF_INET6, p, &addr);
87 addr.s6_addr16[7] = htons(0x0001);
89 else {
90 return addr6;
93 inet_ntop(AF_INET6, &addr, addr6, sizeof(addr6));
94 if (in6addr)
95 memcpy(in6addr, &addr, sizeof(addr));
97 return addr6;
99 #endif
101 int using_dhcpc(void)
103 switch (get_wan_proto()) {
104 case WP_DHCP:
105 return 1;
106 case WP_L2TP:
107 case WP_PPTP:
108 return nvram_get_int("pptp_dhcp");
110 return 0;
113 int wl_client(int unit, int subunit)
115 char *mode = nvram_safe_get(wl_nvname("mode", unit, subunit));
117 return ((strcmp(mode, "sta") == 0) || (strcmp(mode, "wet") == 0));
120 int foreach_wif(int include_vifs, void *param,
121 int (*func)(int idx, int unit, int subunit, void *param))
123 char ifnames[256];
124 char name[64], ifname[64], *next = NULL;
125 int unit = -1, subunit = -1;
126 int i;
127 int ret = 0;
129 snprintf(ifnames, sizeof(ifnames), "%s %s %s %s %s",
130 nvram_safe_get("lan_ifnames"), nvram_safe_get("lan1_ifnames"), nvram_safe_get("lan2_ifnames"), nvram_safe_get("lan3_ifnames"), nvram_safe_get("wan_ifnames"));
131 remove_dups(ifnames, sizeof(ifnames));
133 i = 0;
134 foreach(name, ifnames, next) {
135 if (nvifname_to_osifname(name, ifname, sizeof(ifname)) != 0)
136 continue;
138 if (wl_probe(ifname) || wl_ioctl(ifname, WLC_GET_INSTANCE, &unit, sizeof(unit)))
139 continue;
141 // Convert eth name to wl name
142 if (osifname_to_nvifname(name, ifname, sizeof(ifname)) != 0)
143 continue;
145 // Slave intefaces have a '.' in the name
146 if (strchr(ifname, '.') && !include_vifs)
147 continue;
149 if (get_ifname_unit(ifname, &unit, &subunit) < 0)
150 continue;
152 ret |= func(i++, unit, subunit, param);
154 return ret;
157 void notice_set(const char *path, const char *format, ...)
159 char p[256];
160 char buf[2048];
161 va_list args;
163 va_start(args, format);
164 vsnprintf(buf, sizeof(buf), format, args);
165 va_end(args);
167 mkdir("/var/notice", 0755);
168 snprintf(p, sizeof(p), "/var/notice/%s", path);
169 f_write_string(p, buf, 0, 0);
170 if (buf[0]) syslog(LOG_INFO, "notice[%s]: %s", path, buf);
174 // #define _x_dprintf(args...) syslog(LOG_DEBUG, args);
175 #define _x_dprintf(args...) do { } while (0);
177 int check_wanup(void)
179 int up = 0;
180 int proto;
181 char buf1[64];
182 char buf2[64];
183 const char *name;
184 int f;
185 struct ifreq ifr;
187 proto = get_wan_proto();
188 if (proto == WP_DISABLED)
190 if (nvram_match("boardrev", "0x11")) { // Ovislink 1600GL - led "connected" off
191 led(LED_WHITE,LED_OFF);
193 return 0;
196 if ((proto == WP_PPTP) || (proto == WP_L2TP) || (proto == WP_PPPOE)) {
197 if (f_read_string("/tmp/ppp/link", buf1, sizeof(buf1)) > 0) {
198 // contains the base name of a file in /var/run/ containing pid of a daemon
199 snprintf(buf2, sizeof(buf2), "/var/run/%s.pid", buf1);
200 if (f_read_string(buf2, buf1, sizeof(buf1)) > 0) {
201 name = psname(atoi(buf1), buf2, sizeof(buf2));
202 if (strcmp(name, "pppd") == 0) up = 1;
204 else {
205 _dprintf("%s: error reading %s\n", __FUNCTION__, buf2);
207 if (!up) {
208 unlink("/tmp/ppp/link");
209 _x_dprintf("required daemon not found, assuming link is dead\n");
212 else {
213 _x_dprintf("%s: error reading %s\n", __FUNCTION__, "/tmp/ppp/link");
216 else if (!nvram_match("wan_ipaddr", "0.0.0.0")) {
217 up = 1;
219 else {
220 _x_dprintf("%s: default !up\n", __FUNCTION__);
223 if ((up) && ((f = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)) {
224 strlcpy(ifr.ifr_name, nvram_safe_get("wan_iface"), sizeof(ifr.ifr_name));
225 if (ioctl(f, SIOCGIFFLAGS, &ifr) < 0) {
226 up = 0;
227 _x_dprintf("%s: SIOCGIFFLAGS\n", __FUNCTION__);
229 close(f);
230 if ((ifr.ifr_flags & IFF_UP) == 0) {
231 up = 0;
232 _x_dprintf("%s: !IFF_UP\n", __FUNCTION__);
235 if (nvram_match("boardrev", "0x11")) { // Ovislink 1600GL - led "connected" on
236 led(LED_WHITE,up);
239 return up;
243 const dns_list_t *get_dns(void)
245 static dns_list_t dns;
246 char s[512];
247 int n;
248 int i, j;
249 struct in_addr ia;
250 char d[7][22];
251 unsigned short port;
252 char *c;
254 dns.count = 0;
256 strlcpy(s, nvram_safe_get("wan_dns"), sizeof(s));
257 if ((nvram_get_int("dns_addget")) || (s[0] == 0)) {
258 n = strlen(s);
259 snprintf(s + n, sizeof(s) - n, " %s", nvram_safe_get("wan_get_dns"));
262 n = sscanf(s, "%21s %21s %21s %21s %21s %21s %21s", d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
263 for (i = 0; i < n; ++i) {
264 port = 53;
266 if ((c = strchr(d[i], ':')) != NULL) {
267 *c++ = 0;
268 if (((j = atoi(c)) < 1) || (j > 0xFFFF)) continue;
269 port = j;
272 if (inet_pton(AF_INET, d[i], &ia) > 0) {
273 for (j = dns.count - 1; j >= 0; --j) {
274 if ((dns.dns[j].addr.s_addr == ia.s_addr) && (dns.dns[j].port == port)) break;
276 if (j < 0) {
277 dns.dns[dns.count].port = port;
278 dns.dns[dns.count++].addr.s_addr = ia.s_addr;
279 if (dns.count == 6) break;
284 return &dns;
287 // -----------------------------------------------------------------------------
289 void set_action(int a)
291 int r = 3;
292 while (f_write("/var/lock/action", &a, sizeof(a), 0, 0) != sizeof(a)) {
293 sleep(1);
294 if (--r == 0) return;
296 if (a != ACT_IDLE) sleep(2);
299 int check_action(void)
301 int a;
302 int r = 3;
304 while (f_read("/var/lock/action", &a, sizeof(a)) != sizeof(a)) {
305 sleep(1);
306 if (--r == 0) return ACT_UNKNOWN;
308 return a;
311 int wait_action_idle(int n)
313 while (n-- > 0) {
314 if (check_action() == ACT_IDLE) return 1;
315 sleep(1);
317 return 0;
320 // -----------------------------------------------------------------------------
322 const wanface_list_t *get_wanfaces(void)
324 static wanface_list_t wanfaces;
325 char *ip, *iface;
326 int proto;
328 wanfaces.count = 0;
330 switch ((proto = get_wan_proto())) {
331 case WP_PPTP:
332 case WP_L2TP:
333 while (wanfaces.count < 2) {
334 if (wanfaces.count == 0) {
335 ip = nvram_safe_get("ppp_get_ip");
336 iface = nvram_safe_get("wan_iface");
337 if (!(*iface)) iface = "ppp+";
339 else /* if (wanfaces.count == 1) */ {
340 ip = nvram_safe_get("wan_ipaddr");
341 if ((!(*ip) || strcmp(ip, "0.0.0.0") == 0) && (wanfaces.count > 0))
342 iface = "";
343 else
344 iface = nvram_safe_get("wan_ifname");
346 strlcpy(wanfaces.iface[wanfaces.count].ip, ip, sizeof(wanfaces.iface[0].ip));
347 strlcpy(wanfaces.iface[wanfaces.count].name, iface, IFNAMSIZ);
348 ++wanfaces.count;
350 break;
351 default:
352 ip = (proto == WP_DISABLED) ? "0.0.0.0" : nvram_safe_get("wan_ipaddr");
353 if (proto == WP_PPPOE) {
354 iface = nvram_safe_get("wan_iface");
355 if (!(*iface)) iface = "ppp+";
357 else {
358 iface = nvram_safe_get("wan_ifname");
360 strlcpy(wanfaces.iface[wanfaces.count].ip, ip, sizeof(wanfaces.iface[0].ip));
361 strlcpy(wanfaces.iface[wanfaces.count++].name, iface, IFNAMSIZ);
362 break;
365 return &wanfaces;
368 const char *get_wanface(void)
370 return (*get_wanfaces()).iface[0].name;
373 #ifdef TCONFIG_IPV6
374 const char *get_wan6face(void)
376 switch (get_ipv6_service()) {
377 case IPV6_NATIVE:
378 case IPV6_NATIVE_DHCP:
379 return get_wanface();
380 case IPV6_ANYCAST_6TO4:
381 return "v6to4";
382 case IPV6_6IN4:
383 return "v6in4";
385 return nvram_safe_get("ipv6_ifname");
387 #endif
389 const char *get_wanip(void)
391 if (!check_wanup()) return "0.0.0.0";
393 return (*get_wanfaces()).iface[0].ip;
396 const char *getifaddr(char *ifname, int family, int linklocal)
398 static char buf[INET6_ADDRSTRLEN];
399 void *addr = NULL;
400 struct ifaddrs *ifap, *ifa;
402 if (getifaddrs(&ifap) != 0) {
403 _dprintf("getifaddrs failed: %s\n", strerror(errno));
404 return NULL;
407 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
408 if ((ifa->ifa_addr == NULL) ||
409 (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0) ||
410 (ifa->ifa_addr->sa_family != family))
411 continue;
413 #ifdef TCONFIG_IPV6
414 if (ifa->ifa_addr->sa_family == AF_INET6) {
415 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
416 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) ^ linklocal)
417 continue;
418 addr = (void *)&(s6->sin6_addr);
420 else
421 #endif
423 struct sockaddr_in *s = (struct sockaddr_in *)(ifa->ifa_addr);
424 addr = (void *)&(s->sin_addr);
427 if ((addr) && inet_ntop(ifa->ifa_addr->sa_family, addr, buf, sizeof(buf)) != NULL) {
428 freeifaddrs(ifap);
429 return buf;
433 freeifaddrs(ifap);
434 return NULL;
437 // -----------------------------------------------------------------------------
439 long get_uptime(void)
441 struct sysinfo si;
442 sysinfo(&si);
443 return si.uptime;
446 char *wl_nvname(const char *nv, int unit, int subunit)
448 static char tmp[128];
449 char prefix[] = "wlXXXXXXXXXX_";
451 if (unit < 0)
452 strcpy(prefix, "wl_");
453 else if (subunit > 0)
454 snprintf(prefix, sizeof(prefix), "wl%d.%d_", unit, subunit);
455 else
456 snprintf(prefix, sizeof(prefix), "wl%d_", unit);
457 return strcat_r(prefix, nv, tmp);
460 int get_radio(int unit)
462 uint32 n;
464 return (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_GET_RADIO, &n, sizeof(n)) == 0) &&
465 ((n & WL_RADIO_SW_DISABLE) == 0);
468 void set_radio(int on, int unit)
470 uint32 n;
472 #ifndef WL_BSS_INFO_VERSION
473 #error WL_BSS_INFO_VERSION
474 #endif
476 #if WL_BSS_INFO_VERSION >= 108
477 n = on ? (WL_RADIO_SW_DISABLE << 16) : ((WL_RADIO_SW_DISABLE << 16) | 1);
478 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_SET_RADIO, &n, sizeof(n));
479 if (!on) {
480 led(LED_WLAN, 0);
481 led(LED_DIAG, 0);
483 #else
484 n = on ? 0 : WL_RADIO_SW_DISABLE;
485 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_SET_RADIO, &n, sizeof(n));
486 if (!on) {
487 led(LED_DIAG, 0);
489 #endif
492 // -----------------------------------------------------------------------------
494 int mtd_getinfo(const char *mtdname, int *part, int *size)
496 FILE *f;
497 char s[256];
498 char t[256];
499 int r;
501 r = 0;
502 if ((strlen(mtdname) < 128) && (strcmp(mtdname, "pmon") != 0)) {
503 sprintf(t, "\"%s\"", mtdname);
504 if ((f = fopen("/proc/mtd", "r")) != NULL) {
505 while (fgets(s, sizeof(s), f) != NULL) {
506 if ((sscanf(s, "mtd%d: %x", part, size) == 2) && (strstr(s, t) != NULL)) {
507 // don't accidentally mess with bl (0)
508 if (*part > 0) r = 1;
509 break;
512 fclose(f);
515 if (!r) {
516 *size = 0;
517 *part = -1;
519 return r;
522 // -----------------------------------------------------------------------------
524 int nvram_get_int(const char *key)
526 return atoi(nvram_safe_get(key));
530 long nvram_xget_long(const char *name, long min, long max, long def)
532 const char *p;
533 char *e;
534 long n;
536 p = nvram_get(name);
537 if ((p != NULL) && (*p != 0)) {
538 n = strtol(p, &e, 0);
539 if ((e != p) && ((*e == 0) || (*e == ' ')) && (n > min) && (n < max)) {
540 return n;
543 return def;
547 int nvram_get_file(const char *key, const char *fname, int max)
549 int n;
550 char *p;
551 char *b;
552 int r;
554 r = 0;
555 p = nvram_safe_get(key);
556 n = strlen(p);
557 if (n <= max) {
558 if ((b = malloc(base64_decoded_len(n) + 128)) != NULL) {
559 n = base64_decode(p, b, n);
560 if (n > 0) r = (f_write(fname, b, n, 0, 0644) == n);
561 free(b);
564 return r;
566 char b[2048];
567 int n;
568 char *p;
570 p = nvram_safe_get(key);
571 n = strlen(p);
572 if (n <= max) {
573 n = base64_decode(p, b, n);
574 if (n > 0) return (f_write(fname, b, n, 0, 0700) == n);
576 return 0;
580 int nvram_set_file(const char *key, const char *fname, int max)
582 char *in;
583 char *out;
584 long len;
585 int n;
586 int r;
588 if ((len = f_size(fname)) > max) return 0;
589 max = (int)len;
590 r = 0;
591 if (f_read_alloc(fname, &in, max) == max) {
592 if ((out = malloc(base64_encoded_len(max) + 128)) != NULL) {
593 n = base64_encode(in, out, max);
594 out[n] = 0;
595 nvram_set(key, out);
596 free(out);
597 r = 1;
599 free(in);
601 return r;
603 char a[2048];
604 char b[4096];
605 int n;
607 if (((n = f_read(fname, &a, sizeof(a))) > 0) && (n <= max)) {
608 n = base64_encode(a, b, n);
609 b[n] = 0;
610 nvram_set(key, b);
611 return 1;
613 return 0;
617 int nvram_contains_word(const char *key, const char *word)
619 return (find_word(nvram_safe_get(key), word) != NULL);
622 int nvram_is_empty(const char *key)
624 char *p;
625 return (((p = nvram_get(key)) == NULL) || (*p == 0));
628 void nvram_commit_x(void)
630 if (!nvram_get_int("debug_nocommit")) nvram_commit();
633 int connect_timeout(int fd, const struct sockaddr *addr, socklen_t len, int timeout)
635 fd_set fds;
636 struct timeval tv;
637 int flags;
638 int n;
639 int r;
641 if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
642 (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) {
643 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
644 return -1;
647 if (connect(fd, addr, len) < 0) {
648 // _dprintf("%s: connect %d = <0\n", __FUNCTION__, fd);
650 if (errno != EINPROGRESS) {
651 _dprintf("%s: error in connect %d errno=%d\n", __FUNCTION__, fd, errno);
652 return -1;
655 while (1) {
656 tv.tv_sec = timeout;
657 tv.tv_usec = 0;
658 FD_ZERO(&fds);
659 FD_SET(fd, &fds);
660 r = select(fd + 1, NULL, &fds, NULL, &tv);
661 if (r == 0) {
662 _dprintf("%s: timeout in select %d\n", __FUNCTION__, fd);
663 return -1;
665 else if (r < 0) {
666 if (errno != EINTR) {
667 _dprintf("%s: error in select %d\n", __FUNCTION__, fd);
668 return -1;
670 // loop
672 else {
673 r = 0;
674 n = sizeof(r);
675 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &n) < 0) || (r != 0)) {
676 _dprintf("%s: error in SO_ERROR %d\n", __FUNCTION__, fd);
677 return -1;
679 break;
684 if (fcntl(fd, F_SETFL, flags) < 0) {
685 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
686 return -1;
689 // _dprintf("%s: OK %d\n", __FUNCTION__, fd);
690 return 0;
693 void chld_reap(int sig)
695 while (waitpid(-1, NULL, WNOHANG) > 0) {}
699 int time_ok(void)
701 return time(0) > Y2K;