ipv6: add DHCPv6 with Prefix Delegation support (based on the patch by Paul Donovan)
[tomato.git] / release / src / router / shared / misc.c
blob4abb575e7fe47bffb6041a3da2ebabebe756de22
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 <sys/socket.h>
18 #include <arpa/inet.h>
19 #include <sys/sysinfo.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
23 #include <bcmnvram.h>
24 #include <bcmdevs.h>
25 #include <wlutils.h>
27 #include "shutils.h"
28 #include "shared.h"
31 int get_wan_proto(void)
33 const char *names[] = { // order must be synced with def at shared.h
34 "static",
35 "dhcp",
36 "l2tp",
37 "pppoe",
38 "pptp",
39 NULL
41 int i;
42 const char *p;
44 p = nvram_safe_get("wan_proto");
45 for (i = 0; names[i] != NULL; ++i) {
46 if (strcmp(p, names[i]) == 0) return i + 1;
48 return WP_DISABLED;
51 #ifdef TCONFIG_IPV6
52 int get_ipv6_service(void)
54 const char *names[] = { // order must be synced with def at shared.h
55 "native", // IPV6_NATIVE
56 "native-pd", // IPV6_NATIVE_DHCP
57 "sit", // IPV6_6IN4
58 "other", // IPV6_MANUAL
59 NULL
61 int i;
62 const char *p;
64 p = nvram_safe_get("ipv6_service");
65 for (i = 0; names[i] != NULL; ++i) {
66 if (strcmp(p, names[i]) == 0) return i + 1;
68 return IPV6_DISABLED;
71 const char *ipv6_router_address(struct in6_addr *in6addr)
73 char *p;
74 struct in6_addr addr;
75 static char addr6[40];
77 if ((p = nvram_get("ipv6_rtr_addr")) && *p) {
78 inet_pton(AF_INET6, p, &addr);
80 else {
81 inet_pton(AF_INET6, nvram_safe_get("ipv6_prefix"), &addr);
82 addr.s6_addr16[7] = htons(0x0001);
85 inet_ntop(AF_INET6, &addr, addr6, sizeof(addr6));
86 if (in6addr)
87 memcpy(in6addr, &addr, sizeof(addr));
89 return addr6;
91 #endif
93 int using_dhcpc(void)
95 switch (get_wan_proto()) {
96 case WP_DHCP:
97 return 1;
98 case WP_L2TP:
99 case WP_PPTP:
100 return nvram_get_int("pptp_dhcp");
102 return 0;
105 int wl_client(int unit, int subunit)
107 char *mode = nvram_safe_get(wl_nvname("mode", unit, subunit));
109 return ((strcmp(mode, "sta") == 0) || (strcmp(mode, "wet") == 0));
112 int foreach_wif(int include_vifs, void *param,
113 int (*func)(int idx, int unit, int subunit, void *param))
115 char ifnames[256];
116 char name[64], ifname[64], *next = NULL;
117 int unit = -1, subunit = -1;
118 int i;
119 int ret = 0;
121 snprintf(ifnames, sizeof(ifnames), "%s %s",
122 nvram_safe_get("lan_ifnames"), nvram_safe_get("wan_ifnames"));
123 remove_dups(ifnames, sizeof(ifnames));
125 i = 0;
126 foreach(name, ifnames, next) {
127 if (nvifname_to_osifname(name, ifname, sizeof(ifname)) != 0)
128 continue;
130 if (wl_probe(ifname) || wl_ioctl(ifname, WLC_GET_INSTANCE, &unit, sizeof(unit)))
131 continue;
133 // Convert eth name to wl name
134 if (osifname_to_nvifname(name, ifname, sizeof(ifname)) != 0)
135 continue;
137 // Slave intefaces have a '.' in the name
138 if (strchr(ifname, '.') && !include_vifs)
139 continue;
141 if (get_ifname_unit(ifname, &unit, &subunit) < 0)
142 continue;
144 ret |= func(i++, unit, subunit, param);
146 return ret;
149 void notice_set(const char *path, const char *format, ...)
151 char p[256];
152 char buf[2048];
153 va_list args;
155 va_start(args, format);
156 vsnprintf(buf, sizeof(buf), format, args);
157 va_end(args);
159 mkdir("/var/notice", 0755);
160 snprintf(p, sizeof(p), "/var/notice/%s", path);
161 f_write_string(p, buf, 0, 0);
162 if (buf[0]) syslog(LOG_INFO, "notice[%s]: %s", path, buf);
166 // #define _x_dprintf(args...) syslog(LOG_DEBUG, args);
167 #define _x_dprintf(args...) do { } while (0);
169 int check_wanup(void)
171 int up = 0;
172 int proto;
173 char buf1[64];
174 char buf2[64];
175 const char *name;
176 int f;
177 struct ifreq ifr;
179 proto = get_wan_proto();
180 if (proto == WP_DISABLED) return 0;
182 if ((proto == WP_PPTP) || (proto == WP_L2TP) || (proto == WP_PPPOE)) {
183 if (f_read_string("/tmp/ppp/link", buf1, sizeof(buf1)) > 0) {
184 // contains the base name of a file in /var/run/ containing pid of a daemon
185 snprintf(buf2, sizeof(buf2), "/var/run/%s.pid", buf1);
186 if (f_read_string(buf2, buf1, sizeof(buf1)) > 0) {
187 name = psname(atoi(buf1), buf2, sizeof(buf2));
188 if (proto == WP_PPPOE) {
189 if (strcmp(name, "pppoecd") == 0) up = 1;
191 else {
192 if (strcmp(name, "pppd") == 0) up = 1;
195 else {
196 _dprintf("%s: error reading %s\n", __FUNCTION__, buf2);
198 if (!up) {
199 unlink("/tmp/ppp/link");
200 _x_dprintf("required daemon not found, assuming link is dead\n");
203 else {
204 _x_dprintf("%s: error reading %s\n", __FUNCTION__, "/tmp/ppp/link");
207 else if (!nvram_match("wan_ipaddr", "0.0.0.0")) {
208 up = 1;
210 else {
211 _x_dprintf("%s: default !up\n", __FUNCTION__);
214 if ((up) && ((f = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)) {
215 strlcpy(ifr.ifr_name, nvram_safe_get("wan_iface"), sizeof(ifr.ifr_name));
216 if (ioctl(f, SIOCGIFFLAGS, &ifr) < 0) {
217 up = 0;
218 _x_dprintf("%s: SIOCGIFFLAGS\n", __FUNCTION__);
220 close(f);
221 if ((ifr.ifr_flags & IFF_UP) == 0) {
222 up = 0;
223 _x_dprintf("%s: !IFF_UP\n", __FUNCTION__);
227 return up;
231 const dns_list_t *get_dns(void)
233 static dns_list_t dns;
234 char s[512];
235 int n;
236 int i, j;
237 struct in_addr ia;
238 char d[7][22];
239 unsigned short port;
240 char *c;
242 dns.count = 0;
244 strlcpy(s, nvram_safe_get("wan_dns"), sizeof(s));
245 if ((nvram_get_int("dns_addget")) || (s[0] == 0)) {
246 n = strlen(s);
247 snprintf(s + n, sizeof(s) - n, " %s", nvram_safe_get("wan_get_dns"));
250 n = sscanf(s, "%21s %21s %21s %21s %21s %21s %21s", d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
251 for (i = 0; i < n; ++i) {
252 port = 53;
254 if ((c = strchr(d[i], ':')) != NULL) {
255 *c++ = 0;
256 if (((j = atoi(c)) < 1) || (j > 0xFFFF)) continue;
257 port = j;
260 if (inet_pton(AF_INET, d[i], &ia) > 0) {
261 for (j = dns.count - 1; j >= 0; --j) {
262 if ((dns.dns[j].addr.s_addr == ia.s_addr) && (dns.dns[j].port == port)) break;
264 if (j < 0) {
265 dns.dns[dns.count].port = port;
266 dns.dns[dns.count++].addr.s_addr = ia.s_addr;
267 if (dns.count == 6) break;
272 return &dns;
275 // -----------------------------------------------------------------------------
277 void set_action(int a)
279 int r = 3;
280 while (f_write("/var/lock/action", &a, sizeof(a), 0, 0) != sizeof(a)) {
281 sleep(1);
282 if (--r == 0) return;
284 if (a != ACT_IDLE) sleep(2);
287 int check_action(void)
289 int a;
290 int r = 3;
292 while (f_read("/var/lock/action", &a, sizeof(a)) != sizeof(a)) {
293 sleep(1);
294 if (--r == 0) return ACT_UNKNOWN;
296 return a;
299 int wait_action_idle(int n)
301 while (n-- > 0) {
302 if (check_action() == ACT_IDLE) return 1;
303 sleep(1);
305 return 0;
308 // -----------------------------------------------------------------------------
310 const char *get_wanip(void)
312 const char *p;
314 if (!check_wanup()) return "0.0.0.0";
315 switch (get_wan_proto()) {
316 case WP_DISABLED:
317 return "0.0.0.0";
318 case WP_PPTP:
319 case WP_L2TP:
320 p = "ppp_get_ip";
321 break;
322 default:
323 p = "wan_ipaddr";
324 break;
326 return nvram_safe_get(p);
329 long get_uptime(void)
331 struct sysinfo si;
332 sysinfo(&si);
333 return si.uptime;
336 char *wl_nvname(const char *nv, int unit, int subunit)
338 static char tmp[128];
339 char prefix[] = "wlXXXXXXXXXX_";
341 if (unit < 0)
342 strcpy(prefix, "wl_");
343 else if (subunit > 0)
344 snprintf(prefix, sizeof(prefix), "wl%d.%d_", unit, subunit);
345 else
346 snprintf(prefix, sizeof(prefix), "wl%d_", unit);
347 return strcat_r(prefix, nv, tmp);
350 int get_radio(int unit)
352 uint32 n;
354 return (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_GET_RADIO, &n, sizeof(n)) == 0) &&
355 ((n & WL_RADIO_SW_DISABLE) == 0);
358 void set_radio(int on, int unit)
360 uint32 n;
362 #ifndef WL_BSS_INFO_VERSION
363 #error WL_BSS_INFO_VERSION
364 #endif
366 #if WL_BSS_INFO_VERSION >= 108
367 n = on ? (WL_RADIO_SW_DISABLE << 16) : ((WL_RADIO_SW_DISABLE << 16) | 1);
368 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_SET_RADIO, &n, sizeof(n));
369 if (!on) {
370 led(LED_WLAN, 0);
371 led(LED_DIAG, 0);
373 #else
374 n = on ? 0 : WL_RADIO_SW_DISABLE;
375 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), WLC_SET_RADIO, &n, sizeof(n));
376 if (!on) {
377 led(LED_DIAG, 0);
379 #endif
382 // -----------------------------------------------------------------------------
384 int mtd_getinfo(const char *mtdname, int *part, int *size)
386 FILE *f;
387 char s[256];
388 char t[256];
389 int r;
391 r = 0;
392 if ((strlen(mtdname) < 128) && (strcmp(mtdname, "pmon") != 0)) {
393 sprintf(t, "\"%s\"", mtdname);
394 if ((f = fopen("/proc/mtd", "r")) != NULL) {
395 while (fgets(s, sizeof(s), f) != NULL) {
396 if ((sscanf(s, "mtd%d: %x", part, size) == 2) && (strstr(s, t) != NULL)) {
397 // don't accidentally mess with bl (0)
398 if (*part > 0) r = 1;
399 break;
402 fclose(f);
405 if (!r) {
406 *size = 0;
407 *part = -1;
409 return r;
412 // -----------------------------------------------------------------------------
414 int nvram_get_int(const char *key)
416 return atoi(nvram_safe_get(key));
420 long nvram_xget_long(const char *name, long min, long max, long def)
422 const char *p;
423 char *e;
424 long n;
426 p = nvram_get(name);
427 if ((p != NULL) && (*p != 0)) {
428 n = strtol(p, &e, 0);
429 if ((e != p) && ((*e == 0) || (*e == ' ')) && (n > min) && (n < max)) {
430 return n;
433 return def;
437 int nvram_get_file(const char *key, const char *fname, int max)
439 int n;
440 char *p;
441 char *b;
442 int r;
444 r = 0;
445 p = nvram_safe_get(key);
446 n = strlen(p);
447 if (n <= max) {
448 if ((b = malloc(base64_decoded_len(n) + 128)) != NULL) {
449 n = base64_decode(p, b, n);
450 if (n > 0) r = (f_write(fname, b, n, 0, 0644) == n);
451 free(b);
454 return r;
456 char b[2048];
457 int n;
458 char *p;
460 p = nvram_safe_get(key);
461 n = strlen(p);
462 if (n <= max) {
463 n = base64_decode(p, b, n);
464 if (n > 0) return (f_write(fname, b, n, 0, 0700) == n);
466 return 0;
470 int nvram_set_file(const char *key, const char *fname, int max)
472 char *in;
473 char *out;
474 long len;
475 int n;
476 int r;
478 if ((len = f_size(fname)) > max) return 0;
479 max = (int)len;
480 r = 0;
481 if (f_read_alloc(fname, &in, max) == max) {
482 if ((out = malloc(base64_encoded_len(max) + 128)) != NULL) {
483 n = base64_encode(in, out, max);
484 out[n] = 0;
485 nvram_set(key, out);
486 free(out);
487 r = 1;
489 free(in);
491 return r;
493 char a[2048];
494 char b[4096];
495 int n;
497 if (((n = f_read(fname, &a, sizeof(a))) > 0) && (n <= max)) {
498 n = base64_encode(a, b, n);
499 b[n] = 0;
500 nvram_set(key, b);
501 return 1;
503 return 0;
507 int nvram_contains_word(const char *key, const char *word)
509 return (find_word(nvram_safe_get(key), word) != NULL);
512 int nvram_is_empty(const char *key)
514 char *p;
515 return (((p = nvram_get(key)) == NULL) || (*p == 0));
518 void nvram_commit_x(void)
520 if (!nvram_get_int("debug_nocommit")) nvram_commit();
523 int connect_timeout(int fd, const struct sockaddr *addr, socklen_t len, int timeout)
525 fd_set fds;
526 struct timeval tv;
527 int flags;
528 int n;
529 int r;
531 if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
532 (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) {
533 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
534 return -1;
537 if (connect(fd, addr, len) < 0) {
538 // _dprintf("%s: connect %d = <0\n", __FUNCTION__, fd);
540 if (errno != EINPROGRESS) {
541 _dprintf("%s: error in connect %d errno=%d\n", __FUNCTION__, fd, errno);
542 return -1;
545 while (1) {
546 tv.tv_sec = timeout;
547 tv.tv_usec = 0;
548 FD_ZERO(&fds);
549 FD_SET(fd, &fds);
550 r = select(fd + 1, NULL, &fds, NULL, &tv);
551 if (r == 0) {
552 _dprintf("%s: timeout in select %d\n", __FUNCTION__, fd);
553 return -1;
555 else if (r < 0) {
556 if (errno != EINTR) {
557 _dprintf("%s: error in select %d\n", __FUNCTION__, fd);
558 return -1;
560 // loop
562 else {
563 r = 0;
564 n = sizeof(r);
565 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &n) < 0) || (r != 0)) {
566 _dprintf("%s: error in SO_ERROR %d\n", __FUNCTION__, fd);
567 return -1;
569 break;
574 if (fcntl(fd, F_SETFL, flags) < 0) {
575 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
576 return -1;
579 // _dprintf("%s: OK %d\n", __FUNCTION__, fd);
580 return 0;
583 void chld_reap(int sig)
585 while (waitpid(-1, NULL, WNOHANG) > 0) {}
589 int time_ok(void)
591 return time(0) > Y2K;