Miniupnpd: update to 2.0
[tomato.git] / release / src / router / rc / dhcp.c
blob37934bd5768ca8f04f54ba4f277291dd53ab84a2
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 struct in6_addr addr;
440 int i, r;
442 TRACE_PT("begin\n");
444 if (!wait_action_idle(10)) return 1;
446 nvram_set("ipv6_rtr_addr", getifaddr(nvram_safe_get("lan_ifname"), AF_INET6, 0));
448 // extract prefix from configured IPv6 address
449 if (inet_pton(AF_INET6, nvram_safe_get("ipv6_rtr_addr"), &addr) > 0) {
450 r = nvram_get_int("ipv6_prefix_length") ? : 64;
451 for (r = 128 - r, i = 15; r > 0; r -= 8) {
452 if (r >= 8)
453 addr.s6_addr[i--] = 0;
454 else
455 addr.s6_addr[i--] &= (0xff << r);
457 inet_ntop(AF_INET6, &addr, prefix, sizeof(prefix));
458 nvram_set("ipv6_prefix", prefix);
461 if (env2nv("new_domain_name_servers", "ipv6_get_dns")) {
462 dns_to_resolv();
463 // start_dnsmasq(); // (re)start KDB don't do twice!
466 // (re)start dnsmasq and httpd
467 start_dnsmasq();
468 start_httpd();
470 TRACE_PT("ipv6_get_dns=%s\n", nvram_safe_get("ipv6_get_dns"));
471 TRACE_PT("end\n");
472 return 0;
475 void start_dhcp6c(void)
477 FILE *f;
478 int prefix_len;
479 char *wan6face;
480 char *argv[] = { "dhcp6c", "-T", "LL", NULL, NULL, NULL };
481 int argc;
482 int ipv6_vlan;
484 TRACE_PT("begin\n");
486 // Check if turned on
487 if (get_ipv6_service() != IPV6_NATIVE_DHCP) return;
489 prefix_len = 64 - (nvram_get_int("ipv6_prefix_length") ? : 64);
490 if (prefix_len < 0)
491 prefix_len = 0;
492 wan6face = nvram_safe_get("wan_iface");
493 ipv6_vlan = nvram_get_int("ipv6_vlan");
495 nvram_set("ipv6_get_dns", "");
496 nvram_set("ipv6_rtr_addr", "");
497 nvram_set("ipv6_prefix", "");
499 // Create dhcp6c.conf
500 unlink("/var/dhcp6c_duid");
501 if ((f = fopen("/etc/dhcp6c.conf", "w"))) {
502 fprintf(f,
503 "interface %s {\n", wan6face);
504 if (nvram_get_int("ipv6_pdonly") == 0) {
505 fprintf(f,
506 " send ia-na 0;\n");
508 fprintf(f,
509 " send ia-pd 0;\n"
510 " send rapid-commit;\n"
511 " request domain-name-servers;\n"
512 " script \"/sbin/dhcp6c-state\";\n"
513 "};\n"
514 "id-assoc pd 0 {\n"
515 " prefix ::/%d infinity;\n"
516 " prefix-interface %s {\n"
517 " sla-id 0;\n"
518 " sla-len %d;\n"
519 " };\n",
520 nvram_get_int("ipv6_prefix_length"),
521 nvram_safe_get("lan_ifname"),
522 prefix_len);
523 if ((ipv6_vlan & 1) && (prefix_len >= 1)) { //2 ipv6 /64 networks
524 fprintf(f,
525 " prefix-interface %s {\n"
526 " sla-id 1;\n"
527 " sla-len %d;\n"
528 " };\n", nvram_safe_get("lan1_ifname"), prefix_len);
530 if ((ipv6_vlan & 2) && (prefix_len >= 2)) { //4 ipv6 /64 networks
531 fprintf(f,
532 " prefix-interface %s {\n"
533 " sla-id 2;\n"
534 " sla-len %d;\n"
535 " };\n", nvram_safe_get("lan2_ifname"), prefix_len);
537 if ((ipv6_vlan & 4) && (prefix_len >= 2)) {
538 fprintf(f,
539 " prefix-interface %s {\n"
540 " sla-id 3;\n"
541 " sla-len %d;\n"
542 " };\n", nvram_safe_get("lan3_ifname"), prefix_len);
544 fprintf(f,
545 "};\n"
546 "id-assoc na 0 { };\n");
547 fclose(f);
550 argc = 3;
551 if (nvram_get_int("debug_ipv6"))
552 argv[argc++] = "-D";
553 argv[argc++] = wan6face;
554 argv[argc] = NULL;
555 _eval(argv, NULL, 0, NULL);
557 TRACE_PT("end\n");
560 void stop_dhcp6c(void)
562 TRACE_PT("begin\n");
564 killall("dhcp6c-event", SIGTERM);
565 killall_tk("dhcp6c");
567 TRACE_PT("end\n");
570 #endif // TCONFIG_IPV6