You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
660 lines
19 KiB
C
660 lines
19 KiB
C
/*
|
|
|
|
Copyright 2003, CyberTAN Inc. All Rights Reserved
|
|
|
|
This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
|
|
the contents of this file may not be disclosed to third parties,
|
|
copied or duplicated in any form without the prior written
|
|
permission of CyberTAN Inc.
|
|
|
|
This software should be used as a reference only, and it not
|
|
intended for production use!
|
|
|
|
THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
|
|
KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
|
|
SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
|
|
|
|
*/
|
|
/*
|
|
|
|
Copyright 2005, Broadcom Corporation
|
|
All Rights Reserved.
|
|
|
|
THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
|
KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
|
SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
|
|
|
*/
|
|
/*
|
|
|
|
Modified for Tomato Firmware
|
|
Portions, Copyright (C) 2006-2009 Jonathan Zarate
|
|
|
|
*/
|
|
|
|
|
|
#include "rc.h"
|
|
|
|
#include <sys/sysinfo.h>
|
|
#include <sys/ioctl.h>
|
|
#include <arpa/inet.h>
|
|
|
|
/* needed by logmsg() */
|
|
#define LOGMSG_DISABLE DISABLE_SYSLOG_OS
|
|
#define LOGMSG_NVDEBUG "dhcp_debug"
|
|
|
|
|
|
static void expires(unsigned int seconds, char *prefix)
|
|
{
|
|
struct sysinfo info;
|
|
char s[32];
|
|
char buf[64];
|
|
|
|
sysinfo(&info);
|
|
memset(s, 0, sizeof(s));
|
|
snprintf(s, sizeof(s), "%u", (unsigned int)info.uptime + seconds);
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
snprintf(buf, sizeof(buf), "/var/lib/misc/dhcpc-%s.expires", prefix);
|
|
f_write_string(buf, s, 0, 0);
|
|
}
|
|
|
|
static void do_renew_file(unsigned int renew, char *prefix)
|
|
{
|
|
char buf[64];
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
snprintf(buf, sizeof(buf), "/var/lib/misc/%s_dhcpc.renewing", prefix);
|
|
|
|
if (renew)
|
|
f_write(buf, NULL, 0, 0, 0);
|
|
else
|
|
unlink(buf);
|
|
}
|
|
|
|
void do_connect_file(unsigned int connect, char *prefix)
|
|
{
|
|
char buf[64];
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
snprintf(buf, sizeof(buf), "/var/lib/misc/%s.connecting", prefix);
|
|
|
|
if (connect)
|
|
f_write(buf, NULL, 0, 0, 0);
|
|
else
|
|
unlink(buf);
|
|
}
|
|
|
|
/* copy env to nvram
|
|
* returns 1 if new/changed, 0 if not changed/no env
|
|
*/
|
|
static int env2nv(char *env, char *nv)
|
|
{
|
|
char *value;
|
|
if ((value = getenv(env)) != NULL) {
|
|
if (!nvram_match(nv, value)) {
|
|
nvram_set(nv, value);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int env2nv_gateway(const char *nv)
|
|
{
|
|
char *v, *g;
|
|
char *b;
|
|
int r = 0;
|
|
|
|
if ((v = getenv("router")) != NULL) {
|
|
if ((b = strdup(v)) != NULL) {
|
|
if ((v = strchr(b, ' ')) != NULL) /* truncate multiple entries */
|
|
*v = 0;
|
|
if (!nvram_match((char *)nv, b)) {
|
|
nvram_set(nv, b);
|
|
r = 1;
|
|
}
|
|
free(b);
|
|
}
|
|
}
|
|
else if ((v = getenv("staticroutes")) != NULL) {
|
|
if ((b = strdup(v)) == NULL)
|
|
return 0;
|
|
|
|
v = b;
|
|
while ((g = strsep(&v, " ")) != NULL) {
|
|
if (strcmp(g, "0.0.0.0/0") == 0) {
|
|
if ((g = strsep(&v, " ")) && *g) {
|
|
if (!nvram_match((char *)nv, g)) {
|
|
nvram_set(nv, g);
|
|
r = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free(b);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static int deconfig(char *ifname, char *prefix)
|
|
{
|
|
char tmp[32];
|
|
|
|
ifconfig(ifname, IFUP, "0.0.0.0", NULL);
|
|
|
|
if (using_dhcpc(prefix)) {
|
|
nvram_set(strcat_r(prefix, "_ipaddr", tmp), "0.0.0.0");
|
|
nvram_set(strcat_r(prefix, "_netmask", tmp), "0.0.0.0");
|
|
nvram_set(strcat_r(prefix, "_gateway", tmp), "0.0.0.0");
|
|
}
|
|
nvram_set(strcat_r(prefix, "_lease", tmp), "0");
|
|
nvram_set(strcat_r(prefix, "_routes1", tmp), "");
|
|
nvram_set(strcat_r(prefix, "_routes2", tmp), "");
|
|
expires(0, prefix);
|
|
|
|
if ((get_wanx_proto(prefix) == WP_DHCP) || (get_wanx_proto(prefix) == WP_LTE)) {
|
|
nvram_set(strcat_r(prefix, "_netmask", tmp), "0.0.0.0");
|
|
nvram_set(strcat_r(prefix, "_gateway_get", tmp), "0.0.0.0");
|
|
nvram_set(strcat_r(prefix, "_get_dns", tmp), "");
|
|
}
|
|
|
|
#ifdef TCONFIG_IPV6
|
|
nvram_set("wan_6rd", "");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bound(char *ifname, int renew, char *prefix)
|
|
{
|
|
char tmp [32];
|
|
char *netmask, *dns, *gw;
|
|
int wan_proto = get_wanx_proto(prefix);
|
|
|
|
do_renew_file(0, prefix);
|
|
|
|
logmsg(LOG_DEBUG, "*** IN %s: interface=%s, wan_prefix=%s, renew=%d, proto=%d", __FUNCTION__, ifname, prefix, renew, wan_proto);
|
|
|
|
nvram_set(strcat_r(prefix, "_routes1", tmp), "");
|
|
nvram_set(strcat_r(prefix, "_routes2", tmp), "");
|
|
env2nv("ip", strcat_r(prefix, "_ipaddr", tmp));
|
|
env2nv_gateway(strcat_r(prefix, "_gateway", tmp));
|
|
env2nv("dns", strcat_r(prefix, "_get_dns", tmp));
|
|
env2nv("domain", strcat_r(prefix, "_get_domain", tmp));
|
|
env2nv("lease", strcat_r(prefix, "_lease", tmp));
|
|
netmask = getenv("subnet") ? : "255.255.255.255";
|
|
if ((wan_proto == WP_DHCP) || (wan_proto == WP_LTE) || (using_dhcpc(prefix))) { /* netmask for DHCP MAN */
|
|
nvram_set(strcat_r(prefix, "_netmask", tmp), netmask);
|
|
nvram_set(strcat_r(prefix, "_gateway_get", tmp), nvram_safe_get(strcat_r(prefix, "_gateway", tmp)));
|
|
}
|
|
|
|
/* RFC3442: If the DHCP server returns both a Classless Static Routes option
|
|
* and a Router option, the DHCP client MUST ignore the Router option.
|
|
* Similarly, if the DHCP server returns both a Classless Static Routes
|
|
* option and a Static Routes option, the DHCP client MUST ignore the
|
|
* Static Routes option.
|
|
* Ref: http://www.faqs.org/rfcs/rfc3442.html
|
|
*/
|
|
/* Classless Static Routes (option 121) */
|
|
if (!env2nv("staticroutes", strcat_r(prefix, "_routes1", tmp)))
|
|
/* or MS Classless Static Routes (option 249) */
|
|
env2nv("msstaticroutes", strcat_r(prefix, "_routes1", tmp));
|
|
|
|
/* Static Routes (option 33) */
|
|
env2nv("routes", strcat_r(prefix, "_routes2", tmp));
|
|
|
|
expires(atoi(safe_getenv("lease")), prefix);
|
|
|
|
#ifdef TCONFIG_IPV6
|
|
env2nv("ip6rd", "wan_6rd");
|
|
#endif
|
|
|
|
logmsg(LOG_DEBUG, "*** %s: %s_ipaddr=%s", __FUNCTION__, prefix, nvram_safe_get(strcat_r(prefix, "_ipaddr", tmp)));
|
|
logmsg(LOG_DEBUG, "*** %s: %s_netmask=%s", __FUNCTION__, prefix, netmask);
|
|
logmsg(LOG_DEBUG, "*** %s: %s_gateway=%s", __FUNCTION__, prefix, nvram_safe_get(strcat_r(prefix, "_gateway", tmp)));
|
|
logmsg(LOG_DEBUG, "*** %s: %s_get_dns=%s", __FUNCTION__, prefix, nvram_safe_get(strcat_r(prefix, "_get_dns", tmp)));
|
|
logmsg(LOG_DEBUG, "*** %s: %s_routes1=%s", __FUNCTION__, prefix, nvram_safe_get(strcat_r(prefix, "_routes1", tmp)));
|
|
logmsg(LOG_DEBUG, "*** %s: %s_routes2=%s", __FUNCTION__, prefix, nvram_safe_get(strcat_r(prefix, "_routes2", tmp)));
|
|
|
|
ifconfig(ifname, IFUP, "0.0.0.0", NULL);
|
|
ifconfig(ifname, IFUP, nvram_safe_get(strcat_r(prefix, "_ipaddr", tmp)), netmask);
|
|
|
|
if ((wan_proto != WP_DHCP) && (wan_proto != WP_LTE)) {
|
|
|
|
/* setup dnsmasq and routes to dns / access servers */
|
|
gw = nvram_safe_get(strcat_r(prefix, "_gateway", tmp));
|
|
if ((*gw) && (strcmp(gw, "0.0.0.0") != 0)) {
|
|
logmsg(LOG_DEBUG, "*** %s: do preset_wan ... ifname=%s gateway=%s netmask=%s prefix=%s", __FUNCTION__, ifname, gw, netmask, prefix);
|
|
preset_wan(ifname, gw, netmask, prefix);
|
|
}
|
|
else {
|
|
logmsg(LOG_DEBUG, "*** %s: NO gateway! Just do DHCP DNS stuff ...", __FUNCTION__);
|
|
dns_to_resolv();
|
|
}
|
|
/* don't clear dns servers for PPTP/L2TP wans, required for pptp/l2tp server name resolution */
|
|
dns = nvram_safe_get(strcat_r(prefix, "_get_dns", tmp));
|
|
if (wan_proto != WP_PPTP && wan_proto != WP_L2TP) {
|
|
nvram_set(strcat_r(prefix, "_get_dns", tmp), renew ? dns : "");
|
|
logmsg(LOG_DEBUG, "*** %s: clear / set dns to resolv.conf", __FUNCTION__);
|
|
}
|
|
switch (wan_proto) {
|
|
case WP_PPTP:
|
|
logmsg(LOG_DEBUG, "*** %s: start_pptp(%s) ...", __FUNCTION__, prefix);
|
|
start_pptp(prefix);
|
|
break;
|
|
case WP_L2TP:
|
|
logmsg(LOG_DEBUG, "*** %s: start_l2tp(%s) ...", __FUNCTION__, prefix);
|
|
start_l2tp(prefix);
|
|
break;
|
|
|
|
case WP_PPPOE:
|
|
logmsg(LOG_DEBUG, "*** %s: start_pppoe(%s) ...", __FUNCTION__, prefix);
|
|
|
|
if (!strcmp(prefix, "wan"))
|
|
start_pppoe(PPPOEWAN, prefix);
|
|
else if (!strcmp(prefix, "wan2"))
|
|
start_pppoe(PPPOEWAN2, prefix);
|
|
#ifdef TCONFIG_MULTIWAN
|
|
else if (!strcmp(prefix, "wan3"))
|
|
start_pppoe(PPPOEWAN3, prefix);
|
|
else if (!strcmp(prefix, "wan4"))
|
|
start_pppoe(PPPOEWAN4, prefix);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
logmsg(LOG_DEBUG, "*** OUT %s: to start_wan_done, ifname=%s prefix=%s ...", __FUNCTION__, ifname, prefix);
|
|
start_wan_done(ifname,prefix);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int renew(char *ifname, char *prefix)
|
|
{
|
|
char *a;
|
|
int changed = 0, routes_changed = 0;
|
|
int wan_proto = get_wanx_proto(prefix);
|
|
char tmp[32];
|
|
|
|
logmsg(LOG_DEBUG, "*** %s: interface=%s, wan_prefix=%s", __FUNCTION__, ifname, prefix);
|
|
|
|
do_renew_file(0, prefix);
|
|
|
|
if ((env2nv("ip", strcat_r(prefix, "_ipaddr", tmp))) ||
|
|
(env2nv_gateway(strcat_r(prefix, "_gateway", tmp))) ||
|
|
(wan_proto == WP_LTE && env2nv("subnet", strcat_r(prefix, "_netmask", tmp))) ||
|
|
(wan_proto == WP_DHCP && env2nv("subnet", strcat_r(prefix, "_netmask", tmp)))) {
|
|
/* WAN IP or gateway changed, restart/reconfigure everything */
|
|
logmsg(LOG_DEBUG, "*** %s: WAN IP or gateway changed, restart/reconfigure everything", __FUNCTION__);
|
|
|
|
return bound(ifname, 1, prefix);
|
|
}
|
|
|
|
if ((wan_proto == WP_DHCP) || (wan_proto == WP_LTE)) {
|
|
changed |= env2nv("domain", strcat_r(prefix, "_get_domain", tmp));
|
|
changed |= env2nv("dns", strcat_r(prefix, "_get_dns", tmp));
|
|
}
|
|
|
|
nvram_set(strcat_r(prefix, "_routes1_save", tmp), nvram_safe_get(strcat_r(prefix, "_routes1", tmp)));
|
|
nvram_set(strcat_r(prefix, "_routes2_save", tmp), nvram_safe_get(strcat_r(prefix, "_routes2", tmp)));
|
|
|
|
/* Classless Static Routes (option 121) or MS Classless Static Routes (option 249) */
|
|
if (getenv("staticroutes"))
|
|
routes_changed |= env2nv("staticroutes", strcat_r(prefix, "_routes1_save", tmp));
|
|
else
|
|
routes_changed |= env2nv("msstaticroutes", strcat_r(prefix, "_routes1_save", tmp));
|
|
/* Static Routes (option 33) */
|
|
routes_changed |= env2nv("routes", strcat_r(prefix, "_routes2_save", tmp));
|
|
|
|
changed |= routes_changed;
|
|
|
|
if ((a = getenv("lease")) != NULL) {
|
|
nvram_set(strcat_r(prefix, "_lease", tmp), a);
|
|
expires(atoi(a), prefix);
|
|
}
|
|
|
|
if (changed) {
|
|
set_host_domain_name();
|
|
start_dnsmasq();
|
|
}
|
|
|
|
if (routes_changed) {
|
|
do_wan_routes(ifname, 0, 0, prefix);
|
|
nvram_set(strcat_r(prefix, "_routes1", tmp), nvram_safe_get(strcat_r(prefix, "_routes1_save", tmp)));
|
|
nvram_set(strcat_r(prefix, "_routes2", tmp), nvram_safe_get(strcat_r(prefix, "_routes2_save", tmp)));
|
|
do_wan_routes(ifname, 0, 1, prefix);
|
|
}
|
|
nvram_unset(strcat_r(prefix, "_routes1_save", tmp));
|
|
nvram_unset(strcat_r(prefix, "_routes2_save", tmp));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dhcpc_event_main(int argc, char **argv)
|
|
{
|
|
char *ifname;
|
|
ifname = getenv("interface");
|
|
char prefix[] = "wanXX";
|
|
|
|
if (nvram_match("wan_ifname", ifname))
|
|
strcpy(prefix, "wan");
|
|
else if (nvram_match("wan_iface", ifname))
|
|
strcpy(prefix, "wan");
|
|
else if (nvram_match("wan2_ifname", ifname))
|
|
strcpy(prefix, "wan2");
|
|
else if (nvram_match("wan2_iface", ifname))
|
|
strcpy(prefix, "wan2");
|
|
#ifdef TCONFIG_MULTIWAN
|
|
else if (nvram_match("wan3_ifname", ifname))
|
|
strcpy(prefix, "wan3");
|
|
else if (nvram_match("wan3_iface", ifname))
|
|
strcpy(prefix, "wan3");
|
|
else if (nvram_match("wan4_ifname", ifname))
|
|
strcpy(prefix, "wan4");
|
|
else if (nvram_match("wan4_iface", ifname))
|
|
strcpy(prefix, "wan4");
|
|
#endif
|
|
else
|
|
strcpy(prefix, "wan");
|
|
|
|
if (!wait_action_idle(10))
|
|
return 0;
|
|
|
|
logmsg(LOG_DEBUG, "*** %s: interface=%s wan_prefix=%s event=%s", __FUNCTION__, ifname, prefix, argv[1]);
|
|
|
|
if ((!argv[1]) || (ifname == NULL))
|
|
return EINVAL;
|
|
else if (strstr(argv[1], "deconfig"))
|
|
return deconfig(ifname, prefix);
|
|
else if (strstr(argv[1], "bound"))
|
|
return bound(ifname, 0, prefix);
|
|
else if ((strstr(argv[1], "renew")) || (strstr(argv[1], "update")))
|
|
return renew(ifname, prefix);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dhcpc_release_main(int argc, char **argv)
|
|
{
|
|
char prefix[] = "wanXX";
|
|
char pid_file[64];
|
|
|
|
if (argc > 1)
|
|
strcpy(prefix, argv[1]);
|
|
else
|
|
strcpy(prefix, "wan");
|
|
|
|
logmsg(LOG_DEBUG, "*** %s: argc=%d wan_prefix=%s", __FUNCTION__, argc, prefix);
|
|
|
|
mwan_table_del(prefix); /* for dual WAN and multi WAN */
|
|
|
|
if (!using_dhcpc(prefix))
|
|
return 1;
|
|
|
|
memset(pid_file, 0, sizeof(pid_file));
|
|
snprintf(pid_file, sizeof(pid_file), "/var/run/udhcpc-%s.pid", prefix);
|
|
if (kill_pidfile_s(pid_file, SIGUSR2) == 0)
|
|
sleep(2);
|
|
|
|
do_renew_file(0, prefix);
|
|
|
|
do_connect_file(0, prefix);
|
|
|
|
mwan_load_balance(); /* for dual WAN and multi WAN */
|
|
|
|
/* WAN LED control */
|
|
wan_led_off(prefix);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dhcpc_renew_main(int argc, char **argv)
|
|
{
|
|
char prefix[] = "wanXX";
|
|
char pid_file[64];
|
|
|
|
if (argc > 1)
|
|
strcpy(prefix, argv[1]);
|
|
else
|
|
strcpy(prefix, "wan");
|
|
|
|
logmsg(LOG_DEBUG, "*** %s: argc=%d wan_prefix=%s", __FUNCTION__, argc, prefix);
|
|
|
|
mwan_table_add(prefix); /* for dual WAN and multi WAN */
|
|
|
|
if (!using_dhcpc(prefix))
|
|
return 1;
|
|
|
|
memset(pid_file, 0, sizeof(pid_file));
|
|
snprintf(pid_file, sizeof(pid_file), "/var/run/udhcpc-%s.pid", prefix);
|
|
if (kill_pidfile_s(pid_file, SIGUSR1) == 0)
|
|
do_renew_file(1, prefix);
|
|
else {
|
|
stop_dhcpc(prefix);
|
|
start_dhcpc(prefix);
|
|
}
|
|
|
|
mwan_load_balance(); /* for dual WAN and multi WAN */
|
|
|
|
return 0;
|
|
}
|
|
|
|
void start_dhcpc(char *prefix)
|
|
{
|
|
char pid_file[64];
|
|
char cmd[512];
|
|
char tmp[64];
|
|
char *ifname;
|
|
int proto;
|
|
char *argv[128];
|
|
int argc = 0;
|
|
pid_t pid;
|
|
|
|
nvram_set(strcat_r(prefix, "_get_dns", tmp), "");
|
|
|
|
do_renew_file(1, prefix);
|
|
|
|
proto = get_wanx_proto(prefix);
|
|
ifname = nvram_safe_get(strcat_r(prefix, "_ifname", tmp));
|
|
|
|
if ((proto == WP_DHCP) || (proto == WP_LTE))
|
|
nvram_set(strcat_r(prefix, "_iface", tmp), ifname);
|
|
|
|
memset(pid_file, 0, sizeof(pid_file));
|
|
snprintf(pid_file, sizeof(pid_file), "/var/run/udhcpc-%s.pid", prefix);
|
|
|
|
memset(tmp, 0, sizeof(tmp));
|
|
if (nvram_invmatch("wan_hostname", "")) {
|
|
strcpy(tmp, "-x hostname:");
|
|
strcat(tmp, nvram_safe_get("wan_hostname"));
|
|
}
|
|
|
|
memset(cmd, 0, sizeof(cmd));
|
|
snprintf(cmd, sizeof(cmd), "/sbin/udhcpc -i %s -b -s /sbin/dhcpc-event -p %s %s %s %s %s %s",
|
|
ifname,
|
|
pid_file,
|
|
tmp,
|
|
nvram_get_int("dhcp_routes") ? "-O33 -O121 -O249" : "", /* routes/staticroutes/msstaticroutes */
|
|
nvram_contains_word("log_events", "dhcpc") ? "-S" : "",
|
|
#ifdef TCONFIG_IPV6
|
|
(get_ipv6_service() == IPV6_6RD_DHCP) ? "-O212 -O150" : "", /* ip6rd rfc/ip6rd comcast */
|
|
#else
|
|
"",
|
|
#endif
|
|
nvram_safe_get("dhcpc_custom")
|
|
);
|
|
|
|
logmsg(LOG_DEBUG, "*** %s: prefix=%s cmd=%s", __FUNCTION__, prefix, cmd);
|
|
|
|
for (argv[argc = 0] = strtok(cmd, " "); argv[argc] != NULL; argv[++argc] = strtok(NULL, " "));
|
|
_eval(argv, NULL, 0, &pid);
|
|
}
|
|
|
|
void stop_dhcpc(char *prefix)
|
|
{
|
|
char pid_file[64];
|
|
|
|
killall("dhcpc-event", SIGTERM);
|
|
|
|
memset(pid_file, 0, sizeof(pid_file));
|
|
snprintf(pid_file, sizeof(pid_file), "/var/run/udhcpc-%s.pid", prefix);
|
|
if (kill_pidfile_s(pid_file, SIGUSR2) == 0) /* release */
|
|
sleep(2);
|
|
|
|
kill_pidfile_s(pid_file, SIGTERM);
|
|
unlink(pid_file);
|
|
|
|
do_renew_file(0, prefix);
|
|
|
|
/* WAN LED control */
|
|
wan_led_off(prefix);
|
|
}
|
|
|
|
#ifdef TCONFIG_IPV6
|
|
int dhcp6c_state_main(int argc, char **argv)
|
|
{
|
|
char prefix[INET6_ADDRSTRLEN];
|
|
const char *lanif;
|
|
struct in6_addr addr;
|
|
int i, r;
|
|
|
|
if (!wait_action_idle(10))
|
|
return 1;
|
|
|
|
lanif = getifaddr(nvram_safe_get("lan_ifname"), AF_INET6, 0);
|
|
|
|
/* check IPv6 addr - change/new ? */
|
|
if (!nvram_match("ipv6_rtr_addr", (char *) lanif)) {
|
|
nvram_set("ipv6_rtr_addr", lanif);
|
|
/* extract prefix from configured IPv6 address */
|
|
if (inet_pton(AF_INET6, nvram_safe_get("ipv6_rtr_addr"), &addr) > 0) {
|
|
r = nvram_get_int("ipv6_prefix_length") ? : 64;
|
|
for (r = 128 - r, i = 15; r > 0; r -= 8) {
|
|
if (r >= 8) {
|
|
addr.s6_addr[i--] = 0;
|
|
} else {
|
|
addr.s6_addr[i--] &= (0xff << r);
|
|
}
|
|
}
|
|
inet_ntop(AF_INET6, &addr, prefix, sizeof(prefix));
|
|
nvram_set("ipv6_prefix", prefix);
|
|
}
|
|
/* (re)start dnsmasq and httpd */
|
|
set_host_domain_name();
|
|
start_dnsmasq();
|
|
start_httpd();
|
|
}
|
|
|
|
/* check DNS */
|
|
if (env2nv("new_domain_name_servers", "ipv6_get_dns"))
|
|
dns_to_resolv();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void start_dhcp6c(void)
|
|
{
|
|
FILE *f;
|
|
int prefix_len;
|
|
char *wan6face;
|
|
char *argv[] = { "/usr/sbin/dhcp6c", "-T", "LL", NULL, NULL, NULL }; /* DUID type 3 (DUID-LL) */
|
|
int argc;
|
|
int ipv6_vlan = 0; /* bit 0 = IPv6 enabled for LAN1, bit 1 = IPv6 enabled for LAN2, bit 2 = IPv6 enabled for LAN3, 1 == TRUE, 0 == FALSE */
|
|
|
|
/* Check if turned on */
|
|
if (get_ipv6_service() != IPV6_NATIVE_DHCP)
|
|
return;
|
|
|
|
prefix_len = 64 - (nvram_get_int("ipv6_prefix_length") ? : 64);
|
|
if (prefix_len < 0)
|
|
prefix_len = 0;
|
|
|
|
wan6face = nvram_safe_get("wan_iface");
|
|
ipv6_vlan = nvram_get_int("ipv6_vlan");
|
|
|
|
nvram_set("ipv6_get_dns", "");
|
|
nvram_set("ipv6_rtr_addr", "");
|
|
nvram_set("ipv6_prefix", "");
|
|
|
|
nvram_set("ipv6_pd_pltime", "0"); /* reset preferred and valid lifetime */
|
|
nvram_set("ipv6_pd_vltime", "0");
|
|
|
|
/* Create dhcp6c.conf */
|
|
unlink("/var/dhcp6c_duid");
|
|
if ((f = fopen("/etc/dhcp6c.conf", "w"))) {
|
|
fprintf(f, "interface %s {\n", wan6face);
|
|
|
|
if (nvram_get_int("ipv6_pdonly") == 0)
|
|
fprintf(f, " send ia-na 0;\n");
|
|
|
|
fprintf(f, " send ia-pd 0;\n"
|
|
" request domain-name-servers;\n"
|
|
" script \"/sbin/dhcp6c-state\";\n"
|
|
"};\n"
|
|
"id-assoc pd 0 {\n"
|
|
" prefix ::/%d infinity;\n"
|
|
" prefix-interface %s {\n"
|
|
" sla-id 0;\n"
|
|
" sla-len %d;\n"
|
|
" ifid 1;\n" /* override the default EUI-64 address selection and create a very userfriendly address --> ::1 */
|
|
" };\n",
|
|
nvram_get_int("ipv6_prefix_length"),
|
|
nvram_safe_get("lan_ifname"),
|
|
prefix_len);
|
|
|
|
/* check IPv6 for LAN1 */
|
|
if ((ipv6_vlan & 0x01) && (prefix_len >= 1) && (strcmp(nvram_safe_get("lan1_ipaddr"), "") != 0)) /* 2x IPv6 /64 networks possible --> for LAN and LAN1 */
|
|
fprintf(f, " prefix-interface %s {\n"
|
|
" sla-id 1;\n"
|
|
" sla-len %d;\n"
|
|
" ifid 1;\n" /* override the default EUI-64 address selection and create a very userfriendly address --> ::1 */
|
|
" };\n", nvram_safe_get("lan1_ifname"), prefix_len);
|
|
|
|
/* check IPv6 for LAN2 */
|
|
if ((ipv6_vlan & 0x02) && (prefix_len >= 2) && (strcmp(nvram_safe_get("lan2_ipaddr"), "") != 0)) /* 4x IPv6 /64 networks possible --> for LAN to LAN2 */
|
|
fprintf(f, " prefix-interface %s {\n"
|
|
" sla-id 2;\n"
|
|
" sla-len %d;\n"
|
|
" ifid 1;\n" /* override the default EUI-64 address selection and create a very userfriendly address --> ::1 */
|
|
" };\n", nvram_safe_get("lan2_ifname"), prefix_len);
|
|
|
|
/* check IPv6 for LAN3 */
|
|
if ((ipv6_vlan & 0x04) && (prefix_len >= 2) && (strcmp(nvram_safe_get("lan3_ipaddr"), "") != 0)) /* 4x IPv6 /64 networks possible --> for LAN to LAN3 */
|
|
fprintf(f, " prefix-interface %s {\n"
|
|
" sla-id 3;\n"
|
|
" sla-len %d;\n"
|
|
" ifid 1;\n" /* override the default EUI-64 address selection and create a very userfriendly address --> ::1 */
|
|
" };\n", nvram_safe_get("lan3_ifname"), prefix_len);
|
|
|
|
fprintf(f, "};\n"
|
|
"id-assoc na 0 { };\n");
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
argc = 3;
|
|
if (nvram_get_int("debug_ipv6"))
|
|
argv[argc++] = "-D";
|
|
|
|
argv[argc++] = wan6face;
|
|
argv[argc] = NULL;
|
|
_eval(argv, NULL, 0, NULL);
|
|
}
|
|
|
|
void stop_dhcp6c(void)
|
|
{
|
|
killall("dhcp6c-event", SIGTERM);
|
|
killall_tk_period_wait("dhcp6c", 50);
|
|
|
|
nvram_set("ipv6_pd_pltime", "0"); /* reset preferred and valid lifetime */
|
|
nvram_set("ipv6_pd_vltime", "0");
|
|
}
|
|
#endif /* TCONFIG_IPV6 */
|