cosmetics
[tomato.git] / release / src / router / rc / dhcp.c
blobd653456052b8dfe3c1537ff4863e0894ea676e63
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 TRACE_PT("end\n");
130 return 0;
133 static int bound(char *ifname, int renew);
135 static int renew(char *ifname)
137 char *a;
138 int changed = 0, routes_changed = 0;
139 int wan_proto = get_wan_proto();
141 TRACE_PT("begin\n");
143 unlink(renewing);
145 if (env2nv("ip", "wan_ipaddr") ||
146 env2nv_gateway("wan_gateway") ||
147 (wan_proto == WP_DHCP && env2nv("subnet", "wan_netmask"))) {
148 /* WAN IP or gateway changed, restart/reconfigure everything */
149 TRACE_PT("end\n");
150 return bound(ifname, 1);
153 if (wan_proto == WP_DHCP) {
154 changed |= env2nv("domain", "wan_get_domain");
155 changed |= env2nv("dns", "wan_get_dns");
158 nvram_set("wan_routes1_save", nvram_safe_get("wan_routes1"));
159 nvram_set("wan_routes2_save", nvram_safe_get("wan_routes2"));
161 /* Classless Static Routes (option 121) or MS Classless Static Routes (option 249) */
162 if (getenv("staticroutes"))
163 routes_changed |= env2nv("staticroutes", "wan_routes1_save");
164 else
165 routes_changed |= env2nv("msstaticroutes", "wan_routes1_save");
166 /* Static Routes (option 33) */
167 routes_changed |= env2nv("routes", "wan_routes2_save");
169 changed |= routes_changed;
171 if ((a = getenv("lease")) != NULL) {
172 nvram_set("wan_lease", a);
173 expires(atoi(a));
176 if (changed) {
177 set_host_domain_name();
178 start_dnsmasq(); // (re)start
181 if (routes_changed) {
182 do_wan_routes(ifname, 0, 0);
183 nvram_set("wan_routes1", nvram_safe_get("wan_routes1_save"));
184 nvram_set("wan_routes2", nvram_safe_get("wan_routes2_save"));
185 do_wan_routes(ifname, 0, 1);
187 nvram_unset("wan_routes1_save");
188 nvram_unset("wan_routes2_save");
190 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
191 TRACE_PT("wan_netmask=%s\n", nvram_safe_get("wan_netmask"));
192 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
193 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
194 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
195 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
196 TRACE_PT("wan_routes1=%s\n", nvram_safe_get("wan_routes1"));
197 TRACE_PT("wan_routes2=%s\n", nvram_safe_get("wan_routes2"));
198 TRACE_PT("end\n");
199 return 0;
202 static int bound(char *ifname, int renew)
204 TRACE_PT("begin\n");
206 unlink(renewing);
208 char *netmask, *dns;
209 int wan_proto = get_wan_proto();
211 dns = nvram_safe_get("wan_get_dns");
212 nvram_set("wan_routes1", "");
213 nvram_set("wan_routes2", "");
214 env2nv("ip", "wan_ipaddr");
215 env2nv_gateway("wan_gateway");
216 env2nv("dns", "wan_get_dns");
217 env2nv("domain", "wan_get_domain");
218 env2nv("lease", "wan_lease");
219 netmask = getenv("subnet") ? : "255.255.255.255";
220 if (wan_proto == WP_DHCP) {
221 nvram_set("wan_netmask", netmask);
222 nvram_set("wan_gateway_get", nvram_safe_get("wan_gateway"));
225 /* RFC3442: If the DHCP server returns both a Classless Static Routes option
226 * and a Router option, the DHCP client MUST ignore the Router option.
227 * Similarly, if the DHCP server returns both a Classless Static Routes
228 * option and a Static Routes option, the DHCP client MUST ignore the
229 * Static Routes option.
230 * Ref: http://www.faqs.org/rfcs/rfc3442.html
232 /* Classless Static Routes (option 121) */
233 if (!env2nv("staticroutes", "wan_routes1"))
234 /* or MS Classless Static Routes (option 249) */
235 env2nv("msstaticroutes", "wan_routes1");
236 /* Static Routes (option 33) */
237 env2nv("routes", "wan_routes2");
239 expires(atoi(safe_getenv("lease")));
241 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
242 TRACE_PT("wan_netmask=%s\n", netmask);
243 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
244 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
245 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
246 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
247 TRACE_PT("wan_routes1=%s\n", nvram_safe_get("wan_routes1"));
248 TRACE_PT("wan_routes2=%s\n", nvram_safe_get("wan_routes2"));
250 ifconfig(ifname, IFUP, "0.0.0.0", NULL);
251 ifconfig(ifname, IFUP, nvram_safe_get("wan_ipaddr"), netmask);
253 if (wan_proto != WP_DHCP) {
254 char *gw = nvram_safe_get("wan_gateway");
256 preset_wan(ifname, gw, netmask);
258 /* clear dns from the resolv.conf */
259 nvram_set("wan_get_dns", renew ? dns : "");
261 switch (wan_proto) {
262 case WP_PPTP:
263 start_pptp(BOOT);
264 break;
265 case WP_L2TP:
266 start_l2tp();
267 break;
270 else {
271 start_wan_done(ifname);
274 TRACE_PT("end\n");
275 return 0;
278 int dhcpc_event_main(int argc, char **argv)
280 char *ifname;
282 if (!wait_action_idle(10)) return 1;
284 if ((argc == 2) && (ifname = getenv("interface")) != NULL) {
285 TRACE_PT("event=%s\n", argv[1]);
287 if (strcmp(argv[1], "deconfig") == 0) return deconfig(ifname);
288 if (strcmp(argv[1], "bound") == 0) return bound(ifname, 0);
289 if ((strcmp(argv[1], "renew") == 0) || (strcmp(argv[1], "update") == 0)) return renew(ifname);
292 return 1;
296 // -----------------------------------------------------------------------------
299 int dhcpc_release_main(int argc, char **argv)
301 TRACE_PT("begin\n");
303 if (!using_dhcpc()) return 1;
305 if (killall("udhcpc", SIGUSR2) == 0) {
306 sleep(2);
309 unlink(renewing);
310 unlink("/var/lib/misc/wan.connecting");
312 TRACE_PT("end\n");
313 return 0;
316 int dhcpc_renew_main(int argc, char **argv)
318 int pid;
320 TRACE_PT("begin\n");
322 if (!using_dhcpc()) return 1;
324 if ((pid = pidof("udhcpc")) > 1) {
325 kill(pid, SIGUSR1);
326 f_write(renewing, NULL, 0, 0, 0);
328 else {
329 stop_dhcpc();
330 start_dhcpc();
333 TRACE_PT("end\n");
334 return 0;
338 // -----------------------------------------------------------------------------
341 void start_dhcpc(void)
343 char cmd[256];
344 char *ifname;
345 char *p;
346 int proto;
348 TRACE_PT("begin\n");
350 nvram_set("wan_get_dns", "");
351 f_write(renewing, NULL, 0, 0, 0);
353 ifname = nvram_safe_get("wan_ifname");
354 proto = get_wan_proto();
355 if (proto == WP_DHCP) {
356 nvram_set("wan_iface", ifname);
359 #if 1 // REMOVEME after 1/1/2012
360 // temporary code for compatibility with old nvram variables
361 int changed = 0;
362 strcpy(cmd, nvram_safe_get("dhcpc_custom"));
363 if (strstr(cmd, "-V ") == NULL) {
364 if ((p = nvram_get("dhcpc_vendorclass")) && (*p)) {
365 changed++;
366 strcat(cmd, " -V ");
367 strcat(cmd, p);
370 if (strstr(cmd, "-r ") == NULL) {
371 if ((p = nvram_get("dhcpc_requestip")) && (*p) && (strcmp(p, "0.0.0.0") != 0)) {
372 changed++;
373 strcat(cmd, " -r ");
374 strcat(cmd, p);
377 if (changed) {
378 nvram_set("dhcpc_custom", cmd);
380 #endif
382 snprintf(cmd, sizeof(cmd),
383 "udhcpc -i %s -b -s dhcpc-event %s %s %s %s %s",
384 ifname,
385 nvram_invmatch("wan_hostname", "") ? "-H" : "", nvram_safe_get("wan_hostname"),
386 nvram_get_int("dhcpc_minpkt") ? "-m" : "",
387 nvram_contains_word("log_events", "dhcpc") ? "-S" : "",
388 nvram_safe_get("dhcpc_custom"));
390 xstart("/bin/sh", "-c", cmd);
392 TRACE_PT("end\n");
395 void stop_dhcpc(void)
397 TRACE_PT("begin\n");
399 killall("dhcpc-event", SIGTERM);
400 if (killall("udhcpc", SIGUSR2) == 0) { // release
401 sleep(2);
403 killall_tk("udhcpc");
404 unlink(renewing);
406 TRACE_PT("end\n");
409 // -----------------------------------------------------------------------------
411 #ifdef TCONFIG_IPV6
413 int dhcp6c_state_main(int argc, char **argv)
415 char prefix[INET6_ADDRSTRLEN];
416 struct in6_addr addr;
417 int i, r;
419 TRACE_PT("begin\n");
421 if (!wait_action_idle(10)) return 1;
423 nvram_set("ipv6_rtr_addr", getifaddr(nvram_safe_get("lan_ifname"), AF_INET6, 0));
425 // extract prefix from configured IPv6 address
426 if (inet_pton(AF_INET6, nvram_safe_get("ipv6_rtr_addr"), &addr) > 0) {
427 r = nvram_get_int("ipv6_prefix_length") ? : 64;
428 for (r = 128 - r, i = 15; r > 0; r -= 8) {
429 if (r >= 8)
430 addr.s6_addr[i--] = 0;
431 else
432 addr.s6_addr[i--] &= (0xff << r);
434 inet_ntop(AF_INET6, &addr, prefix, sizeof(prefix));
435 nvram_set("ipv6_prefix", prefix);
438 if (env2nv("new_domain_name_servers", "ipv6_get_dns")) {
439 dns_to_resolv();
440 start_dnsmasq(); // (re)start
443 // (re)start radvd and httpd
444 start_radvd();
445 start_httpd();
447 TRACE_PT("ipv6_get_dns=%s\n", nvram_safe_get("ipv6_get_dns"));
448 TRACE_PT("end\n");
449 return 0;
452 void start_dhcp6c(void)
454 FILE *f;
455 int prefix_len;
456 char *wan6face;
457 char *argv[] = { "dhcp6c", NULL, NULL, NULL };
458 int argc;
460 TRACE_PT("begin\n");
462 // Check if turned on
463 if (get_ipv6_service() != IPV6_NATIVE_DHCP) return;
465 prefix_len = 64 - (nvram_get_int("ipv6_prefix_length") ? : 64);
466 if (prefix_len < 0)
467 prefix_len = 0;
468 wan6face = nvram_safe_get("wan_iface");
470 nvram_set("ipv6_get_dns", "");
471 nvram_set("ipv6_rtr_addr", "");
472 nvram_set("ipv6_prefix", "");
474 // Create dhcp6c.conf
475 if ((f = fopen("/etc/dhcp6c.conf", "w"))) {
476 fprintf(f,
477 "interface %s {\n"
478 " send ia-pd 0;\n"
479 " send rapid-commit;\n"
480 " request domain-name-servers;\n"
481 " script \"/sbin/dhcp6c-state\";\n"
482 "};\n"
483 "id-assoc pd 0 {\n"
484 " prefix-interface lo {\n"
485 " sla-id 0;\n"
486 " sla-len %d;\n"
487 " };\n"
488 " prefix-interface %s {\n"
489 " sla-id 1;\n"
490 " sla-len %d;\n"
491 " };\n"
492 "};\n",
493 wan6face,
494 prefix_len,
495 nvram_safe_get("lan_ifname"),
496 prefix_len);
497 fclose(f);
500 argc = 1;
501 if (nvram_get_int("debug_ipv6"))
502 argv[argc++] = "-D";
503 argv[argc++] = wan6face;
504 argv[argc] = NULL;
505 _eval(argv, NULL, 0, NULL);
507 TRACE_PT("end\n");
510 void stop_dhcp6c(void)
512 TRACE_PT("begin\n");
514 killall("dhcp6c-event", SIGTERM);
515 killall_tk("dhcp6c");
517 TRACE_PT("end\n");
520 #endif // TCONFIG_IPV6