Merge Tomato 1.26
[tomato.git] / release / src / router / shared / misc.c
blobf8ddcb020447abd8cc02d87da08cf5997cd2fb76
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>
22 #include <bcmnvram.h>
23 #include <bcmdevs.h>
24 #include <wlutils.h>
26 #include "shutils.h"
27 #include "shared.h"
29 #if 0
30 #define _dprintf cprintf
31 #else
32 #define _dprintf(args...) do { } while(0)
33 #endif
36 int get_wan_proto(void)
38 const char *names[] = { // order must be synced with def at shared.h
39 "static",
40 "dhcp",
41 "l2tp",
42 "pppoe",
43 "pptp",
44 NULL
46 int i;
47 const char *p;
49 p = nvram_safe_get("wan_proto");
50 for (i = 0; names[i] != NULL; ++i) {
51 if (strcmp(p, names[i]) == 0) return i + 1;
53 return WP_DISABLED;
56 int using_dhcpc(void)
58 switch (get_wan_proto()) {
59 case WP_DHCP:
60 case WP_L2TP:
61 return 1;
63 return 0;
66 int wl_client(void)
68 return ((nvram_match("wl_mode", "sta")) || (nvram_match("wl_mode", "wet")));
71 void notice_set(const char *path, const char *format, ...)
73 char p[256];
74 char buf[2048];
75 va_list args;
77 va_start(args, format);
78 vsnprintf(buf, sizeof(buf), format, args);
79 va_end(args);
81 mkdir("/var/notice", 0755);
82 snprintf(p, sizeof(p), "/var/notice/%s", path);
83 f_write_string(p, buf, 0, 0);
84 if (buf[0]) syslog(LOG_INFO, "notice[%s]: %s", path, buf);
88 // #define _x_dprintf(args...) syslog(LOG_DEBUG, args);
89 #define _x_dprintf(args...) do { } while (0);
91 int check_wanup(void)
93 int up = 0;
94 int proto;
95 char buf1[64];
96 char buf2[64];
97 const char *name;
98 int f;
99 struct ifreq ifr;
101 proto = get_wan_proto();
102 if (proto == WP_DISABLED) return 0;
104 if ((proto == WP_PPTP) || (proto == WP_L2TP) || (proto == WP_PPPOE)) {
105 if (f_read_string("/tmp/ppp/link", buf1, sizeof(buf1)) > 0) {
106 // contains the base name of a file in /var/run/ containing pid of a daemon
107 snprintf(buf2, sizeof(buf2), "/var/run/%s.pid", buf1);
108 if (f_read_string(buf2, buf1, sizeof(buf1)) > 0) {
109 name = psname(atoi(buf1), buf2, sizeof(buf2));
110 if (proto == WP_PPPOE) {
111 if (strcmp(name, "pppoecd") == 0) up = 1;
113 else {
114 if (strcmp(name, "pppd") == 0) up = 1;
117 else {
118 _dprintf("%s: error reading %s\n", __FUNCTION__, buf2);
120 if (!up) {
121 unlink("/tmp/ppp/link");
122 _x_dprintf("required daemon not found, assuming link is dead\n");
125 else {
126 _x_dprintf("%s: error reading %s\n", __FUNCTION__, "/tmp/ppp/link");
129 else if (!nvram_match("wan_ipaddr", "0.0.0.0")) {
130 up = 1;
132 else {
133 _x_dprintf("%s: default !up\n", __FUNCTION__);
136 if ((up) && ((f = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)) {
137 strlcpy(ifr.ifr_name, nvram_safe_get("wan_iface"), sizeof(ifr.ifr_name));
138 if (ioctl(f, SIOCGIFFLAGS, &ifr) < 0) {
139 up = 0;
140 _x_dprintf("%s: SIOCGIFFLAGS\n", __FUNCTION__);
142 close(f);
143 if ((ifr.ifr_flags & IFF_UP) == 0) {
144 up = 0;
145 _x_dprintf("%s: !IFF_UP\n", __FUNCTION__);
149 return up;
153 const dns_list_t *get_dns(void)
155 static dns_list_t dns;
156 char s[512];
157 int n;
158 int i, j;
159 struct in_addr ia;
160 char d[4][22];
161 unsigned short port;
162 char *c;
164 dns.count = 0;
166 strlcpy(s, nvram_safe_get("wan_dns"), sizeof(s));
167 if ((nvram_get_int("dns_addget")) || (s[0] == 0)) {
168 n = strlen(s);
169 snprintf(s + n, sizeof(s) - n, " %s", nvram_safe_get("wan_get_dns"));
172 n = sscanf(s, "%21s %21s %21s %21s", d[0], d[1], d[2], d[3]);
173 for (i = 0; i < n; ++i) {
174 port = 53;
176 if ((c = strchr(d[i], ':')) != NULL) {
177 *c++ = 0;
178 if (((j = atoi(c)) < 1) || (j > 0xFFFF)) continue;
179 port = j;
182 if (inet_pton(AF_INET, d[i], &ia) > 0) {
183 for (j = dns.count - 1; j >= 0; --j) {
184 if ((dns.dns[j].addr.s_addr == ia.s_addr) && (dns.dns[j].port == port)) break;
186 if (j < 0) {
187 dns.dns[dns.count].port = port;
188 dns.dns[dns.count++].addr.s_addr = ia.s_addr;
189 if (dns.count == 3) break;
194 return &dns;
197 // -----------------------------------------------------------------------------
199 void set_action(int a)
201 int r = 3;
202 while (f_write("/var/lock/action", &a, sizeof(a), 0, 0) != sizeof(a)) {
203 sleep(1);
204 if (--r == 0) return;
206 if (a != ACT_IDLE) sleep(2);
209 int check_action(void)
211 int a;
212 int r = 3;
214 while (f_read("/var/lock/action", &a, sizeof(a)) != sizeof(a)) {
215 sleep(1);
216 if (--r == 0) return ACT_UNKNOWN;
218 return a;
221 int wait_action_idle(int n)
223 while (n-- > 0) {
224 if (check_action() == ACT_IDLE) return 1;
225 sleep(1);
227 return 0;
230 // -----------------------------------------------------------------------------
232 const char *get_wanip(void)
234 const char *p;
236 if (!check_wanup()) return "0.0.0.0";
237 switch (get_wan_proto()) {
238 case WP_DISABLED:
239 return "0.0.0.0";
240 case WP_PPTP:
241 p = "pptp_get_ip";
242 break;
243 case WP_L2TP:
244 p = "l2tp_get_ip";
245 break;
246 default:
247 p = "wan_ipaddr";
248 break;
250 return nvram_safe_get(p);
253 long get_uptime(void)
255 struct sysinfo si;
256 sysinfo(&si);
257 return si.uptime;
260 int get_radio(void)
262 uint32 n;
264 return (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_RADIO, &n, sizeof(n)) == 0) &&
265 ((n & WL_RADIO_SW_DISABLE) == 0);
268 void set_radio(int on)
270 uint32 n;
272 #ifndef WL_BSS_INFO_VERSION
273 #error WL_BSS_INFO_VERSION
274 #endif
276 #if WL_BSS_INFO_VERSION >= 108
277 n = on ? (WL_RADIO_SW_DISABLE << 16) : ((WL_RADIO_SW_DISABLE << 16) | 1);
278 wl_ioctl(nvram_safe_get("wl_ifname"), WLC_SET_RADIO, &n, sizeof(n));
279 if (!on) {
280 led(LED_WLAN, 0);
281 led(LED_DIAG, 0);
283 #else
284 n = on ? 0 : WL_RADIO_SW_DISABLE;
285 wl_ioctl(nvram_safe_get("wl_ifname"), WLC_SET_RADIO, &n, sizeof(n));
286 if (!on) {
287 led(LED_DIAG, 0);
289 #endif
292 int nvram_get_int(const char *key)
294 return atoi(nvram_safe_get(key));
298 long nvram_xget_long(const char *name, long min, long max, long def)
300 const char *p;
301 char *e;
302 long n;
304 p = nvram_get(name);
305 if ((p != NULL) && (*p != 0)) {
306 n = strtol(p, &e, 0);
307 if ((e != p) && ((*e == 0) || (*e == ' ')) && (n > min) && (n < max)) {
308 return n;
311 return def;
315 int nvram_get_file(const char *key, const char *fname, int max)
317 int n;
318 char *p;
319 char *b;
320 int r;
322 r = 0;
323 p = nvram_safe_get(key);
324 n = strlen(p);
325 if (n <= max) {
326 if ((b = malloc(base64_decoded_len(n) + 128)) != NULL) {
327 n = base64_decode(p, b, n);
328 if (n > 0) r = (f_write(fname, b, n, 0, 0644) == n);
329 free(b);
332 return r;
334 char b[2048];
335 int n;
336 char *p;
338 p = nvram_safe_get(key);
339 n = strlen(p);
340 if (n <= max) {
341 n = base64_decode(p, b, n);
342 if (n > 0) return (f_write(fname, b, n, 0, 0700) == n);
344 return 0;
348 int nvram_set_file(const char *key, const char *fname, int max)
350 char *in;
351 char *out;
352 long len;
353 int n;
354 int r;
356 if ((len = f_size(fname)) > max) return 0;
357 max = (int)len;
358 r = 0;
359 if (f_read_alloc(fname, &in, max) == max) {
360 if ((out = malloc(base64_encoded_len(max) + 128)) != NULL) {
361 n = base64_encode(in, out, max);
362 out[n] = 0;
363 nvram_set(key, out);
364 free(out);
365 r = 1;
367 free(in);
369 return r;
371 char a[2048];
372 char b[4096];
373 int n;
375 if (((n = f_read(fname, &a, sizeof(a))) > 0) && (n <= max)) {
376 n = base64_encode(a, b, n);
377 b[n] = 0;
378 nvram_set(key, b);
379 return 1;
381 return 0;
385 int nvram_contains_word(const char *key, const char *word)
387 return (find_word(nvram_safe_get(key), word) != NULL);
390 int nvram_is_empty(const char *key)
392 char *p;
393 return (((p = nvram_get(key)) == NULL) || (*p == 0));
396 void nvram_commit_x(void)
398 if (!nvram_get_int("debug_nocommit")) nvram_commit();
401 int connect_timeout(int fd, const struct sockaddr *addr, socklen_t len, int timeout)
403 fd_set fds;
404 struct timeval tv;
405 int flags;
406 int n;
407 int r;
409 if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
410 (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) {
411 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
412 return -1;
415 if (connect(fd, addr, len) < 0) {
416 // _dprintf("%s: connect %d = <0\n", __FUNCTION__, fd);
418 if (errno != EINPROGRESS) {
419 _dprintf("%s: error in connect %d errno=%d\n", __FUNCTION__, fd, errno);
420 return -1;
423 while (1) {
424 tv.tv_sec = timeout;
425 tv.tv_usec = 0;
426 FD_ZERO(&fds);
427 FD_SET(fd, &fds);
428 r = select(fd + 1, NULL, &fds, NULL, &tv);
429 if (r == 0) {
430 _dprintf("%s: timeout in select %d\n", __FUNCTION__, fd);
431 return -1;
433 else if (r < 0) {
434 if (errno != EINTR) {
435 _dprintf("%s: error in select %d\n", __FUNCTION__, fd);
436 return -1;
438 // loop
440 else {
441 r = 0;
442 n = sizeof(r);
443 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &n) < 0) || (r != 0)) {
444 _dprintf("%s: error in SO_ERROR %d\n", __FUNCTION__, fd);
445 return -1;
447 break;
452 if (fcntl(fd, F_SETFL, flags) < 0) {
453 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
454 return -1;
457 // _dprintf("%s: OK %d\n", __FUNCTION__, fd);
458 return 0;
462 int time_ok(void)
464 return time(0) > Y2K;