DHCP routes: handle renewal correctly
[tomato.git] / release / src / router / rc / dhcp.c
blob0b2d35e615e3e6947c607e03352edf6407e44dca
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>
43 #define IFUP (IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST)
45 static void expires(unsigned int seconds)
47 struct sysinfo info;
48 char s[32];
50 sysinfo(&info);
51 sprintf(s, "%u", (unsigned int)info.uptime + seconds);
52 f_write_string("/var/lib/misc/dhcpc.expires", s, 0, 0);
55 // copy env to nvram
56 // returns 1 if new/changed, 0 if not changed/no env
57 static int env2nv(char *env, char *nv)
59 char *value;
60 if ((value = getenv(env)) != NULL) {
61 if (!nvram_match(nv, value)) {
62 nvram_set(nv, value);
63 return 1;
66 return 0;
69 static void env2nv_gateway(const char *nv)
71 char *v;
72 char *b;
73 if ((v = getenv("router")) != NULL) {
74 if ((b = strdup(v)) != NULL) {
75 if ((v = strchr(b, ' ')) != NULL) *v = 0; // truncate multiple entries
76 nvram_set(nv, b);
77 free(b);
82 static const char renewing[] = "/var/lib/misc/dhcpc.renewing";
84 static int deconfig(char *ifname)
86 TRACE_PT("begin\n");
88 ifconfig(ifname, IFUP, "0.0.0.0", NULL);
90 nvram_set("wan_ipaddr", "0.0.0.0");
91 nvram_set("wan_netmask", "0.0.0.0");
92 nvram_set("wan_gateway", "0.0.0.0");
93 nvram_set("wan_get_dns", "");
94 nvram_set("wan_lease", "0");
95 nvram_set("wan_routes", "");
96 nvram_set("wan_msroutes", "");
97 expires(0);
99 // int i = 10;
100 // while ((route_del(ifname, 0, NULL, NULL, NULL) == 0) && (i-- > 0)) { }
102 TRACE_PT("end\n");
103 return 0;
106 static int renew(char *ifname)
108 char *a, *b;
109 int changed, routes_changed;
111 TRACE_PT("begin\n");
113 unlink(renewing);
115 changed = env2nv("ip", "wan_ipaddr");
116 changed |= env2nv("subnet", "wan_netmask");
117 if (changed) {
118 ifconfig(ifname, IFUP, nvram_safe_get("wan_ipaddr"), nvram_safe_get("wan_netmask"));
121 if (get_wan_proto() == WP_L2TP) {
122 env2nv_gateway("wan_gateway_buf");
124 else {
125 a = strdup(nvram_safe_get("wan_gateway"));
126 env2nv_gateway("wan_gateway");
127 b = nvram_safe_get("wan_gateway");
128 if ((a) && (strcmp(a, b) != 0)) {
129 route_del(ifname, 0, "0.0.0.0", a, "0.0.0.0");
130 route_add(ifname, 0, "0.0.0.0", b, "0.0.0.0");
131 changed = 1;
133 free(a);
136 changed |= env2nv("domain", "wan_get_domain");
137 changed |= env2nv("dns", "wan_get_dns");
139 nvram_set("wan_routes_save", nvram_safe_get("wan_routes"));
140 nvram_set("wan_msroutes_save", nvram_safe_get("wan_msroutes"));
141 routes_changed = env2nv("msroutes", "wan_msroutes_save");
143 /* RFC3442: If the DHCP server returns both a Classless Static Routes option
144 * and a Router option, the DHCP client MUST ignore the Router option.
145 * Overwrite "wan_routes" by "staticroutes" value if present.
147 if (!env2nv("staticroutes", "wan_routes_save"))
148 routes_changed |= env2nv("routes", "wan_routes_save");
149 else
150 routes_changed = 1;
151 changed |= routes_changed;
153 if ((a = getenv("lease")) != NULL) {
154 nvram_set("wan_lease", a);
155 expires(atoi(a));
158 if (changed) {
159 set_host_domain_name();
160 start_dnsmasq(); // (re)start
163 if (routes_changed) {
164 do_wan_routes(ifname, 0, 0);
165 nvram_set("wan_routes", nvram_safe_get("wan_routes_save"));
166 nvram_set("wan_msroutes", nvram_safe_get("wan_msroutes_save"));
167 do_wan_routes(ifname, 0, 1);
169 nvram_unset("wan_routes_save");
170 nvram_unset("wan_msroutes_save");
172 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
173 TRACE_PT("wan_netmask=%s\n", nvram_safe_get("wan_netmask"));
174 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
175 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
176 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
177 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
178 TRACE_PT("wan_routes=%s\n", nvram_safe_get("wan_routes"));
179 TRACE_PT("wan_msroutes=%s\n", nvram_safe_get("wan_msroutes"));
180 TRACE_PT("end\n");
181 return 0;
184 static int bound(char *ifname)
186 TRACE_PT("begin\n");
188 unlink(renewing);
190 env2nv("ip", "wan_ipaddr");
191 env2nv("subnet", "wan_netmask");
192 env2nv_gateway("wan_gateway");
193 env2nv("dns", "wan_get_dns");
194 env2nv("domain", "wan_get_domain");
195 env2nv("lease", "wan_lease");
196 env2nv("msroutes", "wan_msroutes");
198 /* RFC3442: If the DHCP server returns both a Classless Static Routes option
199 * and a Router option, the DHCP client MUST ignore the Router option.
200 * Overwrite "wan_routes" by "staticroutes" value if present.
202 if (!env2nv("staticroutes", "wan_routes"))
203 env2nv("routes", "wan_routes");
205 expires(atoi(safe_getenv("lease")));
207 TRACE_PT("wan_ipaddr=%s\n", nvram_safe_get("wan_ipaddr"));
208 TRACE_PT("wan_netmask=%s\n", nvram_safe_get("wan_netmask"));
209 TRACE_PT("wan_gateway=%s\n", nvram_safe_get("wan_gateway"));
210 TRACE_PT("wan_get_domain=%s\n", nvram_safe_get("wan_get_domain"));
211 TRACE_PT("wan_get_dns=%s\n", nvram_safe_get("wan_get_dns"));
212 TRACE_PT("wan_lease=%s\n", nvram_safe_get("wan_lease"));
213 TRACE_PT("wan_routes=%s\n", nvram_safe_get("wan_routes"));
214 TRACE_PT("wan_msroutes=%s\n", nvram_safe_get("wan_msroutes"));
216 ifconfig(ifname, IFUP, nvram_safe_get("wan_ipaddr"), nvram_safe_get("wan_netmask"));
218 int wan_proto = get_wan_proto();
219 if (wan_proto == WP_L2TP || wan_proto == WP_PPTP) {
220 int i = 0;
222 /* Delete all default routes */
223 while ((route_del(ifname, 0, NULL, NULL, NULL) == 0) || (i++ < 10));
225 /* Set default route to gateway if specified */
226 route_add(ifname, 0, "0.0.0.0", nvram_safe_get("wan_gateway"), "0.0.0.0");
228 /* Backup the default gateway. It should be used if L2TP connection is broken */
229 nvram_set("wan_gateway_buf", nvram_get("wan_gateway"));
231 dns_to_resolv();
232 start_dnsmasq();
233 /* clear dns from the resolv.conf */
234 nvram_set("wan_get_dns","");
236 start_firewall();
237 switch (wan_proto) {
238 case WP_PPTP:
239 start_pptp(BOOT);
240 // we don't need dhcp anymore ?
241 // xstart("service", "dhcpc", "stop");
242 break;
243 case WP_L2TP:
244 start_l2tp();
245 break;
248 else {
249 start_wan_done(ifname);
252 TRACE_PT("end\n");
253 return 0;
256 int dhcpc_event_main(int argc, char **argv)
258 char *ifname;
260 if (!wait_action_idle(10)) return 1;
262 if ((argc == 2) && (ifname = getenv("interface")) != NULL) {
263 TRACE_PT("event=%s\n", argv[1]);
265 if (strcmp(argv[1], "deconfig") == 0) return deconfig(ifname);
266 if (strcmp(argv[1], "bound") == 0) return bound(ifname);
267 if ((strcmp(argv[1], "renew") == 0) || (strcmp(argv[1], "update") == 0)) return renew(ifname);
270 return 1;
274 // -----------------------------------------------------------------------------
277 int dhcpc_release_main(int argc, char **argv)
279 TRACE_PT("begin\n");
281 if (!using_dhcpc()) return 1;
283 deconfig(nvram_safe_get("wan_ifname"));
284 killall("udhcpc", SIGUSR2);
285 unlink(renewing);
286 unlink("/var/lib/misc/wan.connecting");
288 TRACE_PT("end\n");
289 return 0;
292 int dhcpc_renew_main(int argc, char **argv)
294 int pid;
296 TRACE_PT("begin\n");
298 if (!using_dhcpc()) return 1;
300 if ((pid = pidof("udhcpc")) > 1) {
301 kill(pid, SIGUSR1);
302 f_write(renewing, NULL, 0, 0, 0);
304 else {
305 stop_dhcpc();
306 start_dhcpc();
309 TRACE_PT("end\n");
310 return 0;
314 // -----------------------------------------------------------------------------
317 void start_dhcpc(void)
319 char *argv[6];
320 int argc;
321 char *ifname;
323 TRACE_PT("begin\n");
325 nvram_set("wan_get_dns", "");
326 f_write(renewing, NULL, 0, 0, 0);
328 ifname = nvram_safe_get("wan_ifname");
329 if (get_wan_proto() != WP_L2TP) {
330 nvram_set("wan_iface", ifname);
333 argc = 0;
334 argv[1] = nvram_safe_get("wan_hostname");
335 if (*argv[1]) {
336 argv[0] = "-H";
337 argc = 2;
340 if (nvram_get_int("dhcpc_minpkt")) argv[argc++] = "-m";
342 if (nvram_contains_word("log_events", "dhcpc")) argv[argc++] = "-S";
343 argv[argc] = NULL;
345 xstart(
346 "udhcpc",
347 "-i", ifname,
348 "-s", "dhcpc-event",
349 argv[0], argv[1], // -H wan_hostname
350 argv[2], // -m
351 argv[3] // -S
353 TRACE_PT("end\n");
356 void stop_dhcpc(void)
358 TRACE_PT("begin\n");
360 killall("dhcpc-event", SIGTERM);
361 if (killall("udhcpc", SIGUSR2) == 0) { // release
362 sleep(2);
364 killall_tk("udhcpc");
365 unlink(renewing);
367 TRACE_PT("end\n");