1/*
2 * Routines for managing persistent storage of port mappings, etc.
3 *
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: nvparse.c,v 1.35 2010/07/30 06:38:12 Exp $
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdarg.h>
24#include <string.h>
25#include <ctype.h>
26#include <unistd.h>
27#include <limits.h>
28#include <sys/types.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <assert.h>
32
33#include <typedefs.h>
34#include <netconf.h>
35#include <bcmnvram.h>
36#include <shutils.h>
37#include <nvparse.h>
38#include <bcmconfig.h>
39
40char *
41safe_snprintf(char *str, int *len, const char *fmt, ...)
42{
43	va_list ap;
44	int n;
45
46	va_start(ap, fmt);
47	n = vsnprintf(str, *len, fmt, ap);
48	va_end(ap);
49
50	if (n > 0) {
51		str += n;
52		*len -= n;
53	} else if (n < 0) {
54		*len = 0;
55	}
56
57	return str;
58}
59
60#ifdef __CONFIG_NAT__
61bool
62valid_autofw_port(const netconf_app_t *app)
63{
64	/* Check outbound protocol */
65	if (app->match.ipproto != IPPROTO_TCP && app->match.ipproto != IPPROTO_UDP)
66		return FALSE;
67
68	/* Check outbound port range */
69	if (ntohs(app->match.dst.ports[0]) > ntohs(app->match.dst.ports[1]))
70		return FALSE;
71
72	/* Check related protocol */
73	if (app->proto != IPPROTO_TCP && app->proto != IPPROTO_UDP)
74		return FALSE;
75
76	/* Check related destination port range */
77	if (ntohs(app->dport[0]) > ntohs(app->dport[1]))
78		return FALSE;
79
80	/* Check mapped destination port range */
81	if (ntohs(app->to[0]) > ntohs(app->to[1]))
82		return FALSE;
83
84	/* Check port range size */
85	if ((ntohs(app->dport[1]) - ntohs(app->dport[0])) !=
86	    (ntohs(app->to[1]) - ntohs(app->to[0])))
87		return FALSE;
88
89	return TRUE;
90}
91
92bool
93get_autofw_port(int which, netconf_app_t *app)
94{
95	char name[] = "autofw_portXXXXXXXXXX", value[1000];
96	char *out_proto, *out_start, *out_end, *in_proto, *in_start, *in_end, *to_start, *to_end;
97	char *enable, *desc;
98
99	memset(app, 0, sizeof(netconf_app_t));
100
101	/* Parse out_proto:out_start-out_end,in_proto:in_start-in_end>to_start-to_end,enable,desc */
102	snprintf(name, sizeof(name), "autofw_port%d", which);
103	if (!nvram_invmatch(name, ""))
104		return FALSE;
105	strncpy(value, nvram_get(name), sizeof(value));
106
107	/* Check for outbound port specification */
108	out_start = value;
109	out_proto = strsep(&out_start, ":");
110	if (!out_start)
111		return FALSE;
112
113	/* Check for related protocol specification */
114	in_proto = out_start;
115	out_start = strsep(&in_proto, ",");
116	if (!in_proto)
117		return FALSE;
118
119	/* Check for related destination port specification */
120	in_start = in_proto;
121	in_proto = strsep(&in_start, ":");
122	if (!in_start)
123		return FALSE;
124
125	/* Check for mapped destination port specification */
126	to_start = in_start;
127	in_start = strsep(&to_start, ">");
128	if (!to_start)
129		return FALSE;
130
131	/* Check for enable specification */
132	enable = to_start;
133	to_end = strsep(&enable, ",");
134	if (!enable)
135		return FALSE;
136
137	/* Check for description specification (optional) */
138	desc = enable;
139	enable = strsep(&desc, ",");
140
141	/* Check for outbound port range (optional) */
142	out_end = out_start;
143	out_start = strsep(&out_end, "-");
144	if (!out_end)
145		out_end = out_start;
146
147	/* Check for related destination port range (optional) */
148	in_end = in_start;
149	in_start = strsep(&in_end, "-");
150	if (!in_end)
151		in_end = in_start;
152
153	/* Check for mapped destination port range (optional) */
154	to_end = to_start;
155	to_start = strsep(&to_end, "-");
156	if (!to_end)
157		to_end = to_start;
158
159	/* Parse outbound protocol */
160	if (!strncasecmp(out_proto, "tcp", 3))
161		app->match.ipproto = IPPROTO_TCP;
162	else if (!strncasecmp(out_proto, "udp", 3))
163		app->match.ipproto = IPPROTO_UDP;
164	else
165		return FALSE;
166
167	/* Parse outbound port range */
168	app->match.dst.ports[0] = htons(atoi(out_start));
169	app->match.dst.ports[1] = htons(atoi(out_end));
170
171	/* Parse related protocol */
172	if (!strncasecmp(in_proto, "tcp", 3))
173		app->proto = IPPROTO_TCP;
174	else if (!strncasecmp(in_proto, "udp", 3))
175		app->proto = IPPROTO_UDP;
176	else
177		return FALSE;
178
179	/* Parse related destination port range */
180	app->dport[0] = htons(atoi(in_start));
181	app->dport[1] = htons(atoi(in_end));
182
183	/* Parse mapped destination port range */
184	app->to[0] = htons(atoi(to_start));
185	app->to[1] = htons(atoi(to_end));
186
187	/* Parse enable */
188	if (!strncasecmp(enable, "off", 3))
189		app->match.flags = NETCONF_DISABLED;
190
191	/* Parse description */
192	if (desc)
193		strncpy(app->desc, desc, sizeof(app->desc));
194
195	/* Set interface name (match packets entering LAN interface) */
196	strncpy(app->match.in.name, nvram_safe_get("lan_ifname"), IFNAMSIZ);
197
198	/* Set LAN source port range (match packets from any source port) */
199	app->match.src.ports[1] = htons(0xffff);
200
201	/* Set target (application specific port forward) */
202	app->target = NETCONF_APP;
203
204	return valid_autofw_port(app);
205}
206
207bool
208set_autofw_port(int which, const netconf_app_t *app)
209{
210	char name[] = "autofw_portXXXXXXXXXX", value[1000], *cur = value;
211	int len;
212
213	if (!valid_autofw_port(app))
214		return FALSE;
215
216	/* Set out_proto:out_start-out_end,in_proto:in_start-in_end>to_start-to_end,enable,desc */
217	snprintf(name, sizeof(name), "autofw_port%d", which);
218	len = sizeof(value);
219
220	/* Set outbound protocol */
221	if (app->match.ipproto == IPPROTO_TCP)
222		cur = safe_snprintf(cur, &len, "tcp");
223	else if (app->match.ipproto == IPPROTO_UDP)
224		cur = safe_snprintf(cur, &len, "udp");
225
226	/* Set outbound port */
227	cur = safe_snprintf(cur, &len, ":");
228	cur = safe_snprintf(cur, &len, "%d", ntohs(app->match.dst.ports[0]));
229	cur = safe_snprintf(cur, &len, "-");
230	cur = safe_snprintf(cur, &len, "%d", ntohs(app->match.dst.ports[1]));
231
232	/* Set related protocol */
233	cur = safe_snprintf(cur, &len, ",");
234	if (app->proto == IPPROTO_TCP)
235		cur = safe_snprintf(cur, &len, "tcp");
236	else if (app->proto == IPPROTO_UDP)
237		cur = safe_snprintf(cur, &len, "udp");
238
239	/* Set related destination port range */
240	cur = safe_snprintf(cur, &len, ":");
241	cur = safe_snprintf(cur, &len, "%d", ntohs(app->dport[0]));
242	cur = safe_snprintf(cur, &len, "-");
243	cur = safe_snprintf(cur, &len, "%d", ntohs(app->dport[1]));
244
245	/* Set mapped destination port range */
246	cur = safe_snprintf(cur, &len, ">");
247	cur = safe_snprintf(cur, &len, "%d", ntohs(app->to[0]));
248	cur = safe_snprintf(cur, &len, "-");
249	cur = safe_snprintf(cur, &len, "%d", ntohs(app->to[1]));
250
251	/* Set enable */
252	cur = safe_snprintf(cur, &len, ",");
253	if (app->match.flags & NETCONF_DISABLED)
254		cur = safe_snprintf(cur, &len, "off");
255	else
256		cur = safe_snprintf(cur, &len, "on");
257
258	/* Set description */
259	if (*app->desc) {
260		cur = safe_snprintf(cur, &len, ",");
261		cur = safe_snprintf(cur, &len, app->desc);
262	}
263
264	/* Do it */
265	if (nvram_set(name, value))
266		return FALSE;
267
268	return TRUE;
269}
270
271bool
272del_autofw_port(int which)
273{
274	char name[] = "autofw_portXXXXXXXXXX";
275
276	snprintf(name, sizeof(name), "autofw_port%d", which);
277	return (nvram_unset(name) == 0) ? TRUE : FALSE;
278}
279
280bool
281valid_forward_port(const netconf_nat_t *nat)
282{
283	/* Check WAN destination port range */
284	if (ntohs(nat->match.dst.ports[0]) > ntohs(nat->match.dst.ports[1]))
285		return FALSE;
286
287	/* Check protocol */
288	if (nat->match.ipproto != IPPROTO_TCP && nat->match.ipproto != IPPROTO_UDP)
289		return FALSE;
290
291	/* Check LAN IP address */
292	if (nat->ipaddr.s_addr == htonl(0))
293		return FALSE;
294
295	/* Check LAN destination port range */
296	if (ntohs(nat->ports[0]) > ntohs(nat->ports[1]))
297		return FALSE;
298
299	/* Check port range size */
300	if ((ntohs(nat->match.dst.ports[1]) - ntohs(nat->match.dst.ports[0])) !=
301	    (ntohs(nat->ports[1]) - ntohs(nat->ports[0])))
302		return FALSE;
303
304	return TRUE;
305}
306
307bool
308get_forward_port(int which, netconf_nat_t *nat)
309{
310	char name[] = "forward_portXXXXXXXXXX", value[1000];
311	char *wan_port0, *wan_port1, *lan_ipaddr, *lan_port0, *lan_port1, *proto;
312	char *enable, *desc;
313
314	memset(nat, 0, sizeof(netconf_nat_t));
315
316	/* Parse wan_port0-wan_port1>lan_ipaddr:lan_port0-lan_port1[:,]proto[:,]enable[:,]desc */
317	snprintf(name, sizeof(name), "forward_port%d", which);
318	if (!nvram_invmatch(name, ""))
319		return FALSE;
320	strncpy(value, nvram_get(name), sizeof(value));
321
322	/* Check for LAN IP address specification */
323	lan_ipaddr = value;
324	wan_port0 = strsep(&lan_ipaddr, ">");
325	if (!lan_ipaddr)
326		return FALSE;
327
328	/* Check for LAN destination port specification */
329	lan_port0 = lan_ipaddr;
330	lan_ipaddr = strsep(&lan_port0, ":");
331	if (!lan_port0)
332		return FALSE;
333
334	/* Check for protocol specification */
335	proto = lan_port0;
336	lan_port0 = strsep(&proto, ":,");
337	if (!proto)
338		return FALSE;
339
340	/* Check for enable specification */
341	enable = proto;
342	proto = strsep(&enable, ":,");
343	if (!enable)
344		return FALSE;
345
346	/* Check for description specification (optional) */
347	desc = enable;
348	enable = strsep(&desc, ":,");
349
350	/* Check for WAN destination port range (optional) */
351	wan_port1 = wan_port0;
352	wan_port0 = strsep(&wan_port1, "-");
353	if (!wan_port1)
354		wan_port1 = wan_port0;
355
356	/* Check for LAN destination port range (optional) */
357	lan_port1 = lan_port0;
358	lan_port0 = strsep(&lan_port1, "-");
359	if (!lan_port1)
360		lan_port1 = lan_port0;
361
362	/* Parse WAN destination port range */
363	nat->match.dst.ports[0] = htons(atoi(wan_port0));
364	nat->match.dst.ports[1] = htons(atoi(wan_port1));
365
366	/* Parse LAN IP address */
367	(void) inet_aton(lan_ipaddr, &nat->ipaddr);
368
369	/* Parse LAN destination port range */
370	nat->ports[0] = htons(atoi(lan_port0));
371	nat->ports[1] = htons(atoi(lan_port1));
372
373	/* Parse protocol */
374	if (!strncasecmp(proto, "tcp", 3))
375		nat->match.ipproto = IPPROTO_TCP;
376	else if (!strncasecmp(proto, "udp", 3))
377		nat->match.ipproto = IPPROTO_UDP;
378	else
379		return FALSE;
380
381	/* Parse enable */
382	if (!strncasecmp(enable, "off", 3))
383		nat->match.flags = NETCONF_DISABLED;
384
385	/* Parse description */
386	if (desc)
387		strncpy(nat->desc, desc, sizeof(nat->desc));
388	/* Set WAN source port range (match packets from any source port) */
389	nat->match.src.ports[1] = htons(0xffff);
390
391	/* Set target (DNAT) */
392	nat->target = NETCONF_DNAT;
393
394	return valid_forward_port(nat);
395}
396
397bool
398set_forward_port(int which, const netconf_nat_t *nat)
399{
400	char name[] = "forward_portXXXXXXXXXX", value[1000], *cur = value;
401	int len;
402
403	if (!valid_forward_port(nat))
404		return FALSE;
405
406	/* Set wan_port0-wan_port1>lan_ipaddr:lan_port0-lan_port1,proto,enable,desc */
407	snprintf(name, sizeof(name), "forward_port%d", which);
408	len = sizeof(value);
409
410	/* Set WAN destination port range */
411	cur = safe_snprintf(cur, &len, "%d", ntohs(nat->match.dst.ports[0]));
412	cur = safe_snprintf(cur, &len, "-");
413	cur = safe_snprintf(cur, &len, "%d", ntohs(nat->match.dst.ports[1]));
414
415	/* Set LAN IP address */
416	cur = safe_snprintf(cur, &len, ">");
417	cur = safe_snprintf(cur, &len, inet_ntoa(nat->ipaddr));
418
419	/* Set LAN destination port range */
420	cur = safe_snprintf(cur, &len, ":");
421	cur = safe_snprintf(cur, &len, "%d", ntohs(nat->ports[0]));
422	cur = safe_snprintf(cur, &len, "-");
423	cur = safe_snprintf(cur, &len, "%d", ntohs(nat->ports[1]));
424
425	/* Set protocol */
426	cur = safe_snprintf(cur, &len, ",");
427	if (nat->match.ipproto == IPPROTO_TCP)
428		cur = safe_snprintf(cur, &len, "tcp");
429	else if (nat->match.ipproto == IPPROTO_UDP)
430		cur = safe_snprintf(cur, &len, "udp");
431
432	/* Set enable */
433	cur = safe_snprintf(cur, &len, ",");
434	if (nat->match.flags & NETCONF_DISABLED)
435		cur = safe_snprintf(cur, &len, "off");
436	else
437		cur = safe_snprintf(cur, &len, "on");
438
439	/* Set description */
440	if (*nat->desc) {
441		cur = safe_snprintf(cur, &len, ",");
442		cur = safe_snprintf(cur, &len, nat->desc);
443	}
444
445	/* Do it */
446	if (nvram_set(name, value))
447		return FALSE;
448
449	return TRUE;
450}
451
452bool
453del_forward_port(int which)
454{
455	char name[] = "forward_portXXXXXXXXXX";
456
457	snprintf(name, sizeof(name), "forward_port%d", which);
458	return (nvram_unset(name) == 0) ? TRUE : FALSE;
459}
460
461static void
462convert_forward_proto(const char *name, int ipproto)
463{
464	char var[1000], *next;
465	char *wan_port0, *wan_port1, *lan_ipaddr, *lan_port0, *lan_port1;
466	netconf_nat_t nat, unused;
467	bool valid;
468	int i;
469
470	foreach(var, nvram_safe_get(name), next) {
471		/* Parse wan_port0-wan_port1>lan_ipaddr:lan_port0-lan_port1 */
472		lan_ipaddr = var;
473		wan_port0 = strsep(&lan_ipaddr, ">");
474		if (!lan_ipaddr)
475			continue;
476		lan_port0 = lan_ipaddr;
477		lan_ipaddr = strsep(&lan_port0, ":");
478		if (!lan_port0)
479			continue;
480		wan_port1 = wan_port0;
481		wan_port0 = strsep(&wan_port1, "-");
482		if (!wan_port1)
483			wan_port1 = wan_port0;
484		lan_port1 = lan_port0;
485		lan_port0 = strsep(&lan_port1, "-");
486		if (!lan_port1)
487			lan_port1 = lan_port0;
488
489		/* Set up parameters */
490		memset(&nat, 0, sizeof(netconf_nat_t));
491		nat.match.ipproto = ipproto;
492		nat.match.dst.ports[0] = htons(atoi(wan_port0));
493		nat.match.dst.ports[1] = htons(atoi(wan_port1));
494		(void) inet_aton(lan_ipaddr, &nat.ipaddr);
495		nat.ports[0] = htons(atoi(lan_port0));
496		nat.ports[1] = htons(atoi(lan_port1));
497
498		/* Replace an unused or invalid entry */
499		for (i = 0; get_forward_port(i, &unused); i++);
500		valid = set_forward_port(i, &nat);
501		assert(valid);
502	}
503
504	nvram_unset(name);
505}
506
507bool
508valid_filter_client(const netconf_filter_t *start, const netconf_filter_t *end)
509{
510	/* Check address range */
511	if (start->match.src.netmask.s_addr) {
512		if (start->match.src.netmask.s_addr != htonl(0xffffffff) ||
513		    start->match.src.netmask.s_addr != end->match.src.netmask.s_addr)
514			return FALSE;
515		if (ntohl(start->match.src.ipaddr.s_addr) > ntohl(end->match.src.ipaddr.s_addr))
516			return FALSE;
517	}
518
519	/* Check destination port range */
520	if (ntohs(start->match.dst.ports[0]) > ntohs(start->match.dst.ports[1]) ||
521	    start->match.dst.ports[0] != end->match.dst.ports[0] ||
522	    start->match.dst.ports[1] != end->match.dst.ports[1])
523		return FALSE;
524
525	/* Check protocol */
526	if ((start->match.ipproto != IPPROTO_TCP && start->match.ipproto != IPPROTO_UDP) ||
527	    start->match.ipproto != end->match.ipproto)
528		return FALSE;
529
530	/* Check day range */
531	if (start->match.days[0] < 0 || start->match.days[0] > 6 ||
532	    start->match.days[1] < 0 || start->match.days[1] > 6 ||
533	    start->match.days[0] != end->match.days[0] ||
534	    start->match.days[1] != end->match.days[1])
535		return FALSE;
536
537	/* Check time range */
538	if (start->match.secs[0] < 0 || start->match.secs[0] >= (24*60*60) ||
539	    start->match.secs[1] < 0 || start->match.secs[1] >= (24*60*60) ||
540	    start->match.secs[0] != end->match.secs[0] ||
541	    start->match.secs[1] != end->match.secs[1])
542		return FALSE;
543
544	return TRUE;
545}
546
547bool
548get_filter_client(int which, netconf_filter_t *start, netconf_filter_t *end)
549{
550	char name[] = "filter_clientXXXXXXXXXX", value[1000];
551	char *lan_ipaddr0, *lan_ipaddr1, *lan_port0, *lan_port1, *proto;
552	char *day_start, *day_end, *sec_start, *sec_end;
553	char *enable, *desc;
554
555	memset(start, 0, sizeof(netconf_filter_t));
556	memset(end, 0, sizeof(netconf_filter_t));
557
558	/* Parse
559	 * [lan_ipaddr0-lan_ipaddr1|*]:lan_port0-lan_port1,proto,day_start-day_end,
560	 * sec_start-sec_end,enable,desc
561	 */
562	snprintf(name, sizeof(name), "filter_client%d", which);
563	if (!nvram_invmatch(name, ""))
564		return FALSE;
565	strncpy(value, nvram_get(name), sizeof(value));
566
567	/* Check for port specification */
568	lan_port0 = value;
569	lan_ipaddr0 = strsep(&lan_port0, ":");
570	if (!lan_port0)
571		return FALSE;
572
573	/* Check for protocol specification */
574	proto = lan_port0;
575	lan_port0 = strsep(&proto, ",");
576	if (!proto)
577		return FALSE;
578
579	/* Check for day specification */
580	day_start = proto;
581	proto = strsep(&day_start, ",");
582	if (!day_start)
583		return FALSE;
584
585	/* Check for time specification */
586	sec_start = day_start;
587	day_start = strsep(&sec_start, ",");
588	if (!sec_start)
589		return FALSE;
590
591	/* Check for enable specification */
592	enable = sec_start;
593	sec_start = strsep(&enable, ",");
594	if (!enable)
595		return FALSE;
596
597	/* Check for description specification (optional) */
598	desc = enable;
599	enable = strsep(&desc, ",");
600
601	/* Check for address range (optional) */
602	lan_ipaddr1 = lan_ipaddr0;
603	lan_ipaddr0 = strsep(&lan_ipaddr1, "-");
604	if (!lan_ipaddr1)
605		lan_ipaddr1 = lan_ipaddr0;
606
607	/* Check for port range (optional) */
608	lan_port1 = lan_port0;
609	lan_port0 = strsep(&lan_port1, "-");
610	if (!lan_port1)
611		lan_port1 = lan_port0;
612
613	/* Check for day range (optional) */
614	day_end = day_start;
615	day_start = strsep(&day_end, "-");
616	if (!day_end)
617		day_end = day_start;
618
619	/* Check for time range (optional) */
620	sec_end = sec_start;
621	sec_start = strsep(&sec_end, "-");
622	if (!sec_end)
623		sec_end = sec_start;
624
625	/* Parse address range */
626	if (*lan_ipaddr0 == '*') {
627		/* Match any IP address */
628		start->match.src.ipaddr.s_addr = end->match.src.ipaddr.s_addr = htonl(0);
629		start->match.src.netmask.s_addr = end->match.src.netmask.s_addr = htonl(0);
630	} else {
631		/* Match a range of IP addresses */
632		inet_aton(lan_ipaddr0, &start->match.src.ipaddr);
633		inet_aton(lan_ipaddr1, &end->match.src.ipaddr);
634		start->match.src.netmask.s_addr = end->match.src.netmask.s_addr = htonl(0xffffffff);
635	}
636
637	/* Parse destination port range */
638	start->match.dst.ports[0] = end->match.dst.ports[0] = htons(atoi(lan_port0));
639	start->match.dst.ports[1] = end->match.dst.ports[1] = htons(atoi(lan_port1));
640
641	/* Parse protocol */
642	if (!strncasecmp(proto, "tcp", 3))
643		start->match.ipproto = end->match.ipproto = IPPROTO_TCP;
644	else if (!strncasecmp(proto, "udp", 3))
645		start->match.ipproto = end->match.ipproto = IPPROTO_UDP;
646	else
647		return FALSE;
648
649	/* Parse day range */
650	start->match.days[0] = end->match.days[0] = atoi(day_start);
651	start->match.days[1] = end->match.days[1] = atoi(day_end);
652
653	/* Parse time range */
654	start->match.secs[0] = end->match.secs[0] = atoi(sec_start);
655	start->match.secs[1] = end->match.secs[1] = atoi(sec_end);
656
657	/* Parse enable */
658	if (!strncasecmp(enable, "off", 3))
659		start->match.flags = end->match.flags = NETCONF_DISABLED;
660
661	/* Parse description */
662	if (desc) {
663		strncpy(start->desc, desc, sizeof(start->desc));
664		strncpy(end->desc, desc, sizeof(end->desc));
665	}
666
667	/* Set interface name (match packets entering LAN interface) */
668	strncpy(start->match.in.name, nvram_safe_get("lan_ifname"), IFNAMSIZ);
669
670	/* Set source port range (match packets from any source port) */
671	start->match.src.ports[1] = end->match.src.ports[1] = htons(0xffff);
672
673	/* Set default target (drop) */
674	start->target = NETCONF_DROP;
675
676	return valid_filter_client(start, end);
677}
678
679bool
680set_filter_client(int which, const netconf_filter_t *start, const netconf_filter_t *end)
681{
682	char name[] = "filter_clientXXXXXXXXXX", value[1000], *cur = value;
683	int len;
684
685	if (!valid_filter_client(start, end))
686		return FALSE;
687
688	/* Set
689	 * [lan_ipaddr0-lan_ipaddr1|*]:lan_port0-lan_port1,proto,day_start-day_end,
690	 * sec_start-sec_end,enable,desc
691	 */
692	snprintf(name, sizeof(name), "filter_client%d", which);
693	len = sizeof(value);
694
695	/* Set address range */
696	if (start->match.src.ipaddr.s_addr == htonl(0) &&
697	    end->match.src.ipaddr.s_addr == htonl(0) &&
698	    start->match.src.netmask.s_addr == htonl(0) &&
699	    end->match.src.netmask.s_addr == htonl(0))
700		cur = safe_snprintf(cur, &len, "*");
701	else {
702		cur = safe_snprintf(cur, &len, inet_ntoa(start->match.src.ipaddr));
703		cur = safe_snprintf(cur, &len, "-");
704		cur = safe_snprintf(cur, &len, inet_ntoa(end->match.src.ipaddr));
705	}
706
707	/* Set port range */
708	cur = safe_snprintf(cur, &len, ":");
709	cur = safe_snprintf(cur, &len, "%d", ntohs(start->match.dst.ports[0]));
710	cur = safe_snprintf(cur, &len, "-");
711	cur = safe_snprintf(cur, &len, "%d", ntohs(start->match.dst.ports[1]));
712
713	/* Set protocol */
714	cur = safe_snprintf(cur, &len, ",");
715	if (start->match.ipproto == IPPROTO_TCP)
716		cur = safe_snprintf(cur, &len, "tcp");
717	else if (start->match.ipproto == IPPROTO_UDP)
718		cur = safe_snprintf(cur, &len, "udp");
719
720	/* Set day range */
721	cur = safe_snprintf(cur, &len, ",");
722	cur = safe_snprintf(cur, &len, "%d", start->match.days[0]);
723	cur = safe_snprintf(cur, &len, "-");
724	cur = safe_snprintf(cur, &len, "%d", start->match.days[1]);
725
726	/* Set time range */
727	cur = safe_snprintf(cur, &len, ",");
728	cur = safe_snprintf(cur, &len, "%d", start->match.secs[0]);
729	cur = safe_snprintf(cur, &len, "-");
730	cur = safe_snprintf(cur, &len, "%d", start->match.secs[1]);
731
732	/* Set enable */
733	cur = safe_snprintf(cur, &len, ",");
734	if (start->match.flags & NETCONF_DISABLED)
735		cur = safe_snprintf(cur, &len, "off");
736	else
737		cur = safe_snprintf(cur, &len, "on");
738
739	/* Set description */
740	if (*start->desc) {
741		cur = safe_snprintf(cur, &len, ",");
742		cur = safe_snprintf(cur, &len, start->desc);
743	}
744
745	/* Do it */
746	if (nvram_set(name, value))
747		return FALSE;
748
749	return TRUE;
750}
751
752bool
753del_filter_client(int which)
754{
755	char name[] = "filter_clientXXXXXXXXXX";
756
757	snprintf(name, sizeof(name), "filter_client%d", which);
758	return (nvram_unset(name) == 0) ? TRUE : FALSE;
759}
760
761#ifdef __CONFIG_URLFILTER__
762bool
763valid_filter_url(const netconf_urlfilter_t *start, const netconf_urlfilter_t *end)
764{
765	/* Check address range */
766	if (start->match.src.netmask.s_addr) {
767		if (start->match.src.netmask.s_addr != htonl(0xffffffff) ||
768		    start->match.src.netmask.s_addr != end->match.src.netmask.s_addr)
769			return FALSE;
770		if (ntohl(start->match.src.ipaddr.s_addr) > ntohl(end->match.src.ipaddr.s_addr))
771			return FALSE;
772	}
773
774	return TRUE;
775}
776
777bool
778get_filter_url(int which, netconf_urlfilter_t *start, netconf_urlfilter_t *end)
779{
780	char name[] = "filter_urlXXXXXXXXXX", value[1000];
781	char *lan_ipaddr0, *lan_ipaddr1;
782	char *url, *enable, *desc;
783
784	memset(start, 0, sizeof(netconf_urlfilter_t));
785	memset(end, 0, sizeof(netconf_urlfilter_t));
786
787	/* Parse
788	 * [lan_ipaddr0-lan_ipaddr1|*]:url,enable,desc
789	 */
790	snprintf(name, sizeof(name), "filter_url%d", which);
791	if (!nvram_invmatch(name, ""))
792		return FALSE;
793	strncpy(value, nvram_get(name), sizeof(value));
794
795	/* Check for URL */
796	url = value;
797	lan_ipaddr0 = strsep(&url, ":");
798	if (!url)
799		return FALSE;
800
801	/* Check for enable specification */
802	enable = url;
803	url = strsep(&enable, ",");
804	if (!enable)
805		return FALSE;
806
807	/* Check for description specification (optional) */
808	desc = enable;
809	enable = strsep(&desc, ",");
810
811	/* Check for address range (optional) */
812	lan_ipaddr1 = lan_ipaddr0;
813	lan_ipaddr0 = strsep(&lan_ipaddr1, "-");
814	if (!lan_ipaddr1)
815		lan_ipaddr1 = lan_ipaddr0;
816
817	/* Parse address range */
818	if (*lan_ipaddr0 == '*') {
819		/* Match any IP address */
820		start->match.src.ipaddr.s_addr = end->match.src.ipaddr.s_addr = htonl(0);
821		start->match.src.netmask.s_addr = end->match.src.netmask.s_addr = htonl(0);
822	} else {
823		/* Match a range of IP addresses */
824		inet_aton(lan_ipaddr0, &start->match.src.ipaddr);
825		inet_aton(lan_ipaddr1, &end->match.src.ipaddr);
826		start->match.src.netmask.s_addr = end->match.src.netmask.s_addr = htonl(0xffffffff);
827	}
828
829	/* Parse enable */
830	if (!strncasecmp(enable, "off", 3))
831		start->match.flags = end->match.flags = NETCONF_DISABLED;
832
833	/* Parse description */
834	if (url) {
835		strncpy(start->url, url, sizeof(start->url));
836		strncpy(end->url, url, sizeof(end->url));
837	}
838
839	/* Parse description */
840	if (desc) {
841		strncpy(start->desc, desc, sizeof(start->desc));
842		strncpy(end->desc, desc, sizeof(end->desc));
843	}
844
845	/* Set interface name (match packets entering LAN interface) */
846	strncpy(start->match.in.name, nvram_safe_get("lan_ifname"), IFNAMSIZ);
847
848	/* Set default target (drop) */
849	start->target = NETCONF_DROP;
850
851	return valid_filter_url(start, end);
852}
853
854bool
855set_filter_url(int which, const netconf_urlfilter_t *start, const netconf_urlfilter_t *end)
856{
857	char name[] = "filter_urlXXXXXXXXXX", value[1000], *cur = value;
858	int len;
859
860	if (!valid_filter_url(start, end))
861		return FALSE;
862
863	/* Set
864	 * [lan_ipaddr0-lan_ipaddr1|*]:url,enable
865	 */
866	snprintf(name, sizeof(name), "filter_url%d", which);
867	len = sizeof(value);
868
869	/* Set address range */
870	if (start->match.src.ipaddr.s_addr == htonl(0) &&
871	    end->match.src.ipaddr.s_addr == htonl(0) &&
872	    start->match.src.netmask.s_addr == htonl(0) &&
873	    end->match.src.netmask.s_addr == htonl(0))
874		cur = safe_snprintf(cur, &len, "*");
875	else {
876		cur = safe_snprintf(cur, &len, inet_ntoa(start->match.src.ipaddr));
877		cur = safe_snprintf(cur, &len, "-");
878		cur = safe_snprintf(cur, &len, inet_ntoa(end->match.src.ipaddr));
879	}
880
881	/* Set URL */
882	cur = safe_snprintf(cur, &len, ":");
883	cur = safe_snprintf(cur, &len, "%s", start->url);
884
885	/* Set enable */
886	cur = safe_snprintf(cur, &len, ",");
887	if (start->match.flags & NETCONF_DISABLED)
888		cur = safe_snprintf(cur, &len, "off");
889	else
890		cur = safe_snprintf(cur, &len, "on");
891
892	/* Set description */
893	if (*start->desc) {
894		cur = safe_snprintf(cur, &len, ",");
895		cur = safe_snprintf(cur, &len, start->desc);
896	}
897
898	/* Do it */
899	if (nvram_set(name, value))
900		return FALSE;
901
902	return TRUE;
903}
904
905bool
906del_filter_url(int which)
907{
908	char name[] = "filter_urlXXXXXXXXXX";
909
910	snprintf(name, sizeof(name), "filter_url%d", which);
911	return (nvram_unset(name) == 0) ? TRUE : FALSE;
912}
913#endif /* __CONFIG_URLFILTER__ */
914#endif	/* __CONFIG_NAT__ */
915
916/*
917 * wl_wds<N> is authentication protocol dependant.
918 * when auth is "psk":
919 *	wl_wds<N>=mac,role,crypto,auth,ssid,passphrase
920 */
921bool
922get_wds_wsec(int unit, int which, unsigned char *mac, char *role,
923             char *crypto, char *auth, ...)
924{
925	char name[] = "wlXXXXXXX_wdsXXXXXXX", value[1000], *next;
926
927	snprintf(name, sizeof(name), "wl%d_wds%d", unit, which);
928	strncpy(value, nvram_safe_get(name), sizeof(value));
929	next = value;
930
931	/* separate mac */
932	strcpy((char *)mac, strsep(&next, ","));
933	if (!next)
934		return FALSE;
935
936	/* separate role */
937	strcpy(role, strsep(&next, ","));
938	if (!next)
939		return FALSE;
940
941	/* separate crypto */
942	strcpy(crypto, strsep(&next, ","));
943	if (!next)
944		return FALSE;
945
946	/* separate auth */
947	strcpy(auth, strsep(&next, ","));
948	if (!next)
949		return FALSE;
950
951	if (!strcmp(auth, "psk")) {
952		va_list va;
953
954		va_start(va, auth);
955
956		/* separate ssid */
957		strcpy(va_arg(va, char *), strsep(&next, ","));
958		if (!next)
959			goto fail;
960
961		/* separate passphrase */
962		strcpy(va_arg(va, char *), next);
963
964		va_end(va);
965		return TRUE;
966fail:
967		va_end(va);
968		return FALSE;
969	}
970
971	return FALSE;
972}
973
974bool
975set_wds_wsec(int unit, int which, unsigned char *mac, char *role,
976             char *crypto, char *auth, ...)
977{
978	char name[] = "wlXXXXXXX_wdsXXXXXXX", value[10000];
979
980	snprintf(name, sizeof(name), "wl%d_wds%d", unit, which);
981	snprintf(value, sizeof(value), "%s,%s,%s,%s",
982	         mac, role, crypto, auth);
983
984	if (!strcmp(auth, "psk")) {
985		int offset;
986		char *str1, *str2;
987		va_list va;
988
989		va_start(va, auth);
990		offset = strlen(value);
991		str1 = va_arg(va, char *);
992		str2 = va_arg(va, char *);
993
994		snprintf(&value[offset], sizeof(value) - offset, ",%s,%s", str1, str2);
995		va_end(va);
996
997		if (nvram_set(name, value))
998			return FALSE;
999
1000		return TRUE;
1001	}
1002
1003	return FALSE;
1004}
1005
1006bool
1007del_wds_wsec(int unit, int which)
1008{
1009	char name[] = "wlXXXXXXX_wdsXXXXXXX";
1010
1011	snprintf(name, sizeof(name), "wl%d_wds%d", unit, which);
1012
1013	nvram_unset(name);
1014
1015	return TRUE;
1016}
1017
1018#ifdef __CONFIG_NAT__
1019static void
1020convert_filter_ip(void)
1021{
1022	char var[1000], *next;
1023	char *lan_ipaddr0, *lan_ipaddr1;
1024	netconf_filter_t start, end, unused;
1025	bool valid;
1026	int i;
1027
1028	foreach(var, nvram_safe_get("filter_ip"), next) {
1029		/* Parse lan_ipaddr0-lan_ipaddr1 */
1030		lan_ipaddr1 = var;
1031		lan_ipaddr0 = strsep(&lan_ipaddr1, "-");
1032		if (!lan_ipaddr0 || !lan_ipaddr1)
1033			continue;
1034
1035		/* Set up parameters */
1036		memset(&start, 0, sizeof(netconf_filter_t));
1037		(void) inet_aton(lan_ipaddr0, &start.match.src.ipaddr);
1038		start.match.src.netmask.s_addr = htonl(0xffffffff);
1039		start.match.dst.ports[1] = htons(0xffff);
1040		memcpy(&end, &start, sizeof(netconf_filter_t));
1041		(void) inet_aton(lan_ipaddr1, &end.match.src.ipaddr);
1042
1043		/* Replace an unused or invalid entry */
1044		start.match.ipproto = end.match.ipproto = IPPROTO_TCP;
1045		for (i = 0; get_filter_client(i, &unused, &unused); i++);
1046		valid = set_filter_client(i, &start, &end);
1047		assert(valid);
1048
1049		/* Replace an unused or invalid entry */
1050		start.match.ipproto = end.match.ipproto = IPPROTO_UDP;
1051		for (; get_filter_client(i, &unused, &unused); i++);
1052		valid = set_filter_client(i, &start, &end);
1053		assert(valid);
1054	}
1055
1056	nvram_unset("filter_ip");
1057}
1058
1059static void
1060convert_filter_proto(const char *name, int ipproto)
1061{
1062	char var[1000], *next;
1063	char *lan_ipaddr, *lan_port0, *lan_port1;
1064	netconf_filter_t start, end, unused;
1065	bool valid;
1066	int i;
1067
1068	foreach(var, nvram_safe_get(name), next) {
1069		/* Parse [lan_ipaddr|*]:lan_port0-lan_port1 */
1070		lan_port0 = var;
1071		lan_ipaddr = strsep(&lan_port0, ":");
1072		if (!lan_ipaddr || !lan_port0)
1073			continue;
1074		lan_port1 = lan_port0;
1075		lan_port0 = strsep(&lan_port1, "-");
1076		if (!lan_port0 || !lan_port1)
1077			continue;
1078
1079		/* Set up parameters */
1080		memset(&start, 0, sizeof(netconf_filter_t));
1081		(void) inet_aton(lan_ipaddr, &start.match.src.ipaddr);
1082		start.match.src.netmask.s_addr = htonl(0xffffffff);
1083		start.match.ipproto = ipproto;
1084		start.match.dst.ports[0] = htons(atoi(lan_port0));
1085		start.match.dst.ports[1] = htons(atoi(lan_port1));
1086		memcpy(&end, &start, sizeof(netconf_filter_t));
1087
1088		/* Replace an unused or invalid entry */
1089		for (i = 0; get_filter_client(i, &unused, &unused); i++);
1090		valid = set_filter_client(i, &start, &end);
1091		assert(valid);
1092	}
1093
1094	nvram_unset(name);
1095}
1096
1097static void
1098convert_filter_port(void)
1099{
1100	char name[1000], *value, *colon;
1101	netconf_filter_t start, end, unused;
1102	bool valid;
1103	int i, j;
1104
1105	/* Maximum number of filter_port entries was 6 */
1106	for (i = 1; i <= 6; i++) {
1107		snprintf(name, sizeof(name), "filter_port%d", i);
1108		if (!(value = nvram_get(name)) || !*value)
1109			goto fail;
1110
1111		memset(&start, 0, sizeof(netconf_filter_t));
1112		memset(&end, 0, sizeof(netconf_filter_t));
1113
1114		/* Only the last bytes of IP addresses were stored in NVRAM */
1115		(void) inet_aton(nvram_safe_get("lan_ipaddr"), &start.match.src.ipaddr);
1116		(void) inet_aton(nvram_safe_get("lan_ipaddr"), &end.match.src.ipaddr);
1117
1118		/* id (unused) */
1119		if (!(colon = strchr(value, ':')))
1120			goto fail;
1121		value = colon + 1;
1122
1123		/* active */
1124		if (!(colon = strchr(value, ':')))
1125			goto fail;
1126		if (!strtoul(value, NULL, 0))
1127			start.match.flags = end.match.flags = NETCONF_DISABLED;
1128		value = colon + 1;
1129
1130		/* flags (unused) */
1131		if (!(colon = strchr(value, ':')))
1132			goto fail;
1133		value = colon + 1;
1134
1135		/* from_ip */
1136		if (!(colon = strchr(value, ':')))
1137			goto fail;
1138		start.match.src.ipaddr.s_addr = htonl((ntohl(start.match.src.ipaddr.s_addr) & ~0xff)
1139		                                      | strtoul(value, NULL, 0));
1140		value = colon + 1;
1141
1142		/* to_ip */
1143		if (!(colon = strchr(value, ':')))
1144			goto fail;
1145		end.match.src.ipaddr.s_addr = htonl((ntohl(end.match.src.ipaddr.s_addr) & ~0xff) |
1146		                                    strtoul(value, NULL, 0));
1147		value = colon + 1;
1148
1149		/* from_port */
1150		if (!(colon = strchr(value, ':')))
1151			goto fail;
1152		start.match.dst.ports[0] = end.match.dst.ports[0] = htons(strtoul(value, NULL, 0));
1153		value = colon + 1;
1154
1155		/* to_port */
1156		if (!(colon = strchr(value, ':')))
1157			goto fail;
1158		start.match.dst.ports[1] = end.match.dst.ports[1] = htons(strtoul(value, NULL, 0));
1159		value = colon + 1;
1160
1161		/* protocol */
1162		if (!(colon = strchr(value, ':')))
1163			goto fail;
1164		start.match.ipproto = end.match.ipproto = strtoul(value, NULL, 0);
1165		value = colon + 1;
1166
1167		/* always */
1168		if (!(colon = strchr(value, ':')))
1169			goto fail;
1170		if (strtoul(value, NULL, 0))
1171			goto done;
1172		value = colon + 1;
1173
1174		/* from_day_of_week */
1175		if (!(colon = strchr(value, ':')))
1176			goto fail;
1177		start.match.days[0] = end.match.days[0] = strtoul(value, NULL, 0);
1178		value = colon + 1;
1179
1180		/* to_day_of_week */
1181		if (!(colon = strchr(value, ':')))
1182			goto fail;
1183		start.match.days[1] = end.match.days[1] = strtoul(value, NULL, 0);
1184		value = colon + 1;
1185
1186		/* from_time_of_day */
1187		if (!(colon = strchr(value, ':')))
1188			goto fail;
1189		start.match.secs[0] = end.match.secs[0] = strtoul(value, NULL, 0);
1190		value = colon + 1;
1191
1192		/* to_time_of_day */
1193		start.match.secs[1] = end.match.secs[1] = strtoul(value, NULL, 0);
1194
1195	done:
1196		/* Replace an unused or invalid entry */
1197		for (j = 0; get_filter_client(j, &unused, &unused); j++);
1198		valid = set_filter_client(j, &start, &end);
1199		assert(valid);
1200
1201	fail:
1202		nvram_unset(name);
1203	}
1204
1205	nvram_unset("filter_port");
1206}
1207#endif	/* __CONFIG_NAT__ */
1208
1209static void
1210convert_maclist(char *prefix)
1211{
1212	char mac[1000], maclist[1000], macmode[1000];
1213	char *value;
1214
1215	snprintf(mac, sizeof(mac), "%s_mac", prefix);
1216	snprintf(maclist, sizeof(maclist), "%s_maclist", prefix);
1217	snprintf(macmode, sizeof(maclist), "%s_macmode", prefix);
1218
1219	if ((value = nvram_get(mac))) {
1220		nvram_set(maclist, value);
1221		/* An empty *_mac used to imply *_macmode=disabled */
1222		if (!*value)
1223			nvram_set(macmode, "disabled");
1224		nvram_unset(mac);
1225	}
1226}
1227
1228#ifdef __CONFIG_NAT__
1229static void
1230convert_autofw_port(void)
1231{
1232	char name[] = "autofw_portXXXXXXXXXX", value[1000];
1233	char *out_proto, *out_start, *out_end, *in_proto, *in_start, *in_end, *to_start, *to_end;
1234	char *enable, *desc;
1235	netconf_app_t app;
1236	bool valid;
1237	int i;
1238
1239	/* Maximum number of autofw_port entries was 10 */
1240	for (i = 0; i < 10; i++) {
1241		memset(&app, 0, sizeof(netconf_app_t));
1242
1243		/* Parse out_proto:out_port,in_proto:in_start-in_end>to_start-to_end,enable,desc */
1244		snprintf(name, sizeof(name), "autofw_port%d", i);
1245		if (!nvram_invmatch(name, ""))
1246			goto fail;
1247		strncpy(value, nvram_get(name), sizeof(value));
1248
1249		/* Check for outbound port specification */
1250		out_start = value;
1251		out_proto = strsep(&out_start, ":");
1252		if (!out_start)
1253			goto fail;
1254
1255		/* Check for related protocol specification */
1256		in_proto = out_start;
1257		out_start = strsep(&in_proto, ",");
1258		if (!in_proto)
1259			goto fail;
1260
1261		/* Check for related destination port specification */
1262		in_start = in_proto;
1263		in_proto = strsep(&in_start, ":");
1264		if (!in_start)
1265			goto fail;
1266
1267		/* Check for mapped destination port specification */
1268		to_start = in_start;
1269		in_start = strsep(&to_start, ">");
1270		if (!to_start)
1271			goto fail;
1272
1273		/* Check for enable specification */
1274		enable = to_start;
1275		to_end = strsep(&enable, ",");
1276		if (!enable)
1277			goto fail;
1278
1279		/* Check for description specification (optional) */
1280		desc = enable;
1281		enable = strsep(&desc, ",");
1282
1283		/* Check for outbound port range (new format) */
1284		out_end = out_start;
1285		out_start = strsep(&out_end, "-");
1286		if (!out_end)
1287			out_end = out_start;
1288		/* !new format already! */
1289		else
1290			continue;
1291
1292		/* Check for related destination port range (optional) */
1293		in_end = in_start;
1294		in_start = strsep(&in_end, "-");
1295		if (!in_end)
1296			in_end = in_start;
1297
1298		/* Check for mapped destination port range (optional) */
1299		to_end = to_start;
1300		to_start = strsep(&to_end, "-");
1301		if (!to_end)
1302			to_end = to_start;
1303
1304		/* Parse outbound protocol */
1305		if (!strncasecmp(out_proto, "tcp", 3))
1306			app.match.ipproto = IPPROTO_TCP;
1307		else if (!strncasecmp(out_proto, "udp", 3))
1308			app.match.ipproto = IPPROTO_UDP;
1309		else
1310			goto fail;
1311
1312		/* Parse outbound port */
1313		app.match.dst.ports[0] = htons(atoi(out_start));
1314		app.match.dst.ports[1] = htons(atoi(out_end));
1315
1316		/* Parse related protocol */
1317		if (!strncasecmp(in_proto, "tcp", 3))
1318			app.proto = IPPROTO_TCP;
1319		else if (!strncasecmp(in_proto, "udp", 3))
1320			app.proto = IPPROTO_UDP;
1321		else
1322			goto fail;
1323
1324		/* Parse related destination port range */
1325		app.dport[0] = htons(atoi(in_start));
1326		app.dport[1] = htons(atoi(in_end));
1327
1328		/* Parse mapped destination port range */
1329		app.to[0] = htons(atoi(to_start));
1330		app.to[1] = htons(atoi(to_end));
1331
1332		/* Parse enable */
1333		if (!strncasecmp(enable, "off", 3))
1334			app.match.flags = NETCONF_DISABLED;
1335
1336		/* Parse description */
1337		if (desc)
1338			strncpy(app.desc, desc, sizeof(app.desc));
1339
1340		/* Set interface name (match packets entering LAN interface) */
1341		strncpy(app.match.in.name, nvram_safe_get("lan_ifname"), IFNAMSIZ);
1342
1343		/* Set LAN source port range (match packets from any source port) */
1344		app.match.src.ports[1] = htons(0xffff);
1345
1346		/* Set target (application specific port forward) */
1347		app.target = NETCONF_APP;
1348
1349		/* Replace an unused or invalid entry */
1350		valid = set_autofw_port(i, &app);
1351		assert(valid);
1352
1353		/* Next filter */
1354		continue;
1355
1356	fail:
1357		nvram_unset(name);
1358	}
1359}
1360
1361static void
1362convert_pppoe(void)
1363{
1364	char *old[] = {
1365		"pppoe_ifname",		/* PPPoE enslaved interface */
1366		"pppoe_username",	/* PPP username */
1367		"pppoe_passwd", 	/* PPP password */
1368		"pppoe_idletime",	/* Dial on demand max idle time (seconds) */
1369		"pppoe_keepalive",	/* Restore link automatically */
1370		"pppoe_demand",		/* Dial on demand */
1371		"pppoe_mru",		/* Negotiate MRU to this value */
1372		"pppoe_mtu",	/* Negotiate MTU to the smaller of this value or the peer MRU */
1373		"pppoe_service",	/* PPPoE service name */
1374		"pppoe_ac",		/* PPPoE access concentrator name */
1375		NULL
1376	};
1377	char new[] = "wan_pppoe_XXXXXXXXXXXXXXXXXX";
1378	char *value;
1379	int i;
1380	for (i = 0; old[i] != NULL; i ++) {
1381		if ((value = nvram_get(old[i]))) {
1382			snprintf(new, sizeof(new), "wan_%s", old[i]);
1383			nvram_set(new, value);
1384			nvram_unset(old[i]);
1385		}
1386	}
1387}
1388#endif	/* __CONFIG_NAT__ */
1389
1390static void
1391convert_static_route(void)
1392{
1393	char word[80], *next;
1394	char *ipaddr, *netmask, *gateway, *metric, *ifname;
1395	char lan_route[1000] = "";
1396	char *lan_cur = lan_route;
1397#ifdef __CONFIG_NAT__
1398	char wan_route[1000] = "";
1399	char *wan_cur = wan_route;
1400#endif	/* __CONFIG_NAT__ */
1401
1402	foreach(word, nvram_safe_get("static_route"), next) {
1403		netmask = word;
1404		ipaddr = strsep(&netmask, ":");
1405		if (!ipaddr || !netmask)
1406			continue;
1407		gateway = netmask;
1408		netmask = strsep(&gateway, ":");
1409		if (!netmask || !gateway)
1410			continue;
1411		metric = gateway;
1412		gateway = strsep(&metric, ":");
1413		if (!gateway || !metric)
1414			continue;
1415		ifname = metric;
1416		metric = strsep(&ifname, ":");
1417		if (!metric || !ifname)
1418			continue;
1419
1420		if (strcmp(ifname, "lan") == 0) {
1421			lan_cur += snprintf(lan_cur, lan_route + sizeof(lan_route) - lan_cur,
1422			                    "%s%s:%s:%s:%s",
1423			                    lan_cur == lan_route ? "" : " ", ipaddr, netmask,
1424			                    gateway, metric);
1425		}
1426#ifdef __CONFIG_NAT__
1427		else if (strcmp(ifname, "wan") == 0) {
1428			wan_cur += snprintf(wan_cur, wan_route + sizeof(wan_route) - wan_cur,
1429			                    "%s%s:%s:%s:%s",
1430				wan_cur == wan_route ? "" : " ", ipaddr, netmask, gateway, metric);
1431		}
1432#endif	/* __CONFIG_NAT__ */
1433		/* what to do? */
1434		else {}
1435	}
1436
1437	if (lan_cur != lan_route)
1438		nvram_set("lan_route", lan_route);
1439
1440#ifdef __CONFIG_NAT__
1441	if (wan_cur != wan_route)
1442		nvram_set("wan_route", wan_route);
1443#endif	/* __CONFIG_NAT__ */
1444
1445	nvram_unset("static_route");
1446}
1447
1448/*
1449 * convert wl_wep - separate WEP encryption from WPA cryptos:
1450 * 	wep|on|restricted|off -> enabled|disabled
1451 * 	tkip|ase|tkip+aes -> wl_crypto
1452 * combine wl_auth_mode and wl_auth:
1453 *	wl_auth 0|1 -> wl_auth_mode open|shared (when wl_auth_mode is disabled)
1454 */
1455static void
1456convert_wsec(void)
1457{
1458	char prefix[] = "wlXXXXXXXXXX_", tmp[64], *wep;
1459	int i;
1460
1461	for (i = 0; i < MAX_NVPARSE; i ++) {
1462		sprintf(prefix, "wl%d_", i);
1463		wep = nvram_get(strcat_r(prefix, "wep", tmp));
1464		if (!wep)
1465			continue;
1466		/* 3.60.xx */
1467		/* convert wep, restricted, or on to enabled */
1468		if (!strcmp(wep, "wep") || !strcmp(wep, "restricted") ||
1469		    !strcmp(wep, "on"))
1470			nvram_set(strcat_r(prefix, "wep", tmp), "enabled");
1471		/* split wep and wpa to wl_wep and wl_crypto */
1472		else if (!strcmp(wep, "tkip") || !strcmp(wep, "aes") ||
1473		         !strcmp(wep, "tkip+aes")) {
1474			nvram_set(strcat_r(prefix, "crypto", tmp), wep);
1475			nvram_set(strcat_r(prefix, "wep", tmp), "disabled");
1476		}
1477		/* treat everything else as disabled */
1478		else if (strcmp(wep, "enabled"))
1479			nvram_set(strcat_r(prefix, "wep", tmp), "disabled");
1480		/* combine 802.11 open/shared authentication mode with WPA to wl_auth_mode */
1481		if (nvram_match(strcat_r(prefix, "auth_mode", tmp), "disabled")) {
1482			if (nvram_match(strcat_r(prefix, "auth", tmp), "1"))
1483				nvram_set(strcat_r(prefix, "auth_mode", tmp), "shared");
1484			else
1485				nvram_set(strcat_r(prefix, "auth_mode", tmp), "open");
1486		}
1487		/* 3.80.xx
1488		 *
1489		 * check only if the wl_auth_mode is set to "shared"
1490		 * wl_auth_carries a default value of "0"
1491		 */
1492		/* split 802.11 auth from wl_auth_mode */
1493		if (nvram_match(strcat_r(prefix, "auth_mode", tmp), "shared"))
1494			nvram_set(strcat_r(prefix, "auth", tmp), "1");
1495		/* split wpa akm from wl_auth_mode */
1496		if (nvram_match(strcat_r(prefix, "auth_mode", tmp), "wpa"))
1497			nvram_set(strcat_r(prefix, "akm", tmp), "wpa");
1498		else if (nvram_match(strcat_r(prefix, "auth_mode", tmp), "psk"))
1499			nvram_set(strcat_r(prefix, "akm", tmp), "psk");
1500		/* preserve radius only in wl_auth_mode */
1501		if (nvram_invmatch(strcat_r(prefix, "auth_mode", tmp), "radius"))
1502			nvram_set(strcat_r(prefix, "auth_mode", tmp), "none");
1503	}
1504}
1505
1506void
1507convert_deprecated(void)
1508{
1509#ifdef __CONFIG_NAT__
1510	/* forward_tcp and forward_udp were space separated lists of port forwards */
1511	convert_forward_proto("forward_tcp", IPPROTO_TCP);
1512	convert_forward_proto("forward_udp", IPPROTO_UDP);
1513
1514	/* filter_ip was a space separated list of IP address ranges */
1515	convert_filter_ip();
1516
1517	/* filter_tcp and filter_udp were space separated lists of IP address and TCP port ranges */
1518	convert_filter_proto("filter_tcp", IPPROTO_TCP);
1519	convert_filter_proto("filter_udp", IPPROTO_UDP);
1520
1521	/* filter_port was a short-lived implementation of filter_client */
1522	convert_filter_port();
1523#endif	/* __CONFIG_NAT__ */
1524
1525	convert_maclist("filter");
1526	convert_maclist("wl");
1527
1528#ifdef __CONFIG_NAT__
1529	/* pppoe_ifname used to save the underlying WAN interface name */
1530	if (nvram_invmatch("pppoe_ifname", "") && nvram_match("wan_proto", "pppoe"))
1531		nvram_set("wan_ifname", nvram_get("pppoe_ifname"));
1532	nvram_unset("pppoe_ifname");
1533
1534	/* autofw_port were single destination port  and now support a port range */
1535	convert_autofw_port();
1536
1537	/* pppoe_XXXXXXXX are now wan_pppoe_XXXXXXXX */
1538	convert_pppoe();
1539#endif	/* __CONFIG_NAT__ */
1540
1541	/* static_route used to save routes for LAN and WAN and is now between lan_route and
1542	 * wan_route
1543	 */
1544	/* convert_static_route(); */
1545
1546	/* convert wl_wep and combine wl_auth_mode and wl_auth */
1547	convert_wsec();
1548}
1549