Merge branch 'Toastman-RT' into Toastman-RT-N
[tomato.git] / release / src / router / rc / dhcp.c
blob13ab35b3c84d3ad32a21de6d2405615fa508ff24
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) {
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_DHCP && env2nv("subnet", "wan_netmask"))) {
152 /* WAN IP or gateway changed, restart/reconfigure everything */
153 TRACE_PT("end\n");
154 return bound(ifname, 1);
157 if (wan_proto == WP_DHCP) {
158 changed |= env2nv("domain", "wan_get_domain");
159 changed |= env2nv("dns", "wan_get_dns");
162 nvram_set("wan_routes1_save", nvram_safe_get("wan_routes1"));
163 nvram_set("wan_routes2_save", nvram_safe_get("wan_routes2"));
165 /* Classless Static Routes (option 121) or MS Classless Static Routes (option 249) */
166 if (getenv("staticroutes"))
167 routes_changed |= env2nv("staticroutes", "wan_routes1_save");
168 else
169 routes_changed |= env2nv("msstaticroutes", "wan_routes1_save");
170 /* Static Routes (option 33) */
171 routes_changed |= env2nv("routes", "wan_routes2_save");
173 changed |= routes_changed;
175 if ((a = getenv("lease")) != NULL) {
176 nvram_set("wan_lease", a);
177 expires(atoi(a));
180 if (changed) {
181 set_host_domain_name();
182 start_dnsmasq(); // (re)start
185 if (routes_changed) {
186 do_wan_routes(ifname, 0, 0);
187 nvram_set("wan_routes1", nvram_safe_get("wan_routes1_save"));
188 nvram_set("wan_routes2", nvram_safe_get("wan_routes2_save"));
189 do_wan_routes(ifname, 0, 1);
191 nvram_unset("wan_routes1_save");
192 nvram_unset("wan_routes2_save");
194 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
195 TRACE_PT("wan_netmask=%s\n", nvram_safe_get("wan_netmask"));
196 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
197 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
198 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
199 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
200 TRACE_PT("wan_routes1=%s\n", nvram_safe_get("wan_routes1"));
201 TRACE_PT("wan_routes2=%s\n", nvram_safe_get("wan_routes2"));
202 TRACE_PT("end\n");
203 return 0;
206 static int bound(char *ifname, int renew)
208 TRACE_PT("begin\n");
210 unlink(renewing);
212 char *netmask, *dns;
213 int wan_proto = get_wan_proto();
215 dns = nvram_safe_get("wan_get_dns");
216 nvram_set("wan_routes1", "");
217 nvram_set("wan_routes2", "");
218 env2nv("ip", "wan_ipaddr");
219 env2nv_gateway("wan_gateway");
220 env2nv("dns", "wan_get_dns");
221 env2nv("domain", "wan_get_domain");
222 env2nv("lease", "wan_lease");
223 netmask = getenv("subnet") ? : "255.255.255.255";
224 if (wan_proto == WP_DHCP) {
225 nvram_set("wan_netmask", netmask);
226 nvram_set("wan_gateway_get", nvram_safe_get("wan_gateway"));
229 /* RFC3442: If the DHCP server returns both a Classless Static Routes option
230 * and a Router option, the DHCP client MUST ignore the Router option.
231 * Similarly, if the DHCP server returns both a Classless Static Routes
232 * option and a Static Routes option, the DHCP client MUST ignore the
233 * Static Routes option.
234 * Ref: http://www.faqs.org/rfcs/rfc3442.html
236 /* Classless Static Routes (option 121) */
237 if (!env2nv("staticroutes", "wan_routes1"))
238 /* or MS Classless Static Routes (option 249) */
239 env2nv("msstaticroutes", "wan_routes1");
240 /* Static Routes (option 33) */
241 env2nv("routes", "wan_routes2");
243 expires(atoi(safe_getenv("lease")));
245 #ifdef TCONFIG_IPV6
246 env2nv("6rd", "wan_6rd");
247 #endif
249 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
250 TRACE_PT("wan_netmask=%s\n", netmask);
251 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
252 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
253 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
254 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
255 TRACE_PT("wan_routes1=%s\n", nvram_safe_get("wan_routes1"));
256 TRACE_PT("wan_routes2=%s\n", nvram_safe_get("wan_routes2"));
257 #ifdef TCONFIG_IPV6
258 TRACE_PT("wan_6rd=%s\n", nvram_safe_get("wan_6rd"));
259 #endif
261 ifconfig(ifname, IFUP, "0.0.0.0", NULL);
262 ifconfig(ifname, IFUP, nvram_safe_get("wan_ipaddr"), netmask);
264 if (wan_proto != WP_DHCP) {
265 char *gw = nvram_safe_get("wan_gateway");
267 preset_wan(ifname, gw, netmask);
269 /* clear dns from the resolv.conf */
270 nvram_set("wan_get_dns", renew ? dns : "");
272 switch (wan_proto) {
273 case WP_PPTP:
274 start_pptp(BOOT);
275 break;
276 case WP_L2TP:
277 start_l2tp();
278 break;
281 else {
282 start_wan_done(ifname);
285 TRACE_PT("end\n");
286 return 0;
289 int dhcpc_event_main(int argc, char **argv)
291 char *ifname;
293 if (!wait_action_idle(10)) return 1;
295 if ((argc == 2) && (ifname = getenv("interface")) != NULL) {
296 TRACE_PT("event=%s\n", argv[1]);
298 if (strcmp(argv[1], "deconfig") == 0) return deconfig(ifname);
299 if (strcmp(argv[1], "bound") == 0) return bound(ifname, 0);
300 if ((strcmp(argv[1], "renew") == 0) || (strcmp(argv[1], "update") == 0)) return renew(ifname);
303 return 1;
307 // -----------------------------------------------------------------------------
310 int dhcpc_release_main(int argc, char **argv)
312 TRACE_PT("begin\n");
314 if (!using_dhcpc()) return 1;
316 if (killall("udhcpc", SIGUSR2) == 0) {
317 sleep(2);
320 unlink(renewing);
321 unlink("/var/lib/misc/wan.connecting");
323 TRACE_PT("end\n");
324 return 0;
327 int dhcpc_renew_main(int argc, char **argv)
329 int pid;
331 TRACE_PT("begin\n");
333 if (!using_dhcpc()) return 1;
335 if ((pid = pidof("udhcpc")) > 1) {
336 kill(pid, SIGUSR1);
337 f_write(renewing, NULL, 0, 0, 0);
339 else {
340 stop_dhcpc();
341 start_dhcpc();
344 TRACE_PT("end\n");
345 return 0;
349 // -----------------------------------------------------------------------------
352 void start_dhcpc(void)
354 char cmd[256];
355 char *ifname;
356 char *p;
357 int proto;
359 TRACE_PT("begin\n");
361 nvram_set("wan_get_dns", "");
362 f_write(renewing, NULL, 0, 0, 0);
364 ifname = nvram_safe_get("wan_ifname");
365 proto = get_wan_proto();
366 if (proto == WP_DHCP) {
367 nvram_set("wan_iface", ifname);
370 #if 1 // REMOVEME after 1/1/2012
371 // temporary code for compatibility with old nvram variables
372 int changed = 0;
373 strcpy(cmd, nvram_safe_get("dhcpc_custom"));
374 if (strstr(cmd, "-V ") == NULL) {
375 if ((p = nvram_get("dhcpc_vendorclass")) && (*p)) {
376 changed++;
377 strcat(cmd, " -V ");
378 strcat(cmd, p);
381 if (strstr(cmd, "-r ") == NULL) {
382 if ((p = nvram_get("dhcpc_requestip")) && (*p) && (strcmp(p, "0.0.0.0") != 0)) {
383 changed++;
384 strcat(cmd, " -r ");
385 strcat(cmd, p);
388 if (changed) {
389 nvram_set("dhcpc_custom", cmd);
391 #endif
393 snprintf(cmd, sizeof(cmd),
394 "udhcpc -i %s -b -s dhcpc-event %s %s %s %s %s %s",
395 ifname,
396 nvram_invmatch("wan_hostname", "") ? "-H" : "", nvram_safe_get("wan_hostname"),
397 nvram_get_int("dhcpc_minpkt") ? "-m" : "",
398 nvram_contains_word("log_events", "dhcpc") ? "-S" : "",
399 nvram_safe_get("dhcpc_custom"),
400 #ifdef TCONFIG_IPV6
401 (get_ipv6_service() == IPV6_6RD_DHCP) ? "-O 6rd" : ""
402 #else
404 #endif
407 xstart("/bin/sh", "-c", cmd);
409 TRACE_PT("end\n");
412 void stop_dhcpc(void)
414 TRACE_PT("begin\n");
416 killall("dhcpc-event", SIGTERM);
417 if (killall("udhcpc", SIGUSR2) == 0) { // release
418 sleep(2);
420 killall_tk("udhcpc");
421 unlink(renewing);
423 TRACE_PT("end\n");
426 // -----------------------------------------------------------------------------
428 #ifdef TCONFIG_IPV6
430 int dhcp6c_state_main(int argc, char **argv)
432 char prefix[INET6_ADDRSTRLEN];
433 struct in6_addr addr;
434 int i, r;
436 TRACE_PT("begin\n");
438 if (!wait_action_idle(10)) return 1;
440 nvram_set("ipv6_rtr_addr", getifaddr(nvram_safe_get("lan_ifname"), AF_INET6, 0));
442 // extract prefix from configured IPv6 address
443 if (inet_pton(AF_INET6, nvram_safe_get("ipv6_rtr_addr"), &addr) > 0) {
444 r = nvram_get_int("ipv6_prefix_length") ? : 64;
445 for (r = 128 - r, i = 15; r > 0; r -= 8) {
446 if (r >= 8)
447 addr.s6_addr[i--] = 0;
448 else
449 addr.s6_addr[i--] &= (0xff << r);
451 inet_ntop(AF_INET6, &addr, prefix, sizeof(prefix));
452 nvram_set("ipv6_prefix", prefix);
455 if (env2nv("new_domain_name_servers", "ipv6_get_dns")) {
456 dns_to_resolv();
457 // start_dnsmasq(); // (re)start KDB don't do twice!
460 // (re)start dnsmasq and httpd
461 start_dnsmasq();
462 start_httpd();
464 TRACE_PT("ipv6_get_dns=%s\n", nvram_safe_get("ipv6_get_dns"));
465 TRACE_PT("end\n");
466 return 0;
469 void start_dhcp6c(void)
471 FILE *f;
472 int prefix_len;
473 char *wan6face;
474 char *argv[] = { "dhcp6c", "-T", "LL", NULL, NULL, NULL };
475 int argc;
477 TRACE_PT("begin\n");
479 // Check if turned on
480 if (get_ipv6_service() != IPV6_NATIVE_DHCP) return;
482 prefix_len = 64 - (nvram_get_int("ipv6_prefix_length") ? : 64);
483 if (prefix_len < 0)
484 prefix_len = 0;
485 wan6face = nvram_safe_get("wan_iface");
487 nvram_set("ipv6_get_dns", "");
488 nvram_set("ipv6_rtr_addr", "");
489 nvram_set("ipv6_prefix", "");
491 // Create dhcp6c.conf
492 if ((f = fopen("/etc/dhcp6c.conf", "w"))) {
493 fprintf(f,
494 "interface %s {\n"
495 " send ia-pd 0;\n"
496 " send rapid-commit;\n"
497 " request domain-name-servers;\n"
498 " script \"/sbin/dhcp6c-state\";\n"
499 "};\n"
500 "id-assoc pd 0 {\n"
501 " prefix-interface %s {\n"
502 " sla-id 0;\n"
503 " sla-len %d;\n"
504 " };\n"
505 "};\n"
506 "id-assoc na 0 { };\n",
507 wan6face,
508 nvram_safe_get("lan_ifname"),
509 prefix_len);
510 fclose(f);
513 argc = 3;
514 if (nvram_get_int("debug_ipv6"))
515 argv[argc++] = "-D";
516 argv[argc++] = wan6face;
517 argv[argc] = NULL;
518 _eval(argv, NULL, 0, NULL);
520 TRACE_PT("end\n");
523 void stop_dhcp6c(void)
525 TRACE_PT("begin\n");
527 killall("dhcp6c-event", SIGTERM);
528 killall_tk("dhcp6c");
530 TRACE_PT("end\n");
533 #endif // TCONFIG_IPV6