4 Copyright (C) 2006-2009 Jonathan Zarate
15 #include <sys/ioctl.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
21 #include <sys/sysinfo.h>
22 #include <sys/types.h>
33 int get_wan_proto(void)
35 const char *names
[] = { // order must be synced with def at shared.h
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;
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
63 "other", // IPV6_MANUAL
65 "6rd-pd", // IPV6_6RD_DHCP
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;
78 const char *ipv6_router_address(struct in6_addr
*in6addr
)
82 static char addr6
[INET6_ADDRSTRLEN
];
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);
97 inet_ntop(AF_INET6
, &addr
, addr6
, sizeof(addr6
));
99 memcpy(in6addr
, &addr
, sizeof(addr
));
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
;
113 if (!prefix
|| !local_ip
|| !local_prefix
|| !local_prefix_len
) {
117 *local_prefix_len
= prefix_len
+ 32 - relay_prefix_len
;
118 if (*local_prefix_len
> 64) {
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));
138 int using_dhcpc(void)
140 switch (get_wan_proto()) {
146 return nvram_get_int("pptp_dhcp");
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
))
162 char name
[64], ifname
[64], *next
= NULL
;
163 int unit
= -1, subunit
= -1;
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
));
182 foreach(name
, ifnames
, next
) {
183 if (nvifname_to_osifname(name
, ifname
, sizeof(ifname
)) != 0)
186 if (wl_probe(ifname
) || wl_ioctl(ifname
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
)))
189 // Convert eth name to wl name
190 if (osifname_to_nvifname(name
, ifname
, sizeof(ifname
)) != 0)
193 // Slave intefaces have a '.' in the name
194 if (strchr(ifname
, '.') && !include_vifs
)
197 if (get_ifname_unit(ifname
, &unit
, &subunit
) < 0)
200 ret
|= func(i
++, unit
, subunit
, param
);
205 void notice_set(const char *path
, const char *format
, ...)
211 va_start(args
, format
);
212 vsnprintf(buf
, sizeof(buf
), format
, 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)
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
);
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;
268 _dprintf("%s: error reading %s\n", __FUNCTION__
, buf2
);
271 unlink("/tmp/ppp/link");
272 _x_dprintf("required daemon not found, assuming link is dead\n");
276 _x_dprintf("%s: error reading %s\n", __FUNCTION__
, "/tmp/ppp/link");
279 else if (!nvram_match("wan_ipaddr", "0.0.0.0")) {
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) {
290 _x_dprintf("%s: SIOCGIFFLAGS\n", __FUNCTION__
);
293 if ((ifr
.ifr_flags
& IFF_UP
) == 0) {
295 _x_dprintf("%s: !IFF_UP\n", __FUNCTION__
);
298 if (nvram_match("boardrev", "0x11")) { // Ovislink 1600GL - led "connected" on
301 if (nvram_match("boardtype", "0x052b") && nvram_match("boardrev", "0x1204")) { //rt-n15u wan led on
304 if (nvram_match("model", "RT-N18U")) {
307 if (get_model() == MODEL_DIR868L
) {
310 if (get_model() == MODEL_WS880
) {
313 if (get_model() == MODEL_R6250
) {
320 const dns_list_t
*get_dns(void)
322 static dns_list_t dns
;
333 strlcpy(s
, nvram_safe_get("wan_dns"), sizeof(s
));
334 if ((nvram_get_int("dns_addget")) || (s
[0] == 0)) {
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
) {
343 if ((c
= strchr(d
[i
], ':')) != NULL
) {
345 if (((j
= atoi(c
)) < 1) || (j
> 0xFFFF)) continue;
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;
354 dns
.dns
[dns
.count
].port
= port
;
355 dns
.dns
[dns
.count
++].addr
.s_addr
= ia
.s_addr
;
356 if (dns
.count
== 6) break;
364 // -----------------------------------------------------------------------------
366 void set_action(int a
)
369 while (f_write("/var/lock/action", &a
, sizeof(a
), 0, 0) != sizeof(a
)) {
371 if (--r
== 0) return;
373 if (a
!= ACT_IDLE
) sleep(2);
376 int check_action(void)
381 while (f_read("/var/lock/action", &a
, sizeof(a
)) != sizeof(a
)) {
383 if (--r
== 0) return ACT_UNKNOWN
;
388 int wait_action_idle(int n
)
391 if (check_action() == ACT_IDLE
) return 1;
397 // -----------------------------------------------------------------------------
399 const wanface_list_t
*get_wanfaces(void)
401 static wanface_list_t wanfaces
;
407 switch ((proto
= get_wan_proto())) {
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))
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
);
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");
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
);
447 const char *get_wanface(void)
449 return (*get_wanfaces()).iface
[0].name
;
453 const char *get_wan6face(void)
455 switch (get_ipv6_service()) {
457 case IPV6_NATIVE_DHCP
:
458 return get_wanface();
459 case IPV6_ANYCAST_6TO4
:
464 return nvram_safe_get("ipv6_ifname");
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
];
479 struct ifaddrs
*ifap
, *ifa
;
481 if (getifaddrs(&ifap
) != 0) {
482 _dprintf("getifaddrs failed: %s\n", strerror(errno
));
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
))
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
)
497 addr
= (void *)&(s6
->sin6_addr
);
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
) {
516 // -----------------------------------------------------------------------------
518 long get_uptime(void)
525 char *wl_nvname(const char *nv
, int unit
, int subunit
)
527 static char tmp
[128];
528 char prefix
[] = "wlXXXXXXXXXX_";
531 strcpy(prefix
, "wl_");
532 else if (subunit
> 0)
533 snprintf(prefix
, sizeof(prefix
), "wl%d.%d_", unit
, subunit
);
535 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
536 return strcat_r(prefix
, nv
, tmp
);
539 int get_radio(int unit
)
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
)
551 #ifndef WL_BSS_INFO_VERSION
552 #error WL_BSS_INFO_VERSION
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
));
559 if (unit
== 0) led(LED_WLAN
, LED_OFF
);
560 else led(LED_5G
, LED_OFF
);
562 if (unit
== 0) led(LED_WLAN
, LED_ON
);
563 else led(LED_5G
, LED_ON
);
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
));
569 led(LED_WLAN
, LED_OFF
);
571 led(LED_WLAN
, LED_ON
);
576 // -----------------------------------------------------------------------------
578 int mtd_getinfo(const char *mtdname
, int *part
, int *size
)
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;
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)
621 if ((p != NULL) && (*p != 0)) {
622 n = strtol(p, &e, 0);
623 if ((e != p) && ((*e == 0) || (*e == ' ')) && (n > min) && (n < max)) {
631 int nvram_get_file(const char *key
, const char *fname
, int max
)
639 p
= nvram_safe_get(key
);
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
);
654 p = nvram_safe_get(key);
657 n = base64_decode(p, b, n);
658 if (n > 0) return (f_write(fname, b, n, 0, 0700) == n);
664 int nvram_set_file(const char *key
, const char *fname
, int max
)
672 if ((len
= f_size(fname
)) > max
) return 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
);
691 if (((n = f_read(fname, &a, sizeof(a))) > 0) && (n <= max)) {
692 n = base64_encode(a, b, n);
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
)
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
)
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
);
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
);
744 r
= select(fd
+ 1, NULL
, &fds
, NULL
, &tv
);
746 _dprintf("%s: timeout in select %d\n", __FUNCTION__
, fd
);
750 if (errno
!= EINTR
) {
751 _dprintf("%s: error in select %d\n", __FUNCTION__
, fd
);
759 if ((getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &r
, &n
) < 0) || (r
!= 0)) {
760 _dprintf("%s: error in SO_ERROR %d\n", __FUNCTION__
, fd
);
768 if (fcntl(fd
, F_SETFL
, flags
) < 0) {
769 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__
, fd
);
773 // _dprintf("%s: OK %d\n", __FUNCTION__, fd);
777 void chld_reap(int sig
)
779 while (waitpid(-1, NULL
, WNOHANG
) > 0) {}
785 return time(0) > Y2K;