Confirm dhcpv6 IP/prefix address has actually changed before restarting dnsmasq/httpd.
[tomato.git] / release / src / router / rc / dhcp.c
blob63688721bcf5a5e28276050ead56640645fcaee6
1 /*
3 Copyright 2003, CyberTAN Inc. All Rights Reserved
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
6 the contents of this file may not be disclosed to third parties,
7 copied or duplicated in any form without the prior written
8 permission of CyberTAN Inc.
10 This software should be used as a reference only, and it not
11 intended for production use!
13 THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
14 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
15 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
16 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
21 Copyright 2005, Broadcom Corporation
22 All Rights Reserved.
24 THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
25 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
26 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
32 Modified for Tomato Firmware
33 Portions, Copyright (C) 2006-2009 Jonathan Zarate
37 #include "rc.h"
39 #include <sys/sysinfo.h>
40 #include <sys/ioctl.h>
41 #include <arpa/inet.h>
43 static void expires(unsigned int seconds)
45 struct sysinfo info;
46 char s[32];
48 sysinfo(&info);
49 sprintf(s, "%u", (unsigned int)info.uptime + seconds);
50 f_write_string("/var/lib/misc/dhcpc.expires", s, 0, 0);
53 // copy env to nvram
54 // returns 1 if new/changed, 0 if not changed/no env
55 static int env2nv(char *env, char *nv)
57 char *value;
58 if ((value = getenv(env)) != NULL) {
59 if (!nvram_match(nv, value)) {
60 nvram_set(nv, value);
61 return 1;
64 return 0;
67 static int env2nv_gateway(const char *nv)
69 char *v, *g;
70 char *b;
71 int r;
73 r = 0;
74 if ((v = getenv("router")) != NULL) {
75 if ((b = strdup(v)) != NULL) {
76 if ((v = strchr(b, ' ')) != NULL) *v = 0; // truncate multiple entries
77 if (!nvram_match((char *)nv, b)) {
78 nvram_set(nv, b);
79 r = 1;
81 free(b);
84 else if ((v = getenv("staticroutes")) != NULL) {
85 if ((b = strdup(v)) == NULL) return 0;
86 v = b;
87 while ((g = strsep(&v, " ")) != NULL) {
88 if (strcmp(g, "0.0.0.0/0") == 0) {
89 if ((g = strsep(&v, " ")) && *g) {
90 if (!nvram_match((char *)nv, g)) {
91 nvram_set(nv, g);
92 r = 1;
94 break;
98 free(b);
101 return r;
104 static const char renewing[] = "/var/lib/misc/dhcpc.renewing";
106 static int deconfig(char *ifname)
108 TRACE_PT("begin\n");
110 ifconfig(ifname, IFUP, "0.0.0.0", NULL);
112 if (using_dhcpc()) {
113 nvram_set("wan_ipaddr", "0.0.0.0");
114 nvram_set("wan_gateway", "0.0.0.0");
116 nvram_set("wan_lease", "0");
117 nvram_set("wan_routes1", "");
118 nvram_set("wan_routes2", "");
119 expires(0);
121 if (get_wan_proto() == WP_DHCP || get_wan_proto() == WP_LTE) {
122 nvram_set("wan_netmask", "0.0.0.0");
123 nvram_set("wan_gateway_get", "0.0.0.0");
124 nvram_set("wan_get_dns", "");
127 // route_del(ifname, 0, NULL, NULL, NULL);
129 #ifdef TCONFIG_IPV6
130 nvram_set("wan_6rd", "");
131 #endif
133 TRACE_PT("end\n");
134 return 0;
137 static int bound(char *ifname, int renew);
139 static int renew(char *ifname)
141 char *a;
142 int changed = 0, routes_changed = 0;
143 int wan_proto = get_wan_proto();
145 TRACE_PT("begin\n");
147 unlink(renewing);
149 if (env2nv("ip", "wan_ipaddr") ||
150 env2nv_gateway("wan_gateway") ||
151 (wan_proto == WP_LTE && env2nv("subnet", "wan_netmask")) ||
152 (wan_proto == WP_DHCP && env2nv("subnet", "wan_netmask"))) {
153 /* WAN IP or gateway changed, restart/reconfigure everything */
154 TRACE_PT("end\n");
155 return bound(ifname, 1);
158 if (wan_proto == WP_DHCP || wan_proto == WP_LTE) {
159 changed |= env2nv("domain", "wan_get_domain");
160 changed |= env2nv("dns", "wan_get_dns");
163 nvram_set("wan_routes1_save", nvram_safe_get("wan_routes1"));
164 nvram_set("wan_routes2_save", nvram_safe_get("wan_routes2"));
166 /* Classless Static Routes (option 121) or MS Classless Static Routes (option 249) */
167 if (getenv("staticroutes"))
168 routes_changed |= env2nv("staticroutes", "wan_routes1_save");
169 else
170 routes_changed |= env2nv("msstaticroutes", "wan_routes1_save");
171 /* Static Routes (option 33) */
172 routes_changed |= env2nv("routes", "wan_routes2_save");
174 changed |= routes_changed;
176 if ((a = getenv("lease")) != NULL) {
177 nvram_set("wan_lease", a);
178 expires(atoi(a));
181 if (changed) {
182 set_host_domain_name();
183 start_dnsmasq(); // (re)start
186 if (routes_changed) {
187 do_wan_routes(ifname, 0, 0);
188 nvram_set("wan_routes1", nvram_safe_get("wan_routes1_save"));
189 nvram_set("wan_routes2", nvram_safe_get("wan_routes2_save"));
190 do_wan_routes(ifname, 0, 1);
192 nvram_unset("wan_routes1_save");
193 nvram_unset("wan_routes2_save");
195 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
196 TRACE_PT("wan_netmask=%s\n", nvram_safe_get("wan_netmask"));
197 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
198 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
199 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
200 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
201 TRACE_PT("wan_routes1=%s\n", nvram_safe_get("wan_routes1"));
202 TRACE_PT("wan_routes2=%s\n", nvram_safe_get("wan_routes2"));
203 TRACE_PT("end\n");
204 return 0;
207 static int bound(char *ifname, int renew)
209 TRACE_PT("begin\n");
211 unlink(renewing);
213 char *netmask, *dns;
214 int wan_proto = get_wan_proto();
216 dns = nvram_safe_get("wan_get_dns");
217 nvram_set("wan_routes1", "");
218 nvram_set("wan_routes2", "");
219 env2nv("ip", "wan_ipaddr");
220 env2nv_gateway("wan_gateway");
221 env2nv("dns", "wan_get_dns");
222 env2nv("domain", "wan_get_domain");
223 env2nv("lease", "wan_lease");
224 netmask = getenv("subnet") ? : "255.255.255.255";
225 if (wan_proto == WP_DHCP || wan_proto == WP_LTE) {
226 nvram_set("wan_netmask", netmask);
227 nvram_set("wan_gateway_get", nvram_safe_get("wan_gateway"));
230 /* RFC3442: If the DHCP server returns both a Classless Static Routes option
231 * and a Router option, the DHCP client MUST ignore the Router option.
232 * Similarly, if the DHCP server returns both a Classless Static Routes
233 * option and a Static Routes option, the DHCP client MUST ignore the
234 * Static Routes option.
235 * Ref: http://www.faqs.org/rfcs/rfc3442.html
237 /* Classless Static Routes (option 121) */
238 if (!env2nv("staticroutes", "wan_routes1"))
239 /* or MS Classless Static Routes (option 249) */
240 env2nv("msstaticroutes", "wan_routes1");
241 /* Static Routes (option 33) */
242 env2nv("routes", "wan_routes2");
244 expires(atoi(safe_getenv("lease")));
246 #ifdef TCONFIG_IPV6
247 env2nv("ip6rd", "wan_6rd");
248 #endif
250 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
251 TRACE_PT("wan_netmask=%s\n", netmask);
252 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
253 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
254 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
255 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
256 TRACE_PT("wan_routes1=%s\n", nvram_safe_get("wan_routes1"));
257 TRACE_PT("wan_routes2=%s\n", nvram_safe_get("wan_routes2"));
258 #ifdef TCONFIG_IPV6
259 TRACE_PT("wan_6rd=%s\n", nvram_safe_get("wan_6rd"));
260 #endif
262 ifconfig(ifname, IFUP, "0.0.0.0", NULL);
263 ifconfig(ifname, IFUP, nvram_safe_get("wan_ipaddr"), netmask);
265 if (wan_proto != WP_DHCP && wan_proto != WP_LTE) {
266 char *gw = nvram_safe_get("wan_gateway");
268 preset_wan(ifname, gw, netmask);
270 /* clear dns from the resolv.conf */
271 nvram_set("wan_get_dns", renew ? dns : "");
273 switch (wan_proto) {
274 case WP_PPTP:
275 start_pptp(BOOT);
276 break;
277 case WP_L2TP:
278 start_l2tp();
279 break;
282 else {
283 start_wan_done(ifname);
286 TRACE_PT("end\n");
287 return 0;
290 int dhcpc_event_main(int argc, char **argv)
292 char *ifname;
294 if (!wait_action_idle(10)) return 1;
296 if ((argc == 2) && (ifname = getenv("interface")) != NULL) {
297 TRACE_PT("event=%s\n", argv[1]);
299 if (strcmp(argv[1], "deconfig") == 0) return deconfig(ifname);
300 if (strcmp(argv[1], "bound") == 0) return bound(ifname, 0);
301 if ((strcmp(argv[1], "renew") == 0) || (strcmp(argv[1], "update") == 0)) return renew(ifname);
304 return 1;
308 // -----------------------------------------------------------------------------
311 int dhcpc_release_main(int argc, char **argv)
313 TRACE_PT("begin\n");
315 if (!using_dhcpc()) return 1;
317 if (killall("udhcpc", SIGUSR2) == 0) {
318 sleep(2);
321 unlink(renewing);
322 unlink("/var/lib/misc/wan.connecting");
324 TRACE_PT("end\n");
325 return 0;
328 int dhcpc_renew_main(int argc, char **argv)
330 int pid;
332 TRACE_PT("begin\n");
334 if (!using_dhcpc()) return 1;
336 if ((pid = pidof("udhcpc")) > 1) {
337 kill(pid, SIGUSR1);
338 f_write(renewing, NULL, 0, 0, 0);
340 else {
341 stop_dhcpc();
342 start_dhcpc();
345 TRACE_PT("end\n");
346 return 0;
350 // -----------------------------------------------------------------------------
353 void start_dhcpc(void)
355 char cmd[256];
356 char *ifname;
357 char *p;
358 int proto;
360 TRACE_PT("begin\n");
362 nvram_set("wan_get_dns", "");
363 f_write(renewing, NULL, 0, 0, 0);
365 proto = get_wan_proto();
367 if (proto == WP_LTE) {
368 ifname = nvram_safe_get("wan_4g");
369 } else {
370 ifname = nvram_safe_get("wan_ifname");
372 if (proto == WP_DHCP || proto == WP_LTE) {
373 nvram_set("wan_iface", ifname);
376 #if 1 // REMOVEME after 1/1/2012
377 // temporary code for compatibility with old nvram variables
378 int changed = 0;
379 strcpy(cmd, nvram_safe_get("dhcpc_custom"));
380 if (strstr(cmd, "-V ") == NULL) {
381 if ((p = nvram_get("dhcpc_vendorclass")) && (*p)) {
382 changed++;
383 strcat(cmd, " -V ");
384 strcat(cmd, p);
387 if (strstr(cmd, "-r ") == NULL) {
388 if ((p = nvram_get("dhcpc_requestip")) && (*p) && (strcmp(p, "0.0.0.0") != 0)) {
389 changed++;
390 strcat(cmd, " -r ");
391 strcat(cmd, p);
394 if (changed) {
395 nvram_set("dhcpc_custom", cmd);
397 #endif
399 snprintf(cmd, sizeof(cmd),
400 "udhcpc -i %s -b -s dhcpc-event %s %s %s %s %s %s",
401 ifname,
402 nvram_invmatch("wan_hostname", "") ? "-H" : "", nvram_safe_get("wan_hostname"),
403 nvram_get_int("dhcpc_minpkt") ? "-m" : "",
404 nvram_contains_word("log_events", "dhcpc") ? "-S" : "",
405 nvram_safe_get("dhcpc_custom"),
406 #ifdef TCONFIG_IPV6
407 (get_ipv6_service() == IPV6_6RD_DHCP) ? "-O ip6rd" : ""
408 #else
410 #endif
413 xstart("/bin/sh", "-c", cmd);
415 TRACE_PT("end\n");
418 void stop_dhcpc(void)
420 TRACE_PT("begin\n");
422 killall("dhcpc-event", SIGTERM);
423 if (killall("udhcpc", SIGUSR2) == 0) { // release
424 sleep(2);
426 killall_tk("udhcpc");
427 unlink(renewing);
429 TRACE_PT("end\n");
432 // -----------------------------------------------------------------------------
434 #ifdef TCONFIG_IPV6
436 int dhcp6c_state_main(int argc, char **argv)
438 char prefix[INET6_ADDRSTRLEN];
439 char *lanif;
440 struct in6_addr addr;
441 int i, r;
443 TRACE_PT("begin\n");
445 if (!wait_action_idle(10)) return 1;
447 lanif = getifaddr(nvram_safe_get("lan_ifname"), AF_INET6, 0);
448 if (!nvram_match("ipv6_rtr_addr", lanif)) {
449 nvram_set("ipv6_rtr_addr", lanif);
450 // extract prefix from configured IPv6 address
451 if (inet_pton(AF_INET6, nvram_safe_get("ipv6_rtr_addr"), &addr) > 0) {
452 r = nvram_get_int("ipv6_prefix_length") ? : 64;
453 for (r = 128 - r, i = 15; r > 0; r -= 8) {
454 if (r >= 8)
455 addr.s6_addr[i--] = 0;
456 else
457 addr.s6_addr[i--] &= (0xff << r);
459 inet_ntop(AF_INET6, &addr, prefix, sizeof(prefix));
460 nvram_set("ipv6_prefix", prefix);
462 // (re)start dnsmasq and httpd
463 set_host_domain_name();
464 start_dnsmasq();
465 start_httpd();
468 if (env2nv("new_domain_name_servers", "ipv6_get_dns")) {
469 dns_to_resolv();
472 TRACE_PT("ipv6_get_dns=%s\n", nvram_safe_get("ipv6_get_dns"));
473 TRACE_PT("end\n");
474 return 0;
477 void start_dhcp6c(void)
479 FILE *f;
480 int prefix_len;
481 char *wan6face;
482 char *argv[] = { "dhcp6c", "-T", "LL", NULL, NULL, NULL };
483 int argc;
484 int ipv6_vlan;
486 TRACE_PT("begin\n");
488 // Check if turned on
489 if (get_ipv6_service() != IPV6_NATIVE_DHCP) return;
491 prefix_len = 64 - (nvram_get_int("ipv6_prefix_length") ? : 64);
492 if (prefix_len < 0)
493 prefix_len = 0;
494 wan6face = nvram_safe_get("wan_iface");
495 ipv6_vlan = nvram_get_int("ipv6_vlan");
497 nvram_set("ipv6_get_dns", "");
498 nvram_set("ipv6_rtr_addr", "");
499 nvram_set("ipv6_prefix", "");
501 // Create dhcp6c.conf
502 unlink("/var/dhcp6c_duid");
503 if ((f = fopen("/etc/dhcp6c.conf", "w"))) {
504 fprintf(f,
505 "interface %s {\n", wan6face);
506 if (nvram_get_int("ipv6_pdonly") == 0) {
507 fprintf(f,
508 " send ia-na 0;\n");
510 fprintf(f,
511 " send ia-pd 0;\n"
512 " request domain-name-servers;\n"
513 " script \"/sbin/dhcp6c-state\";\n"
514 "};\n"
515 "id-assoc pd 0 {\n"
516 " prefix ::/%d infinity;\n"
517 " prefix-interface %s {\n"
518 " sla-id 0;\n"
519 " sla-len %d;\n"
520 " };\n",
521 nvram_get_int("ipv6_prefix_length"),
522 nvram_safe_get("lan_ifname"),
523 prefix_len);
524 if ((ipv6_vlan & 1) && (prefix_len >= 1)) { //2 ipv6 /64 networks
525 fprintf(f,
526 " prefix-interface %s {\n"
527 " sla-id 1;\n"
528 " sla-len %d;\n"
529 " };\n", nvram_safe_get("lan1_ifname"), prefix_len);
531 if ((ipv6_vlan & 2) && (prefix_len >= 2)) { //4 ipv6 /64 networks
532 fprintf(f,
533 " prefix-interface %s {\n"
534 " sla-id 2;\n"
535 " sla-len %d;\n"
536 " };\n", nvram_safe_get("lan2_ifname"), prefix_len);
538 if ((ipv6_vlan & 4) && (prefix_len >= 2)) {
539 fprintf(f,
540 " prefix-interface %s {\n"
541 " sla-id 3;\n"
542 " sla-len %d;\n"
543 " };\n", nvram_safe_get("lan3_ifname"), prefix_len);
545 fprintf(f,
546 "};\n"
547 "id-assoc na 0 { };\n");
548 fclose(f);
551 argc = 3;
552 if (nvram_get_int("debug_ipv6"))
553 argv[argc++] = "-D";
554 argv[argc++] = wan6face;
555 argv[argc] = NULL;
556 _eval(argv, NULL, 0, NULL);
558 TRACE_PT("end\n");
561 void stop_dhcp6c(void)
563 TRACE_PT("begin\n");
565 killall("dhcp6c-event", SIGTERM);
566 killall_tk("dhcp6c");
568 TRACE_PT("end\n");
571 #endif // TCONFIG_IPV6