Netgear WNR3500L: correct leds behavior
[tomato.git] / release / src / router / rc / misc.c
blobc21dd870bc3b848c518913393e639a6f1532db59
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "rc.h"
10 #include <stdarg.h>
11 #include <sys/ioctl.h>
12 #include <net/if_arp.h>
14 #include <bcmdevs.h>
15 #include <wlutils.h>
16 #include <dirent.h>
17 #include <sys/wait.h>
20 void usage_exit(const char *cmd, const char *help)
22 fprintf(stderr, "Usage: %s %s\n", cmd, help);
23 exit(1);
26 #if 0 // replaced by #define in rc.h
27 int modprobe(const char *mod)
29 #if 1
30 return eval("modprobe", "-s", (char *)mod);
31 #else
32 int r = eval("modprobe", "-s", (char *)mod);
33 cprintf("modprobe %s = %d\n", mod, r);
34 return r;
35 #endif
37 #endif // 0
39 int modprobe_r(const char *mod)
41 #if 1
42 return eval("modprobe", "-r", (char *)mod);
43 #else
44 int r = eval("modprobe", "-r", (char *)mod);
45 cprintf("modprobe -r %s = %d\n", mod, r);
46 return r;
47 #endif
50 #ifndef ct_modprobe
51 #ifdef LINUX26
52 #define ct_modprobe(mod, args...) ({ \
53 modprobe("nf_conntrack_"mod, ## args); \
54 modprobe("nf_nat_"mod); \
56 #else
57 #define ct_modprobe(mod, args...) ({ \
58 modprobe("ip_conntrack_"mod, ## args); \
59 modprobe("ip_nat_"mod, ## args); \
61 #endif
62 #endif
64 #ifndef ct_modprobe_r
65 #ifdef LINUX26
66 #define ct_modprobe_r(mod) ({ \
67 modprobe_r("nf_nat_"mod); \
68 modprobe_r("nf_conntrack_"mod); \
70 #else
71 #define ct_modprobe_r(mod) ({ \
72 modprobe_r("ip_nat_"mod); \
73 modprobe_r("ip_conntrack_"mod); \
75 #endif
76 #endif
78 int _xstart(const char *cmd, ...)
80 va_list ap;
81 char *argv[16];
82 int argc;
83 int pid;
85 argv[0] = (char *)cmd;
86 argc = 1;
87 va_start(ap, cmd);
88 while ((argv[argc++] = va_arg(ap, char *)) != NULL) {
91 va_end(ap);
93 return _eval(argv, NULL, 0, &pid);
96 int endswith (const char *str, char *cmp)
98 int cmp_len, str_len, i;
100 cmp_len = strlen (cmp);
101 str_len = strlen (str);
102 if (cmp_len > str_len)
103 return (0);
104 for (i = 0; i < cmp_len; i++) {
105 if (str[(str_len - 1) - i] != cmp[(cmp_len - 1) - i])
106 return (0);
108 return (1);
112 static void execute_with_maxwait(char *const argv[], int wtime)
114 pid_t pid;
116 if (_eval(argv, NULL, 0, &pid) != 0)
117 pid = -1;
118 else {
119 while (wtime-- > 0) {
120 waitpid(pid, NULL, WNOHANG); /* Reap the zombie if it has terminated. */
121 if (kill(pid, 0) != 0) break;
122 sleep(1);
124 //printf("killdon: errno: %d pid %d\n", errno, pid);
128 /* This is a bit ugly. Why didn't they allow another parameter to filter???? */
129 static char *filter_extension;
130 static int endswith_filter(const struct dirent *entry)
132 return endswith(entry->d_name, filter_extension);
135 void run_userfile(char *folder, char *extension, const char *arg1, int wtime)
137 unsigned char buf[128];
138 char *argv[3];
139 struct dirent **namelist;
140 int i, n;
142 /* Do them in sorted order. */
143 filter_extension = extension;
144 n = scandir(folder, &namelist, endswith_filter, alphasort);
145 if (n <= 0)
146 return;
147 else {
148 for (i = 0; i < n; ++i) {
149 sprintf (buf, "%s/%s", folder, namelist[i]->d_name);
150 argv[0] = buf;
151 argv[1] = (char *)arg1;
152 argv[2] = NULL;
153 execute_with_maxwait(argv, wtime);
154 free(namelist[i]);
156 free(namelist);
161 /* Run user-supplied script(s), with 1 argument.
162 * Return when the script(s) have finished,
163 * or after wtime seconds, even if they aren't finished.
165 * Extract NAME from nvram variable named as "script_NAME".
167 * The sole exception to the nvram item naming rule is sesx.
168 * That one is "sesx_script" rather than "script_sesx", due
169 * to historical accident.
171 * The other exception is time-scheduled commands.
172 * These have names that start with "sch_".
173 * No directories are searched for corresponding user scripts.
175 * Execute in this order:
176 * nvram item: nv (run as a /bin/sh script)
177 * All files with a suffix of ".NAME" in these directories:
178 * /etc/config/
179 * /jffs/etc/config/
180 * /opt/etc/config/
181 * /mmc/etc/config/
182 * /tmp/config/
185 At this time, the names/events are:
186 (Unless otherwise noted, there are no parameters. Otherwise, one parameter).
187 sesx SES/AOSS Button custom script. Param: ??
188 brau "bridge/auto" button pushed. Param: mode (bridge/auto/etc)
189 fire When firewall service has been started or re-started.
190 shut At system shutdown, just before wan/lan/usb/etc. are stopped.
191 init At system startup, just before wan/lan/usb/etc. are started.
192 The root filesystem and /jffs are mounted, but not any USB devices.
193 usbmount After an auto-mounted USB drive is mounted.
194 usbumount Before an auto-mounted USB drive is unmounted.
195 usbhotplug When any USB device is attached or removed.
196 wanup After WAN has come up.
197 autostop When a USB partition gets un-mounted. Param: the mount-point (directory).
198 If unmounted from the GUI, the directory is still mounted and accessible.
199 If the USB drive was unplugged, it is still mounted but not accessible.
201 User scripts -- no directories are searched. One parameter.
202 autorun When a USB disk partition gets auto-mounted. Param: the mount-point (directory).
203 But not if the partition was already mounted.
204 Only the files in that directory will be run.
206 void run_nvscript(const char *nv, const char *arg1, int wtime)
208 FILE *f;
209 char *script;
210 char s[256];
211 char *argv[3];
212 int check_dirs = 1;
214 script = nvram_get(nv);
215 if ((script) && (*script != 0)) {
216 sprintf(s, "/tmp/%s.sh", nv);
217 if ((f = fopen(s, "w")) != NULL) {
218 fputs("#!/bin/sh\n", f);
219 fputs(script, f);
220 fputs("\n", f);
221 fclose(f);
222 chmod(s, 0700);
224 chdir("/tmp");
226 argv[0] = s;
227 argv[1] = (char *)arg1;
228 argv[2] = NULL;
230 //printf("Running: '%s %s'\n", argv[0], argv[1]? argv[1]: "");
231 execute_with_maxwait(argv, wtime);
232 chdir("/");
236 sprintf(s, ".%s", nv);
237 if (strncmp("sch_c", nv, 5) == 0) {
238 check_dirs = 0;
240 else if (strncmp("sesx_", nv, 5) == 0) {
241 s[5] = 0;
243 else if (strncmp("script_", nv, 7) == 0) {
244 strcpy(&s[1], &nv[7]);
247 if (nvram_match("userfiles_disable", "1")) {
248 // backdoor to disable user scripts execution
249 check_dirs = 0;
252 if ((check_dirs) && strcmp(s, ".")) {
253 //printf("checking for user scripts: '%s'\n", s);
254 run_userfile("/etc/config", s, arg1, wtime);
255 run_userfile("/jffs/etc/config", s, arg1, wtime);
256 run_userfile("/opt/etc/config", s, arg1, wtime);
257 run_userfile("/mmc/etc/config", s, arg1, wtime);
258 run_userfile("/tmp/config", s, arg1, wtime);
262 static void write_ct_timeout(const char *type, const char *name, unsigned int val)
264 unsigned char buf[128];
265 char v[16];
267 sprintf(buf, "/proc/sys/net/ipv4/netfilter/ip_conntrack_%s_timeout%s%s",
268 type, (name && name[0]) ? "_" : "", name ? name : "");
269 sprintf(v, "%u", val);
271 f_write_string(buf, v, 0, 0);
274 #ifndef write_tcp_timeout
275 #define write_tcp_timeout(name, val) write_ct_timeout("tcp", name, val)
276 #endif
278 #ifndef write_udp_timeout
279 #define write_udp_timeout(name, val) write_ct_timeout("udp", name, val)
280 #endif
282 static unsigned int read_ct_timeout(const char *type, const char *name)
284 unsigned char buf[128];
285 unsigned int val = 0;
286 char v[16];
288 sprintf(buf, "/proc/sys/net/ipv4/netfilter/ip_conntrack_%s_timeout%s%s",
289 type, (name && name[0]) ? "_" : "", name ? name : "");
290 if (f_read_string(buf, v, sizeof(v)) > 0)
291 val = atoi(v);
293 return val;
296 #ifndef read_tcp_timeout
297 #define read_tcp_timeout(name) read_ct_timeout("tcp", name)
298 #endif
300 #ifndef read_udp_timeout
301 #define read_udp_timeout(name) read_ct_timeout("udp", name)
302 #endif
304 void setup_conntrack(void)
306 unsigned int v[10];
307 const char *p;
308 char buf[70];
309 int i;
311 p = nvram_safe_get("ct_tcp_timeout");
312 if (sscanf(p, "%u%u%u%u%u%u%u%u%u%u",
313 &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]) == 10) { // lightly verify
314 write_tcp_timeout("established", v[1]);
315 write_tcp_timeout("syn_sent", v[2]);
316 write_tcp_timeout("syn_recv", v[3]);
317 write_tcp_timeout("fin_wait", v[4]);
318 write_tcp_timeout("time_wait", v[5]);
319 write_tcp_timeout("close", v[6]);
320 write_tcp_timeout("close_wait", v[7]);
321 write_tcp_timeout("last_ack", v[8]);
323 else {
324 v[1] = read_tcp_timeout("established");
325 v[2] = read_tcp_timeout("syn_sent");
326 v[3] = read_tcp_timeout("syn_recv");
327 v[4] = read_tcp_timeout("fin_wait");
328 v[5] = read_tcp_timeout("time_wait");
329 v[6] = read_tcp_timeout("close");
330 v[7] = read_tcp_timeout("close_wait");
331 v[8] = read_tcp_timeout("last_ack");
332 sprintf(buf, "0 %u %u %u %u %u %u %u %u 0",
333 v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
334 nvram_set("ct_tcp_timeout", buf);
337 p = nvram_safe_get("ct_udp_timeout");
338 if (sscanf(p, "%u%u", &v[0], &v[1]) == 2) {
339 write_udp_timeout(NULL, v[0]);
340 write_udp_timeout("stream", v[1]);
342 else {
343 v[0] = read_udp_timeout(NULL);
344 v[1] = read_udp_timeout("stream");
345 sprintf(buf, "%u %u", v[0], v[1]);
346 nvram_set("ct_udp_timeout", buf);
349 p = nvram_safe_get("ct_timeout");
350 if (sscanf(p, "%u%u", &v[0], &v[1]) == 2) {
351 write_ct_timeout("generic", NULL, v[0]);
352 write_ct_timeout("icmp", NULL, v[1]);
354 else {
355 v[0] = read_ct_timeout("generic", NULL);
356 v[1] = read_ct_timeout("icmp", NULL);
357 sprintf(buf, "%u %u", v[0], v[1]);
358 nvram_set("ct_timeout", buf);
361 #ifdef LINUX26
362 p = nvram_safe_get("ct_hashsize");
363 i = atoi(p);
364 if (i >= 127) {
365 f_write_string("/sys/module/nf_conntrack/parameters/hashsize", p, 0, 0);
367 else if (f_read_string("/sys/module/nf_conntrack/parameters/hashsize", buf, sizeof(buf)) > 0) {
368 if (atoi(buf) > 0) nvram_set("ct_hashsize", buf);
370 #endif
372 p = nvram_safe_get("ct_max");
373 i = atoi(p);
374 if (i >= 128) {
375 f_write_string("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", p, 0, 0);
377 else if (f_read_string("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", buf, sizeof(buf)) > 0) {
378 if (atoi(buf) > 0) nvram_set("ct_max", buf);
381 if (!nvram_match("nf_pptp", "0")) {
382 ct_modprobe("proto_gre");
383 ct_modprobe("pptp");
385 else {
386 ct_modprobe_r("pptp");
387 ct_modprobe_r("proto_gre");
390 if (!nvram_match("nf_h323", "0")) {
391 ct_modprobe("h323");
393 else {
394 ct_modprobe_r("h323");
397 #ifdef LINUX26
398 if (!nvram_match("nf_sip", "0")) {
399 ct_modprobe("sip");
401 else {
402 ct_modprobe_r("sip");
404 #endif
406 if (!nvram_match("nf_rtsp", "0")) {
407 ct_modprobe("rtsp");
409 else {
410 ct_modprobe_r("rtsp");
413 // !!TB - FTP Server
414 #ifdef TCONFIG_FTP
415 i = nvram_get_int("ftp_port");
416 if (nvram_match("ftp_enable", "1") && (i > 0) && (i != 21))
418 char ports[32];
420 sprintf(ports, "ports=21,%d", i);
421 ct_modprobe("ftp", ports);
423 else
424 #endif
425 if (!nvram_match("nf_ftp", "0")
426 #ifdef TCONFIG_FTP
427 || nvram_match("ftp_enable", "1") // !!TB - FTP Server
428 #endif
430 ct_modprobe("ftp");
432 else {
433 ct_modprobe_r("ftp");
438 void set_mac(const char *ifname, const char *nvname, int plus)
440 int sfd;
441 struct ifreq ifr;
442 int up;
443 int j;
445 if ((sfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
446 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
447 return;
450 strcpy(ifr.ifr_name, ifname);
452 up = 0;
453 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0) {
454 if ((up = ifr.ifr_flags & IFF_UP) != 0) {
455 ifr.ifr_flags &= ~IFF_UP;
456 if (ioctl(sfd, SIOCSIFFLAGS, &ifr) != 0) {
457 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
461 else {
462 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
465 if (!ether_atoe(nvram_safe_get(nvname), (unsigned char *)&ifr.ifr_hwaddr.sa_data)) {
466 if (!ether_atoe(nvram_safe_get("et0macaddr"), (unsigned char *)&ifr.ifr_hwaddr.sa_data)) {
468 // goofy et0macaddr, make something up
469 nvram_set("et0macaddr", "00:01:23:45:67:89");
470 ifr.ifr_hwaddr.sa_data[0] = 0;
471 ifr.ifr_hwaddr.sa_data[1] = 0x01;
472 ifr.ifr_hwaddr.sa_data[2] = 0x23;
473 ifr.ifr_hwaddr.sa_data[3] = 0x45;
474 ifr.ifr_hwaddr.sa_data[4] = 0x67;
475 ifr.ifr_hwaddr.sa_data[5] = 0x89;
478 while (plus-- > 0) {
479 for (j = 5; j >= 3; --j) {
480 ifr.ifr_hwaddr.sa_data[j]++;
481 if (ifr.ifr_hwaddr.sa_data[j] != 0) break; // continue if rolled over
486 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
487 if (ioctl(sfd, SIOCSIFHWADDR, &ifr) == -1) {
488 _dprintf("Error setting %s address\n", ifname);
491 if (up) {
492 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0) {
493 ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
494 if (ioctl(sfd, SIOCSIFFLAGS, &ifr) == -1) {
495 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
498 else {
499 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
503 close(sfd);
507 const char *default_wanif(void)
509 return ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) ||
510 (check_hw_type() == HW_BCM4712)) ? "vlan1" : "eth1";
515 const char *default_wlif(void)
517 switch (check_hw_type()) {
518 case HW_BCM4702:
519 case HW_BCM4704_BCM5325F:
520 case HW_BCM4704_BCM5325F_EWC:
521 return "eth2";
523 return "eth1";
528 int _vstrsep(char *buf, const char *sep, ...)
530 va_list ap;
531 char **p;
532 int n;
534 n = 0;
535 va_start(ap, sep);
536 while ((p = va_arg(ap, char **)) != NULL) {
537 if ((*p = strsep(&buf, sep)) == NULL) break;
538 ++n;
540 va_end(ap);
541 return n;
544 void simple_unlock(const char *name)
546 char fn[256];
548 snprintf(fn, sizeof(fn), "/var/lock/%s.lock", name);
549 f_write(fn, NULL, 0, 0, 0600);
552 void simple_lock(const char *name)
554 int n;
555 char fn[256];
557 n = 5 + (getpid() % 10);
558 snprintf(fn, sizeof(fn), "/var/lock/%s.lock", name);
559 while (unlink(fn) != 0) {
560 if (--n == 0) {
561 syslog(LOG_DEBUG, "Breaking %s", fn);
562 break;
564 sleep(1);
568 void killall_tk(const char *name)
570 int n;
572 if (killall(name, SIGTERM) == 0) {
573 n = 5;
574 while ((killall(name, 0) == 0) && (n-- > 0)) {
575 _dprintf("%s: waiting name=%s n=%d\n", __FUNCTION__, name, n);
576 sleep(1);
578 if (n < 0) {
579 n = 5;
580 while ((killall(name, SIGKILL) == 0) && (n-- > 0)) {
581 _dprintf("%s: SIGKILL name=%s n=%d\n", __FUNCTION__, name, n);
582 sleep(2);
588 long fappend(FILE *out, const char *fname)
590 FILE *in;
591 char buf[1024];
592 int n;
593 long r;
595 if ((in = fopen(fname, "r")) == NULL) return -1;
596 r = 0;
597 while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
598 if (fwrite(buf, 1, n, out) != n) {
599 r = -1;
600 break;
602 else {
603 r += n;
606 fclose(in);
607 return r;