1/*
2 * Broadcom Home Gateway Reference Design
3 * Web Page Configuration Support Routines
4 *
5 * Copyright 2005, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: broadcom.c,v 1.1.1.1 2008/10/15 03:31:22 james26_jang Exp $
13 */
14
15#ifdef WEBS
16#include <webs.h>
17#include <uemf.h>
18#include <ej.h>
19#else /* !WEBS */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <ctype.h>
24#include <errno.h>
25#include <unistd.h>
26#include <limits.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <assert.h>
33#include <httpd.h>
34#endif /* WEBS */
35
36
37/* Required for hash table headers*/
38#if defined(linux)
39/* Use SVID search */
40#define __USE_GNU
41#include <search.h>
42#endif
43
44#include <typedefs.h>
45#include <proto/ethernet.h>
46#include <bcmparams.h>
47#include <bcmnvram.h>
48#include <bcmutils.h>
49#include <shutils.h>
50#include <netconf.h>
51#include <nvparse.h>
52#include <wlutils.h>
53#include <bcmcvar.h>
54#include <ezc.h>
55#include <bcmconfig.h>
56#include <opencrypto.h>
57#include <time.h>
58#include <epivers.h>
59
60
61int internal_init(void);
62
63static char * encrypt_var(char *varname, char *ctext, int ctext_len, char *ptext, int *ptext_len,char *key, int keylen);
64static char * decrypt_var(char *varname, char *ptext, int ptext_len, char *ctext, int *ctext_len,char *key, int keylen);
65static char * make_wl_prefix(char *prefix,int prefix_size, int mode, char *ifname);
66static char * remove_dups(char *inlist, int inlist_size);
67static char * rfctime(const time_t *timep);
68static char * reltime(unsigned int seconds);
69static bool find_ethaddr_in_list (void *ethaddr, struct maclist *list);
70
71#define wan_prefix(unit, prefix)	snprintf(prefix, sizeof(prefix), "wan%d_", unit)
72
73/*
74 * Country names and abbreviations from ISO 3166
75 */
76typedef struct {
77	char *name;     /* Long name */
78	char *abbrev;   /* Abbreviation */
79} country_name_t;
80country_name_t country_names[];     /* At end of this file */
81
82struct variable variables[];
83extern struct nvram_tuple router_defaults[];
84
85enum {
86	NOTHING,
87	REBOOT,
88	RESTART,
89};
90
91static const char * const apply_header =
92"<head>"
93"<title>Broadcom Home Gateway Reference Design: Apply</title>"
94"<meta http-equiv=\"Content-Type\" content=\"application/html; charset=utf-8\">"
95"<style type=\"text/css\">"
96"body { background: white; color: black; font-family: arial, sans-serif; font-size: 9pt }"
97".title	{ font-family: arial, sans-serif; font-size: 13pt; font-weight: bold }"
98".subtitle { font-family: arial, sans-serif; font-size: 11pt }"
99".label { color: #306498; font-family: arial, sans-serif; font-size: 7pt }"
100"</style>"
101"</head>"
102"<body>"
103"<p>"
104"<span class=\"title\">APPLY</span><br>"
105"<span class=\"subtitle\">This screen notifies you of any errors "
106"that were detected while changing the router's settings.</span>"
107"<form method=\"get\" action=\"apply.cgi\">"
108"<p>"
109;
110
111static const char * const apply_footer =
112"<p>"
113"<input type=\"button\" name=\"action\" value=\"Continue\" OnClick=\"document.location.href='%s';\">"
114"</form>"
115"<p class=\"label\">&#169;2001-2005 Broadcom Corporation. All rights reserved.</p>"
116"</body>"
117;
118
119static int ret_code;
120static char posterr_msg[255];
121static int action = NOTHING;
122
123#define ERR_MSG_SIZE sizeof(posterr_msg)
124#if defined(linux)
125
126#include <fcntl.h>
127#include <signal.h>
128#include <time.h>
129#include <sys/klog.h>
130#include <sys/wait.h>
131#include <sys/ioctl.h>
132#include <net/if.h>
133
134typedef u_int64_t u64;
135typedef u_int32_t u32;
136typedef u_int16_t u16;
137typedef u_int8_t u8;
138#include <linux/ethtool.h>
139#include <linux/sockios.h>
140#include <net/if_arp.h>
141
142#define sys_restart() kill(1, SIGHUP)
143#define sys_reboot() kill(1, SIGTERM)
144#define sys_stats(url) eval("stats", (url))
145
146#ifndef WEBS
147
148#define MIN_BUF_SIZE	4096
149
150/* Upgrade from remote server or socket stream */
151static int
152sys_upgrade(char *url, FILE *stream, int *total)
153{
154	char upload_fifo[] = "/tmp/uploadXXXXXX";
155	FILE *fifo = NULL;
156	char *write_argv[] = { "write", upload_fifo, "linux", NULL };
157	pid_t pid;
158	char *buf = NULL;
159	int count, ret = 0;
160	long flags = -1;
161	int size = BUFSIZ;
162
163	assert(stream);
164	assert(total);
165
166	if (url)
167		return eval("write", url, "linux");
168
169	/* Feed write from a temporary FIFO */
170	if (!mktemp(upload_fifo) ||
171	    mkfifo(upload_fifo, S_IRWXU) < 0||
172	    (ret = _eval(write_argv, NULL, 0, &pid)) ||
173	    !(fifo = fopen(upload_fifo, "w"))) {
174		if (!ret)
175			ret = errno;
176		goto err;
177	}
178
179	/* Set nonblock on the socket so we can timeout */
180	if ((flags = fcntl(fileno(stream), F_GETFL)) < 0 ||
181	    fcntl(fileno(stream), F_SETFL, flags | O_NONBLOCK) < 0) {
182		ret = errno;
183		goto err;
184	}
185
186	/*
187	* The buffer must be at least as big as what the stream file is
188	* using so that it can read all the data that has been buffered
189	* in the stream file. Otherwise it would be out of sync with fn
190	* select specially at the end of the data stream in which case
191	* the select tells there is no more data available but there in
192	* fact is data buffered in the stream file's buffer. Since no
193	* one has changed the default stream file's buffer size, let's
194	* use the constant BUFSIZ until someone changes it.
195	*/
196	if (size < MIN_BUF_SIZE)
197		size = MIN_BUF_SIZE;
198	if ((buf = malloc(size)) == NULL) {
199		ret = ENOMEM;
200		goto err;
201	}
202
203	/* Pipe the rest to the FIFO */
204	cprintf("Upgrading.\n");
205	while (total && *total) {
206		if (waitfor(fileno(stream), 5) <= 0)
207			break;
208		count = safe_fread(buf, 1, size, stream);
209		if (!count && (ferror(stream) || feof(stream)))
210			break;
211		*total -= count;
212		safe_fwrite(buf, 1, count, fifo);
213		cprintf(".");
214	}
215	fclose(fifo);
216	fifo = NULL;
217
218	/* Wait for write to terminate */
219	waitpid(pid, &ret, 0);
220	cprintf("done\n");
221
222	/* Reset nonblock on the socket */
223	if (fcntl(fileno(stream), F_SETFL, flags) < 0) {
224		ret = errno;
225		goto err;
226	}
227
228 err:
229 	if (buf)
230		free(buf);
231	if (fifo)
232		fclose(fifo);
233	unlink(upload_fifo);
234	return ret;
235}
236
237#endif /* WEBS */
238
239/* Dump firewall log */
240static int
241ej_dumplog(int eid, webs_t wp, int argc, char_t **argv)
242{
243	char buf[4096], *line, *next, *s;
244	int len, ret = 0;
245
246	time_t tm;
247	char *verdict, *src, *dst, *proto, *spt, *dpt;
248
249	if (klogctl(3, buf, 4096) < 0) {
250		websError(wp, 400, "Insufficient memory\n");
251		return -1;
252	}
253
254	for (next = buf; (line = strsep(&next, "\n"));) {
255		if (!strncmp(line, "<4>DROP", 7))
256			verdict = "denied";
257		else if (!strncmp(line, "<4>ACCEPT", 9))
258			verdict = "accepted";
259		else
260			continue;
261
262		/* Parse into tokens */
263		s = line;
264		len = strlen(s);
265		while (strsep(&s, " "));
266
267		/* Initialize token values */
268		time(&tm);
269		src = dst = proto = spt = dpt = "n/a";
270
271		/* Set token values */
272		for (s = line; s < &line[len] && *s; s += strlen(s) + 1) {
273			if (!strncmp(s, "TIME=", 5))
274				tm = strtoul(&s[5], NULL, 10);
275			else if (!strncmp(s, "SRC=", 4))
276				src = &s[4];
277			else if (!strncmp(s, "DST=", 4))
278				dst = &s[4];
279			else if (!strncmp(s, "PROTO=", 6))
280				proto = &s[6];
281			else if (!strncmp(s, "SPT=", 4))
282				spt = &s[4];
283			else if (!strncmp(s, "DPT=", 4))
284				dpt = &s[4];
285		}
286
287		ret += websWrite(wp, "%s %s connection %s to %s:%s from %s:%s\n",
288				 rfctime(&tm), proto, verdict, dst, dpt, src, spt);
289		ret += websWrite(wp, "<br>");
290	}
291
292	return ret;
293}
294
295static int
296ej_syslog(int eid, webs_t wp, int argc, char_t **argv)
297{
298	FILE *fp;
299	char buf[256] = "/sbin/logread > ";
300	char tmp[] = "/tmp/log.XXXXXX";
301	int ret;
302
303	if (!nvram_match("log_ram_enable", "1")) {
304		websError(wp, 400, "\"Syslog in RAM\" is not enabled.\n");
305		return (-1);
306	}
307
308	mktemp(tmp);
309	strcat(buf, tmp);
310	system(buf);
311
312	fp = fopen(tmp, "r");
313
314	unlink(tmp);
315
316	if (fp == NULL) {
317		websError(wp, 400, "logread error\n");
318		return (-1);
319	}
320
321	websWrite(wp, "<pre>");
322
323	ret = 0;
324	while(fgets(buf, sizeof(buf), fp))
325		ret += websWrite(wp, buf);
326
327	ret += websWrite(wp, "</pre>");
328
329	fclose(fp);
330
331	return (ret);
332}
333
334struct lease_t {
335	unsigned char chaddr[16];
336	u_int32_t yiaddr;
337	u_int32_t expires;
338	char hostname[64];
339};
340
341/* Dump leases in <tr><td>hostname</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
342static int
343ej_lan_leases(int eid, webs_t wp, int argc, char_t **argv)
344{
345	FILE *fp = NULL;
346	struct lease_t lease;
347	int i;
348	int index,num_interfaces=0;
349	char buf[128];
350	struct in_addr addr;
351	unsigned long expires = 0;
352	char sigusr1[] = "-XX";
353	int ret = 0;
354	char word[32], *next = NULL;
355
356	/* Write out leases file */
357	sprintf(sigusr1, "-%d", SIGUSR1);
358	eval("killall", sigusr1, "udhcpd");
359
360	/* Count the number of lan and guest interfaces */
361
362	if (nvram_get("lan_ifname"))
363		num_interfaces++;
364
365	if (nvram_get("unbridged_ifnames"))
366		foreach(word,nvram_get("unbridged_ifnames"),next)
367			num_interfaces++;
368
369	for (index =0; index < num_interfaces; index++){
370		snprintf(buf,sizeof(buf),"/tmp/udhcpd%d.leases",index);
371
372		if (!(fp = fopen(buf, "r")))
373			continue;
374
375		while (fread(&lease, sizeof(lease), 1, fp)) {
376			/* Do not display reserved leases */
377			if (ETHER_ISNULLADDR(lease.chaddr))
378				continue;
379			ret += websWrite(wp, "<tr><td>%s</td><td>", lease.hostname);
380			for (i = 0; i < 6; i++) {
381				ret += websWrite(wp, "%02X", lease.chaddr[i]);
382				if (i != 5) ret += websWrite(wp, ":");
383			}
384			addr.s_addr = lease.yiaddr;
385			ret += websWrite(wp, "</td><td>%s</td><td>", inet_ntoa(addr));
386			expires = ntohl(lease.expires);
387			if (!expires)
388				ret += websWrite(wp, "Expired");
389			else
390				ret += websWrite(wp, "%s", reltime(expires));
391			ret += websWrite(wp, "</td></tr>");
392		}
393
394		fclose(fp);
395	}
396
397	return ret;
398}
399
400/* Renew lease */
401static int
402sys_renew(void)
403{
404	int unit;
405	char tmp[NVRAM_BUFSIZE];
406	char *str = NULL;
407	int pid;
408
409	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
410		unit = 0;
411
412	snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit);
413	if ((str = file2str(tmp))) {
414		pid = atoi(str);
415		free(str);
416		return kill(pid, SIGUSR1);
417	}
418
419	return -1;
420}
421
422/* Release lease */
423static int
424sys_release(void)
425{
426	int unit;
427	char tmp[NVRAM_BUFSIZE];
428	char *str= NULL;
429	int pid;
430
431	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
432		unit = 0;
433
434	snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit);
435	if ((str = file2str(tmp))) {
436		pid = atoi(str);
437		free(str);
438		return kill(pid, SIGUSR2);
439	}
440
441	return -1;
442}
443
444#ifdef __CONFIG_NAT__
445#define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
446
447/* Return WAN link state */
448static int
449ej_wan_link(int eid, webs_t wp, int argc, char_t **argv)
450{
451	char *wan_ifname;
452	int s;
453	struct ifreq ifr;
454	struct ethtool_cmd ecmd;
455	FILE *fp= NULL;
456	int unit;
457	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
458
459	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
460		unit = 0;
461	wan_prefix(unit, prefix);
462
463	/* non-exist and disabled */
464	if (nvram_match(strcat_r(prefix, "proto", tmp), "") ||
465	    nvram_match(strcat_r(prefix, "proto", tmp), "disabled")) {
466		return websWrite(wp, "N/A");
467	}
468	/* PPPoE connection status */
469	else if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) {
470		wan_ifname = nvram_safe_get(strcat_r(prefix, "pppoe_ifname", tmp));
471		if ((fp = fopen(strcat_r("/tmp/ppp/link.", wan_ifname, tmp), "r"))) {
472			fclose(fp);
473			return websWrite(wp, "Connected");
474		} else
475			return websWrite(wp, "Disconnected");
476	}
477	/* Get real interface name */
478	else
479		wan_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
480
481	/* Open socket to kernel */
482	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
483		return websWrite(wp, "N/A");
484
485	/* Check for hardware link */
486	strncpy(ifr.ifr_name, wan_ifname, IFNAMSIZ);
487	ifr.ifr_data = (void *) &ecmd;
488	ecmd.cmd = ETHTOOL_GSET;
489	if (ioctl(s, SIOCETHTOOL, &ifr) < 0) {
490		close(s);
491		return websWrite(wp, "Unknown");
492	}
493	if (!ecmd.speed) {
494		close(s);
495		return websWrite(wp, "Disconnected");
496	}
497
498	/* Check for valid IP address */
499	strncpy(ifr.ifr_name, wan_ifname, IFNAMSIZ);
500	if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
501		close(s);
502		return websWrite(wp, "Connecting");
503	}
504
505	/* Otherwise we are probably configured */
506	close(s);
507	return websWrite(wp, "Connected");
508}
509
510/* Display IP Address lease */
511static int
512ej_wan_lease(int eid, webs_t wp, int argc, char_t **argv)
513{
514	unsigned long expires = 0;
515	int ret = 0;
516	int unit;
517	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
518
519	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
520		unit = 0;
521	wan_prefix(unit, prefix);
522
523	if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) {
524		char *str;
525		time_t now;
526
527		snprintf(tmp, sizeof(tmp), "/tmp/udhcpc%d.expires", unit);
528		if ((str = file2str(tmp))) {
529			expires = atoi(str);
530			free(str);
531		}
532		time(&now);
533		if (expires <= now)
534			ret += websWrite(wp, "Expired");
535		else
536			ret += websWrite(wp, "%s", reltime(expires - now));
537	} else
538		ret += websWrite(wp, "N/A");
539
540	return ret;
541}
542#endif	/* __CONFIG_NAT__ */
543
544/* Report sys up time */
545static int
546ej_sysuptime(int eid, webs_t wp, int argc, char_t **argv)
547{
548	char *str = file2str("/proc/uptime");
549	if (str) {
550		unsigned int up = atoi(str);
551		free(str);
552		return websWrite(wp, reltime(up));
553	}
554	return websWrite(wp, "N/A");
555}
556
557#ifdef __CONFIG_NAT__
558/* Return a list of wan interfaces (eth0/eth1/eth2/eth3) */
559static int
560ej_wan_iflist(int eid, webs_t wp, int argc, char_t **argv)
561{
562	char name[IFNAMSIZ], *next;
563	int ret = 0;
564	int unit;
565	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
566	char ea[64];
567	int s;
568	struct ifreq ifr;
569
570	/* current unit # */
571	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
572		unit = 0;
573	wan_prefix(unit, prefix);
574
575	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
576		return errno;
577
578	/* build wan interface name list */
579	foreach(name, nvram_safe_get("wan_ifnames"), next) {
580		strncpy(ifr.ifr_name, name, IFNAMSIZ);
581		if (ioctl(s, SIOCGIFHWADDR, &ifr))
582			continue;
583		ret += websWrite(wp, "<option value=\"%s\" %s>%s (%s)</option>", name,
584				 nvram_match(strcat_r(prefix, "ifname", tmp), name) ? "selected" : "",
585				 name, ether_etoa(ifr.ifr_hwaddr.sa_data, ea));
586	}
587
588	close(s);
589
590	return ret;
591}
592#endif	/* __CONFIG_NAT__ */
593
594
595#endif /* vxworks */
596
597static int
598ej_lan_guest_iflist(int eid, webs_t wp, int argc, char_t **argv)
599{
600	int ret = 0;
601	char ifnames[255],name[IFNAMSIZ],os_name[IFNAMSIZ],*next=NULL;
602	char buf[32],*config_num, *value=NULL;
603
604	if (ejArgs(argc, argv, "%s", &config_num) < 1) {
605		websError(wp, 400, "Insufficient args\n");
606		return -1;
607	}
608
609	/* Do some of the housekeeping here to remove any leftover invalid NVRAM vars
610	   prior to display */
611
612	snprintf(ifnames, sizeof(ifnames), "%s", nvram_safe_get("unbridged_ifnames"));
613
614	snprintf(buf, sizeof(buf), "lan%s_ifname", config_num);
615
616	value = nvram_safe_get(buf);
617
618
619	if (!*ifnames)
620		{
621			ret += websWrite(wp, "<option value=\"NONE\" selected >NONE</option>");
622			return ret;
623		}
624
625	if (!remove_dups(ifnames,sizeof(ifnames))){
626			websError(wp, 400, "Unable to remove duplicate interfaces from ifname list<br>");
627			return -1;
628		}
629
630	foreach(name, ifnames, next) {
631
632
633		if (nvifname_to_osifname( name, os_name, sizeof(os_name) ) < 0)
634			continue;
635
636		ret += websWrite(wp, "<option value=\"%s\"%s>%s%s</option>",
637			name, strcmp(name,value) ? "":" selected ",
638			name, !wl_probe(os_name) ? " (Wireless)" : "");
639	}
640
641	ret += websWrite(wp, "<option value=\"NONE\"%s>NONE</option>",(*value) ? "" : " selected ");
642
643	return ret;
644}
645static int
646ej_asp_list(int eid, webs_t wp, int argc, char_t **argv)
647{
648	websWrite(wp,
649	  "<tr>\n"
650	  "  <td><a href=\"index.asp\"><img border=\"0\" src=\"basic.gif\" alt=\"Basic\"></a></td>\n"
651	  "  <td><a href=\"lan.asp\"><img border=\"0\" src=\"lan.gif\" alt=\"LAN\"></a></td>\n");
652#ifdef __CONFIG_NAT__
653	websWrite(wp,
654	  "  <td><a href=\"wan.asp\"><img border=\"0\" src=\"wan.gif\" alt=\"WAN\"></a></td>\n");
655#endif
656	websWrite(wp,
657	  "  <td><a href=\"status.asp\"><img border=\"0\" src=\"status.gif\" alt=\"Status\"></a></td>\n");
658#ifdef __CONFIG_NAT__
659	websWrite(wp,
660	  "  <td><a href=\"filter.asp\"><img border=\"0\" src=\"filter.gif\" alt=\"Filters\"></a></td>\n"
661	  "  <td><a href=\"forward.asp\"><img border=\"0\" src=\"forward.gif\" alt=\"Routing\"></a></td>\n");
662#endif
663	websWrite(wp,
664	  "  <td><a href=\"wireless.asp\"><img border=\"0\" src=\"wireless.gif\" alt=\"Wireless\"></a></td>\n"
665	  "  <td><a href=\"security.asp\"><img border=\"0\" src=\"security.gif\" alt=\"Security\"></a></td>\n"
666	  "  <td><a href=\"firmware.asp\"><img border=\"0\" src=\"firmware.gif\" alt=\"Firmware\"></a></td>\n");
667	websWrite(wp,
668	  "  <td width=\"100%%\"></td>\n"
669	  "</tr>\n");
670	return 0;
671}
672
673static char *
674rfctime(const time_t *timep)
675{
676	static char s[201];
677	struct tm tm;
678
679#if defined(linux)
680	setenv("TZ", nvram_safe_get("time_zone"), 1);
681#endif
682	memcpy(&tm, localtime(timep), sizeof(struct tm));
683	strftime(s, 200, "%a, %d %b %Y %H:%M:%S %z", &tm);
684	return s;
685}
686
687static char *
688reltime(unsigned int seconds)
689{
690	static char s[] = "XXXXX days, XX hours, XX minutes, XX seconds";
691	char *c = s;
692
693	if (seconds > 60*60*24) {
694		c += sprintf(c, "%d days, ", seconds / (60*60*24));
695		seconds %= 60*60*24;
696	}
697	if (seconds > 60*60) {
698		c += sprintf(c, "%d hours, ", seconds / (60*60));
699		seconds %= 60*60;
700	}
701	if (seconds > 60) {
702		c += sprintf(c, "%d minutes, ", seconds / 60);
703		seconds %= 60;
704	}
705	c += sprintf(c, "%d seconds", seconds);
706
707	return s;
708}
709
710/* Report time in RFC-822 format */
711static int
712ej_localtime(int eid, webs_t wp, int argc, char_t **argv)
713{
714	time_t tm;
715
716	time(&tm);
717	return websWrite(wp, rfctime(&tm));
718}
719
720static int
721ej_wl_mode_list(int eid, webs_t wp, int argc, char_t **argv)
722{
723	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
724	char wl_mode[]="wlXXXXXXXXXX_mode";
725	char *name=NULL, *next=NULL;
726	int ap = 0, sta = 0, wet = 0, wds = 0;
727	char cap[WLC_IOCTL_SMLEN];
728	char caps[WLC_IOCTL_SMLEN];
729
730
731	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
732		websError(wp, 400, "unit number variable doesn't exist\n");
733		return -1;
734	}
735
736	snprintf(wl_mode,sizeof(wl_mode),"%smode",prefix);
737
738	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
739
740	if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
741		return -1;
742
743	foreach(cap, caps, next) {
744		if (!strcmp(cap, "ap"))
745			ap = wds = 1;
746		else if (!strcmp(cap, "sta"))
747			sta = 1;
748		else if (!strcmp(cap, "wet"))
749			wet = 1;
750	}
751
752	if (ap)
753		websWrite(wp, "<option value=\"ap\" %s>Access Point</option>\n",
754				nvram_match(wl_mode, "ap" ) ? "selected" : "");
755	if (wds)
756		websWrite(wp, "<option value=\"wds\" %s>Wireless Bridge</option>\n",
757				nvram_match(wl_mode, "wds" ) ? "selected" : "");
758	if (wet)
759		websWrite(wp, "<option value=\"wet\" %s>Wireless Ethernet</option>\n",
760			nvram_match(wl_mode, "wet" ) ? "selected" : "");
761	return 0;
762}
763
764static int
765ej_wl_guest_ssid(int eid, webs_t wp, int argc, char_t **argv)
766{
767
768	char *bss_config_num=NULL,*ssid=NULL;
769	char vif[64],*unit=NULL;
770
771	if (ejArgs(argc, argv, "%s", &bss_config_num) < 1) {
772		websError(wp, 400, "Insufficient args\n");
773		return -1;
774	}
775
776
777	unit = nvram_get("wl_unit");
778	if (!unit){
779		websError(wp, 400, "unit number variable doesn't exist\n");
780		return -1;
781	}
782
783	snprintf(vif,sizeof(vif),"wl%s.%s_ssid",unit,bss_config_num);
784
785	ssid  = nvram_get(vif);
786
787	return (ssid ? websWrite(wp, "%s", ssid): 0);
788}
789static int
790ej_wl_inlist(int eid, webs_t wp, int argc, char_t **argv)
791{
792	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
793	char *name=NULL, *next=NULL;
794	char cap[WLC_IOCTL_SMLEN];
795	char caps[WLC_IOCTL_SMLEN];
796	char *var=NULL, *item=NULL;
797
798	if (ejArgs(argc, argv, "%s %s", &var, &item) < 2) {
799		websError(wp, 400, "Insufficient args\n");
800		return -1;
801	}
802
803	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
804		websError(wp, 400, "unit number variable doesn't exist\n");
805		return -1;
806	}
807
808	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
809
810	if (wl_iovar_get(name, var, (void *)caps, WLC_IOCTL_SMLEN))
811		return -1;
812
813	foreach(cap, caps, next) {
814		if (!strcmp(cap, item))
815			return websWrite(wp, "1");
816	}
817
818	return websWrite(wp, "0");
819}
820
821static int
822ej_wl_wds_status(int eid, webs_t wp, int argc, char_t **argv)
823{
824	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
825	char *macs=NULL, *next=NULL, *name=NULL;
826	char mac[100];
827	int i=0, len=0;
828	sta_info_t *sta=NULL;
829	char buf[300];
830
831	if (ejArgs(argc, argv, "%d", &i) < 1) {
832		websError(wp, 400, "Insufficient args\n");
833		return -1;
834	}
835
836	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
837		websError(wp, 400, "Insufficient args\n");
838		return -1;
839	}
840
841	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
842	macs = nvram_safe_get(strcat_r(prefix, "wds", tmp));
843
844	foreach(mac, macs, next) {
845		if (i-- == 0) {
846			len = sprintf(buf, "sta_info");
847			ether_atoe(mac, (unsigned char *)&buf[len + 1]);
848			if (atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp))) &&
849			    !wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))) {
850				sta = (sta_info_t *)buf;
851				return websWrite(wp, "%s", (sta->flags & WL_WDS_LINKUP) ? "up" : "down");
852			}
853			else
854				return websWrite(wp, "%s", "unknown");
855		}
856	}
857
858	return 0;
859}
860
861static int
862ej_ses_button_display(int eid, webs_t wp, int argc, char_t **argv)
863{
864
865	return 1;
866}
867
868
869static int
870ej_ses_cl_button_display(int eid, webs_t wp, int argc, char_t **argv)
871{
872
873	return 1;
874}
875static int
876ej_wl_radio_roam_option(int eid, webs_t wp, int argc, char_t **argv)
877{
878	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
879	char *name=NULL;
880	int radio_status = 0;
881
882	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
883		websError(wp, 400, "unit number variable doesn't exist\n");
884		return -1;
885	}
886	name = nvram_get(strcat_r(prefix, "ifname", tmp));
887
888	if (!name){
889		websError(wp, 400, "Could not find: %s\n",strcat_r(prefix, "ifname", tmp));
890		return -1;
891	}
892
893	wl_ioctl(name, WLC_GET_RADIO, &radio_status, sizeof (radio_status));
894	radio_status &= WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE;
895
896	if (!radio_status) /* Radio on*/
897		websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"RadioOff\" >");
898	else /* Radio Off */
899		websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"RadioOn\" >");
900
901	return 1;
902
903
904}
905static int
906wl_radio_onoff(webs_t wp, int disable)
907{
908	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
909	char *name=NULL;
910	char *interface_status=NULL;
911	uint radiomaskval = 0;
912
913	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
914		websError(wp, 400, "unit number variable doesn't exist\n");
915		return -1;
916	}
917
918	interface_status = nvram_get(strcat_r(prefix, "radio", tmp));
919
920	if (interface_status != NULL) {
921		if (!strcmp(interface_status, "1")) {
922			name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
923			radiomaskval = WL_RADIO_SW_DISABLE << 16 | disable;
924			wl_ioctl(name, WLC_SET_RADIO, &radiomaskval, sizeof (disable));
925		}
926		else {
927			websWrite(wp, "Interface is not Enabled...");
928			return 0;
929		}
930	}
931	else {
932		websWrite(wp, "Interface  status UnKnown...");
933		return 0;
934	}
935
936
937	return 0;
938
939}
940
941/*
942 * Example:
943 * lan_ipaddr=192.168.1.1
944 * <% nvram_get("lan_ipaddr"); %> produces "192.168.1.1"
945 * <% nvram_get("undefined"); %> produces ""
946 */
947static int
948ej_nvram_get(int eid, webs_t wp, int argc, char_t **argv)
949{
950	char *name=NULL, *c=NULL;
951	int ret = 0;
952
953	if (ejArgs(argc, argv, "%s", &name) < 1) {
954		websError(wp, 400, "Insufficient args\n");
955		return -1;
956	}
957
958	assert(name);
959
960	for (c = nvram_safe_get(name); *c; c++) {
961		if (isprint((int) *c) &&
962		    *c != '"' && *c != '&' && *c != '<' && *c != '>')
963			ret += websWrite(wp, "%c", *c);
964		else
965			ret += websWrite(wp, "&#%d", *c);
966	}
967
968	return ret;
969}
970
971/*
972 * Example:
973 * wan_proto=dhcp
974 * <% nvram_match("wan_proto", "dhcp", "selected"); %> produces "selected"
975 * <% nvram_match("wan_proto", "static", "selected"); %> does not produce
976 */
977static int
978ej_nvram_match(int eid, webs_t wp, int argc, char_t **argv)
979{
980	char *name=NULL, *match=NULL, *output=NULL;
981
982	if (ejArgs(argc, argv, "%s %s %s", &name, &match, &output) < 3) {
983		websError(wp, 400, "Insufficient args\n");
984		return -1;
985	}
986
987	assert(name);
988	assert(match);
989	assert(output);
990
991	if (nvram_match(name, match))
992		return websWrite(wp, output);
993
994	return 0;
995}
996
997static int
998ej_wme_match_op(int eid, webs_t wp, int argc, char_t **argv)
999{
1000	char *name=NULL, *match=NULL, *output=NULL;
1001	char word[256], *next=NULL;
1002
1003	if (ejArgs(argc, argv, "%s %s %s", &name, &match, &output) < 3) {
1004		websError(wp, 400, "Insufficient args\n");
1005		return -1;
1006	}
1007
1008	assert(name);
1009	assert(match);
1010	assert(output);
1011
1012	foreach(word, nvram_safe_get(name), next) {
1013		if (!strcmp(word, match))
1014			return websWrite(wp, output);
1015	}
1016
1017	return 0;
1018}
1019
1020static int
1021wl_print_channel_list(webs_t wp, char *name, char *phytype, char *abbrev)
1022{
1023	int j, status = 0;
1024	wl_channels_in_country_t *cic = (wl_channels_in_country_t *)malloc(WLC_IOCTL_MAXLEN);
1025
1026	assert(name);
1027	assert(phytype);
1028	assert(abbrev);
1029
1030	if (!cic) {
1031		status = -1;
1032		goto exit;
1033	}
1034
1035	cic->buflen = WLC_IOCTL_MAXLEN;
1036	strcpy(cic->country_abbrev, abbrev);
1037	if (!strcmp(phytype, "a"))
1038		cic->band = WLC_BAND_A;
1039	else if ((!strcmp(phytype, "b")) || (!strcmp(phytype, "g")))
1040		cic->band = WLC_BAND_B;
1041	else {
1042		status = -1;
1043		goto exit;
1044	}
1045
1046	if (wl_ioctl(name, WLC_GET_CHANNELS_IN_COUNTRY, cic, cic->buflen) == 0) {
1047		if (cic->count == 0) {
1048			status = 0;
1049			goto exit;
1050		}
1051		websWrite(wp, "\t\tif (country == \"%s\")\n\t\t\tchannels = new Array(0",
1052			abbrev);
1053		for(j = 0; j < cic->count; j++)
1054			websWrite(wp, ", %d", cic->channel[j]);
1055		websWrite(wp,");\n");
1056	}
1057
1058exit:
1059	if (cic)
1060		free((void *)cic);
1061	return status;
1062}
1063
1064static int
1065ej_wl_country_list(int eid, webs_t wp, int argc, char_t **argv)
1066{
1067	int i =0, status = 0;
1068	char *name =NULL;
1069	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1070	char *phytype = NULL;
1071	wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN);
1072	country_name_t *cntry=NULL;
1073	char *abbrev=NULL;
1074
1075	if (!cl) {
1076		status = -1;
1077		goto exit;
1078	}
1079
1080	if (ejArgs(argc, argv, "%s", &phytype) < 1) {
1081		websError(wp, 400, "Insufficient args\n");
1082		status = -1;
1083		goto exit;
1084	}
1085
1086	assert(phytype);
1087	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
1088		websError(wp, 400, "unit number variable doesn't exist\n");
1089		status = -1;
1090		goto exit;
1091	}
1092
1093	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1094
1095	cl->buflen = WLC_IOCTL_MAXLEN;
1096	cl->band_set = TRUE;
1097
1098	if (!strcmp(phytype, "a"))
1099		cl->band = WLC_BAND_A;
1100	else if ((!strcmp(phytype, "b")) || (!strcmp(phytype, "g")))
1101		cl->band = WLC_BAND_B;
1102	else {
1103		status = -1;
1104		goto exit;
1105	}
1106
1107	if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) {
1108		websWrite(wp, "\t\tvar countries = new Array(");
1109		for(i = 0; i < cl->count; i++) {
1110			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
1111			websWrite(wp, "\"%s\"", abbrev);
1112			if (i != (cl->count - 1))
1113				websWrite(wp, ", ");
1114		}
1115		websWrite(wp, ");\n");
1116		for(i = 0; i < cl->count; i++) {
1117			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
1118			for(cntry = country_names;
1119				cntry->name && strcmp(abbrev, cntry->abbrev);
1120				cntry++);
1121			websWrite(wp, "\t\tdocument.forms[0].wl_country_code[%d] = new Option(\"%s\", \"%s\");\n",
1122				i, cntry->name ? cntry->name : abbrev, abbrev);
1123		}
1124	}
1125
1126exit:
1127	if (cl)
1128		free((void *)cl);
1129	return status;
1130}
1131
1132static int
1133ej_wl_channel_list(int eid, webs_t wp, int argc, char_t **argv)
1134{
1135	int  i, status = 0;
1136	char *name=NULL;
1137	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1138	char *phytype = NULL;
1139	wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN);
1140	char *abbrev=NULL;
1141
1142	if (!cl) {
1143		status = -1;
1144		goto exit;
1145	}
1146
1147	if (ejArgs(argc, argv, "%s", &phytype) < 1) {
1148		websError(wp, 400, "Insufficient args\n");
1149		status = -1;
1150		goto exit;
1151	}
1152
1153	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
1154		websError(wp, 400, "unit number variable doesn't exist\n");
1155		status = -1;
1156		goto exit;
1157	}
1158
1159	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1160
1161	cl->buflen = WLC_IOCTL_MAXLEN;
1162	cl->band_set = TRUE;
1163
1164	if (!strcmp(phytype, "a"))
1165		cl->band = WLC_BAND_A;
1166	else if ((!strcmp(phytype, "b")) || (!strcmp(phytype, "g")))
1167		cl->band = WLC_BAND_B;
1168	else {
1169		status = -1;
1170		goto exit;
1171	}
1172
1173	if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) {
1174		for(i = 0; i < cl->count; i++) {
1175			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
1176			wl_print_channel_list(wp, name, phytype, abbrev);
1177		}
1178	}
1179
1180
1181exit:
1182	if (cl)
1183		free((void *)cl);
1184	return status;
1185}
1186
1187static bool find_ethaddr_in_list (void *ethaddr, struct maclist *list)
1188{
1189	int i=0;
1190
1191	assert(ethaddr);
1192	assert(list);
1193
1194	for (i = 0; i < list->count; i ++) {
1195		if (!bcmp(ethaddr, (void *)&list->ea[i], ETHER_ADDR_LEN)) {
1196			return TRUE;
1197		}
1198	}
1199
1200	return FALSE;
1201}
1202
1203static int
1204ej_wl_auth_list(int eid, webs_t wp, int argc, char_t **argv)
1205{
1206	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1207	char *name=NULL;
1208	struct maclist *auth=NULL, *assoc=NULL, *authorized=NULL, *wme=NULL;
1209	int max_sta_count, maclist_size;
1210	int i=0;
1211
1212	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
1213		websError(wp, 400, "unit number variable doesn't exist\n");
1214		return -1;
1215	}
1216
1217	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1218
1219	/* buffers and length */
1220	max_sta_count = MAX_STA_COUNT;
1221	maclist_size = sizeof(auth->count) + max_sta_count * sizeof(struct ether_addr);
1222
1223	auth = malloc(maclist_size);
1224	assoc = malloc(maclist_size);
1225	authorized = malloc(maclist_size);
1226	wme = malloc(maclist_size);
1227
1228	if (!auth || !assoc || !authorized || !wme)
1229		goto exit;
1230
1231	/* query wl for authenticated sta list */
1232	strcpy((char*)auth, "authe_sta_list");
1233	if (wl_ioctl(name, WLC_GET_VAR, auth, maclist_size))
1234		goto exit;
1235
1236	/* query wl for associated sta list */
1237	assoc->count = max_sta_count;
1238	if (wl_ioctl(name, WLC_GET_ASSOCLIST, assoc, maclist_size))
1239		goto exit;
1240
1241	/* query wl for authorized sta list */
1242	strcpy((char*)authorized, "autho_sta_list");
1243	if (wl_ioctl(name, WLC_GET_VAR, authorized, maclist_size))
1244		goto exit;
1245
1246	/* query wl for WME sta list */
1247	strcpy((char*)wme, "wme_sta_list");
1248	if (wl_ioctl(name, WLC_GET_VAR, wme, maclist_size))
1249		goto exit;
1250
1251	/* build authenticated/associated/authorized sta list */
1252	for (i = 0; i < auth->count; i ++) {
1253		char ea[ETHER_ADDR_STR_LEN];
1254		char *value;
1255		websWrite(wp, "<tr><td>%s</td>", ether_etoa((void *)&auth->ea[i], ea));
1256
1257		value = (find_ethaddr_in_list ((void *)&auth->ea[i], assoc))? "Yes" : "No";
1258		websWrite(wp, "<td>%s</td>", value);
1259
1260		value = (find_ethaddr_in_list ((void *)&auth->ea[i], authorized))? "Yes" : "No";
1261		websWrite(wp, "<td>%s</td>", value);
1262
1263		value = (find_ethaddr_in_list ((void *)&auth->ea[i], wme))? "Yes" : "No";
1264		websWrite(wp, "<td>%s</td>", value);
1265
1266		websWrite(wp, "</tr>");
1267	}
1268
1269	/* error/exit */
1270exit:
1271	if (auth) free(auth);
1272	if (assoc) free(assoc);
1273	if (authorized) free(authorized);
1274	if (wme) free(wme);
1275
1276	return 0;
1277}
1278
1279/*
1280 * Example:
1281 * wan_proto=dhcp
1282 * <% nvram_invmatch("wan_proto", "dhcp", "disabled"); %> does not produce
1283 * <% nvram_invmatch("wan_proto", "static", "disabled"); %> produces "disabled"
1284 */
1285static int
1286ej_nvram_invmatch(int eid, webs_t wp, int argc, char_t **argv)
1287{
1288	char *name=NULL, *invmatch=NULL, *output=NULL;
1289
1290	if (ejArgs(argc, argv, "%s %s %s", &name, &invmatch, &output) < 3) {
1291		websError(wp, 400, "Insufficient args\n");
1292		return -1;
1293	}
1294
1295	assert(name);
1296	assert(invmatch);
1297	assert(output);
1298
1299	if (nvram_invmatch(name, invmatch))
1300		return websWrite(wp, output);
1301
1302	return 0;
1303}
1304
1305/*
1306 * Example:
1307 * filter_maclist=00:12:34:56:78:00 00:87:65:43:21:00
1308 * <% nvram_list("filter_maclist", 1); %> produces "00:87:65:43:21:00"
1309 * <% nvram_list("filter_maclist", 100); %> produces ""
1310 */
1311static int
1312ej_nvram_list(int eid, webs_t wp, int argc, char_t **argv)
1313{
1314	char *name=NULL;
1315	int which=0;
1316	char word[256], *next=NULL;
1317
1318	if (ejArgs(argc, argv, "%s %d", &name, &which) < 2) {
1319		websError(wp, 400, "Insufficient args\n");
1320		return -1;
1321	}
1322
1323	foreach(word, nvram_safe_get(name), next) {
1324		if (which-- == 0)
1325			return websWrite(wp, word);
1326	}
1327
1328	return 0;
1329}
1330
1331static int
1332ej_nvram_inlist(int eid, webs_t wp, int argc, char_t **argv)
1333{
1334	char *name, *item, *output;
1335	char word[256], *next;
1336
1337	if (ejArgs(argc, argv, "%s %s %s", &name, &item, &output) < 3) {
1338		websError(wp, 400, "Insufficient args\n");
1339		return -1;
1340	}
1341
1342	foreach(word, nvram_safe_get(name), next) {
1343		if (!strcmp(word, item))
1344			return websWrite(wp, output);
1345	}
1346
1347	return 0;
1348}
1349
1350static int
1351ej_nvram_invinlist(int eid, webs_t wp, int argc, char_t **argv)
1352{
1353	char *name, *item, *output;
1354	char word[256], *next;
1355
1356	if (ejArgs(argc, argv, "%s %s %s", &name, &item, &output) < 3) {
1357		websError(wp, 400, "Insufficient args\n");
1358		return -1;
1359	}
1360
1361	foreach(word, nvram_safe_get(name), next) {
1362		if (!strcmp(word, item))
1363			return 0;
1364	}
1365
1366	return websWrite(wp, output);
1367}
1368
1369#ifdef __CONFIG_NAT__
1370/*
1371 * Example:
1372 * <% filter_client(1, 10); %> produces a table of the first 10 client filter entries
1373 */
1374static int
1375ej_filter_client(int eid, webs_t wp, int argc, char_t **argv)
1376{
1377	int i, n, j, ret = 0;
1378	netconf_filter_t start, end;
1379	bool valid;
1380	char port[] = "XXXXX";
1381	char *days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
1382	char *hours[] = {
1383		"12:00 AM", "1:00 AM", "2:00 AM", "3:00 AM", "4:00 AM", "5:00 AM",
1384		"6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM",
1385		"12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM",
1386		"6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM"
1387	};
1388
1389	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
1390		websError(wp, 400, "Insufficient args\n");
1391		return -1;
1392	}
1393
1394	for (; i <= n; i++) {
1395		valid = get_filter_client(i, &start, &end);
1396
1397		ret += websWrite(wp, "<tr>");
1398		ret += websWrite(wp, "<td></td>");
1399
1400		/* Print address range */
1401		ret += websWrite(wp, "<td><input name=\"filter_client_from_start%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
1402				 i, valid ? inet_ntoa(start.match.src.ipaddr) : "");
1403		ret += websWrite(wp, "<td>-</td>");
1404		ret += websWrite(wp, "<td><input name=\"filter_client_from_end%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
1405				 i, valid ? inet_ntoa(end.match.src.ipaddr) : "");
1406		ret += websWrite(wp, "<td></td>");
1407
1408		/* Print protocol */
1409		ret += websWrite(wp, "<td>");
1410		ret += websWrite(wp, "<select name=\"filter_client_proto%d\">", i);
1411		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
1412				 valid && start.match.ipproto == IPPROTO_TCP ? "selected" : "");
1413		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
1414				 valid && start.match.ipproto == IPPROTO_UDP ? "selected" : "");
1415		ret += websWrite(wp, "</select>");
1416		ret += websWrite(wp, "</td>");
1417		ret += websWrite(wp, "<td></td>");
1418
1419		/* Print port range */
1420		if (valid)
1421			snprintf(port, sizeof(port), "%d", ntohs(start.match.dst.ports[0]));
1422		else
1423			*port = '\0';
1424		ret += websWrite(wp, "<td><input name=\"filter_client_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1425				 i, port);
1426		ret += websWrite(wp, "<td>-</td>");
1427		if (valid)
1428			snprintf(port, sizeof(port), "%d", ntohs(start.match.dst.ports[1]));
1429		else
1430			*port = '\0';
1431		ret += websWrite(wp, "<td><input name=\"filter_client_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1432				 i, port);
1433		ret += websWrite(wp, "<td></td>");
1434
1435		/* Print day range */
1436		ret += websWrite(wp, "<td>");
1437		ret += websWrite(wp, "<select name=\"filter_client_from_day%d\">", i);
1438		for (j = 0; j < ARRAYSIZE(days); j++)
1439			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
1440					 j, valid && start.match.days[0] == j ? "selected" : "", days[j]);
1441		ret += websWrite(wp, "</select>");
1442		ret += websWrite(wp, "</td>");
1443		ret += websWrite(wp, "<td>-</td>");
1444		ret += websWrite(wp, "<td>");
1445		ret += websWrite(wp, "<select name=\"filter_client_to_day%d\">", i);
1446		for (j = 0; j < ARRAYSIZE(days); j++)
1447			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
1448					 j, valid && start.match.days[1] == j ? "selected" : "", days[j]);
1449		ret += websWrite(wp, "</select>");
1450		ret += websWrite(wp, "</td>");
1451		ret += websWrite(wp, "<td></td>");
1452
1453		/* Print time range */
1454		ret += websWrite(wp, "<td>");
1455		ret += websWrite(wp, "<select name=\"filter_client_from_sec%d\">", i);
1456		for (j = 0; j < ARRAYSIZE(hours); j++)
1457			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
1458					 j * 3600, valid && start.match.secs[0] == (j * 3600) ? "selected" : "", hours[j]);
1459		ret += websWrite(wp, "</select>");
1460		ret += websWrite(wp, "</td>");
1461		ret += websWrite(wp, "<td>-</td>");
1462
1463		ret += websWrite(wp, "<td>");
1464		ret += websWrite(wp, "<select name=\"filter_client_to_sec%d\">", i);
1465		for (j = 0; j < ARRAYSIZE(hours); j++)
1466			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
1467					 j * 3600, valid && start.match.secs[1] == (j * 3600) ? "selected" : "", hours[j]);
1468		/* Special case for 11:59:59 PM */
1469		ret += websWrite(wp, "<option value=\"%d\" %s>12:00 AM</option>",
1470				 24 * 3600 - 1, valid && start.match.secs[1] == (24 * 3600 - 1) ? "selected" : "");
1471		ret += websWrite(wp, "</select>");
1472		ret += websWrite(wp, "</td>");
1473		ret += websWrite(wp, "<td></td>");
1474
1475		/* Print enable */
1476		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"filter_client_enable%d\" %s></td>",
1477				 i, valid && !(start.match.flags & NETCONF_DISABLED) ? "checked" : "");
1478
1479		ret += websWrite(wp, "</tr>");
1480	}
1481
1482	return ret;
1483}
1484
1485/*
1486 * Example:
1487 * <% forward_port(1, 10); %> produces a table of the first 10 port forward entries
1488 */
1489static int
1490ej_forward_port(int eid, webs_t wp, int argc, char_t **argv)
1491{
1492	int i, n, ret = 0;
1493	netconf_nat_t nat;
1494	bool valid;
1495	char port[] = "XXXXX";
1496
1497	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
1498		websError(wp, 400, "Insufficient args\n");
1499		return -1;
1500	}
1501
1502	for (; i <= n; i++) {
1503		valid = get_forward_port(i, &nat);
1504
1505		ret += websWrite(wp, "<tr>");
1506		ret += websWrite(wp, "<td></td>");
1507
1508		/* Print protocol */
1509		ret += websWrite(wp, "<td>");
1510		ret += websWrite(wp, "<select name=\"forward_port_proto%d\">", i);
1511		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
1512				 valid && nat.match.ipproto == IPPROTO_TCP ? "selected" : "");
1513		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
1514				 valid && nat.match.ipproto == IPPROTO_UDP ? "selected" : "");
1515		ret += websWrite(wp, "</select>");
1516		ret += websWrite(wp, "</td>");
1517		ret += websWrite(wp, "<td></td>");
1518
1519		/* Print WAN destination port range */
1520		if (valid)
1521			snprintf(port, sizeof(port), "%d", ntohs(nat.match.dst.ports[0]));
1522		else
1523			*port = '\0';
1524		ret += websWrite(wp, "<td><input name=\"forward_port_from_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1525				 i, port);
1526		ret += websWrite(wp, "<td>-</td>");
1527		if (valid)
1528			snprintf(port, sizeof(port), "%d", ntohs(nat.match.dst.ports[1]));
1529		else
1530			*port = '\0';
1531		ret += websWrite(wp, "<td><input name=\"forward_port_from_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1532				 i, port);
1533		ret += websWrite(wp, "<td>></td>");
1534
1535		/* Print address range */
1536		ret += websWrite(wp, "<td><input name=\"forward_port_to_ip%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
1537				 i, valid ? inet_ntoa(nat.ipaddr) : "");
1538		ret += websWrite(wp, "<td>:</td>");
1539
1540		/* Print LAN destination port range */
1541		if (valid)
1542			snprintf(port, sizeof(port), "%d", ntohs(nat.ports[0]));
1543		else
1544			*port = '\0';
1545		ret += websWrite(wp, "<td><input name=\"forward_port_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1546				 i, port);
1547		ret += websWrite(wp, "<td>-</td>");
1548		if (valid)
1549			snprintf(port, sizeof(port), "%d", ntohs(nat.ports[1]));
1550		else
1551			*port = '\0';
1552		ret += websWrite(wp, "<td><input name=\"forward_port_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1553				 i, port);
1554		ret += websWrite(wp, "<td></td>");
1555
1556		/* Print enable */
1557		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"forward_port_enable%d\" %s></td>",
1558				 i, valid && !(nat.match.flags & NETCONF_DISABLED) ? "checked" : "");
1559
1560		ret += websWrite(wp, "</tr>");
1561	}
1562
1563	return ret;
1564}
1565
1566static int
1567ej_autofw_port(int eid, webs_t wp, int argc, char_t **argv)
1568{
1569	int i, n, ret = 0;
1570	netconf_app_t app;
1571	bool valid;
1572	char port[] = "XXXXX";
1573
1574	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
1575		websError(wp, 400, "Insufficient args\n");
1576		return -1;
1577	}
1578
1579	for (; i <= n; i++) {
1580		valid = get_autofw_port(i, &app);
1581
1582		/* Parse out_proto:out_port,in_proto:in_start-in_end>to_start-to_end,enable,desc */
1583		ret += websWrite(wp, "<tr>");
1584		ret += websWrite(wp, "<td></td>");
1585
1586		/* Print outbound protocol */
1587		ret += websWrite(wp, "<td>");
1588		ret += websWrite(wp, "<select name=\"autofw_port_out_proto%d\">", i);
1589		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
1590				 valid && app.match.ipproto == IPPROTO_TCP ? "selected" : "");
1591		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
1592				 valid && app.match.ipproto == IPPROTO_UDP ? "selected" : "");
1593		ret += websWrite(wp, "</select>");
1594		ret += websWrite(wp, "</td>");
1595		ret += websWrite(wp, "<td></td>");
1596
1597		/* Print outbound port */
1598		if (valid)
1599			snprintf(port, sizeof(port), "%d", ntohs(app.match.dst.ports[0]));
1600		else
1601			*port = '\0';
1602		ret += websWrite(wp, "<td><input name=\"autofw_port_out_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1603				 i, port);
1604		ret += websWrite(wp, "<td>-</td>");
1605		if (valid)
1606			snprintf(port, sizeof(port), "%d", ntohs(app.match.dst.ports[1]));
1607		else
1608			*port = '\0';
1609		ret += websWrite(wp, "<td><input name=\"autofw_port_out_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1610				 i, port);
1611		ret += websWrite(wp, "<td></td>");
1612
1613		/* Print related protocol */
1614		ret += websWrite(wp, "<td>");
1615		ret += websWrite(wp, "<select name=\"autofw_port_in_proto%d\">", i);
1616		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
1617				 valid && app.proto == IPPROTO_TCP ? "selected" : "");
1618		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
1619				 valid && app.proto == IPPROTO_UDP ? "selected" : "");
1620		ret += websWrite(wp, "</select>");
1621		ret += websWrite(wp, "</td>");
1622		ret += websWrite(wp, "<td></td>");
1623
1624		/* Print related destination port range */
1625		if (valid)
1626			snprintf(port, sizeof(port), "%d", ntohs(app.dport[0]));
1627		else
1628			*port = '\0';
1629		ret += websWrite(wp, "<td><input name=\"autofw_port_in_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1630				 i, port);
1631		ret += websWrite(wp, "<td>-</td>");
1632		if (valid)
1633			snprintf(port, sizeof(port), "%d", ntohs(app.dport[1]));
1634		else
1635			*port = '\0';
1636		ret += websWrite(wp, "<td><input name=\"autofw_port_in_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1637				 i, port);
1638		ret += websWrite(wp, "<td></td>");
1639
1640		/* Print mapped destination port range */
1641		if (valid)
1642			snprintf(port, sizeof(port), "%d", ntohs(app.to[0]));
1643		else
1644			*port = '\0';
1645		ret += websWrite(wp, "<td><input name=\"autofw_port_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1646				 i, port);
1647		ret += websWrite(wp, "<td>-</td>");
1648		if (valid)
1649			snprintf(port, sizeof(port), "%d", ntohs(app.to[1]));
1650		else
1651			*port = '\0';
1652		ret += websWrite(wp, "<td><input name=\"autofw_port_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
1653				 i, port);
1654		ret += websWrite(wp, "<td></td>");
1655
1656		/* Print enable */
1657		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"autofw_port_enable%d\" %s></td>",
1658				 i, valid && !(app.match.flags & NETCONF_DISABLED) ? "checked" : "");
1659
1660		ret += websWrite(wp, "</tr>");
1661	}
1662
1663	return ret;
1664}
1665#endif	/* __CONFIG_NAT__ */
1666
1667/*
1668 * Example:
1669 * lan_route=192.168.2.0:255.255.255.0:192.168.2.1:1
1670 * <% lan_route("ipaddr", 0); %> produces "192.168.2.0"
1671 */
1672static int
1673ej_lan_route(int eid, webs_t wp, int argc, char_t **argv)
1674{
1675	char *arg;
1676	int which;
1677	char word[256], *next;
1678	char *ipaddr, *netmask, *gateway, *metric;
1679
1680	if (ejArgs(argc, argv, "%s %d", &arg, &which) < 2) {
1681		websError(wp, 400, "Insufficient args\n");
1682		return -1;
1683	}
1684
1685	foreach(word, nvram_safe_get("lan_route"), next) {
1686		if (which-- == 0) {
1687			netmask = word;
1688			ipaddr = strsep(&netmask, ":");
1689			if (!ipaddr || !netmask)
1690				continue;
1691			gateway = netmask;
1692			netmask = strsep(&gateway, ":");
1693			if (!netmask || !gateway)
1694				continue;
1695			metric = gateway;
1696			gateway = strsep(&metric, ":");
1697			if (!gateway || !metric)
1698				continue;
1699			if (!strcmp(arg, "ipaddr"))
1700				return websWrite(wp, ipaddr);
1701			else if (!strcmp(arg, "netmask"))
1702				return websWrite(wp, netmask);
1703			else if (!strcmp(arg, "gateway"))
1704				return websWrite(wp, gateway);
1705			else if (!strcmp(arg, "metric"))
1706				return websWrite(wp, metric);
1707		}
1708	}
1709
1710	return 0;
1711}
1712
1713#ifdef __CONFIG_NAT__
1714/*
1715 * Example:
1716 * wan_route=192.168.10.0:255.255.255.0:192.168.10.1:1
1717 * <% wan_route("ipaddr", 0); %> produces "192.168.10.0"
1718 */
1719static int
1720ej_wan_route(int eid, webs_t wp, int argc, char_t **argv)
1721{
1722	char *arg;
1723	int which;
1724	char word[256], *next;
1725	char *ipaddr, *netmask, *gateway, *metric;
1726	int unit;
1727	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
1728
1729
1730	if (ejArgs(argc, argv, "%s %d", &arg, &which) < 2) {websError(wp, 400, "Insufficient args\n");
1731		websError(wp, 400, "Insufficient args\n");
1732		return -1;
1733	}
1734
1735	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
1736		unit = 0;
1737	wan_prefix(unit, prefix);
1738
1739	foreach(word, nvram_safe_get(strcat_r(prefix, "route", tmp)), next) {
1740		if (which-- == 0) {
1741			netmask = word;
1742			ipaddr = strsep(&netmask, ":");
1743			if (!ipaddr || !netmask)
1744				continue;
1745			gateway = netmask;
1746			netmask = strsep(&gateway, ":");
1747			if (!netmask || !gateway)
1748				continue;
1749			metric = gateway;
1750			gateway = strsep(&metric, ":");
1751			if (!gateway || !metric)
1752				continue;
1753			if (!strcmp(arg, "ipaddr"))
1754				return websWrite(wp, ipaddr);
1755			else if (!strcmp(arg, "netmask"))
1756				return websWrite(wp, netmask);
1757			else if (!strcmp(arg, "gateway"))
1758				return websWrite(wp, gateway);
1759			else if (!strcmp(arg, "metric"))
1760				return websWrite(wp, metric);
1761		}
1762	}
1763
1764	return 0;
1765}
1766#endif	/* __CONFIG_NAT__ */
1767
1768/* Return a list of the currently present wireless interfaces */
1769static int
1770ej_wl_list(int eid, webs_t wp, int argc, char_t **argv)
1771{
1772	char name[IFNAMSIZ], *next=NULL;
1773	char wl_name[IFNAMSIZ],os_name[IFNAMSIZ];
1774	int unit=-1,subunit=-1, ret = 0;
1775	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1776	char unit_str[]="000000";
1777	char *hwaddr=NULL, *ssid=NULL, *virtual=NULL;
1778	char ifnames[256];
1779
1780	if (ejArgs(argc, argv, "%s", &virtual) > 0) {
1781		if (strcmp(virtual,"INCLUDE_VIFS")){
1782			websError(wp, 400, "Unknown argument %s\n",virtual);
1783			return -1;
1784		}
1785	}
1786
1787
1788	snprintf(ifnames, sizeof(ifnames), "%s %s %s",
1789		nvram_safe_get("wan_ifnames"),
1790		nvram_safe_get("lan_ifnames"),
1791		nvram_safe_get("unbridged_ifnames"));
1792
1793	if (!remove_dups(ifnames,sizeof(ifnames))){
1794			websError(wp, 400, "Unable to remove duplicate interfaces from ifname list<br>");
1795			return -1;
1796		}
1797
1798	foreach(name, ifnames, next) {
1799
1800		if ( nvifname_to_osifname( name, os_name, sizeof(os_name) ) < 0 )
1801			continue;
1802
1803		if (wl_probe(os_name) ||
1804		    wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
1805			continue;
1806
1807		/* Convert eth name to wl name */
1808
1809		if( osifname_to_nvifname( name, wl_name, sizeof(wl_name) ) != 0 )
1810		{
1811			websError(wp, 400, "wl name for interface:%s not found\n",name);
1812			return -1;
1813		}
1814
1815		/* Get configured ethernet MAC address */
1816		snprintf(prefix, sizeof(prefix), "wl%d_", unit);
1817		hwaddr = nvram_get(strcat_r(prefix, "hwaddr", tmp));
1818
1819		/* Slave intefaces have a '.' in the name. assume the MAC address
1820		   is the same as the primary interface*/
1821		if (strchr(wl_name,'.')) {
1822			/* If Physical interfaces are specified do not
1823			   process the slave interfaces skip writing out the info
1824			  */
1825			if (virtual)
1826				snprintf(prefix, sizeof(prefix),"%s_",wl_name);
1827			else
1828				continue;
1829		}
1830
1831		if (get_ifname_unit(wl_name,&unit,&subunit) < 0) {
1832			websError(wp, 400, "Error extracting unit and subunit name from %s\n",wl_name);
1833			return -1;
1834		}
1835
1836		/* Should not need to test if pysical interfaces flag is set,
1837		   since that the code above will skip this portion. However
1838		   it guards against future problems if this gets reworked
1839		   in the future as the explicit checks here prevent any
1840		   ambiguity
1841		*/
1842
1843		if ((subunit > 0 ) && (virtual) )
1844			snprintf(unit_str,sizeof(unit_str),"%d.%d",unit,subunit);
1845		else
1846			snprintf(unit_str,sizeof(unit_str),"%d",unit);
1847
1848		ssid = nvram_get(strcat_r(prefix, "ssid", tmp));
1849
1850		if (!hwaddr || !*hwaddr || !ssid || !*ssid)
1851			continue;
1852
1853		ret += websWrite(wp, "<option value=\"%s\" %s>%s(%s)</option>\n", unit_str,
1854				(!strncmp(unit_str,nvram_safe_get("wl_unit"),sizeof(unit_str))) ? "selected" : "",
1855				 ssid, hwaddr);
1856	}
1857
1858	if (!ret)
1859		ret += websWrite(wp, "<option value=\"-1\" selected>None</option>");
1860
1861	return ret;
1862}
1863
1864/* Return a list of the supported bands on the currently selected wireless interface */
1865static int
1866ej_wl_phytypes(int eid, webs_t wp, int argc, char_t **argv)
1867{
1868	int  ret = 0;
1869	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1870	char *phytype=NULL;
1871	char *phylist=NULL;
1872	int i=0;
1873
1874	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL))
1875		return websWrite(wp, "None");
1876
1877	/* Get available phy types of the currently selected wireless interface */
1878	phylist = nvram_safe_get(strcat_r(prefix, "phytypes", tmp));
1879
1880	/* Get configured phy type */
1881	phytype = nvram_safe_get("wl_phytype");
1882
1883	for (i = 0; i < strlen(phylist); i++) {
1884		ret += websWrite(wp, "<option value=\"%c\" %s>802.11%c (%s GHz)</option>",
1885				 phylist[i], phylist[i] == *phytype ? "selected" : "", phylist[i],
1886				 phylist[i] == 'a' ? "5" : "2.4");
1887	}
1888
1889	return ret;
1890}
1891
1892/* Return a radio ID given a phy type */
1893static int
1894ej_wl_radioid(int eid, webs_t wp, int argc, char_t **argv)
1895{
1896	char *phytype=NULL, var[NVRAM_BUFSIZE], *next;
1897	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1898	int which;
1899
1900	if (ejArgs(argc, argv, "%s", &phytype) < 1) {
1901		websError(wp, 400, "Insufficient args\n");
1902		return -1;
1903	}
1904
1905	assert(phytype);
1906
1907	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL))
1908		return websWrite(wp, "None");
1909
1910	which = strcspn(nvram_safe_get(strcat_r(prefix, "phytypes", tmp)), phytype);
1911	foreach(var, nvram_safe_get(strcat_r(prefix, "radioids", tmp)), next) {
1912		if (which == 0)
1913			return websWrite(wp, var);
1914		which--;
1915	}
1916
1917	return websWrite(wp, "None");
1918}
1919
1920/* Return current core revision */
1921static int
1922ej_wl_corerev(int eid, webs_t wp, int argc, char_t **argv)
1923{
1924	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1925
1926	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL))
1927		return websWrite(wp, "None");
1928
1929	return websWrite(wp, nvram_safe_get(strcat_r(prefix, "corerev", tmp)));
1930}
1931
1932/* Return current wireless channel */
1933static int
1934ej_wl_cur_channel(int eid, webs_t wp, int argc, char_t **argv)
1935{
1936	char *name=NULL;
1937	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1938	channel_info_t ci;
1939
1940	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
1941		websError(wp, 400, "unit number variable doesn't exist\n");
1942		return -1;
1943	}
1944
1945	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1946
1947	wl_ioctl(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
1948	return websWrite(wp, "Current: %d", ci.target_channel);
1949}
1950
1951/* Return current country */
1952static int
1953ej_wl_cur_country(int eid, webs_t wp, int argc, char_t **argv)
1954{
1955	char *name=NULL;
1956	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1957	char buf[WLC_CNTRY_BUF_SZ];
1958
1959	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
1960		websError(wp, 400, "unit number variable doesn't exist\n");
1961		return -1;
1962	}
1963
1964	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1965
1966	wl_ioctl(name, WLC_GET_COUNTRY, buf, sizeof(buf));
1967	return websWrite(wp, "%s", buf);
1968}
1969
1970/* Return current phytype */
1971static int
1972ej_wl_cur_phytype(int eid, webs_t wp, int argc, char_t **argv)
1973{
1974	char *name;
1975	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1976	int phytype;
1977
1978	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
1979		websError(wp, 400, "unit number variable doesn't exist\n");
1980		return -1;
1981	}
1982
1983	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1984
1985	/* Get configured phy type */
1986	wl_ioctl(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
1987
1988	return websWrite(wp, "Current: 802.11%s", phytype == WLC_PHY_TYPE_A ? "a" :
1989		phytype == WLC_PHY_TYPE_B ? "b" : "g");
1990}
1991
1992#ifdef __CONFIG_NAT__
1993static char *
1994wan_name(int unit, char *prefix, char *name, int len)
1995{
1996	char tmp[NVRAM_BUFSIZE], *desc;
1997	desc = nvram_safe_get(strcat_r(prefix, "desc", tmp));
1998	snprintf(tmp, sizeof(tmp), "Connection %d", unit + 1);
1999	snprintf(name, len, "%s", !strcmp(desc, "") ? tmp : desc);
2000	return name;
2001}
2002
2003/* Return a list of wan connections (Connection <N>/<Connection Name>) */
2004static int
2005ej_wan_list(int eid, webs_t wp, int argc, char_t **argv)
2006{
2007	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
2008	int unit, ret = 0;
2009
2010	/* build wan connection name list */
2011	for (unit = 0; unit < MAX_NVPARSE; unit ++) {
2012		wan_prefix(unit, prefix);
2013		if (!nvram_get(strcat_r(prefix, "unit", tmp)))
2014			continue;
2015		ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", unit,
2016				unit == atoi(nvram_safe_get("wan_unit")) ? "selected" : "",
2017				wan_name(unit, prefix, tmp, sizeof(tmp)));
2018	}
2019
2020	return ret;
2021}
2022#endif	/* __CONFIG_NAT__ */
2023
2024/* write "selected" to page if the argument matches the current
2025	 wl_ure setting */
2026static int
2027ej_ure_list(int eid, webs_t wp, int argc, char_t **argv)
2028{
2029	char *temp;
2030	int match_value;
2031	int nv_value;
2032
2033	if (ejArgs(argc, argv, "%d", &match_value) < 1) {
2034		websError(wp, 400, "Insufficient args\n");
2035		return EINVAL;
2036	}
2037
2038	temp = nvram_get("wl_ure");
2039	if(strlen( temp ) == 0) {
2040		if( match_value == 0 )
2041		{
2042			/* treat empty string as "0" */
2043			websWrite(wp, "selected" );
2044		}
2045		return 0;
2046	}
2047
2048	nv_value = atoi( temp );
2049	if( nv_value == match_value) {
2050		websWrite(wp, "selected" );
2051	}
2052
2053	return 0;
2054}
2055
2056/* Return wlX_ure setting for the current wireless interface.  If
2057   the current wireless interface is a virtual interface, return
2058   the value of the parent interface
2059*/
2060static int
2061ej_ure_enabled(int eid, webs_t wp, int argc, char_t **argv)
2062{
2063	char *temp;
2064	int unit = -1;
2065	int sub_unit = -1;
2066	char nv_param[NVRAM_MAX_PARAM_LEN];
2067
2068	temp = nvram_get("wl_unit");
2069	if(strlen( temp ) == 0) {
2070 		websError(wp, 400, "Error getting wl_unit\n");
2071		return EINVAL;
2072	}
2073
2074	if( get_ifname_unit( temp, &unit, &sub_unit ) != 0 ) {
2075 		websError(wp, 400, "Error getting unit/subunit\n");
2076		return EINVAL;
2077	}
2078
2079	sprintf( nv_param, "wl%d_ure", unit );
2080	temp = nvram_safe_get( nv_param );
2081	if( strncmp( temp, "1", 1 ) == 0 ) {
2082		websWrite(wp, "\"1\"");
2083	}
2084	else {
2085		websWrite(wp, "\"0\"");
2086	}
2087
2088	return 0;
2089}
2090
2091
2092char *webs_buf=NULL;
2093int webs_buf_offset=0;
2094
2095/* This routine extracts the index variable in the string
2096   format
2097   eg get_string_index("lan_","lan0_ifname",buf,sizeof(buf))
2098   returns the string "0" in buf.
2099
2100   In the case of where there is no index
2101   eg get_string_index("lan_","lan_ifname",buf,sizeof(buf))
2102   returns NULL in buf[0].
2103
2104   Inputs :
2105   - prefix: prefix to start of index string
2106   - varname: value to process
2107   - outbuf: output buffer
2108   - bufsize: output buffer size
2109
2110   Returns:
2111   -string null terminated string in output buffer
2112   -pointer to output buffer or NULL if error
2113*/
2114char *
2115get_index_string(char *prefix, char *varname, char *outbuf, int bufsize)
2116{
2117	int offset, len;
2118
2119	if (!prefix) return NULL;
2120	if (!varname) return NULL;
2121	if (!outbuf) return NULL;
2122	if (!bufsize) return NULL;
2123
2124	memset(outbuf,0,bufsize);
2125
2126	/* offset is the start of the index number eg
2127	 *  offset of dhcp0 is 4. prefix contains the "dhcp" as
2128	 *  the prefix
2129	 */
2130
2131	offset = strlen(prefix);
2132
2133	/* This calculates the string length of the index
2134	 * ie the index value represented as a string
2135	 * strchr(varname,'_') is the end of the index string.
2136	 * strchr(varname,'_') - varname is the length of the var including
2137	 * the index string but before the underscore "_"
2138	*/
2139	len = strchr(varname,'_') - varname - offset ;
2140
2141	if (len > bufsize) return NULL;
2142
2143	if (len) strncpy(outbuf,&varname[offset],len);
2144	outbuf[len]='\0';
2145
2146	return outbuf;
2147}
2148
2149static void
2150validate_list(webs_t wp, char *value, struct variable *v,
2151	      int (*valid)(webs_t, char *, struct variable *), char *varname )
2152{
2153	int n, i;
2154	char name[100];
2155	char buf[1000] = "", *cur = buf;
2156
2157	assert(v);
2158
2159	ret_code = EINVAL;
2160	n = atoi(value);
2161
2162	for (i = 0; i < n; i++) {
2163		snprintf(name, sizeof(name), "%s%d", v->name, i);
2164		if (!(value = websGetVar(wp, name, NULL)))
2165				return;
2166
2167		if (!*value && v->nullok)
2168			continue;
2169		if (!valid(wp, value, v ))
2170			continue;
2171		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s",
2172				cur == buf ? "" : " ", value);
2173	}
2174
2175	/* Use varname override if specified. Used to make the routine
2176	   multiinstance compatible */
2177	if (varname)
2178		nvram_set(varname, buf);
2179	else
2180		nvram_set(v->name, buf);
2181
2182	ret_code = 0;
2183}
2184
2185static int
2186valid_ipaddr(webs_t wp, char *value, struct variable *v)
2187{
2188	unsigned int buf[4];
2189	struct in_addr ipaddr, netaddr, broadaddr, netmask;
2190
2191	assert(v);
2192
2193	if (sscanf(value, "%d.%d.%d.%d", &buf[0], &buf[1], &buf[2], &buf[3]) != 4) {
2194		websBufferWrite(wp, "Invalid <b>%s</b> %s: not an IP address<br>",
2195			  v->longname, value);
2196		return FALSE;
2197	}
2198
2199	ipaddr.s_addr = htonl((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
2200
2201	if (v->argv) {
2202		(void) inet_aton(nvram_safe_get(v->argv[0]), &netaddr);
2203		(void) inet_aton(nvram_safe_get(v->argv[1]), &netmask);
2204		netaddr.s_addr &= netmask.s_addr;
2205		broadaddr.s_addr = netaddr.s_addr | ~netmask.s_addr;
2206		if (netaddr.s_addr != (ipaddr.s_addr & netmask.s_addr)) {
2207			websBufferWrite(wp, "Invalid <b>%s</b> %s: not in the %s/",
2208				  v->longname, value, inet_ntoa(netaddr));
2209			websBufferWrite(wp, "%s network<br>", inet_ntoa(netmask));
2210			return FALSE;
2211		}
2212		if (ipaddr.s_addr == netaddr.s_addr) {
2213			websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the network address<br>",
2214				  v->longname, value);
2215			return FALSE;
2216		}
2217		if (ipaddr.s_addr == broadaddr.s_addr) {
2218			websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the broadcast address<br>",
2219				  v->longname, value);
2220			return FALSE;
2221		}
2222	}
2223
2224	return TRUE;
2225}
2226
2227static void
2228validate_ipaddr(webs_t wp, char *value, struct variable *v , char *varname)
2229{
2230
2231	assert(v);
2232
2233	ret_code = EINVAL;
2234
2235	if (!valid_ipaddr(wp, value, v) ) return;
2236
2237	if (varname)
2238		nvram_set(varname,value) ;
2239	else
2240		nvram_set(v->name, value);
2241
2242	ret_code = 0;
2243
2244}
2245
2246static void
2247validate_ipaddrs(webs_t wp, char *value, struct variable *v, char *varname)
2248{
2249	ret_code = EINVAL;
2250	validate_list(wp, value, v, valid_ipaddr, varname);
2251}
2252
2253static int
2254valid_choice(webs_t wp, char *value, struct variable *v)
2255{
2256	char **choice=NULL;
2257
2258	assert(v);
2259
2260	for (choice = v->argv; *choice; choice++) {
2261		if (!strcmp(value, *choice))
2262			return TRUE;
2263	}
2264
2265	websBufferWrite(wp, "Invalid <b>%s</b> %s: not one of ", v->longname, value);
2266	for (choice = v->argv; *choice; choice++)
2267		websBufferWrite(wp, "%s%s", choice == v->argv ? "" : "/", *choice);
2268	websBufferWrite(wp, "<br>");
2269
2270	return FALSE;
2271}
2272
2273static void
2274validate_choice(webs_t wp, char *value, struct variable *v, char *varname)
2275{
2276
2277	assert(v);
2278
2279	ret_code = EINVAL;
2280
2281	if (!valid_choice(wp, value, v)) return;
2282
2283	if (varname )
2284		nvram_set(varname,value) ;
2285	else
2286		nvram_set(v->name, value);
2287	ret_code = 0;
2288
2289}
2290
2291static void
2292validate_router_disable(webs_t wp, char *value, struct variable *v,
2293												char *varname)
2294{
2295	char *temp = NULL;
2296
2297	assert(v);
2298
2299	ret_code = EINVAL;
2300
2301	if (!valid_choice(wp, value, v)) return;
2302
2303	/* we need to find out if we're changing the router mode or not.  if
2304		 we're really changing the setting, we need to reboot */
2305	temp = nvram_safe_get( v->name );
2306
2307	cprintf( "\n\n temp = %s, value = %s\n\n", temp, value );
2308
2309	if( strcmp( temp, value ) )
2310		action = REBOOT;
2311
2312	if (varname )
2313		nvram_set(varname,value) ;
2314	else
2315		nvram_set(v->name, value);
2316	ret_code = 0;
2317
2318}
2319
2320static int
2321valid_range(webs_t wp, char *value, struct variable *v)
2322{
2323	int n, start, end;
2324
2325	assert(v);
2326
2327	n = atoi(value);
2328	start = atoi(v->argv[0]);
2329	end = atoi(v->argv[1]);
2330
2331	if (n < start || n > end) {
2332		websBufferWrite(wp, "Invalid <b>%s</b> %s: out of range %d-%d<br>",
2333			  v->longname, value, start, end);
2334		return FALSE;
2335	}
2336
2337	return TRUE;
2338}
2339
2340static void
2341validate_range(webs_t wp, char *value, struct variable *v , char *varname)
2342{
2343
2344	assert(v);
2345
2346	ret_code = EINVAL;
2347
2348	if (!valid_range(wp, value, v)) return ;
2349
2350	if (varname )
2351		nvram_set(varname,value) ;
2352	else
2353		nvram_set(v->name, value);
2354
2355	ret_code = 0;
2356}
2357
2358static int
2359valid_name(webs_t wp, char *value, struct variable *v)
2360{
2361	int n, min, max;
2362
2363	assert(v);
2364
2365	n = strlen(value);
2366	min = atoi(v->argv[0]);
2367	max = atoi(v->argv[1]);
2368
2369	if (n > max) {
2370		websBufferWrite(wp, "Invalid <b>%s</b> %s: longer than %d characters<br>",
2371			  v->longname, value, max);
2372		return FALSE;
2373	}
2374	else if (n < min) {
2375		websBufferWrite(wp, "Invalid <b>%s</b> %s: shorter than %d characters<br>",
2376			  v->longname, value, min);
2377		return FALSE;
2378	}
2379
2380	return TRUE;
2381}
2382
2383static void
2384validate_guest_lan_ifname(webs_t wp, char *value, struct variable *v, char *varname )
2385{
2386	int index,unit;
2387	char ifname[IFNAMSIZ],os_name[IFNAMSIZ];
2388
2389	assert(v);
2390	assert(value);
2391
2392	ret_code = EINVAL;
2393
2394	if (!*value){
2395		websBufferWrite(wp, "Guest LAN interface must be specified.<br>");
2396		return;
2397	}
2398
2399	if (!v->argv[0]){
2400		websBufferWrite(wp, "Guest LAN interface index must be specified.<br>");
2401		return;
2402	}
2403
2404	index = atoi (v->argv[0]);
2405
2406	if ((index < 1 ) || (index > 4))
2407		if (!v->argv[0]){
2408		websBufferWrite(wp, "Guest LAN interface index must be between 1 and 4.<br>");
2409		return;
2410	}
2411
2412	if (nvifname_to_osifname( value, os_name, sizeof(os_name) ) < 0){
2413		websBufferWrite(wp, "Unable to translate Guest LAN interface name: %s.<br>",value);
2414			return;
2415	}
2416
2417	if (wl_probe(os_name) ||
2418		    wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit))){
2419			websBufferWrite(wp, "Guest LAN interface %s is not a Wireless Interface.<br>",value);
2420			return;
2421	}
2422
2423	/* Guest SSID are not part of a bridge, unset lanX_ifnames */
2424
2425	snprintf(ifname,sizeof(ifname),"lan%d_ifname",index);
2426	nvram_set(ifname,value);
2427
2428	snprintf(ifname,sizeof(ifname),"lan%d_ifnames",index);
2429	nvram_unset(ifname);
2430
2431	ret_code=0;
2432}
2433static void
2434validate_guest_ssid(webs_t wp, char *value, struct variable *v, char *varname )
2435{
2436/* Validation of the guest ssids does 3 things
2437 * 1)adds the wlX.Y_ssid field
2438 * 2)updates the wlX_vif list
2439 * 3)removes entry from wlX_vif if the interface is empty
2440*/
2441
2442	char *wl_unit=NULL;
2443	char wl_vif[]="wlXXXXXXXXX_vifs",*wl_vif_value=NULL;
2444	char wl_ssid[]="wlXXXXXXXXX_ssid";
2445	char wl_guest[]="wlXXXXXXXXX_guest";
2446	char wl_radio[]="wlXXXXXXXXX_radio";
2447	char wl_mode[]="wlXXXXXXXXX_mode";
2448	char buf[]="wlXXXXXXXXX_vifs";
2449	char prefix[]="wlXXXXX";
2450	int p=-1;
2451	char *subunit=NULL,unit[]="0000";
2452	char *argv[3];
2453	int wl_ure = -1;
2454
2455	assert(v);
2456	assert(value);
2457
2458	ret_code = EINVAL;
2459
2460
2461	if (varname)
2462		wl_unit=varname;
2463	else
2464
2465		wl_unit=websGetVar(wp, "wl_unit", NULL);
2466
2467	if (get_ifname_unit(wl_unit,&p,NULL) < 0) return ;
2468
2469	if (p < 0) return;
2470
2471	snprintf(unit,sizeof(unit),"%d",p);
2472	subunit = v->argv[0];
2473
2474	/* If SSID is not null try to validate it for correct range */
2475	if (*value){
2476		struct variable local;
2477
2478		memcpy(&local,v,sizeof(local));
2479		argv[0]="1";
2480		argv[1]="32";
2481		argv[2]=NULL;
2482		local.argv=argv;
2483		if (!valid_name(wp, value, &local)) return;
2484	}
2485
2486	snprintf(wl_ssid,sizeof(wl_ssid),"wl%s.%s_ssid",unit,subunit);
2487	snprintf(wl_vif,sizeof(wl_vif),"wl%s_vifs",unit);
2488	snprintf(wl_guest,sizeof(wl_guest),"wl%s.%s_guest",unit,subunit);
2489
2490	memset(buf,0,sizeof(buf));
2491
2492	/* This logic here decides if updates to virtual interface list on the
2493	   parent is required */
2494
2495	wl_vif_value = nvram_get(wl_vif);
2496
2497	if (wl_vif_value ){
2498	 		char vif[]="wlXXXXXXXXX";
2499			char *ptr=NULL;
2500
2501			snprintf(vif,sizeof(vif),"wl%s.%s",unit,subunit);
2502
2503			/* Look to see if the virtual interface is present on
2504			   on the list already
2505			*/
2506			ptr=strstr(wl_vif_value,vif);
2507
2508			if (*value){
2509				/* New interface , non-NULL SSID add to wl_vifs */
2510				if (!ptr)
2511					snprintf(buf,sizeof(buf),"%s wl%s.%s",wl_vif_value,unit,subunit);
2512				else
2513				/* Interface present ,non-NULL SSID copy entire vifs string */
2514					snprintf(buf,sizeof(buf),"%s",wl_vif_value);
2515			}else{
2516			/* Purge interface from wl_vifs as the SSID is now NULL */
2517
2518			/* vif present , delete from wl_vifs */
2519				if ((ptr)){
2520					char name[IFNAMSIZ], *next = NULL;
2521
2522					memset(buf,0,sizeof(buf));
2523
2524					foreach(name,wl_vif_value,next)
2525						/* Copy all the interfaces except the the one we want to remove*/
2526						if (strcmp(name,vif)){
2527							int len;
2528
2529							len = strlen(buf);
2530							if (*buf)
2531								strncat(buf," ",len-1);
2532							strncat(buf,name,len-strlen(name));
2533						}
2534				}else
2535					/* Interface absent from wl_vifs, just copy vifs string */
2536					snprintf(buf,sizeof(buf),"%s",wl_vif_value);
2537			}
2538	}else
2539		if (*value) snprintf(buf,sizeof(buf),"wl%s.%s",unit,subunit);
2540
2541	/* before allowing any "nvram_set()":  If URE is enabled, we want to
2542		 error here if an SSID isn't present */
2543	wl_ure = atoi( websGetVar( wp, "wl_ure", NULL ) );
2544	if(( wl_ure == 1) && (strlen(value) == 0 ))
2545	{
2546		websError(wp, 400, "Guest SSID not defined for URE mode\n");
2547		ret_code = EINVAL;
2548		return;
2549	}
2550
2551	/* Regenerate virtual interface list */
2552	if (*buf)
2553		nvram_set(wl_vif,buf);
2554	else
2555		nvram_unset(wl_vif);
2556
2557
2558	/* Update/clean up wlX.Y_guest flag and wlX.Y_ssid */
2559
2560	snprintf(prefix,sizeof(prefix),"wl%s.%s",unit,subunit);
2561	snprintf(wl_radio,sizeof(wl_radio),"wl%s.%s_radio",unit,subunit);
2562	snprintf(wl_mode,sizeof(wl_mode),"wl%s.%s_mode",unit,subunit);
2563
2564	if (*value){
2565		if ( wl_ure == 0 )
2566			nvram_set(wl_guest,"1");
2567		else
2568			nvram_unset(wl_guest);
2569		nvram_set(wl_mode,"ap");
2570		nvram_set(wl_ssid,value);
2571		nvram_set(wl_radio,"1");
2572	}else{
2573		nvram_unset(wl_ssid);
2574		nvram_set(wl_guest,"0");
2575		nvram_unset(wl_radio);
2576		nvram_unset(wl_mode);
2577	}
2578
2579	ret_code = 0;
2580}
2581static void
2582validate_name(webs_t wp, char *value, struct variable *v, char *varname )
2583{
2584	ret_code = EINVAL;
2585
2586	assert(v);
2587
2588	if (!valid_name(wp, value, v)) return;
2589
2590	if (varname )
2591		nvram_set(varname,value) ;
2592	else
2593		nvram_set(v->name, value);
2594
2595	ret_code = 0;
2596}
2597
2598static void
2599validate_ure(webs_t wp, char *value, struct variable *v, char *varname)
2600{
2601	char *temp=NULL;
2602	int wl_unit = -1;
2603	int wl_subunit = -1;
2604	int wl_ure = -1;
2605	int ii = 0;
2606	char nv_param[NVRAM_MAX_PARAM_LEN];
2607	char nv_interface[NVRAM_MAX_PARAM_LEN];
2608	char os_interface[NVRAM_MAX_PARAM_LEN];
2609	char interface_list[NVRAM_MAX_VALUE_LEN];
2610	int interface_list_size = sizeof(interface_list);
2611	char *wan0_ifname = "wan0_ifname";
2612	char *lan_ifnames = "lan_ifnames";
2613	char *wan_ifnames = "wan_ifnames";
2614
2615	if ((temp = websGetVar(wp, "wl_unit", NULL)))
2616	{
2617		if( *temp )
2618			get_ifname_unit( temp, &wl_unit, &wl_subunit );
2619
2620		if( wl_subunit != -1 )
2621		{
2622			websError(wp, 400, "URE can't be enabled for a virtual I/F\n");
2623			ret_code = EINVAL;
2624			return;
2625		}
2626	}
2627
2628	if((temp = websGetVar(wp, "wl_ure", NULL)))
2629	{
2630		if( *temp )
2631			wl_ure = atoi( temp );
2632	}
2633
2634	if( wl_ure < 0 || wl_unit < 0 )
2635	{
2636		websError(wp, 400, "Insufficient args\n");
2637		ret_code = EINVAL;
2638		return;
2639	}
2640
2641#if defined(linux)
2642	if ( nvram_match( "router_disable", "1" ) && wl_ure == 1 )
2643	{
2644		websError(wp, 400, "Basic Page: Router Mode != Router\n");
2645		ret_code = EINVAL;
2646		return;
2647	}
2648#endif /* defined( linux ) */
2649
2650	if( wl_ure == 1 )
2651	{
2652		/* turning on URE*/
2653
2654		/* If TR, we can only allow a single TR interface */
2655		for( ii = 0; ii < DEV_NUMIFS; ii++ ) {
2656			if( ii == wl_unit )
2657				continue;
2658
2659			sprintf( nv_param, "wl%d_ure", ii );
2660			temp = nvram_safe_get( nv_param );
2661			if( temp && strlen( temp ) > 0 )
2662			{
2663				if( atoi( temp ) == 1 ) {
2664					websError(wp, 400, "Can not have more than one URE interface\n");
2665					ret_code = EINVAL;
2666					return;
2667				}
2668			}
2669		}
2670
2671
2672		/*  Make sure that an SSID has been set for the virtual I/F here!!!	*/
2673		temp = websGetVar(wp, "wl_guest_ssid_1", NULL);
2674		if ( !temp || strlen( temp ) == 0 )
2675		{
2676			websError(wp, 400, "No definition for Guest SSID\n");
2677			ret_code = EINVAL;
2678			return;
2679		}
2680
2681		sprintf( nv_param, "wl_ure" );
2682		temp = nvram_safe_get( nv_param );
2683		if( strncmp( temp, "0", 1 ) == 0 || strlen( temp ) == 0 )
2684		{
2685			action = REBOOT;
2686		}
2687		else {
2688			/* nothing to do, bail out now */
2689			return;
2690		}
2691 		/* turn URE on for this primary interface */
2692		nvram_set( nv_param, "1" );
2693
2694		nvram_set( "ure_disable", "0" );
2695
2696		/* Set the wl modes for the primary wireless adapter and it's
2697			 virtual interface */
2698		sprintf( nv_param, "wl%d_mode", wl_unit );
2699		nvram_set( nv_param, "sta" );
2700		nvram_set( "wl_mode", "sta" );
2701
2702		sprintf( nv_param, "wl%d.1_mode", wl_unit );
2703		nvram_set( nv_param, "ap" );
2704
2705		/* For URE with routing(Travel Router)we're using the STA part of our URE
2706			 enabled radio as our WAN connection.  So, we need to remove this
2707			 interface from the list of bridged lan interfaces and set it up as the
2708			 WAN device.
2709		*/
2710		temp = nvram_safe_get(lan_ifnames);
2711		if( interface_list_size <= strlen( temp ) )
2712		{
2713			websError(wp, 400, "string too long\n");
2714			ret_code = 1;
2715			return;
2716		}
2717		strncpy( interface_list, temp, interface_list_size );
2718		/* this may be confusing, right now the interface name that is stored
2719			 in the nvram lists is OS specific.  For linux it's an "ethX" for
2720			 wireless interfaces and for VxWorks "wlX" is stored as "wlX" so
2721			 this is trying to make OS independant code */
2722		sprintf( nv_interface, "wl%d", wl_unit );
2723		nvifname_to_osifname( nv_interface, os_interface, sizeof(os_interface) );
2724		remove_from_list( os_interface, interface_list, interface_list_size );
2725		nvram_set( lan_ifnames, interface_list );
2726
2727		/* Now remove the existing WAN interface from "wan_ifnames" */
2728		temp = nvram_safe_get( wan_ifnames );
2729		if( interface_list_size <= (strlen( temp ) + strlen( interface_list )) )
2730		{
2731			websError(wp, 400, "string too long\n");
2732			ret_code = 1;
2733			return;
2734		}
2735		strncpy( interface_list, temp, interface_list_size );
2736		temp = nvram_safe_get( wan0_ifname );
2737		if( strlen( temp ) != 0 )
2738		{
2739			remove_from_list( temp, interface_list, interface_list_size );
2740		}
2741
2742		/* set the new WAN interface as the pimary WAN interface and add to
2743		   the list wan_ifnames */
2744		nvram_set( wan0_ifname, os_interface );
2745		add_to_list( os_interface, interface_list, interface_list_size );
2746		nvram_set( wan_ifnames, interface_list );
2747
2748		/* now add the AP to the list of bridged lan interfaces */
2749		temp = nvram_safe_get(lan_ifnames);
2750		if( interface_list_size <= strlen( temp ) )
2751		{
2752			websError(wp, 400, "string too long\n");
2753			ret_code = 1;
2754			return;
2755		}
2756		strncpy( interface_list, temp, interface_list_size );
2757		sprintf( nv_interface, "wl%d.1", wl_unit );
2758		/* virtual interfaces that appear in NVRAM lists are ALWAYS stored
2759			 as the NVRAM_FORM so we can add to list without translating */
2760		if( add_to_list( nv_interface, interface_list, interface_list_size ) != 0 )
2761		{
2762			websError(wp, 400, "Failed to add AP interface to lan_ifnames\n");
2763			ret_code = 1;
2764			return;
2765		}
2766		nvram_set( lan_ifnames, interface_list );
2767
2768		/* Security - We don't support any RADIUS-based authentication, so
2769			 we must force these options to OFF */
2770		/* turn off wlX_auth_mode and wlX.1_auth_mode */
2771		sprintf( nv_param, "wl%d_auth_mode", wl_unit );
2772		nvram_set( nv_param, "none" );
2773		sprintf( nv_param, "wl%d.1_auth_mode", wl_unit );
2774		nvram_set( nv_param, "none" );
2775		/* remove wpa and wpa2 from wlX_akm and wlX.1_akm */
2776		/* wl_akm should be used here rather than wlX_akm, it's an
2777			 indexed param, so wl_akm represents wlX_akm */
2778		sprintf( nv_param, "wl_akm" );
2779		temp = nvram_get( nv_param );
2780		if( temp && *temp )
2781		{
2782			memset( interface_list, 0, interface_list_size );
2783			/* NOTE: using "interface_list" to hold security nvram values */
2784			strncpy( interface_list, temp, interface_list_size - 1 );
2785			remove_from_list("wpa", interface_list, interface_list_size );
2786			remove_from_list("wpa2", interface_list, interface_list_size );
2787			nvram_set( nv_param, interface_list );
2788		}
2789		sprintf( nv_param, "wl%d.1_akm", wl_unit );
2790		temp = nvram_get( nv_param );
2791		if( temp && *temp )
2792		{
2793			memset( interface_list, 0, interface_list_size );
2794			/* NOTE: using "interface_list" to hold security nvram values */
2795			strncpy( interface_list, temp, interface_list_size - 1 );
2796			remove_from_list("wpa", interface_list, interface_list_size );
2797			remove_from_list("wpa2", interface_list, interface_list_size );
2798			nvram_set( nv_param, interface_list );
2799		}
2800	}
2801	else
2802	{
2803		sprintf( nv_param, "wl_ure");
2804		temp = nvram_get( nv_param );
2805		if( strncmp( temp, "1", 1 ) != 0 ) {
2806			/* nothing to do, bail out now */
2807			return;
2808		}
2809		nvram_set( nv_param, "0" );
2810
2811		nvram_set( "ure_disable", "1" );
2812
2813		/* Restore default WAN interface */
2814
2815		/* Now remove the existing WAN interface from "wan_ifnames" */
2816		temp = nvram_safe_get( wan_ifnames );
2817		if( interface_list_size <= (strlen( temp ) + strlen( interface_list )) )
2818		{
2819			websError(wp, 400, "string too long\n");
2820			ret_code = 1;
2821			return;
2822		}
2823		strncpy( interface_list, temp, interface_list_size );
2824		temp = nvram_safe_get( wan0_ifname );
2825		if( strlen( temp ) != 0 )
2826		{
2827			remove_from_list( temp, interface_list, interface_list_size );
2828		}
2829
2830		strcpy( os_interface, "eth1" );
2831		nvram_set( wan0_ifname, os_interface );
2832		add_to_list( os_interface, interface_list, interface_list_size );
2833		nvram_set( wan_ifnames, interface_list );
2834
2835		/* Now we need to remove the virtual I/F from the bridged lan interfaces */
2836		temp = nvram_safe_get(lan_ifnames);
2837		if( interface_list_size <= strlen( temp ) )
2838		{
2839			websError(wp, 400, "string too long\n");
2840			ret_code = 1;
2841			return;
2842		}
2843		strncpy( interface_list, temp, interface_list_size );
2844		sprintf( nv_interface, "wl%d.1", wl_unit );
2845		/* virtual interfaces that appear in NVRAM lists are ALWAYS stored
2846			 as the NVRAM_FORM so we can add to list without translating */
2847		remove_from_list( nv_interface, interface_list, interface_list_size );
2848		/* Add our primary interface to lan_ifnames - default behavior */
2849		sprintf( nv_interface, "wl%d", wl_unit );
2850		nvifname_to_osifname( nv_interface, os_interface, sizeof(os_interface) );
2851		add_to_list( os_interface, interface_list, interface_list_size );
2852		nvram_set( lan_ifnames, interface_list );
2853	}
2854	action = REBOOT;
2855
2856	/* We're unsetting the WAN hardware address so that we get the correct
2857		 address for the new WAN interface the next time we boot. */
2858	nvram_unset( "wan0_hwaddr" );
2859
2860	ret_code = 0;
2861	return;
2862}
2863
2864static int
2865valid_hwaddr(webs_t wp, char *value, struct variable *v)
2866{
2867	unsigned char hwaddr[6];
2868
2869	assert(v);
2870
2871	/* Make exception for "NOT IMPLELEMENTED" string */
2872	if (!strcmp(value,"NOT_IMPLEMENTED"))
2873		return(TRUE);
2874
2875	/* Check for bad, multicast, broadcast, or null address */
2876	if (!ether_atoe(value, hwaddr) ||
2877	    (hwaddr[0] & 1) ||
2878	    (hwaddr[0] & hwaddr[1] & hwaddr[2] & hwaddr[3] & hwaddr[4] & hwaddr[5]) == 0xff ||
2879	    (hwaddr[0] | hwaddr[1] | hwaddr[2] | hwaddr[3] | hwaddr[4] | hwaddr[5]) == 0x00) {
2880		websBufferWrite(wp, "Invalid <b>%s</b> %s: not a MAC address<br>",
2881			  v->longname, value);
2882		return FALSE;
2883	}
2884
2885	return TRUE;
2886}
2887
2888#ifdef __CONFIG_NAT__
2889static void
2890validate_hwaddr(webs_t wp, char *value, struct variable *v, char *varname )
2891{
2892
2893	ret_code = EINVAL;
2894
2895	if (!valid_hwaddr(wp, value, v)) return;
2896
2897	if(varname )
2898		nvram_set(varname,value);
2899	else
2900		nvram_set(v->name, value);
2901
2902	ret_code = 0;
2903
2904
2905}
2906#endif	/* __CONFIG_NAT__ */
2907
2908static void
2909validate_hwaddrs(webs_t wp, char *value, struct variable *v, char *varname )
2910{
2911
2912	assert(v);
2913
2914	ret_code = EINVAL;
2915	validate_list(wp, value, v, valid_hwaddr, varname);
2916}
2917
2918static void
2919validate_country(webs_t wp, char *value, struct variable *v, char *varname)
2920{
2921	country_name_t *country=NULL;
2922
2923	assert(v);
2924
2925	ret_code = EINVAL;
2926	for(country = country_names; country->name; country++)
2927		if (!strcmp(value, country->abbrev)){
2928			if (varname)
2929				nvram_set(varname,value);
2930			else
2931				nvram_set(v->name, value);
2932			ret_code = 0;
2933			return ;
2934		}
2935	websBufferWrite(wp, "Country abbreviation <b>%s</b>: is invalid<br>",value);
2936}
2937
2938static void
2939validate_dhcp(webs_t wp, char *value, struct variable *v, char *varname)
2940{
2941	struct variable dhcp_variables[] = {
2942		{ longname: "DHCP Server Starting LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
2943		{ longname: "DHCP Server Ending LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
2944	};
2945	char *start=NULL, *end=NULL;
2946	char dhcp_start[20]="dhcp_start";
2947	char dhcp_end[20]="dhcp_start";
2948	char lan_proto[20]="lan_proto";
2949	char lan_ipaddr[20]="lan_ipaddr";
2950	char lan_netmask[20]= "lan_netmask";
2951	char *dhcp0_argv[3],*dhcp1_argv[3];
2952	char index[5];
2953
2954	assert(v);
2955
2956	ret_code = EINVAL;
2957
2958	memset(index,sizeof(index),0);
2959	/* fixup the nvram varnames if varname override is provided */
2960	if (varname){
2961		if (!get_index_string(v->prefix,
2962			varname,index,sizeof(index)))
2963				return;
2964
2965		snprintf(dhcp_start,sizeof(dhcp_start),"dhcp%s_start",index);
2966		snprintf(dhcp_end,sizeof(dhcp_end),"dhcp%s_end",index);
2967		snprintf(lan_proto,sizeof(lan_proto),"lan%s_proto",index);
2968		snprintf(lan_ipaddr,sizeof(lan_ipaddr),"lan%s_ipaddr",index);
2969		snprintf(lan_netmask,sizeof(lan_netmask),"lan%s_netmask",index);
2970		dhcp0_argv[0]=lan_ipaddr;
2971		dhcp0_argv[1]=lan_netmask;
2972		dhcp0_argv[2]=NULL;
2973		dhcp1_argv[0]=lan_ipaddr;
2974		dhcp1_argv[1]=lan_netmask;
2975		dhcp1_argv[2]=NULL;
2976		dhcp_variables[0].argv = dhcp0_argv;
2977		dhcp_variables[1].argv = dhcp1_argv;
2978	}
2979
2980	if (!(start = websGetVar(wp, dhcp_start, NULL)) ||
2981	    !(end = websGetVar(wp, dhcp_end, NULL)))
2982		return;
2983	if (!*start) start = end;
2984	if (!*end) end = start;
2985	if (!*start && !*end && !strcmp(nvram_safe_get(lan_proto), "dhcp")) {
2986		websBufferWrite(wp, "Invalid <b>%s</b>: must specify a range<br>", v->longname);
2987		return;
2988	}
2989	if (!valid_ipaddr(wp, start, &dhcp_variables[0]) ||
2990	    !valid_ipaddr(wp, end, &dhcp_variables[1]))
2991		return;
2992	if (ntohl(inet_addr(start)) > ntohl(inet_addr(end))) {
2993		websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
2994			  dhcp_variables[0].longname, start, dhcp_variables[1].longname, end);
2995		return;
2996	}
2997
2998	nvram_set(dhcp_start, start);
2999	nvram_set(dhcp_end, end);
3000
3001	ret_code = 0;
3002}
3003
3004static void
3005validate_lan_ipaddr(webs_t wp, char *value, struct variable *v, char *varname)
3006{
3007	struct variable fields[] = {
3008		{ name: "lan_ipaddr", longname: "LAN IP Address" },
3009		{ name: "lan_netmask", longname: "LAN Subnet Mask" },
3010	};
3011	char *lan_ipaddr=NULL, *lan_netmask=NULL;
3012	char tmp_ipaddr[20], tmp_netmask[20];
3013	struct in_addr ipaddr, netmask, netaddr, broadaddr;
3014	char lan_ipaddrs[][20] = { "dhcp_start", "dhcp_end", "dmz_ipaddr" };
3015#ifdef __CONFIG_NAT__
3016	netconf_filter_t start, end;
3017	netconf_nat_t nat;
3018	bool valid;
3019#endif	/* __CONFIG_NAT__ */
3020	int i;
3021
3022	assert(v);
3023
3024	ret_code = EINVAL;
3025
3026	/* Insert name overrides */
3027	if (varname)
3028	{
3029		char index[5];
3030
3031		if (!get_index_string(v->prefix,
3032			varname,index,sizeof(index)))
3033				return ;
3034
3035		snprintf(tmp_ipaddr,sizeof(tmp_ipaddr),"lan%s_ipaddr",index);
3036		snprintf(tmp_netmask,sizeof(tmp_netmask),"lan%s_netmask",index);
3037		fields[0].name = tmp_ipaddr;
3038		fields[1].name = tmp_netmask;
3039		snprintf(lan_ipaddrs[0],sizeof(lan_ipaddrs[0]),"dhcp%s_start",index);
3040		snprintf(lan_ipaddrs[1],sizeof(lan_ipaddrs[1]),"dhcp%s_end",index);
3041	}
3042	/* Basic validation */
3043	if (!(lan_ipaddr = websGetVar(wp, fields[0].name, NULL)) ||
3044	    !(lan_netmask = websGetVar(wp, fields[1].name, NULL)) ||
3045	    !valid_ipaddr(wp, lan_ipaddr, &fields[0]) ||
3046	    !valid_ipaddr(wp, lan_netmask, &fields[1]))
3047		return;
3048
3049	/* Check for broadcast or network address */
3050	(void) inet_aton(lan_ipaddr, &ipaddr);
3051	(void) inet_aton(lan_netmask, &netmask);
3052	netaddr.s_addr = ipaddr.s_addr & netmask.s_addr;
3053	broadaddr.s_addr = netaddr.s_addr | ~netmask.s_addr;
3054	if (ipaddr.s_addr == netaddr.s_addr) {
3055		websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the network address<br>",
3056			  fields[0].longname, lan_ipaddr);
3057		return;
3058	}
3059	if (ipaddr.s_addr == broadaddr.s_addr) {
3060		websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the broadcast address<br>",
3061			  fields[0].longname, lan_ipaddr);
3062		return;
3063	}
3064
3065
3066	nvram_set(fields[0].name, lan_ipaddr);
3067	nvram_set(fields[1].name, lan_netmask);
3068
3069
3070	/* Fix up LAN IP addresses */
3071	for (i = 0; i < ARRAYSIZE(lan_ipaddrs); i++) {
3072
3073		value = nvram_get(lan_ipaddrs[i]);
3074		if (value && *value) {
3075			(void) inet_aton(value, &ipaddr);
3076			ipaddr.s_addr &= ~netmask.s_addr;
3077			ipaddr.s_addr |= netaddr.s_addr;
3078
3079			nvram_set(lan_ipaddrs[i], inet_ntoa(ipaddr));
3080		}
3081	}
3082
3083#ifdef __CONFIG_NAT__
3084	/* Fix up client filters and port forwards */
3085	for (i = 0; i < MAX_NVPARSE; i++) {
3086		if (get_filter_client(i, &start, &end)) {
3087			start.match.src.ipaddr.s_addr &= ~netmask.s_addr;
3088			start.match.src.ipaddr.s_addr |= netaddr.s_addr;
3089			end.match.src.ipaddr.s_addr &= ~netmask.s_addr;
3090			end.match.src.ipaddr.s_addr |= netaddr.s_addr;
3091
3092			valid = set_filter_client(i, &start, &end);
3093			a_assert(valid);
3094		}
3095		if (get_forward_port(i, &nat)) {
3096			nat.ipaddr.s_addr &= ~netmask.s_addr;
3097			nat.ipaddr.s_addr |= netaddr.s_addr;
3098			valid = set_forward_port(i, &nat);
3099			a_assert(valid);
3100		}
3101	}
3102#endif	/* __CONFIG_NAT__ */
3103
3104	ret_code = 0;
3105}
3106
3107#ifdef __CONFIG_NAT__
3108static void
3109validate_filter_client(webs_t wp, char *value, struct variable *v, char *varname)
3110{
3111	int n, i, j;
3112	bool valid;
3113	struct variable fields[] = {
3114		{ name: "filter_client_from_start%d", longname: "LAN Client Filter Starting IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
3115		{ name: "filter_client_from_end%d", longname: "LAN Client Filter Ending IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
3116		{ name: "filter_client_proto%d", longname: "LAN Client Filter Protocol", argv: ARGV("tcp", "udp") },
3117		{ name: "filter_client_to_start%d", longname: "LAN Client Filter Starting Destination Port", argv: ARGV("0", "65535") },
3118		{ name: "filter_client_to_end%d", longname: "LAN Client Filter Ending Destination Port", argv: ARGV("0", "65535") },
3119		{ name: "filter_client_from_day%d", longname: "LAN Client Filter Starting Day", argv: ARGV("0", "6") },
3120		{ name: "filter_client_to_day%d", longname: "LAN Client Filter Ending Day", argv: ARGV("0", "6") },
3121		{ name: "filter_client_from_sec%d", longname: "LAN Client Filter Starting Second", argv: ARGV("0", "86400") },
3122		{ name: "filter_client_to_sec%d", longname: "LAN Client Filter Ending Second", argv: ARGV("0", "86400") },
3123	};
3124	char *from_start=NULL, *from_end=NULL, *proto=NULL, *to_start=NULL;
3125	char *to_end=NULL, *from_day=NULL, *to_day=NULL, *from_sec=NULL, *to_sec=NULL, *enable=NULL;
3126	char **locals[] = { &from_start, &from_end, &proto, &to_start, &to_end, &from_day, &to_day, &from_sec, &to_sec };
3127	char name[1000];
3128	netconf_filter_t start, end;
3129
3130	assert(v);
3131
3132	ret_code = EINVAL;
3133
3134	/* filter_client indicates how many to expect */
3135	if (!valid_range(wp, value, v)){
3136		websBufferWrite(wp, "Invalid filter client string <b>%s</b><br>",value);
3137		return;
3138	}
3139	n = atoi(value);
3140
3141	for (i = 0; i <= n; i++) {
3142		/* Set up field names */
3143		for (j = 0; j < ARRAYSIZE(fields); j++) {
3144			snprintf(name, sizeof(name), fields[j].name, i);
3145			if (!(*locals[j] = websGetVar(wp, name, NULL)))
3146				break;
3147		}
3148		/* Incomplete web page */
3149		if (j < ARRAYSIZE(fields))
3150			continue;
3151		/* Enable is a checkbox */
3152		snprintf(name, sizeof(name), "filter_client_enable%d", i);
3153		if (websGetVar(wp, name, NULL))
3154			enable = "on";
3155		else
3156			enable = "off";
3157		/* Delete entry if all fields are blank */
3158		if (!*from_start && !*from_end && !*to_start && !*to_end) {
3159			del_filter_client(i);
3160			continue;
3161		}
3162		/* Fill in empty fields with default values */
3163		if (!*from_start) from_start = from_end;
3164		if (!*from_end) from_end = from_start;
3165		if (!*to_start) to_start = to_end;
3166		if (!*to_end) to_end = to_start;
3167		if (!*from_start || !*from_end) {
3168			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname);
3169			continue;
3170		}
3171		if (!*to_start || !*to_end) {
3172			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Destination Port Range<br>", v->longname);
3173			continue;
3174		}
3175		/* Check individual fields */
3176		if (!valid_ipaddr(wp, from_start, &fields[0]) ||
3177		    !valid_ipaddr(wp, from_end, &fields[1]) ||
3178		    !valid_choice(wp, proto, &fields[2]) ||
3179		    !valid_range(wp, to_start, &fields[3]) ||
3180		    !valid_range(wp, to_end, &fields[4]) ||
3181		    !valid_range(wp, from_day, &fields[5]) ||
3182		    !valid_range(wp, to_day, &fields[6]) ||
3183		    !valid_range(wp, from_sec, &fields[7]) ||
3184		    !valid_range(wp, to_sec, &fields[8]))
3185			continue;
3186		/* Check dependencies between fields */
3187		if (ntohl(inet_addr(from_start)) > ntohl(inet_addr(from_end))) {
3188			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3189				  fields[0].longname, from_start, fields[1].longname, from_end);
3190			continue;
3191		}
3192		if (atoi(to_start) > atoi(to_end)) {
3193			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3194				  fields[3].longname, to_start, fields[4].longname, to_end);
3195			continue;
3196		}
3197
3198		/* Set up parameters */
3199		memset(&start, 0, sizeof(netconf_filter_t));
3200		if (!strcmp(proto, "tcp"))
3201			start.match.ipproto = IPPROTO_TCP;
3202		else if (!strcmp(proto, "udp"))
3203			start.match.ipproto = IPPROTO_UDP;
3204		(void) inet_aton(from_start, &start.match.src.ipaddr);
3205		start.match.src.netmask.s_addr = htonl(0xffffffff);
3206		start.match.dst.ports[0] = htons(atoi(to_start));
3207		start.match.dst.ports[1] = htons(atoi(to_end));
3208		start.match.days[0] = atoi(from_day);
3209		start.match.days[1] = atoi(to_day);
3210		start.match.secs[0] = atoi(from_sec);
3211		start.match.secs[1] = atoi(to_sec);
3212		if (!strcmp(enable, "off"))
3213			start.match.flags |= NETCONF_DISABLED;
3214		memcpy(&end, &start, sizeof(netconf_filter_t));
3215		(void) inet_aton(from_end, &end.match.src.ipaddr);
3216
3217		/* Do it */
3218		valid = set_filter_client(i, &start, &end);
3219		a_assert(valid);
3220	}
3221
3222		ret_code = 0;
3223}
3224
3225static void
3226validate_forward_port(webs_t wp, char *value, struct variable *v, char *varname)
3227{
3228	int n, i, j;
3229	bool valid;
3230	struct variable fields[] = {
3231		{ name: "forward_port_proto%d", longname: "Port Forward Protocol", argv: ARGV("tcp", "udp") },
3232		{ name: "forward_port_from_start%d", longname: "Port Forward Starting WAN Port", argv: ARGV("0", "65535") },
3233		{ name: "forward_port_from_end%d", longname: "Port Forward Ending WAN Port", argv: ARGV("0", "65535") },
3234		{ name: "forward_port_to_ip%d", longname: "Port Forward LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
3235		{ name: "forward_port_to_start%d", longname: "Port Forward Starting LAN Port", argv: ARGV("0", "65535") },
3236		{ name: "forward_port_to_end%d", longname: "Port Forward Ending LAN Port", argv: ARGV("0", "65535") },
3237	};
3238	char *proto=NULL, *from_start=NULL, *from_end=NULL;
3239	char *to_ip=NULL, *to_start=NULL, *to_end=NULL, *enable=NULL;
3240	char **locals[] = { &proto, &from_start, &from_end, &to_ip, &to_start, &to_end };
3241	char name[1000];
3242	netconf_nat_t nat;
3243
3244	assert(v);
3245
3246	ret_code = EINVAL;
3247
3248	/* forward_port indicates how many to expect */
3249	if (!valid_range(wp, value, v)){
3250		websBufferWrite(wp, "Invalid forward port string <b>%s</b><br>",value);
3251		return;
3252	}
3253	n = atoi(value);
3254
3255	for (i = 0; i <= n; i++) {
3256		/* Set up field names */
3257		for (j = 0; j < ARRAYSIZE(fields); j++) {
3258			snprintf(name, sizeof(name), fields[j].name, i);
3259			if (!(*locals[j] = websGetVar(wp, name, NULL)))
3260				break;
3261		}
3262		/* Incomplete web page */
3263		if (j < ARRAYSIZE(fields))
3264			continue;
3265		/* Enable is a checkbox */
3266		snprintf(name, sizeof(name), "forward_port_enable%d", i);
3267		if (websGetVar(wp, name, NULL))
3268			enable = "on";
3269		else
3270			enable = "off";
3271		/* Delete entry if all fields are blank */
3272		if (!*from_start && !*from_end && !*to_ip && !*to_start && !*to_end) {
3273			del_forward_port(i);
3274			continue;
3275		}
3276		/* Fill in empty fields with default values */
3277		if (!*from_start) from_start = from_end;
3278		if (!*from_end) from_end = from_start;
3279		if (!*to_start && !*to_end)
3280			to_start = from_start;
3281		if (!*to_start) to_start = to_end;
3282		if (!*to_end) to_end = to_start;
3283		if (!*from_start || !*from_end) {
3284			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname);
3285			continue;
3286		}
3287		if (!*to_ip) {
3288			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address<br>", v->longname);
3289			continue;
3290		}
3291		if (!*to_start || !*to_end) {
3292			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Destination Port Range<br>", v->longname);
3293			continue;
3294		}
3295		/* Check individual fields */
3296		if (!valid_choice(wp, proto, &fields[0]) ||
3297		    !valid_range(wp, from_start, &fields[1]) ||
3298		    !valid_range(wp, from_end, &fields[2]) ||
3299		    !valid_ipaddr(wp, to_ip, &fields[3]) ||
3300		    !valid_range(wp, to_start, &fields[4]) ||
3301		    !valid_range(wp, to_end, &fields[5]))
3302			continue;
3303		if (atoi(from_start) > atoi(from_end)) {
3304			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3305				  fields[1].longname, from_start, fields[2].longname, from_end);
3306			continue;
3307		}
3308		if (atoi(to_start) > atoi(to_end)) {
3309			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3310				  fields[4].longname, to_start, fields[5].longname, to_end);
3311			continue;
3312		}
3313		if ((atoi(from_end) - atoi(from_start)) != (atoi(to_end) - atoi(to_start))) {
3314			websBufferWrite(wp, "Invalid <b>%s</b>: WAN Port Range and LAN Port Range must be the same size<br>", v->longname);
3315			continue;
3316		}
3317
3318		/* Set up parameters */
3319		memset(&nat, 0, sizeof(netconf_nat_t));
3320		if (!strcmp(proto, "tcp"))
3321			nat.match.ipproto = IPPROTO_TCP;
3322		else if (!strcmp(proto, "udp"))
3323			nat.match.ipproto = IPPROTO_UDP;
3324		nat.match.dst.ports[0] = htons(atoi(from_start));
3325		nat.match.dst.ports[1] = htons(atoi(from_end));
3326		(void) inet_aton(to_ip, &nat.ipaddr);
3327		nat.ports[0] = htons(atoi(to_start));
3328		nat.ports[1] = htons(atoi(to_end));
3329		if (!strcmp(enable, "off"))
3330			nat.match.flags |= NETCONF_DISABLED;
3331
3332		/* Do it */
3333		valid = set_forward_port(i, &nat);
3334		a_assert(valid);
3335	}
3336	ret_code =0;
3337}
3338
3339static void
3340validate_autofw_port(webs_t wp, char *value, struct variable *v, char *varname)
3341{
3342	int n, i, j;
3343	bool valid;
3344	struct variable fields[] = {
3345		{ name: "autofw_port_out_proto%d", longname: "Outbound Protocol", argv: ARGV("tcp", "udp") },
3346		{ name: "autofw_port_out_start%d", longname: "Outbound Port Start", argv: ARGV("0", "65535") },
3347		{ name: "autofw_port_out_end%d", longname: "Outbound Port End", argv: ARGV("0", "65535") },
3348		{ name: "autofw_port_in_proto%d", longname: "Inbound Protocol", argv: ARGV("tcp", "udp") },
3349		{ name: "autofw_port_in_start%d", longname: "Inbound Port Start", argv: ARGV("0", "65535") },
3350		{ name: "autofw_port_in_end%d", longname: "Inbound Port End", argv: ARGV("0", "65535") },
3351 		{ name: "autofw_port_to_start%d", longname: "To Port Start", argv: ARGV("0", "65535") },
3352 		{ name: "autofw_port_to_end%d", longname: "To Port End", argv: ARGV("0", "65535") },
3353	};
3354	char *out_proto=NULL, *out_start=NULL, *out_end=NULL, *in_proto=NULL;
3355	char *in_start=NULL, *in_end=NULL, *to_start=NULL, *to_end=NULL, *enable=NULL;
3356	char **locals[] = { &out_proto, &out_start, &out_end, &in_proto, &in_start, &in_end, &to_start, &to_end };
3357	char name[1000];
3358	netconf_app_t app;
3359
3360	assert(v);
3361
3362	ret_code = EINVAL;
3363
3364	/* autofw_port indicates how many to expect */
3365	if (!valid_range(wp, value, v)){
3366		websBufferWrite(wp, "Invalid auto forward port string <b>%s</b><br>",value);
3367		return;
3368	}
3369	n = atoi(value);
3370
3371	for (i = 0; i <= n; i++) {
3372		/* Set up field names */
3373		for (j = 0; j < ARRAYSIZE(fields); j++) {
3374			snprintf(name, sizeof(name), fields[j].name, i);
3375			if (!(*locals[j] = websGetVar(wp, name, NULL)))
3376				break;
3377		}
3378		/* Incomplete web page */
3379		if (j < ARRAYSIZE(fields))
3380			continue;
3381		/* Enable is a checkbox */
3382		snprintf(name, sizeof(name), "autofw_port_enable%d", i);
3383		if (websGetVar(wp, name, NULL))
3384			enable = "on";
3385		else
3386			enable = "off";
3387		/* Delete entry if all fields are blank */
3388		if (!*out_start && !*out_end && !*in_start && !*in_end && !*to_start && !*to_end) {
3389			del_autofw_port(i);
3390			continue;
3391		}
3392		/* Fill in empty fields with default values */
3393		if (!*out_start) out_start = out_end;
3394		if (!*out_end) out_end = out_start;
3395		if (!*in_start) in_start = in_end;
3396		if (!*in_end) in_end = in_start;
3397		if (!*to_start && !*to_end)
3398			to_start = in_start;
3399		if (!*to_start) to_start = to_end;
3400		if (!*to_end) to_end = to_start;
3401		if (!*out_start || !*out_end) {
3402			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an Outbound Port Range<br>", v->longname);
3403			continue;
3404		}
3405		if (!*in_start || !*in_end) {
3406			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an Inbound Port Range<br>", v->longname);
3407			continue;
3408		}
3409		if (!*to_start || !*to_end) {
3410			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a To Port Range<br>", v->longname);
3411			continue;
3412		}
3413		/* Check individual fields */
3414		if (!valid_choice(wp, out_proto, &fields[0]) ||
3415		    !valid_range(wp, out_start, &fields[1]) ||
3416		    !valid_range(wp, out_end, &fields[2]) ||
3417		    !valid_choice(wp, in_proto, &fields[3]) ||
3418		    !valid_range(wp, in_start, &fields[4]) ||
3419		    !valid_range(wp, in_end, &fields[5]) ||
3420		    !valid_range(wp, to_start, &fields[6]) ||
3421		    !valid_range(wp, to_end, &fields[7]))
3422			continue;
3423		/* Check dependencies between fields */
3424		if (atoi(out_start) > atoi(out_end)) {
3425			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3426				  fields[1].longname, out_start, fields[2].longname, out_end);
3427			continue;
3428		}
3429		if (atoi(in_start) > atoi(in_end)) {
3430			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3431				  fields[4].longname, in_start, fields[5].longname, in_end);
3432			continue;
3433		}
3434		if (atoi(to_start) > atoi(to_end)) {
3435			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
3436				  fields[6].longname, in_start, fields[7].longname, in_end);
3437			continue;
3438		}
3439		if ((atoi(in_end) - atoi(in_start)) != (atoi(to_end) - atoi(to_start))) {
3440			websBufferWrite(wp, "Invalid <b>%s</b>: Inbound Port Range and To Port Range must be the same size<br>", v->longname);
3441			continue;
3442		}
3443#ifdef NEW_PORT_TRIG
3444		if ((atoi(in_end) - atoi(in_start)) > 100) {
3445			websBufferWrite(wp, "Invalid <b>%s</b>: Inbound Port Range must be less than 100<br>", v->longname);
3446			continue;
3447		}
3448#endif
3449
3450		/* Set up parameters */
3451		memset(&app, 0, sizeof(netconf_app_t));
3452		if (!strcmp(out_proto, "tcp"))
3453			app.match.ipproto = IPPROTO_TCP;
3454		else if (!strcmp(out_proto, "udp"))
3455			app.match.ipproto = IPPROTO_UDP;
3456		app.match.dst.ports[0] = htons(atoi(out_start));
3457		app.match.dst.ports[1] = htons(atoi(out_end));
3458		if (!strcmp(in_proto, "tcp"))
3459			app.proto = IPPROTO_TCP;
3460		else if (!strcmp(in_proto, "udp"))
3461			app.proto = IPPROTO_UDP;
3462		app.dport[0] = htons(atoi(in_start));
3463		app.dport[1] = htons(atoi(in_end));
3464		app.to[0] = htons(atoi(to_start));
3465		app.to[1] = htons(atoi(to_end));
3466		if (!strcmp(enable, "off"))
3467			app.match.flags |= NETCONF_DISABLED;
3468
3469		/* Do it */
3470		valid = set_autofw_port(i, &app);
3471		a_assert(valid);
3472	}
3473	ret_code = 0;
3474}
3475#endif	/* __CONFIG_NAT__ */
3476
3477static void
3478validate_lan_route(webs_t wp, char *value, struct variable *v, char *varname)
3479{
3480	int n, i;
3481	char buf[1000] = "", *cur = buf;
3482	char lan_ipaddr[20] ="lan_ipaddr";
3483	char lan_netmask[20]="lan_netmask";
3484	char *lan_argv[3];
3485
3486	struct variable lan_route_variables[] = {
3487		{ longname: "Route IP Address", argv: NULL },
3488		{ longname: "Route Subnet Mask", argv: NULL },
3489		{ longname: "Route Gateway", argv: NULL },
3490		{ longname: "Route Metric", argv: ARGV("0", "15") },
3491	};
3492
3493	assert(v);
3494
3495	ret_code = EINVAL;
3496
3497	/* Insert name overrides */
3498	if (varname)
3499	{
3500		char index[5];
3501
3502		if (!get_index_string(v->prefix,varname,
3503			index,sizeof(index)))
3504				return;
3505
3506		snprintf(lan_ipaddr,sizeof(lan_ipaddr),"lan%s_ipaddr",index);
3507		snprintf(lan_netmask,sizeof(lan_netmask),"lan%s_netmask",index);
3508	}
3509
3510	n = atoi(value);
3511
3512	for (i = 0; i < n; i++) {
3513		char lan_route_ipaddr[] = "lan_route_ipaddrXXX";
3514		char lan_route_netmask[] = "lan_route_netmaskXXX";
3515		char lan_route_gateway[] = "lan_route_gatewayXXX";
3516		char lan_route_metric[] = "lan_route_metricXXX";
3517		char *ipaddr, *netmask, *gateway, *metric;
3518
3519 		snprintf(lan_route_ipaddr, sizeof(lan_route_ipaddr), "%s_ipaddr%d", v->name, i);
3520		snprintf(lan_route_netmask, sizeof(lan_route_netmask), "%s_netmask%d", v->name, i);
3521 		snprintf(lan_route_gateway, sizeof(lan_route_gateway), "%s_gateway%d", v->name, i);
3522 		snprintf(lan_route_metric, sizeof(lan_route_metric), "%s_metric%d", v->name, i);
3523		if (!(ipaddr = websGetVar(wp, lan_route_ipaddr, NULL)) ||
3524		    !(netmask = websGetVar(wp, lan_route_netmask, NULL)) ||
3525		    !(gateway = websGetVar(wp, lan_route_gateway, NULL)) ||
3526		    !(metric = websGetVar(wp, lan_route_metric, NULL)))
3527			return;
3528		if (!*ipaddr && !*netmask && !*gateway && !*metric)
3529			continue;
3530		if (!*ipaddr && !*netmask && *gateway) {
3531			ipaddr = "0.0.0.0";
3532			netmask = "0.0.0.0";
3533		}
3534		if (!*gateway)
3535			gateway = "0.0.0.0";
3536		if (!*metric)
3537			metric = "0";
3538		if (!*ipaddr) {
3539			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an IP Address<br>", v->longname);
3540			continue;
3541		}
3542		if (!*netmask) {
3543			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Subnet Mask<br>", v->longname);
3544			continue;
3545		}
3546
3547		lan_argv[0]=lan_ipaddr;
3548		lan_argv[1]=lan_netmask;
3549		lan_argv[2]=NULL;
3550
3551		lan_route_variables[2].argv = lan_argv;
3552		if (!valid_ipaddr(wp, ipaddr, &lan_route_variables[0]) ||
3553		    !valid_ipaddr(wp, netmask, &lan_route_variables[1]) ||
3554		    !valid_ipaddr(wp, gateway, &lan_route_variables[2]) ||
3555		    !valid_range(wp, metric, &lan_route_variables[3]))
3556			continue;
3557		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s:%s:%s",
3558				cur == buf ? "" : " ", ipaddr, netmask, gateway, metric);
3559	}
3560
3561	if (varname)
3562		nvram_set(varname,buf);
3563	else
3564		nvram_set(v->name, buf);
3565	ret_code = 0;
3566}
3567
3568#ifdef __CONFIG_NAT__
3569static void
3570validate_wan_route(webs_t wp, char *value, struct variable *v, char *varname)
3571{
3572	int n, i;
3573	char buf[1000] = "", *cur = buf;
3574	struct variable wan_route_variables[] = {
3575		{ longname: "Route IP Address", argv: NULL },
3576		{ longname: "Route Subnet Mask", argv: NULL },
3577		{ longname: "Route Gateway", argv: NULL },
3578		{ longname: "Route Metric", argv: ARGV("0", "15") },
3579	};
3580
3581	assert(v);
3582
3583	ret_code = EINVAL;
3584
3585	n = atoi(value);
3586
3587	for (i = 0; i < n; i++) {
3588		char wan_route_ipaddr[] = "wan_route_ipaddrXXX";
3589		char wan_route_netmask[] = "wan_route_netmaskXXX";
3590		char wan_route_gateway[] = "wan_route_gatewayXXX";
3591		char wan_route_metric[] = "wan_route_metricXXX";
3592		char *ipaddr, *netmask, *gateway, *metric;
3593
3594 		snprintf(wan_route_ipaddr, sizeof(wan_route_ipaddr), "%s_ipaddr%d", v->name, i);
3595		snprintf(wan_route_netmask, sizeof(wan_route_netmask), "%s_netmask%d", v->name, i);
3596 		snprintf(wan_route_gateway, sizeof(wan_route_gateway), "%s_gateway%d", v->name, i);
3597 		snprintf(wan_route_metric, sizeof(wan_route_metric), "%s_metric%d", v->name, i);
3598		if (!(ipaddr = websGetVar(wp, wan_route_ipaddr, NULL)) ||
3599		    !(netmask = websGetVar(wp, wan_route_netmask, NULL)) ||
3600		    !(gateway = websGetVar(wp, wan_route_gateway, NULL)) ||
3601		    !(metric = websGetVar(wp, wan_route_metric, NULL)))
3602			continue;
3603		if (!*ipaddr && !*netmask && !*gateway && !*metric)
3604			continue;
3605		if (!*ipaddr && !*netmask && *gateway) {
3606			ipaddr = "0.0.0.0";
3607			netmask = "0.0.0.0";
3608		}
3609		if (!*gateway)
3610			gateway = "0.0.0.0";
3611		if (!*metric)
3612			metric = "0";
3613		if (!*ipaddr) {
3614			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an IP Address<br>", v->longname);
3615			continue;
3616		}
3617		if (!*netmask) {
3618			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Subnet Mask<br>", v->longname);
3619			continue;
3620		}
3621		if (!valid_ipaddr(wp, ipaddr, &wan_route_variables[0]) ||
3622		    !valid_ipaddr(wp, netmask, &wan_route_variables[1]) ||
3623		    !valid_ipaddr(wp, gateway, &wan_route_variables[2]) ||
3624		    !valid_range(wp, metric, &wan_route_variables[3]))
3625			continue;
3626		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s:%s:%s",
3627				cur == buf ? "" : " ", ipaddr, netmask, gateway, metric);
3628	}
3629
3630
3631	nvram_set(v->name, buf);
3632
3633	ret_code = 0;
3634}
3635#endif	/* __CONFIG_NAT__ */
3636
3637static void
3638validate_wl_auth(webs_t wp, char *value, struct variable *v, char *varname)
3639{
3640
3641	assert(v);
3642
3643	ret_code = EINVAL;
3644
3645	if (!valid_choice(wp, value, v)){
3646		websBufferWrite(wp, "Invalid auth value string <b>%s</b><br>",value);
3647		return;
3648	}
3649
3650	if (!strcmp(value, "1")) {
3651		char *wep = websGetVar(wp, "wl_wep", "");
3652		if (!wep || strcmp(wep, "enabled")) {
3653			websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>802.11 Authentication</b> is <b>%s</b><br>", value);
3654			return;
3655		}
3656	}
3657
3658	if (varname)
3659		nvram_set(varname, value);
3660	else
3661		nvram_set(v->name, value);
3662	ret_code = 0;
3663}
3664
3665static void
3666validate_wl_preauth(webs_t wp, char *value, struct variable *v, char *varname)
3667{
3668	char *ptr=NULL;
3669
3670	assert(v);
3671
3672	ptr =( (varname) ? varname : v->name );
3673
3674	if (!strcmp(value, "disabled"))
3675			nvram_set(ptr, "0");
3676	else
3677			nvram_set(ptr, "1");
3678
3679	ret_code =0;
3680
3681	return;
3682}
3683
3684static void
3685validate_wl_auth_mode(webs_t wp, char *value, struct variable *v, char *varname)
3686{
3687
3688	assert(v);
3689
3690	ret_code = EINVAL;
3691
3692	if (!valid_choice(wp, value, v)){
3693		websBufferWrite(wp, "Invalid auto mode string <b>%s</b>",value);
3694		return;
3695	}
3696
3697	if (!strcmp(value, "radius")) {
3698		char *wep = websGetVar(wp, "wl_wep", "");
3699		char *ipaddr = websGetVar(wp, "wl_radius_ipaddr", "");
3700		if (!wep || strcmp(wep, "enabled")) {
3701			websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>Network Authentication</b> is <b>%s</b><br>", value);
3702			return;
3703		}
3704		if (!ipaddr || !strcmp(ipaddr, "")) {
3705			websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>RADIUS Server</b><br>", v->longname);
3706			return;
3707		}
3708	}
3709
3710	if (varname)
3711		nvram_set(varname, value);
3712	else
3713		nvram_set(v->name, value);
3714
3715	ret_code = 0;
3716
3717}
3718
3719static void
3720validate_wl_akm(webs_t wp, char *value, struct variable *v, char *varname)
3721{
3722	char akms[WLC_IOCTL_SMLEN] = "";
3723	char *wpa=NULL, *psk=NULL;
3724#ifdef BCMWPA2
3725	char *wpa2=NULL, *psk2=NULL;
3726#endif
3727
3728	assert(v);
3729
3730	ret_code = EINVAL;
3731
3732	wpa = websGetVar(wp, "wl_akm_wpa", NULL);
3733	if( !wpa )
3734		wpa = "disabled";
3735	psk = websGetVar(wp, "wl_akm_psk", NULL);
3736#ifdef BCMWPA2
3737	wpa2 = websGetVar(wp, "wl_akm_wpa2", NULL);
3738	if( !wpa2 )
3739		wpa2 = "disabled";
3740	psk2 = websGetVar(wp, "wl_akm_psk2", NULL);
3741#endif
3742	if (!wpa || !psk
3743#ifdef BCMWPA2
3744	    || !wpa2 || !psk2
3745#endif
3746	    ) {
3747	    	ret_code = 0;
3748		return;
3749	}
3750
3751	if (!strcmp(wpa, "enabled")
3752#ifdef BCMWPA2
3753	    || !strcmp(wpa2, "enabled")
3754#endif /* BCMWPA2 */
3755	    ) {
3756		char *ipaddr = websGetVar(wp, "wl_radius_ipaddr", "");
3757		if (!ipaddr || !strcmp(ipaddr, "")) {
3758			websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>RADIUS Server</b><br>", v->longname);
3759			return;
3760		}
3761	}
3762
3763	if (!strcmp(psk, "enabled")
3764#ifdef BCMWPA2
3765	    || !strcmp(psk2, "enabled")
3766#endif /* BCMWPA2 */
3767	    ) {
3768		char *key = websGetVar(wp, "wl_wpa_psk", "");
3769		if (!key || !strcmp(key, "")) {
3770			websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>WPA Pre-Shared Key</b><br>", v->longname);
3771			return;
3772		}
3773	}
3774
3775	if (!strcmp(wpa, "enabled") || !strcmp(psk, "enabled")
3776#ifdef BCMWPA2
3777	    || !strcmp(wpa2, "enabled") || !strcmp(psk2, "enabled")
3778#endif /* BCMWPA2 */
3779	    ) {
3780		char *crypto = websGetVar(wp, "wl_crypto", "");
3781		if (!crypto || (strcmp(crypto, "tkip") && strcmp(crypto, "aes") &&
3782			strcmp(crypto, "tkip+aes"))) {
3783			websBufferWrite(wp, "Invalid <b>%s</b>: <b>Crypto Algorithm</b> mode must be TKIP or AES or TKIP+AES<br>", v->longname);
3784			return;
3785		}
3786	}
3787
3788	if (!strcmp(wpa, "enabled"))
3789		strcat(akms, "wpa ");
3790	if (!strcmp(psk, "enabled"))
3791		strcat(akms, "psk ");
3792#ifdef BCMWPA2
3793	if (!strcmp(wpa2, "enabled"))
3794		strcat(akms, "wpa2 ");
3795	if (!strcmp(psk2, "enabled"))
3796		strcat(akms, "psk2 ");
3797#endif
3798	if (varname)
3799		nvram_set(varname, akms);
3800	else
3801		nvram_set("wl_akm", akms);
3802
3803	ret_code = 0;
3804}
3805
3806static void
3807validate_wl_wpa_psk(webs_t wp, char *value, struct variable *v, char *varname)
3808{
3809	int len = strlen(value);
3810	char *c=NULL;
3811
3812	assert(v);
3813
3814	ret_code = EINVAL;
3815
3816	if (len == 64) {
3817		for (c = value; *c; c++) {
3818			if (!isxdigit((int) *c)) {
3819				websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>", v->longname, *c);
3820				return;
3821			}
3822		}
3823	} else if (len < 8 || len > 63) {
3824		websBufferWrite(wp, "Invalid <b>%s</b>: must be between 8 and 63 ASCII characters or 64 hexadecimal digits<br>", v->longname);
3825		return;
3826	}
3827
3828	if (varname)
3829		nvram_set(varname, value);
3830	else
3831		nvram_set(v->name, value);
3832
3833	ret_code = 0;
3834}
3835
3836static void
3837validate_wl_key(webs_t wp, char *value, struct variable *v, char *varname)
3838{
3839	char *c=NULL;
3840
3841	assert(v);
3842
3843	ret_code = EINVAL;
3844
3845	switch (strlen(value)) {
3846	case 5:
3847	case 13:
3848		break;
3849	case 10:
3850	case 26:
3851		for (c = value; *c; c++) {
3852			if (!isxdigit((int) *c)) {
3853				websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>", v->longname, *c);
3854				return;
3855			}
3856		}
3857		break;
3858	default:
3859		websBufferWrite(wp, "Invalid <b>%s</b>: must be 5 or 13 ASCII characters or 10 or 26 hexadecimal digits<br>", v->longname);
3860		return;
3861	}
3862
3863	if (varname)
3864		nvram_set(varname, value);
3865	else
3866		nvram_set(v->name, value);
3867
3868	ret_code = 0;
3869}
3870
3871static void
3872validate_wl_wep(webs_t wp, char *value, struct variable *v, char *varname)
3873{
3874	char *auth_mode=NULL,*name=NULL, *auth=NULL;
3875
3876	assert(v);
3877
3878	ret_code = EINVAL;
3879
3880	if (!valid_choice(wp, value, v)){
3881		websBufferWrite(wp, "Invalid wep string <b>%s</b>",value);
3882		return;
3883	}
3884	if (varname)
3885		name = varname;
3886	else
3887		name = v->name;
3888
3889	auth = websGetVar(wp, "wl_auth", NULL);
3890	auth_mode = websGetVar(wp, "wl_auth_mode", NULL);
3891	if (!strcmp(value, "enabled")) {
3892		if (!auth_mode || strcmp(auth_mode, "radius")) {
3893			char wl_key[] = "wl_keyXXX";
3894			char wl_key_index[] = "wl_keyXXX";
3895
3896			if (varname){
3897				char index[5];
3898				if (!get_index_string(v->prefix,varname,index,sizeof(index)))
3899						return;
3900				snprintf(wl_key_index, sizeof(wl_key_index),"wl%s_key",index);
3901			}else
3902				snprintf(wl_key_index, sizeof(wl_key_index),"wl_key");
3903
3904			snprintf(wl_key, sizeof(wl_key), "%s%s",wl_key_index, nvram_safe_get(wl_key_index));
3905			if (!strlen(nvram_safe_get(wl_key))) {
3906				websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>Network Key %s</b><br>",
3907						v->longname, nvram_safe_get(wl_key_index));
3908				if (nvram_match(name, "enabled")) {
3909					websBufferWrite(wp, "<b>%s</b> is <b>Disabled</b><br>", v->longname);
3910					nvram_set(name, "disabled");
3911				}
3912				return;
3913			}
3914		}
3915	}
3916	else {
3917	    	if (!auth || !strcmp(auth, "shared") || ( auth_mode && !strcmp(auth_mode, "radius"))) {
3918			websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>Network Authentication</b> is <b>%s</b><br>", auth_mode);
3919			return;
3920	    	}
3921	}
3922
3923	nvram_set(name, value);
3924
3925	ret_code = 0;
3926}
3927
3928static void
3929validate_wl_crypto(webs_t wp, char *value, struct variable *v, char *varname)
3930{
3931
3932	assert(v);
3933
3934	ret_code = EINVAL;
3935
3936	if (!valid_choice(wp, value, v)){
3937		websBufferWrite(wp, "Invalid crypto config string <b>%s</b>",value);
3938		return;
3939	}
3940
3941	if (varname)
3942		nvram_set(varname, value);
3943	else
3944		nvram_set(v->name, value);
3945
3946	ret_code = 0;
3947}
3948
3949#ifdef __CONFIG_NAT__
3950static void
3951validate_wan_ifname(webs_t wp, char *value, struct variable *v, char *varname)
3952{
3953	char ifname[64], *next=NULL;
3954
3955	assert(v);
3956
3957	ret_code = EINVAL;
3958	foreach (ifname, nvram_safe_get("wan_ifnames"), next)
3959		if (!strcmp(ifname, value)) {
3960			nvram_set(v->name, value);
3961			ret_code = 0;
3962			return;
3963		}
3964	websBufferWrite(wp, "Invalid <b>%s</b>: must be one of <b>%s</b><br>", v->longname, nvram_safe_get("wan_ifnames"));
3965}
3966#endif	/* __CONFIG_NAT__ */
3967
3968static void
3969validate_wl_afterburner(webs_t wp, char *value, struct variable *v, char *varname)
3970{
3971
3972	assert(v);
3973
3974	ret_code = EINVAL;
3975
3976	if (!valid_choice(wp, value, v)){
3977		websBufferWrite(wp, "Invalid  afterburner config string <b>%s</b>",value);
3978		return;
3979	}
3980
3981	/* force certain wireless variables to fixed values */
3982	if (!strcmp(value, "auto")) {
3983		if ( nvram_invmatch("wl_mode", "ap"))  {
3984			/* notify the user */
3985			websBufferWrite(wp, "Invalid <b>%s</b>: AfterBurner mode requires:"
3986				"<br><b>Mode</b> set to <b>Access Point</b>"
3987				"<br><b>Fragmentation value</b> set to <b>2346(disable fragmentation)</b>"
3988				"<br><b>AfterBurner mode is disabled!</b>"
3989				"<br>", v->longname);
3990			return;
3991		}
3992	}
3993
3994	if (varname)
3995		nvram_set(varname, value);
3996	else
3997		nvram_set(v->name, value);
3998
3999	ret_code = 0;
4000}
4001
4002static void
4003validate_wl_lazywds(webs_t wp, char *value, struct variable *v, char *varname)
4004{
4005	assert(v);
4006
4007	ret_code = EINVAL;
4008	validate_choice(wp, value, v, varname);
4009}
4010
4011static void
4012validate_wl_wds_hwaddrs(webs_t wp, char *value, struct variable *v, char *varname)
4013{
4014	assert(v);
4015
4016	ret_code = EINVAL;
4017	validate_list(wp, value, v, valid_hwaddr, varname);
4018}
4019
4020static void
4021validate_wl_mode(webs_t wp, char *value, struct variable *v, char *varname)
4022{
4023	char *afterburner=NULL;
4024
4025	assert(v);
4026
4027	ret_code = EINVAL;
4028
4029	if (strcmp(value, "ap") &&
4030	    (afterburner = websGetVar(wp, "wl_afterburner", NULL)) && (!strcmp(afterburner, "auto"))) {
4031		websBufferWrite(wp, "Invalid <b>%s</b>: must be set to <b>Access Point</b> when AfterBurner is enabled.<br>", v->longname);
4032		return;
4033	}
4034	validate_choice(wp, value, v, varname);
4035}
4036
4037static void
4038validate_noack(webs_t wp, char *value, struct variable *v,char *varname)
4039{
4040	char *wme=NULL;
4041
4042	assert(v);
4043
4044	ret_code = EINVAL;
4045
4046	/* return if wme is not enabled */
4047	if (!(wme = websGetVar(wp, "wl_wme", NULL))){
4048		ret_code = 0;
4049		return;
4050	}else if (strcmp(wme, "on")){
4051		ret_code = 0;
4052		return;
4053	}
4054
4055	validate_choice(wp, value, v, varname);
4056}
4057
4058static void
4059validate_wl_wme_params(webs_t wp, char *value, struct variable *v,char *varname)
4060{
4061	int n, i;
4062	int cwmin = 0, cwmax = 0;
4063	char *wme=NULL, *afterburner=NULL;
4064	char name[100];
4065	char buf[1000] = "", *cur = buf;
4066	struct {
4067		char *name;
4068		int range;
4069		char *arg1;
4070		char *arg2;
4071	} field_attrib[] = {
4072		{ "WME AC CWmin", 1, "0", "32767" },
4073		{ "WME AC CWmax", 1, "0", "32767" },
4074		{ "WME AC AIFSN", 1, "1", "15" },
4075		{ "WME AC TXOP(b)", 1, "0", "65504" },
4076		{ "WME AC TXOP(a/g)", 1, "0", "65504" },
4077		{ "WME AC Admin Forced", 0, "on", "off" }
4078	};
4079
4080	assert(v);
4081
4082	ret_code = EINVAL;
4083
4084	/* return if wme is not enabled */
4085	if (!(wme = websGetVar(wp, "wl_wme", NULL))){
4086		ret_code =0;
4087		return;
4088	} else if (strcmp(wme, "on")){
4089		ret_code = 0;
4090		return;
4091	}
4092
4093	/* return if afterburner enabled */
4094	if ((afterburner = websGetVar(wp, "wl_afterburner", NULL)) && (!strcmp(afterburner, "auto"))){
4095		ret_code =0;
4096		return;
4097	}
4098
4099	n = atoi(value) + 1;
4100
4101	for (i = 0; i < n; i++) {
4102		snprintf(name, sizeof(name), "%s%d", v->name, i);
4103		if (!(value = websGetVar(wp, name, NULL))){
4104			ret_code = 0;
4105			return;
4106		}
4107
4108		if (!*value && v->nullok)
4109			continue;
4110
4111		if (i == 0)
4112			cwmin = atoi(value);
4113		else if (i == 1) {
4114			cwmax = atoi(value);
4115			if (cwmax < cwmin) {
4116				websBufferWrite(wp, "Invalid <b>%s</b> %d: greater than <b>%s</b> %d<br>",
4117					field_attrib[0].name, cwmin, field_attrib[i].name, cwmax);
4118				return;
4119			}
4120		}
4121		if (field_attrib[i].range) {
4122			if (atoi(value) < atoi(field_attrib[i].arg1) || atoi(value) > atoi(field_attrib[i].arg2)) {
4123				websBufferWrite(wp, "Invalid <b>%s</b> %d: should be in range %s to %s<br>",
4124					field_attrib[i].name, atoi(value), field_attrib[i].arg1, field_attrib[i].arg2);
4125				return;
4126			}
4127		} else {
4128			if (strcmp(value, field_attrib[i].arg1) && strcmp(value, field_attrib[i].arg2)) {
4129				websBufferWrite(wp, "Invalid <b>%s</b> %s: should be %s or %s<br>",
4130					field_attrib[i].name, value, field_attrib[i].arg1, field_attrib[i].arg2);
4131			}
4132		}
4133
4134		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s",
4135				cur == buf ? "" : " ", value);
4136	}
4137
4138	if (varname)
4139		nvram_set(varname, buf);
4140	else
4141		nvram_set(v->name, buf);
4142
4143	ret_code = 0;
4144}
4145
4146/* Hook to write wl_* default set through to wl%d_* variable set */
4147static void
4148wl_unit(webs_t wp, char *value, struct variable *v, char *varname)
4149{
4150	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
4151
4152	assert(v);
4153
4154	ret_code = 0;
4155
4156	if (!value) return;
4157
4158	/* The unit numbers are built dynamically so what is
4159	   present is assumed to be running */
4160
4161	snprintf(prefix,sizeof(prefix),"wl%s_",value);
4162
4163	/* Write through to selected variable set */
4164	for (; v >= variables && !strncmp(v->name, "wl_", 3); v--){
4165		if ( v->ezc_flags & WEB_IGNORE)
4166			continue;
4167		nvram_set(strcat_r(prefix, &v->name[3], tmp), nvram_safe_get(v->name));
4168	}
4169}
4170
4171#ifdef __CONFIG_NAT__
4172static void
4173wan_primary(webs_t wp)
4174{
4175	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
4176	int i;
4177
4178	for (i = 0; i < MAX_NVPARSE; i ++) {
4179		/* skip non-exist and disabled connection */
4180		wan_prefix(i, prefix);
4181		if (!nvram_get(strcat_r(prefix, "unit", tmp))||
4182		    nvram_match(strcat_r(prefix, "proto", tmp), "disabled"))
4183			continue;
4184		/* make connection <i> primary */
4185		nvram_set(strcat_r(prefix, "primary", tmp), "1");
4186		/* notify the user */
4187		websBufferWrite(wp, "<br><b>%s</b> is set to primary.",
4188			wan_name(i, prefix, tmp, sizeof(tmp)));
4189		break;
4190	}
4191}
4192
4193/* Hook to write wan_* default set through to wan%d_* variable set */
4194static void
4195wan_unit(webs_t wp, char *value, struct variable *v, char *varname)
4196{
4197	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
4198	char pppx[] = "pppXXXXXXXXXXX";
4199	int unit, i;
4200	char *wan_ifname=NULL;
4201	int wan_disabled = 0;
4202	int wan_prim = 0;
4203	int wan_wildcard = 0;
4204	char *wan_pppoe_service=NULL;
4205	char *wan_pppoe_ac=NULL;
4206	char wan_tmp[NVRAM_BUFSIZE];
4207	int wildcard;
4208	char *pppoe_service=NULL;
4209	char *pppoe_ac=NULL;
4210	char ea[ETHER_ADDR_LEN], wan_ea[ETHER_ADDR_LEN];
4211
4212	assert(v);
4213	ret_code = 0;
4214
4215	/* Do not write through if no connections are present */
4216	if ((unit = atoi(value)) < 0)
4217		return;
4218
4219	/* override wan_pppoe_ifname */
4220	if (nvram_match("wan_proto", "pppoe")) {
4221		snprintf(pppx, sizeof(pppx), "ppp%d", unit);
4222		nvram_set("wan_pppoe_ifname", pppx);
4223	}
4224
4225	/*
4226	* Need to make sure this connection can co-exist with others.
4227	* Disable others if it can't (assuming this is the wanted one).
4228	* Disabled connection is for sure no problem to co-exist with
4229	* other connections.
4230	*/
4231	if (nvram_match("wan_proto", "disabled")) {
4232		/* Non primary always go with disabled connection. */
4233		nvram_set("wan_primary", "0");
4234		wan_disabled = 1;
4235	}
4236	/*
4237	* PPPoE connection is for sure no problem to co-exist with
4238	* other PPPoE connections even when they share the same
4239	* ethernet interface, but we need to make sure certain
4240	* PPPoE parameters are reasonablely different from eatch other
4241	* if they share the same ethernet interface.
4242	*/
4243	else if (nvram_match("wan_proto", "pppoe")) {
4244		/* must disable others if this connection is wildcard (any service any ac) */
4245		wan_pppoe_service = nvram_get("wan_pppoe_service");
4246		wan_pppoe_ac = nvram_get("wan_pppoe_ac");
4247		wan_wildcard = (wan_pppoe_service == NULL || *wan_pppoe_service == 0) &&
4248			(wan_pppoe_ac == NULL || *wan_pppoe_ac == 0);
4249		wan_ifname = nvram_safe_get("wan_ifname");
4250		wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp));
4251		/* check all PPPoE connections that share the same interface */
4252		for (i = 0; i < MAX_NVPARSE; i ++) {
4253			/* skip the current connection */
4254			if (i == unit)
4255				continue;
4256			/* skip non-exist and connection that does not share the same i/f */
4257			wan_prefix(i, prefix);
4258			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
4259			    nvram_match(strcat_r(prefix, "proto", tmp), "disabled") ||
4260			    nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname))
4261				continue;
4262			/* PPPoE can share the same i/f, but none can be wildcard */
4263			if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) {
4264				if (wan_wildcard) {
4265					/* disable connection <i> */
4266					nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
4267					nvram_set(strcat_r(prefix, "primary", tmp), "0");
4268					/* notify the user */
4269					websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because both "
4270						"<b>PPPoE Service Name</b> and <b>PPPoE Access Concentrator</b> "
4271						"in <b>%s</b> are empty.",
4272						wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp);
4273				}
4274				else {
4275					pppoe_service = nvram_get(strcat_r(prefix, "pppoe_service", tmp));
4276					pppoe_ac = nvram_get(strcat_r(prefix, "pppoe_ac", tmp));
4277					wildcard = (pppoe_service == NULL || *pppoe_service == 0) &&
4278						(pppoe_ac == NULL || *pppoe_ac == 0);
4279					/* allow connection <i> if certain pppoe parameters are not all same */
4280					if (!wildcard &&
4281					    (nvram_invmatch(strcat_r(prefix, "pppoe_service", tmp), nvram_safe_get("wan_pppoe_service")) ||
4282					         nvram_invmatch(strcat_r(prefix, "pppoe_ac", tmp), nvram_safe_get("wan_pppoe_ac"))))
4283						continue;
4284					/* disable connection <i> */
4285					nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
4286					nvram_set(strcat_r(prefix, "primary", tmp), "0");
4287					/* notify the user */
4288					websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because both its "
4289						"<b>PPPoE Service Name</b> and <b>PPPoE Access Concentrator</b> "
4290						"are empty.",
4291						wan_name(i, prefix, tmp, sizeof(tmp)));
4292				}
4293			}
4294			/* other types can't (?) share the same i/f with PPPoE */
4295			else {
4296				/* disable connection <i> */
4297				nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
4298				nvram_set(strcat_r(prefix, "primary", tmp), "0");
4299				/* notify the user */
4300				websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because it can't  "
4301					"share the same interface with <b>%s</b>.",
4302					wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp);
4303			}
4304		}
4305	}
4306	/*
4307	* All other types (now DHCP, Static) can't co-exist with
4308	* other connections if they use the same ethernet i/f.
4309	*/
4310	else {
4311		wan_ifname = nvram_safe_get("wan_ifname");
4312		wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp));
4313		/* check all connections that share the same interface */
4314		for (i = 0; i < MAX_NVPARSE; i ++) {
4315			/* skip the current connection */
4316			if (i == unit)
4317				continue;
4318			/* check if connection <i> exists and share the same i/f*/
4319			wan_prefix(i, prefix);
4320			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
4321			    nvram_match(strcat_r(prefix, "proto", tmp), "disabled") ||
4322			    nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname))
4323				continue;
4324			/* disable connection <i> */
4325			nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
4326			nvram_set(strcat_r(prefix, "primary", tmp), "0");
4327			/* notify the user */
4328			websBufferWrite(wp, "<br><b>%s</b> is disabled because it can't share "
4329				"the ethernet interface with <b>%s</b>.",
4330				wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp);
4331		}
4332	}
4333
4334	/*
4335	* Check if MAC address has been changed. Need to sync it to all connections
4336	* that share the same i/f if it is changed.
4337	*/
4338	wan_prefix(unit, prefix);
4339	ether_atoe(nvram_safe_get("wan_hwaddr"), wan_ea);
4340	ether_atoe(nvram_safe_get(strcat_r(prefix, "hwaddr", tmp)), ea);
4341	if (memcmp(ea, wan_ea, ETHER_ADDR_LEN)) {
4342		wan_ifname = nvram_safe_get("wan_ifname");
4343		wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp));
4344		/* sync all connections that share the same interface */
4345		for (i = 0; i < MAX_NVPARSE; i ++) {
4346			/* skip the current connection */
4347			if (i == unit)
4348				continue;
4349			/* check if connection <i> exists and share the same i/f*/
4350			wan_prefix(i, prefix);
4351			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
4352			    nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname))
4353				continue;
4354			/* check if connection <i>'s hardware address is different */
4355			if (ether_atoe(nvram_safe_get(strcat_r(prefix, "hwaddr", tmp)), ea) &&
4356			    !memcmp(ea, wan_ea, ETHER_ADDR_LEN))
4357			    continue;
4358			/* change connection <i>'s hardware address */
4359			nvram_set(strcat_r(prefix, "hwaddr", tmp), nvram_safe_get("wan_hwaddr"));
4360			/* notify the user */
4361			websBufferWrite(wp, "<br><b>MAC Address</b> in <b>%s</b> is changed to "
4362				"<b>%s</b> because it shares the ethernet interface with <b>%s</b>.",
4363				wan_name(i, prefix, tmp, sizeof(tmp)), nvram_safe_get("wan_hwaddr"),
4364				wan_tmp);
4365		}
4366	}
4367
4368	/* Set prefix */
4369	wan_prefix(unit, prefix);
4370
4371	/* Write through to selected variable set */
4372	for (; v >= variables && !strncmp(v->name, "wan_", 4); v--){
4373		if (v->ezc_flags & WEB_IGNORE)
4374			continue;
4375		nvram_set(strcat_r(prefix, &v->name[4], tmp), nvram_safe_get(v->name));
4376	}
4377
4378	/*
4379	* There must be one and only one primary connection among all
4380	* enabled connections so that traffic can be routed by default
4381	* through the primary connection unless they are targetted to
4382	* a specific connection by means of static routes. (Primary ~=
4383	* Default Gateway).
4384	*/
4385	/* the current connection is primary, set others to non-primary */
4386	if (!wan_disabled && nvram_match(strcat_r(prefix, "primary", tmp), "1")) {
4387		/* set other connections to non-primary */
4388		for (i = 0; i < MAX_NVPARSE; i ++) {
4389			/* skip the current connection */
4390			if (i == unit)
4391				continue;
4392			/* skip non-exist and disabled connection */
4393			wan_prefix(i, prefix);
4394			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
4395			    nvram_match(strcat_r(prefix, "proto", tmp), "disabled"))
4396				continue;
4397			/* skip non-primary connection */
4398			if (nvram_invmatch(strcat_r(prefix, "primary", tmp), "1"))
4399				continue;
4400			/* force primary to non-primary */
4401			nvram_set(strcat_r(prefix, "primary", tmp), "0");
4402			/* notify the user */
4403			websBufferWrite(wp, "<br><b>%s</b> is set to non-primary.",
4404				wan_name(i, prefix, tmp, sizeof(tmp)));
4405		}
4406		wan_prim = 1;
4407	}
4408	/* the current connection is not parimary, check if there is any primary */
4409	else {
4410		/* check other connections to see if there is any primary */
4411		for (i = 0; i < MAX_NVPARSE; i ++) {
4412			/* skip the current connection */
4413			if (i == unit)
4414				continue;
4415			/* primary connection exists, honor it */
4416			wan_prefix(i, prefix);
4417			if (nvram_match(strcat_r(prefix, "primary", tmp), "1")) {
4418				wan_prim = 1;
4419				break;
4420			}
4421		}
4422	}
4423	/* no one is primary, pick the first enabled one as primary */
4424	if (!wan_prim)
4425		wan_primary(wp);
4426}
4427#endif	/* __CONFIG_NAT__ */
4428
4429/* This is the monster V-block
4430 *
4431 * It controls the following functions
4432 *
4433 * Configuration variables are validated and saved in NVRAM
4434 * Variables saved by NVRAM save/restore routine
4435 * Method in which the variables are to be validates
4436 * SES handling
4437 *
4438 * The control flags:
4439 * EZC_FLAGS_READ,EZC_FLAGS_WRITE :Ses read/write flags
4440 * NVRAM_ENCRYPT: Encrypt variable prior to downloading NVRAM variable to file
4441 * NVRAM_MI: Multi instance NVRAM variable eg wlXX,wanXX
4442 * NVRAM_VLAN_MULTI: Special flag to handle oddball vlanXXname and its cousins
4443 * NVRAM_MP: Variable can be single & multi instance eg lan_ifname, lanX_ifname
4444 * NVRAM_IGNORE: Dont save/restore this var.
4445 * WEB_IGNORE: Don't validate or process this var during web validation.
4446 *
4447 * Below is the definition of the structure
4448 *struct variable {
4449 *	char *name; <- name of variable
4450 * 	char *longname; <- display name
4451 * 	char *prefix; <- prefix for processing the multi-instance versions
4452 *	void (*validate)(); <- Validation routine
4453 * 	char **argv; <- Optional argument vector for validation routine
4454 *	int nullok; <- value can be NULL
4455 *	int ezc_flags; <- control flags
4456 * };
4457 *
4458 * IMPORTANT:
4459 * =========
4460 *
4461 * The variables in tne table below determine if they will be saved/restored
4462 * by the UI NVRAM save/restore feature
4463 *
4464 * If an NVRAM variable is not present in this list it will
4465 * not be processed and thus will not be saved or restored.
4466 *
4467*/
4468
4469/*
4470 * Variables are set in order (put dependent variables later). Set
4471 * nullok to TRUE to ignore zero-length values of the variable itself.
4472 * For more complicated validation that cannot be done in one pass or
4473 * depends on additional form components or can throw an error in a
4474 * unique painful way, write your own validation routine and assign it
4475 * to a hidden variable (e.g. filter_ip).
4476 *
4477 * EZC_FLAGS_READ : implies the variable will be returned for ezconfig read request
4478 * EZC_FLAGS_WRITE : allows the variable to be modified by the ezconfig tool
4479 *
4480 * The variables marked with EZConfig have to maintain backward compatibility.
4481 * If they cannot then the ezc_version has to be bumped up
4482 *
4483 */
4484static char wl_prefix[]="wl";
4485static char wan_prefix[]="wan";
4486static char lan_prefix[]="lan";
4487static char dhcp_prefix[]="dhcp";
4488static char vlan_prefix[]="vlan";
4489
4490static struct hsearch_data vtab;
4491
4492struct variable variables[] = {
4493	/* basic settings */
4494	{ "http_username", "Router Username",NULL, validate_name, ARGV("0", "63"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4495	{ "http_passwd", "Router Password",NULL, validate_name, ARGV("0", "63"), TRUE, NVRAM_ENCRYPT | EZC_FLAGS_WRITE },
4496	{ "http_wanport", "Router WAN Port",NULL, validate_range, ARGV("0", "65535"), TRUE, 0 },
4497	{ "http_lanport", "HTTP daemon lanport",NULL, NULL, NULL, TRUE, 0 },
4498	{ "router_disable", "Router Mode",NULL, validate_router_disable, ARGV("0", "1"), FALSE, 0 },
4499	{ "fw_disable", "Firewall",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4500	{ "time_zone", "Time Zone",NULL, validate_choice, ARGV("PST8PDT", "MST7MDT", "CST6CDT", "EST5EDT"), FALSE },
4501	{ "upnp_enable", "UPnP",NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
4502	{ "ezc_enable", "EZConfig",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE},
4503	{ "ntp_server", "NTP Servers",NULL, validate_ipaddrs, NULL, TRUE, 0 },
4504	{ "log_level", "Connection Logging",NULL, validate_range, ARGV("0", "3"), FALSE, 0 },
4505	{ "log_ipaddr", "Log LAN IP Address",NULL, validate_ipaddr, ARGV("lan_ipaddr", "lan_netmask"), TRUE, 0 },
4506	{ "log_ram_enable", "Syslog in RAM",NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
4507	/* LAN settings */
4508	{ "lan_ifname" "LAN Interface Name", lan_prefix, NULL, NULL, FALSE, NVRAM_MI|NVRAM_IGNORE },
4509	{ "lan_dhcp", "DHCP Client", lan_prefix, validate_choice, ARGV("1", "0"), FALSE, NVRAM_MI | NVRAM_MP },
4510	{ "lan_ipaddr", "IP Address", lan_prefix, validate_lan_ipaddr, NULL, FALSE, NVRAM_MI| NVRAM_MP | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4511	{ "lan_netmask", "Subnet Mask", lan_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
4512	{ "lan_gateway", "Gateway Address", lan_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
4513	{ "lan_proto", "DHCP Server", lan_prefix, validate_choice, ARGV("dhcp", "static"), FALSE, NVRAM_MI| NVRAM_MP | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4514	{ "dhcp_start", "DHCP Server LAN IP Address Range", dhcp_prefix, validate_dhcp, NULL, FALSE, NVRAM_MI| NVRAM_MP | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4515	{ "dhcp_end", "DHCP Server LAN IP End Address", dhcp_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
4516	{ "dhcp_wins", "DHCP WINS domain", dhcp_prefix, NULL, NULL, TRUE, NVRAM_MI | NVRAM_MP},
4517	{ "dhcp_domain", "DHCP domain", dhcp_prefix, NULL, NULL, TRUE, NVRAM_MI | NVRAM_MP },
4518	{ "lan_lease", "DHCP Server Lease Time", lan_prefix, validate_range, ARGV("1", "604800"), FALSE,  NVRAM_MI | NVRAM_MP  |EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4519	{ "lan_stp", "Spanning Tree Protocol", lan_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | NVRAM_MP| EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4520	{ "lan_route", "Static Routes", lan_prefix, validate_lan_route, NULL, FALSE,  NVRAM_MI | NVRAM_MP },
4521	{ "lan_wins", "Lan WINS", lan_prefix, NULL, NULL, TRUE, NVRAM_MI| NVRAM_MP},
4522	{ "lan_domain", "Lan Domain", lan_prefix,NULL, NULL, TRUE,  NVRAM_MI| NVRAM_MP },
4523	{ "lan_route","LAN route", lan_prefix, NULL, NULL, TRUE,  NVRAM_MI| NVRAM_MP },
4524	{ "lan_guest_ifname","Guest LAN 1", lan_prefix, validate_guest_lan_ifname, ARGV("1"), FALSE,  NVRAM_MI| NVRAM_IGNORE},
4525	/*VLAN config vars. These are multi-instance Used by NVRAM save/restore for the moment */
4526	{ "vlanhwname", "VLAN HW name", vlan_prefix, NULL, NULL, TRUE, NVRAM_VLAN_MULTI},
4527	{ "vlanports", "VLAN Ports", vlan_prefix, NULL, NULL, TRUE, NVRAM_VLAN_MULTI},
4528#ifdef __CONFIG_NAT__
4529	/* ALL wan_XXXX variables below till wan_unit variable are per-interface */
4530	{ "wan_desc", "Description", wan_prefix, validate_name, ARGV("0", "255"), TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4531	{ "wan_proto", "Protocol", wan_prefix, validate_choice, ARGV("dhcp", "static", "pppoe", "disabled"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4532	{ "wan_hostname", "Host Name", wan_prefix, validate_name, ARGV("0", "255"), TRUE, NVRAM_MI |EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4533	{ "wan_domain", "Domain Name", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4534	{ "wan_ifname", "Interface Name", wan_prefix, validate_wan_ifname, NULL, TRUE, NVRAM_MI  },
4535	{ "wan_hwaddr", "MAC Address", wan_prefix, validate_hwaddr, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4536	{ "wan_ipaddr", "IP Address", wan_prefix, validate_ipaddr, NULL, FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4537	{ "wan_netmask", "Subnet Mask", wan_prefix, validate_ipaddr, NULL, FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4538	{ "wan_gateway", "Default Gateway", wan_prefix, validate_ipaddr, NULL, TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4539	{ "wan_dns", "DNS Servers", wan_prefix, validate_ipaddrs, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4540	{ "wan_wins", "WINS Servers", wan_prefix, validate_ipaddrs, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4541	{ "wan_pppoe_ifname", "PPPoE Interface Name", wan_prefix, NULL, NULL, TRUE, NVRAM_MI  },
4542	{ "wan_pppoe_username", "PPPoE Username", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4543	{ "wan_pppoe_passwd", "PPPoE Password", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_WRITE },
4544	{ "wan_pppoe_service", "PPPoE Service Name", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4545	{ "wan_pppoe_ac", "PPPoE Access Concentrator", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4546	{ "wan_pppoe_keepalive", "PPPoE Keep Alive", wan_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4547	{ "wan_pppoe_demand", "PPPoE Connect on Demand", wan_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4548	{ "wan_pppoe_idletime", "PPPoE Max Idle Time", wan_prefix, validate_range, ARGV("1", "3600"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4549	{ "wan_pppoe_mru", "PPPoE MRU", wan_prefix, validate_range, ARGV("128", "16384"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4550	{ "wan_pppoe_mtu", "PPPoE MTU", wan_prefix, validate_range, ARGV("128", "16384"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4551	{ "wan_primary", "Primary Interface", wan_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI },
4552	{ "wan_route", "Static Routes", wan_prefix, validate_wan_route, NULL, FALSE, NVRAM_MI  },
4553	/* MUST leave this entry here after all wl_XXXX per-interface variables */
4554	{ "wan_unit", "WAN Instance", wan_prefix, wan_unit, NULL, TRUE, NVRAM_MI|NVRAM_MP },
4555	/* filter settings */
4556	{ "filter_macmode", "MAC Filter Mode", NULL, validate_choice, ARGV("disabled", "allow", "deny"), FALSE, 0 },
4557	{ "filter_maclist", "MAC Filter", NULL, validate_hwaddrs, NULL, TRUE, 0 },
4558	{ "filter_client", "LAN Client Filter", NULL, validate_filter_client, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
4559	/* routing settings */
4560	{ "forward_port", "Port Forward", NULL, validate_forward_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
4561	{ "autofw_port", "Application Specific Port Forward", NULL, validate_autofw_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
4562	{ "dmz_ipaddr", "DMZ LAN IP Address", NULL, validate_ipaddr, ARGV("lan_ipaddr", "lan_netmask"), TRUE, 0 },
4563#endif	/* __CONFIG_NAT__ */
4564	/* ALL wl_XXXX variables are per-interface */
4565	{ "wl_ssid", "Network Name (ESSID)", wl_prefix, validate_name, ARGV("1", "32"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4566	{ "wl_guest_ssid_1", "Guest Network Name 1(SSID)", wl_prefix, validate_guest_ssid, ARGV("1"), FALSE, NVRAM_MI|NVRAM_IGNORE },
4567	{ "wl_guest_ssid_2", "Guest Network Name 2(SSID)", wl_prefix, validate_guest_ssid, ARGV("2"), FALSE, NVRAM_MI|NVRAM_IGNORE },
4568	{ "wl_guest_ssid_3", "Guest Network Name 3(SSID)", wl_prefix, validate_guest_ssid, ARGV("3"), FALSE, NVRAM_MI|NVRAM_IGNORE },
4569	{ "wl_guest_ssid_4", "Guest Network Name 4(SSID)", wl_prefix, validate_guest_ssid, ARGV("4"), FALSE, NVRAM_MI|NVRAM_IGNORE },
4570	{ "wl_ure", "URE Mode",NULL, validate_ure, ARGV("0"), FALSE, NVRAM_MI|NVRAM_IGNORE },
4571	{ "wl_closed", "Network Type", wl_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4572        { "wl_ap_isolate", "AP Isolate", wl_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI |  0 },
4573	{ "wl_country_code", "Country Code", wl_prefix, validate_country, NULL, FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4574	{ "wl_mode", "Mode", wl_prefix, validate_wl_mode, ARGV("ap", "wds", "sta", "wet", "apsta"), FALSE,NVRAM_MI },
4575	{ "wl_infra", "Network", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
4576	{ "wl_lazywds", "Bridge Restrict", wl_prefix, validate_wl_lazywds, ARGV("0", "1"), FALSE,NVRAM_MI },
4577	{ "wl_wds", "Bridges", wl_prefix, validate_wl_wds_hwaddrs, NULL, TRUE, NVRAM_MI },
4578	{ "wl_wds_timeout", "Link Timeout Interval", wl_prefix, NULL, NULL, TRUE, NVRAM_MI },
4579	{ "wl_macmode", "MAC Restrict Mode", wl_prefix, validate_choice, ARGV("disabled", "allow", "deny"), FALSE,NVRAM_MI },
4580	{ "wl_maclist", "Allowed MAC Address", wl_prefix, validate_hwaddrs, NULL, TRUE, NVRAM_MI },
4581	{ "wl_radio", "Radio Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
4582	{ "wl_phytype", "Radio Band", wl_prefix, validate_choice, ARGV("a", "b", "g"), TRUE, NVRAM_MI },
4583	{ "wl_antdiv", "Antenna Diversity", wl_prefix, validate_choice, ARGV("-1", "0", "1", "3"), FALSE, NVRAM_MI },
4584	/* Channel and rate are fixed in wlconf() if incorrect */
4585	{ "wl_channel", "Channel", wl_prefix, validate_range, ARGV("0", "216"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4586	{ "wl_reg_mode", "Regulatory Mode", wl_prefix, validate_choice, ARGV("off", "h", "d"), FALSE, NVRAM_MI },
4587	{ "wl_dfs_preism", "Pre-Network Radar Check", wl_prefix, validate_range, ARGV("0", "99"), FALSE,NVRAM_MI },
4588	{ "wl_dfs_postism", "In Network Radar Check", wl_prefix, validate_range, ARGV("10", "99"), FALSE,NVRAM_MI },
4589	{ "wl_tpc_db", "TPC Mitigation (db)",  wl_prefix, validate_range, ARGV("0", "99"), FALSE,NVRAM_MI },
4590	{ "wl_rate", "Rate", wl_prefix, validate_range, ARGV("0", "54000000"), FALSE,NVRAM_MI },
4591	{ "wl_rateset", "Supported Rates", wl_prefix, validate_choice, ARGV("all", "default", "12"), FALSE,NVRAM_MI },
4592	{ "wl_mrate", "Multicast Rate", wl_prefix, validate_range, ARGV("0", "54000000"), FALSE,NVRAM_MI },
4593	{ "wl_frag", "Fragmentation Threshold", wl_prefix, validate_range, ARGV("256", "2346"), FALSE,NVRAM_MI },
4594	{ "wl_rts", "RTS Threshold", wl_prefix, validate_range, ARGV("0", "2347"), FALSE, NVRAM_MI },
4595	{ "wl_dtim", "DTIM Period", wl_prefix, validate_range, ARGV("1", "255"), FALSE, NVRAM_MI },
4596	{ "wl_bcn", "Beacon Interval", wl_prefix, validate_range, ARGV("1", "65535"), FALSE, NVRAM_MI },
4597	{ "wl_plcphdr", "Preamble Type", wl_prefix, validate_choice, ARGV("long", "short"), FALSE, NVRAM_MI },
4598	{ "wl_maxassoc", "Max Assocation Limit", wl_prefix, validate_range, ARGV("1", "256"), FALSE,NVRAM_MI },
4599	{ "wl_gmode", "54g Mode", wl_prefix, validate_choice, ARGV(XSTR(GMODE_AUTO), XSTR(GMODE_ONLY), XSTR(GMODE_PERFORMANCE), XSTR(GMODE_LRS), XSTR(GMODE_LEGACY_B)), FALSE,NVRAM_MI |  0 },
4600	{ "wl_gmode_protection", "54g Protection", wl_prefix, validate_choice, ARGV("off", "auto"), FALSE,NVRAM_MI },
4601	{ "wl_frameburst", "XPress Technology", wl_prefix, validate_choice, ARGV("off", "on"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4602	{ "wl_afterburner", "AfterBurner Technology", wl_prefix, validate_wl_afterburner, ARGV("off", "auto"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4603	{ "wl_wme", "WME Support", wl_prefix, validate_choice, ARGV("off", "on"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4604	{ "wl_wme_no_ack", "No-Acknowledgement", wl_prefix, validate_noack, ARGV("off", "on"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4605	{ "wl_wme_ap_bk", "WME AP BK", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4606	{ "wl_wme_ap_be", "WME AP BE", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4607	{ "wl_wme_ap_vi", "WME AP VI", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4608	{ "wl_wme_ap_vo", "WME AP VO", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4609	{ "wl_wme_sta_bk", "WME STA BK", wl_prefix, validate_wl_wme_params, NULL, TRUE,NVRAM_MI },
4610	{ "wl_wme_sta_be", "WME STA BE", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4611	{ "wl_wme_sta_vi", "WME STA VI", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4612	{ "wl_wme_sta_vo", "WME STA VO", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI },
4613	/* security parameters */
4614	{ "wl_key", "Network Key Index", wl_prefix, validate_range, ARGV("1", "4"), FALSE,NVRAM_MI | EZC_FLAGS_WRITE },
4615	{ "wl_key1", "Network Key 1", wl_prefix, validate_wl_key, NULL, TRUE, NVRAM_MI | NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
4616	{ "wl_key2", "Network Key 2", wl_prefix, validate_wl_key, NULL, TRUE, NVRAM_MI | NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
4617	{ "wl_key3", "Network Key 3", wl_prefix, validate_wl_key, NULL, TRUE,NVRAM_MI |  NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
4618	{ "wl_key4", "Network Key 4", wl_prefix, validate_wl_key, NULL, TRUE,NVRAM_MI | NVRAM_ENCRYPT |  EZC_FLAGS_WRITE},
4619	{ "wl_auth", "802.11 Authentication", wl_prefix, validate_wl_auth, ARGV("0", "1"), FALSE, NVRAM_MI | 0},
4620	{ "wl_auth_mode", "Network Authentication", wl_prefix, validate_wl_auth_mode, ARGV("radius", "none"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4621	{ "wl_akm", "Authenticated Key Management", wl_prefix, validate_wl_akm, NULL, FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4622	{ "wl_wep", "WEP Encryption", wl_prefix, validate_wl_wep, ARGV("disabled", "enabled"), FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4623	{ "wl_crypto", "WPA Encryption", wl_prefix, validate_wl_crypto, ARGV("tkip", "aes", "tkip+aes"), FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4624#ifdef BCMWPA2
4625	{ "wl_net_reauth", "Network Re-auth Interval", wl_prefix, NULL, NULL, TRUE, NVRAM_MI  },
4626	{ "wl_preauth", "Network Preauthentication Support", wl_prefix, validate_wl_preauth, ARGV("disabled", "enabled"), FALSE,NVRAM_MI |  0 },
4627#endif
4628	{ "wl_radius_ipaddr", "RADIUS Server", wl_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4629	{ "wl_radius_port", "RADIUS Port", wl_prefix, validate_range, ARGV("0", "65535"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4630	{ "wl_radius_key", "RADIUS Shared Secret", wl_prefix, validate_name, ARGV("0", "255"), TRUE, NVRAM_MI |  NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
4631	{ "wl_wpa_psk", "WPA Pre-Shared Key", wl_prefix, validate_wl_wpa_psk, ARGV("64"), TRUE, NVRAM_ENCRYPT | NVRAM_MI |  EZC_FLAGS_WRITE},
4632	{ "wl_wpa_gtk_rekey", "Network Key Rotation Interval", wl_prefix, NULL, NULL, TRUE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
4633	/* Multi SSID Guest interface flag */
4634	{ "wl_guest", "Guest SSID Interface", wl_prefix, NULL, NULL, TRUE, WEB_IGNORE | NVRAM_MI  },
4635	/* MUST leave this entry here after all wl_XXXX variables */
4636	{ "wl_unit", "802.11 Instance", wl_prefix, wl_unit, NULL, TRUE, NVRAM_IGNORE | NVRAM_MI | NVRAM_MP },
4637	/* Internal variables */
4638	{ "os_server", "OS Server", NULL, NULL, NULL, TRUE, 0 },
4639	{ "stats_server", "Stats Server", NULL, NULL, NULL, TRUE, 0 },
4640	{ "timer_interval", "Timer Interval", NULL, NULL, NULL, TRUE, 0 },
4641	{ "lan_ifname", "LAN Interface Name", lan_prefix, NULL, NULL, TRUE, NVRAM_MI | NVRAM_MP },
4642	{ "lan_ifnames", "LAN Interface Names", NULL, NULL, NULL, TRUE, 0 },
4643	{ "wan_ifnames", "WAN Interface Names", NULL, NULL, NULL, TRUE, 0 },
4644};
4645
4646/* build hashtable of the monster v-block
4647
4648   Inputs:
4649   -tab: 	hash table  structure
4650   -vblock:	the monster V-block
4651   -num_items:	estimated size of hash table
4652
4653   Returns: 0 on success -1 on error
4654*/
4655
4656int
4657hash_vtab(struct hsearch_data *tab,struct variable *vblock,int num_items)
4658{
4659	ENTRY e, *ep=NULL;
4660	int count;
4661
4662	assert(tab);
4663	assert(vblock);
4664
4665	if (!num_items) return -1;
4666
4667	if (!hcreate_r(num_items,tab))
4668	{
4669			return -1;
4670	}
4671
4672
4673	for (count=0; count < num_items; count++)
4674	{
4675		e.key = vblock[count].name;
4676		e.data = &vblock[count];
4677		if (!hsearch_r(e, ENTER, &ep, tab))
4678			return -1;
4679	}
4680
4681	return 0;
4682
4683}
4684/* The routine gets the pointer into the giant "V" block above give the cgi var name..
4685   Inputs:
4686   -varname: Pointer to cgi var name
4687
4688   Returns: entry within "V" block or NULL if not found.
4689
4690   It will try the following forms
4691   varXX_type
4692   var_typeXX
4693   vlanXXtype
4694
4695   where XX is the instance number
4696
4697*/
4698
4699static struct variable*
4700get_var_handle(char *varname)
4701{
4702	ENTRY e, *ep=NULL;
4703	struct variable *variable=NULL;
4704	char *ptr=NULL,*ptr2=NULL;
4705	int offset;
4706	char prefix[8],tmp[64];
4707
4708	if (!varname ) return NULL;
4709	if (!*varname) return NULL;
4710
4711	ep=NULL;
4712	e.key = varname;
4713	hsearch_r(e, FIND, &ep, &vtab);
4714
4715
4716	/* found something */
4717	if (ep)
4718	{
4719		variable = (struct variable *)ep->data;
4720		if ( variable->ezc_flags & NVRAM_MP) return variable;
4721
4722		/* Drop the variable is multi instance but not
4723		   Multi personality
4724		*/
4725
4726		if ( variable->ezc_flags & NVRAM_MI) return NULL;
4727		if ( variable->ezc_flags & NVRAM_VLAN_MULTI) return NULL;
4728		if ( variable->ezc_flags & NVRAM_GENERIC_MULTI) return NULL;
4729
4730		return variable;
4731
4732	}
4733
4734	/* variable not found could be the form of vlanXXtype, varXX_type or var_typeXX*/
4735
4736	ptr=strchr(varname,'_');
4737
4738	/* Is it  vlanXXtype ? */
4739	if (!ptr)
4740	{
4741		if (!strstr(varname,"vlan")) return NULL;
4742		strcpy(tmp,"vlan");
4743		offset=4;
4744		ptr=&varname[offset];
4745		while (*ptr){
4746				if (!isdigit((int)*ptr)) tmp[offset++] = *ptr;
4747				ptr++;
4748		}
4749
4750		tmp[offset] = '\0';
4751		ep = NULL;
4752		e.key = tmp;
4753		hsearch_r(e, FIND, &ep, &vtab);
4754
4755		/* check to see if this has the
4756		   NVRAM_VLAN MULTI flag set in the v-block
4757		*/
4758		if (ep){
4759			variable = (struct variable *)ep->data;
4760			if (variable->ezc_flags & NVRAM_VLAN_MULTI)
4761					return variable;
4762		}
4763
4764		return  NULL;
4765	}
4766
4767	/* Is it varXX_type ? */
4768	ptr2=varname;
4769	offset=0;
4770	memset(prefix,0,sizeof(prefix));
4771	while (ptr2 < ptr){
4772		if (isdigit((int)*ptr2)) break;
4773		prefix[offset++] =*ptr2;
4774		ptr2++;
4775	}
4776	snprintf(tmp,sizeof(tmp),"%s%s",prefix,ptr);
4777
4778	ep = NULL;
4779	e.key = tmp;
4780	hsearch_r(e, FIND, &ep, &vtab);
4781
4782	if (ep){
4783		variable = (struct variable *)ep->data;
4784		if (variable->ezc_flags & NVRAM_MI)
4785	 			return  variable;
4786	}
4787
4788	/* Is is a var_typeXX */
4789	strncpy(tmp,varname,sizeof(tmp));
4790	offset = strlen(varname) - 1 ;
4791	while(isdigit((int)tmp[offset]))
4792			tmp[offset--] = '\0';
4793	ep = NULL;
4794	e.key = tmp;
4795	hsearch_r(e, FIND, &ep, &vtab);
4796
4797	if (ep){
4798		variable = (struct variable *)ep->data;
4799		if (variable->ezc_flags & NVRAM_GENERIC_MULTI)
4800	 			return  variable;
4801	}
4802
4803	return  NULL;
4804}
4805int
4806variables_arraysize(void)
4807{
4808	return ARRAYSIZE(variables);
4809}
4810
4811/* Need to do special handling for the lan cgi stuff as the DHCP ranges need
4812 overlap checking . In addition multi index variables are also present
4813  on the same page. This breaks the conventional validation flow as implemented
4814*/
4815static void
4816validate_lan_cgi(webs_t wp)
4817{
4818	char cgi_vars[][32]= {
4819		       "lan_ifname",
4820		       "lan_ifnames",
4821		       "lan_dhcp",
4822		       "lan_ipaddr",
4823		       "lan_netmask",
4824		       "lan_gateway",
4825		       "lan_proto",
4826		       "dhcp_start",
4827		       "dhcp_end",
4828		       "lan_lease",
4829		       "lan_stp",
4830		       "lan_route"
4831		       };
4832
4833	int count,num_ifaces;
4834	char *varname=NULL,*value=NULL;
4835	struct variable *v=NULL;
4836	int num_items = sizeof(cgi_vars)/sizeof(cgi_vars[0]);
4837	struct in_addr i_addr,g_addr,i_mask,g_mask;
4838	char err_msg[255] ;
4839	char vector[16];
4840	int router_enable=0;
4841
4842	ret_code = EINVAL;
4843
4844	memset(err_msg,0,sizeof(err_msg));
4845	memset(vector,0,sizeof(vector));
4846
4847	websBufferInit(wp);
4848	if (!webs_buf) {
4849		snprintf(err_msg,sizeof(err_msg),"out of memory<br>");
4850		goto validate_lan_cgi_error;
4851	}
4852
4853	value =  websGetVar(wp, "num_lan_ifaces" , NULL);
4854	if (!value){
4855		snprintf(err_msg,sizeof(err_msg),
4856			"unable to get number of lan interfaces<br>");
4857		goto validate_lan_cgi_error;
4858	}
4859
4860	num_ifaces=atoi(value);
4861
4862	router_enable = nvram_match("router_disable","0");
4863
4864
4865	/* Build a SSID valid enabled vector, skip processing if the
4866	   vector is not set. Set vector on virtual i/f only if wl_vifs is set
4867	*/
4868	for (count=0; count < num_ifaces ; count++){
4869		char buf[64];
4870
4871		if (count)
4872			snprintf(buf,sizeof(buf),"lan%d_ifname",count);
4873		else
4874			snprintf(buf,sizeof(buf),"lan_ifname");
4875
4876		value =  websGetVar(wp, buf , NULL);
4877		if (value)
4878		{
4879			if (!*value)
4880				continue;
4881
4882			/* Clear lan mac address if the ip configuration is unset */
4883			if (!strcmp(value,"NONE")){
4884				/* Clear lanX_ifname if the inteface name has been set to NONE in the web page */
4885				nvram_unset(buf);
4886				/* Clear up lanX_hwaddr */
4887				snprintf(buf,sizeof(buf),"lan%d_hwaddr",count);
4888				nvram_unset(buf);
4889				continue;
4890			}
4891
4892			if (strstr(value,".")){
4893				int unit=-1,subunit=-1;
4894				char *wl_vifs;
4895
4896				if (get_ifname_unit(value,&unit,&subunit) < 0)
4897					continue;
4898				if (subunit < 0 )
4899					continue;
4900
4901				snprintf(buf,sizeof(buf),"wl%d_vifs",unit);
4902
4903				wl_vifs = nvram_get(buf);
4904
4905				if (!wl_vifs)
4906					continue;
4907
4908				if (!strstr(wl_vifs,value) )
4909					continue;
4910			}
4911
4912			vector[count] = 1;
4913		}
4914
4915	}
4916
4917	/* check to see if the ip addresses overlap */
4918
4919	for (count=0; count < num_ifaces ; count++){
4920		int entry;
4921		char *valueA,*valueB;
4922		char lanA_ipaddr[32],lanA_netmask[32];
4923		char lanB_ipaddr[32],lanB_netmask[32];
4924		char dhcpA_start[32],dhcpB_start[32];
4925		char dhcpA_end[32],dhcpB_end[32];
4926		char lanA_ifname[32],lanB_ifname[32];
4927		char lanA_proto[32],lanB_proto[32];
4928
4929		/*Skip entry if the SSID is not turned on */
4930		if (!vector[count])
4931			continue;
4932
4933		if (count){
4934			snprintf(lanA_ifname,sizeof(lanA_ifname),"lan%d_ifname",count);
4935			snprintf(lanA_ipaddr,sizeof(lanA_ipaddr),"lan%d_ipaddr",count);
4936			snprintf(lanA_netmask,sizeof(lanA_netmask),"lan%d_netmask",count);
4937			snprintf(lanA_proto,sizeof(lanA_proto),"lan%d_proto",count);
4938			snprintf(dhcpA_start,sizeof(dhcpA_start),"dhcp%d_start",count);
4939			snprintf(dhcpA_end,sizeof(dhcpA_end),"dhcp%d_end",count);
4940		}else{
4941			snprintf(lanA_ifname,sizeof(lanA_ifname),"lan_ifname");
4942			snprintf(lanA_ipaddr,sizeof(lanA_ipaddr),"lan_ipaddr");
4943			snprintf(lanA_netmask,sizeof(lanA_netmask),"lan_netmask");
4944			snprintf(lanA_proto,sizeof(lanA_proto),"lan_proto");
4945			snprintf(dhcpA_start,sizeof(dhcpA_start),"dhcp_start");
4946			snprintf(dhcpA_end,sizeof(dhcpA_end),"dhcp_end");
4947		}
4948
4949		for (entry=0; entry < num_ifaces; entry++){
4950
4951			if (count == entry)
4952				continue;
4953
4954			/*Skip entry if the SSID is not turned on */
4955			if (!vector[entry])
4956				continue;
4957
4958			if (entry){
4959				snprintf(lanB_ifname,sizeof(lanB_ifname),"lan%d_ifname",entry);
4960				snprintf(lanB_ipaddr,sizeof(lanB_ipaddr),"lan%d_ipaddr",entry);
4961				snprintf(lanB_netmask,sizeof(lanB_netmask),"lan%d_netmask",entry);
4962				snprintf(lanB_proto,sizeof(lanB_proto),"lan%d_proto",count);
4963				snprintf(dhcpB_start,sizeof(dhcpB_start),"dhcp%d_start",entry);
4964				snprintf(dhcpB_end,sizeof(dhcpB_end),"dhcp%d_end",entry);
4965			}else{
4966				snprintf(lanB_ifname,sizeof(lanB_ifname),"lan_ifname");
4967				snprintf(lanB_ipaddr,sizeof(lanB_ipaddr),"lan_ipaddr");
4968				snprintf(lanB_netmask,sizeof(lanB_netmask),"lan_netmask");
4969				snprintf(lanB_proto,sizeof(lanB_proto),"lan_proto");
4970				snprintf(dhcpB_start,sizeof(dhcpB_start),"dhcp_start");
4971				snprintf(dhcpB_end,sizeof(dhcpB_end),"dhcp_end");
4972			}
4973
4974			/* Check for the same interface unit numbers */
4975			valueA = websGetVar(wp , lanA_ifname , NULL);
4976			valueB = websGetVar(wp , lanB_ifname , NULL);
4977
4978			if ((!valueA) ||(!valueB)) {
4979				snprintf(err_msg,sizeof(err_msg),
4980					"<br>%s is NULL<br>",(valueA) ? lanB_ifname : lanA_ifname);
4981	      			goto validate_lan_cgi_error;
4982			}
4983
4984			if (!strcmp(valueA,valueB)){
4985				snprintf(err_msg,sizeof(err_msg),
4986					"<br>Interface %s selected more than once<br>",valueA);
4987	      			goto validate_lan_cgi_error;
4988			}
4989
4990			value =  websGetVar(wp, lanA_ipaddr , NULL);
4991			if (! value ) goto validate_lan_cgi_error;
4992			(void)inet_aton(value,&i_addr);
4993
4994			value = websGetVar(wp, lanB_ipaddr , NULL);
4995			if (! value ) goto validate_lan_cgi_error;
4996			(void)inet_aton(value,&g_addr);
4997
4998			value =  websGetVar(wp, lanA_netmask , NULL);
4999			if (! value ) goto validate_lan_cgi_error;
5000			(void)inet_aton(value,&i_mask);
5001
5002			value = websGetVar(wp, lanB_netmask , NULL);
5003			if (! value ) goto validate_lan_cgi_error;
5004			(void)inet_aton(value,&g_mask);
5005
5006			if ((i_addr.s_addr & i_mask.s_addr)==(g_addr.s_addr & g_mask.s_addr) ){
5007				snprintf(err_msg,sizeof(err_msg),
5008					"<br>Overlapping IP address ranges:<br>(RangeA=%s/%s) (RangeB=%s/%s)<br>",
5009						lanA_ipaddr,lanA_netmask,lanB_ipaddr,lanB_netmask);
5010	      			goto validate_lan_cgi_error;
5011			}
5012
5013			valueA = websGetVar(wp , lanA_proto , NULL);
5014			valueB = websGetVar(wp , lanB_proto , NULL);
5015
5016			/* If any of the proto vars are null skip the check */
5017			if ((!valueA) ||(!valueB))
5018						continue;
5019
5020			/* Overlapping DHCP range check only if DHCP is the lan proto on both*/
5021			if (!strcmp(valueA,"dhcp") && !strcmp(valueB,"dhcp"))
5022			{
5023				value =  websGetVar(wp, dhcpA_start , NULL);
5024				if (! value ) goto validate_lan_cgi_error;
5025				(void) inet_aton(value,&i_addr);
5026
5027				value = websGetVar(wp, dhcpB_start , NULL);
5028				if (! value ) goto validate_lan_cgi_error;
5029				(void) inet_aton(value,&g_addr);
5030
5031				/* Are they in the same subnetwork ? */
5032
5033				if ((i_addr.s_addr & i_mask.s_addr)==(g_addr.s_addr & g_mask.s_addr) ){
5034					snprintf(err_msg,sizeof(err_msg),
5035						"<br>Overlapping DHCP start ranges<br>(RangeA=%s/%s) (RangeB=%s/%s)<br>",
5036							dhcpA_start,lanA_netmask,dhcpB_start,lanB_netmask);
5037	      					goto validate_lan_cgi_error;
5038				}
5039
5040				value =  websGetVar(wp, dhcpA_end , NULL);
5041				if (! value ) goto validate_lan_cgi_error;
5042				(void) inet_aton(value,&i_addr);
5043
5044				value = websGetVar(wp, dhcpB_end , NULL);
5045				if (! value ) goto validate_lan_cgi_error;
5046				(void) inet_aton(value,&g_addr);
5047
5048				/* Are they in the same subnetwork ? */
5049
5050				if ((i_addr.s_addr & i_mask.s_addr)==(g_addr.s_addr & g_mask.s_addr) ){
5051					snprintf(err_msg,sizeof(err_msg),
5052						 "<br>Overlapping DHCP end ranges<br>(RangeA=%s/%s) (RangeB=%s/%s)<br>",
5053							dhcpA_end,lanA_netmask,dhcpB_end,lanB_netmask);
5054	      					goto validate_lan_cgi_error;
5055				}
5056			}
5057		}
5058	}
5059
5060	ret_code = 0;
5061
5062	/* The individual validation functions will set ret_code to EINVAL
5063	   if an error is encountered. On success zero is returned.
5064	   Validation stops on the first error encountered
5065	*/
5066	for  ( count = 0; ( count < num_items && !(ret_code) ); count++){
5067
5068		char var[64];
5069		int entry;
5070
5071		/* Lookup template */
5072		varname = cgi_vars[count];
5073		v = get_var_handle(varname);
5074
5075		/* Enumerate thru list of interfaces */
5076		if (v)
5077			for (entry=0; entry < num_ifaces; entry++){
5078
5079				/* Skip entry if the SSID is not turned on */
5080				if (!vector[entry])
5081					continue;
5082
5083				if (v->ezc_flags & WEB_IGNORE)
5084					continue;
5085
5086				if (entry && v->prefix )
5087					snprintf(var,sizeof(var),"%s%d_%s",
5088						v->prefix,entry,&varname[strlen(v->prefix) + 1]);
5089				else
5090					snprintf(var,sizeof(var),"%s",varname);
5091
5092				value = websGetVar(wp, var, NULL);
5093
5094				if (value){
5095					if ((!*value && v->nullok) || !v->validate)
5096						nvram_set(var, value);
5097					else
5098						v->validate(wp, value, v, var);
5099				}
5100			}
5101
5102	}
5103
5104	/* Set lanX_dhcp to static for all interfaces in router mode */
5105	if (router_enable)
5106		for (count = 0; count < num_ifaces; count++){
5107			char lan_dhcp[]="lanXXXXX_dhcp";
5108			/* Skip entry if the SSID is not turned on */
5109			if (!vector[count])
5110				continue;
5111			if (count)
5112				snprintf(lan_dhcp,sizeof(lan_dhcp),"lan%d_dhcp",count);
5113			else
5114				snprintf(lan_dhcp,sizeof(lan_dhcp),"lan_dhcp");
5115			nvram_set(lan_dhcp,"0");
5116
5117		}
5118
5119	/* Handlers already print error messages. No need for further explanation */
5120	if (ret_code)
5121		snprintf(err_msg,sizeof(err_msg),"Error during variable validation.<br>");
5122
5123validate_lan_cgi_error:
5124	if (*err_msg)
5125		websWrite(wp, err_msg);
5126
5127	websBufferFlush(wp);
5128}
5129
5130static void
5131validate_cgi(webs_t wp)
5132{
5133	struct variable *v=NULL;
5134	char *value=NULL;
5135
5136	websBufferInit(wp);
5137	if (!webs_buf) {
5138		websWrite(wp, "out of memory<br>");
5139		websDone(wp, 0);
5140		return;
5141	}
5142
5143
5144	/* Validate and set variables in table order */
5145	for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) {
5146		if (!(value = websGetVar(wp, v->name, NULL)))
5147			continue;
5148
5149		if (v->ezc_flags & WEB_IGNORE)
5150					continue;
5151
5152		if ((!*value && v->nullok) || !v->validate)
5153				nvram_set(v->name, value);
5154		else
5155				v->validate(wp, value, v, NULL);
5156
5157	}
5158
5159	websBufferFlush(wp);
5160}
5161
5162static int
5163apply_cgi(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
5164	  char_t *url, char_t *path, char_t *query)
5165{
5166	char *value=NULL;
5167	char *page=NULL;
5168	action = NOTHING;
5169
5170	websHeader(wp);
5171	websWrite(wp, (char_t *) apply_header);
5172
5173	page = websGetVar(wp, "page", "");
5174
5175	value = websGetVar(wp, "action", "");
5176
5177	/* Apply values */
5178	if (!strcmp(value, "Apply")) {
5179		action = RESTART;
5180		websWrite(wp, "Validating values...");
5181
5182		if (strcmp("lan.asp",page))
5183			validate_cgi(wp);
5184		else
5185			validate_lan_cgi(wp);
5186		if(ret_code)
5187		{
5188			websWrite(wp, "<br>");
5189			action = NOTHING;
5190		}else{
5191			websWrite(wp, "done<br>");
5192			websWrite(wp, "Committing values...");
5193			nvram_set("is_modified", "1");
5194			nvram_set("is_default", "0");
5195			nvram_commit();
5196			websWrite(wp, "done<br>");
5197		}
5198	}
5199
5200	/* Restore defaults */
5201	else if (!strncmp(value, "Restore", 7)) {
5202		websWrite(wp, "Restoring defaults...");
5203		nvram_set("sdram_ncdl", "0");
5204		nvram_set("restore_defaults", "1");
5205		nvram_commit();
5206		websWrite(wp, "done<br>");
5207		action = REBOOT;
5208	}
5209
5210	/* Release lease */
5211	else if (!strcmp(value, "Release")) {
5212		websWrite(wp, "Releasing lease...");
5213		if (sys_release())
5214			websWrite(wp, "error<br>");
5215		else
5216			websWrite(wp, "done<br>");
5217		action = NOTHING;
5218	}
5219
5220	/* Renew lease */
5221	else if (!strcmp(value, "Renew")) {
5222		websWrite(wp, "Renewing lease...");
5223		if (sys_renew())
5224			websWrite(wp, "error<br>");
5225		else
5226			websWrite(wp, "done<br>");
5227		action = NOTHING;
5228	}
5229
5230	/* Reboot router */
5231	else if (!strcmp(value, "Reboot")) {
5232		websWrite(wp, "Rebooting...");
5233		action = REBOOT;
5234	}
5235
5236	/* Upgrade image */
5237	else if (!strcmp(value, "Upgrade")) {
5238		char *os_name = nvram_safe_get("os_name");
5239		char *os_server = websGetVar(wp, "os_server", nvram_safe_get("os_server"));
5240		char *os_version = websGetVar(wp, "os_version", "current");
5241		char url[PATH_MAX];
5242		if (!*os_version)
5243			os_version = "current";
5244		snprintf(url, sizeof(url), "%s/%s/%s/%s.trx",
5245			 os_server, os_name, os_version, os_name);
5246		websWrite(wp, "Retrieving %s...", url);
5247		if (sys_upgrade(url, NULL, NULL)) {
5248			websWrite(wp, "error<br>");
5249			goto footer;
5250		} else {
5251			websWrite(wp, "done<br>");
5252			action = REBOOT;
5253		}
5254	}
5255
5256	/* Report stats */
5257	else if (!strcmp(value, "Stats")) {
5258		char *server = websGetVar(wp, "stats_server", nvram_safe_get("stats_server"));
5259		websWrite(wp, "Contacting %s...", server);
5260		if (sys_stats(server)) {
5261			websWrite(wp, "error<br>");
5262			goto footer;
5263		} else {
5264			websWrite(wp, "done<br>");
5265			nvram_set("stats_server", server);
5266		}
5267	}
5268	/* Radio On Off  */
5269	else if (!strcmp(value, "RadioOff")) {
5270		websWrite(wp, "Turing Off Radio...");
5271		wl_radio_onoff(wp, 1);
5272		action = NOTHING;
5273	}
5274	else if (!strcmp(value, "RadioOn")) {
5275		websWrite(wp, "Radio on...");
5276		wl_radio_onoff(wp, 0);
5277		action = NOTHING;
5278	}
5279#ifdef __CONFIG_NAT__
5280	/* Delete connection */
5281	else if (!strcmp(value, "Delete")) {
5282		int unit;
5283		if (!(value = websGetVar(wp, "wan_unit", NULL)) ||
5284		    (unit = atoi(value)) < 0 || unit >= MAX_NVPARSE) {
5285			websWrite(wp, "Unable to delete connection, index error.");
5286			action = NOTHING;
5287		}
5288		else {
5289			struct nvram_tuple *t;
5290			char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
5291			int unit2, units = 0;
5292			/*
5293			* We can't delete the last connection since we can't differentiate
5294			* the cases where user does not want any connection (user deletes
5295			* the last one) vs. the router is booted the first time when there
5296			* is no connection at all (where a default one is created anyway).
5297			*/
5298			for (unit2 = 0; unit2 < MAX_NVPARSE; unit2 ++) {
5299				wan_prefix(unit2, prefix);
5300				if (nvram_get(strcat_r(prefix, "unit", tmp)) && units++ > 0)
5301					break;
5302			}
5303			if (units < 2) {
5304				websWrite(wp, "Can not delete the last connection.");
5305				action = NOTHING;
5306			}
5307			else {
5308				/* set prefix */
5309				wan_prefix(unit, prefix);
5310				/* remove selected wan%d_ set */
5311				websWrite(wp, "Deleting connection...");
5312				for (t = router_defaults; t->name; t ++) {
5313					if (!strncmp(t->name, "wan_", 4))
5314						nvram_unset(strcat_r(prefix, &t->name[4], tmp));
5315				}
5316				/* fix unit number */
5317				unit2 = unit;
5318				for (; unit < MAX_NVPARSE; unit ++) {
5319					wan_prefix(unit, prefix);
5320					if (nvram_get(strcat_r(prefix, "unit", tmp)))
5321						break;
5322				}
5323				if (unit >= MAX_NVPARSE) {
5324					unit = unit2 - 1;
5325					for (; unit >= 0; unit --) {
5326						wan_prefix(unit, prefix);
5327						if (nvram_get(strcat_r(prefix, "unit", tmp)))
5328							break;
5329					}
5330				}
5331				snprintf(tmp, sizeof(tmp), "%d", unit);
5332				nvram_set("wan_unit", tmp);
5333				/* check if there is any primary connection - see comment in wan_unit() */
5334				for (unit = 0; unit < MAX_NVPARSE; unit ++) {
5335					wan_prefix(unit, prefix);
5336					if (!nvram_get(strcat_r(prefix, "unit", tmp)))
5337						continue;
5338					if (nvram_invmatch(strcat_r(prefix, "proto", tmp), "disabled") &&
5339					    nvram_match(strcat_r(prefix, "primary", tmp), "1"))
5340						break;
5341				}
5342				/* no one is primary, pick the first enabled one as primary */
5343				if (unit >= MAX_NVPARSE)
5344					wan_primary(wp);
5345				/* save the change */
5346				nvram_set("is_modified", "1");
5347				nvram_set("is_default", "0");
5348				nvram_commit();
5349				websWrite(wp, "done<br>");
5350				action = RESTART;
5351			}
5352		}
5353	}
5354#endif	/* __CONFIG_NAT__ */
5355
5356	/* Invalid action */
5357	else
5358		websWrite(wp, "Invalid action %s<br>", value);
5359
5360 footer:
5361	websWrite(wp, (char_t *) apply_footer, websGetVar(wp, "page", ""));
5362	websFooter(wp);
5363	websDone(wp, 200);
5364
5365	if (action == RESTART)
5366		sys_restart();
5367	else if (action == REBOOT)
5368		sys_reboot();
5369
5370	return 1;
5371}
5372
5373/* Copy all wl%d_XXXXX to wl_XXXXX */
5374static int
5375copy_wl_index_to_unindex(webs_t wp, char_t *urlPrefix, char_t *webDir,
5376													int arg, char_t *url, char_t *path, char_t *query)
5377{
5378	struct variable *v=NULL;
5379	char *value=NULL;
5380	char name[IFNAMSIZ], os_name[IFNAMSIZ], *next=NULL;
5381	int unit = 0;
5382	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5383	char unit_str[]={'\0','\0','\0','\0','\0'};
5384	int applying = 0;
5385
5386	/* Can enter this function through GET or POST */
5387	if ((value = websGetVar(wp, "action", NULL))) {
5388		if (strcmp(value, "Select"))
5389		{
5390			/* we need to make sure wl_unit on the web page matches the
5391				 wl_unit in NVRAM.  If they match, bail out now, otherwise
5392				 proceed with the rest of the function */
5393
5394			if ((value = websGetVar(wp, "wl_unit", NULL))) {
5395				if (!strcmp( nvram_safe_get("wl_unit" ), value))
5396					return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
5397			}
5398			applying = 1;
5399		}
5400	}
5401
5402	/* copy wl%d_XXXXXXXX to wl_XXXXXXXX */
5403	if ((value = websGetVar(wp, "wl_unit", NULL))) {
5404		strncpy(unit_str,value,sizeof(unit_str));
5405	} else {
5406		char ifnames[256];
5407		snprintf(ifnames, sizeof(ifnames), "%s %s %s",
5408			nvram_safe_get("lan_ifnames"),
5409			nvram_safe_get("wan_ifnames"),
5410			nvram_safe_get("unbridged_ifnames"));
5411
5412		if (!remove_dups(ifnames,sizeof(ifnames))){
5413			websError(wp, 400, "Unable to remove duplicate interfaces from ifname list<br>");
5414			return -1;
5415		}
5416
5417		/* Probe for first wl interface */
5418		foreach(name, ifnames, next) {
5419			if (nvifname_to_osifname( name, os_name, sizeof(os_name) ) < 0)
5420				continue;
5421			if (wl_probe(os_name) == 0 &&
5422			    wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)) == 0){
5423			    	snprintf(unit_str,sizeof(unit_str),"%d",unit);
5424				break;
5425			}
5426		}
5427
5428	}
5429	if (*unit_str) {
5430		snprintf(prefix, sizeof(prefix), "wl%s_", unit_str);
5431		for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) {
5432			if (v->ezc_flags & WEB_IGNORE)
5433				continue;
5434			if (!strncmp(v->name, "wl_", 3))
5435				nvram_set(v->name, nvram_safe_get(strcat_r(prefix, &v->name[3], tmp)));
5436			if (!strncmp(v->name, "wl_unit", 7))
5437				break;
5438		}
5439	}
5440
5441	/* Set currently selected unit */
5442	nvram_set("wl_unit", unit_str);
5443
5444	if( applying )
5445		return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
5446
5447	/* Display the page */
5448	return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query);
5449}
5450
5451
5452#ifdef __CONFIG_NAT__
5453static int
5454wan_asp(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
5455	     char_t *url, char_t *path, char_t *query)
5456{
5457	struct variable *v=NULL;
5458	char *value=NULL;
5459	int unit = 0;
5460	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
5461	char ustr[16];
5462	struct nvram_tuple *t=NULL;
5463
5464	/* Can enter this function through GET or POST */
5465	if ((value = websGetVar(wp, "action", NULL))) {
5466		if (!strcmp(value, "New")) {
5467			/* pick one that 'does not' exist */
5468			for (unit = 0; unit < MAX_NVPARSE; unit ++) {
5469				wan_prefix(unit, prefix);
5470				if (!nvram_get(strcat_r(prefix, "unit", tmp)))
5471					break;
5472			}
5473			if (unit >= MAX_NVPARSE) {
5474				websHeader(wp);
5475				websWrite(wp, (char_t *) apply_header);
5476				websWrite(wp, "Unable to create new connection. Maximum %d.", MAX_NVPARSE);
5477				websWrite(wp, (char_t *) apply_footer, websGetVar(wp, "page", ""));
5478				websFooter(wp);
5479				websDone(wp, 200);
5480				return 1;
5481			}
5482			/* copy default to newly created wan%d_ set */
5483			for (t = router_defaults; t->name; t ++) {
5484				if (!strncmp(t->name, "wan_", 4))
5485					nvram_set(strcat_r(prefix, &t->name[4], tmp), t->value);
5486			}
5487			/* the following variables must be overwritten */
5488			snprintf(ustr, sizeof(ustr), "%d", unit);
5489			nvram_set(strcat_r(prefix, "unit", tmp), ustr);
5490			nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
5491			nvram_set(strcat_r(prefix, "ifname", tmp), nvram_safe_get("wan_ifname"));
5492			nvram_set(strcat_r(prefix, "hwaddr", tmp), nvram_safe_get("wan_hwaddr"));
5493			nvram_set(strcat_r(prefix, "ifnames", tmp), nvram_safe_get("wan_ifnames"));
5494			/* commit change */
5495			nvram_set("is_modified", "1");
5496			nvram_set("is_default", "0");
5497			nvram_commit();
5498		}
5499		else if (!strcmp(value, "Select")) {
5500			if ((value = websGetVar(wp, "wan_unit", NULL)))
5501				unit = atoi(value);
5502			else
5503				unit = -1;
5504		}
5505		else
5506			return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
5507	}
5508	else if ((value = websGetVar(wp, "wan_unit", NULL)))
5509		unit = atoi(value);
5510	else
5511		unit = atoi(nvram_safe_get("wan_unit"));
5512	if (unit < 0 || unit >= MAX_NVPARSE)
5513		unit = 0;
5514
5515	/* Set prefix */
5516	wan_prefix(unit, prefix);
5517
5518	/* copy wan%d_ set to wan_ set */
5519	for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) {
5520		if (v->ezc_flags & WEB_IGNORE)
5521			continue;
5522		if (strncmp(v->name, "wan_", 4))
5523			continue;
5524		value = nvram_get(strcat_r(prefix, &v->name[4], tmp));
5525		if (value)
5526			nvram_set(v->name, value);
5527		if (!strncmp(v->name, "wan_unit", 8))
5528			break;
5529	}
5530
5531	/* Set currently selected unit */
5532	snprintf(tmp, sizeof(tmp), "%d", unit);
5533	nvram_set("wan_unit", tmp);
5534
5535	/* Display the page */
5536	return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query);
5537}
5538#endif	/* __CONFIG_NAT__ */
5539
5540#ifdef WEBS
5541
5542void
5543initHandlers(void)
5544{
5545	websAspDefine("nvram_get", ej_nvram_get);
5546	websAspDefine("nvram_match", ej_nvram_match);
5547	websAspDefine("nvram_invmatch", ej_nvram_invmatch);
5548	websAspDefine("nvram_list", ej_nvram_list);
5549	websAspDefine("filter_client", ej_filter_client);
5550	websAspDefine("forward_port", ej_forward_port);
5551	websAspDefine("static_route", ej_static_route);
5552	websAspDefine("localtime", ej_localtime);
5553	websAspDefine("dumplog", ej_dumplog);
5554	websAspDefine("syslog", ej_syslog);
5555	websAspDefine("dumpleases", ej_dumpleases);
5556	websAspDefine("link", ej_link);
5557	websAspDefine("wme_match_op", ej_wme_match_op);
5558
5559	websUrlHandlerDefine("/apply.cgi", NULL, 0, apply_cgi, 0);
5560	websUrlHandlerDefine("/wireless.asp", NULL, 0, copy_wl_index_to_unindex, 0);
5561
5562	websSetPassword(nvram_safe_get("http_passwd"));
5563
5564	websSetRealm("Broadcom Home Gateway Reference Design");
5565
5566	/* Initialize hash table */
5567	hash_vtab(&vtab,v,variables_arraysize());
5568}
5569
5570#else /* !WEBS */
5571
5572int internal_init(void)
5573{
5574	/* Initialize hash table */
5575	if (hash_vtab(&vtab,variables,variables_arraysize()))
5576		return -1;
5577	return 0;
5578}
5579static void
5580do_auth(char *userid, char *passwd, char *realm)
5581{
5582	assert(userid);
5583	assert(passwd);
5584	assert(realm);
5585
5586	strncpy(userid, nvram_safe_get("http_username"), AUTH_MAX);
5587	strncpy(passwd, nvram_safe_get("http_passwd"), AUTH_MAX);
5588	strncpy(realm, "Broadcom Home Gateway Reference Design", AUTH_MAX);
5589}
5590
5591char post_buf[POST_BUF_SIZE];
5592char ezc_version[128];
5593char no_cache[] =
5594"Cache-Control: no-cache\r\n"
5595"Pragma: no-cache\r\n"
5596"Expires: 0"
5597;
5598
5599char download_hdr[] =
5600"Cache-Control: no-cache\r\n"
5601"Pragma: no-cache\r\n"
5602"Expires: 0\r\n"
5603"Content-Type: application/download\r\n"
5604"Content-Disposition: attachment ; filename=nvram.txt"
5605;
5606
5607static void
5608do_apply_post(char *url, FILE *stream, int len, char *boundary)
5609{
5610	assert(url);
5611	assert(stream);
5612
5613	/* Get query */
5614	if (!fgets(post_buf, MIN(len + 1, sizeof(post_buf)), stream))
5615		return;
5616	len -= strlen(post_buf);
5617
5618	/* Initialize CGI */
5619	init_cgi(post_buf);
5620
5621	/* Slurp anything remaining in the request */
5622	while (len--)
5623		(void) fgetc(stream);
5624}
5625
5626static void
5627do_apply_cgi(char *url, FILE *stream)
5628{
5629	char *path=NULL, *query=NULL;
5630
5631	assert(url);
5632	assert(stream);
5633
5634	/* Parse path */
5635	query = url;
5636	path = strsep(&query, "?") ? : url;
5637
5638	apply_cgi(stream, NULL, NULL, 0, url, path, query);
5639
5640	/* Reset CGI */
5641	init_cgi(NULL);
5642}
5643
5644
5645static void
5646do_upgrade_post(char *url, FILE *stream, int len, char *boundary)
5647{
5648	char buf[1024];
5649
5650	assert(url);
5651	assert(stream);
5652
5653	ret_code = EINVAL;
5654
5655	/* Look for our part */
5656	while (len > 0) {
5657		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
5658			return;
5659		len -= strlen(buf);
5660		if (!strncasecmp(buf, "Content-Disposition:", 20) &&
5661		    strstr(buf, "name=\"file\""))
5662			break;
5663	}
5664
5665	/* Skip boundary and headers */
5666	while (len > 0) {
5667		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
5668			return;
5669		len -= strlen(buf);
5670		if (!strcmp(buf, "\n") || !strcmp(buf, "\r\n"))
5671			break;
5672	}
5673
5674	ret_code = sys_upgrade(NULL, stream, &len);
5675
5676	/* Slurp anything remaining in the request */
5677	while (len--)
5678		(void) fgetc(stream);
5679}
5680
5681static void
5682do_upgrade_cgi(char *url, FILE *stream)
5683{
5684	assert(url);
5685	assert(stream);
5686
5687	websHeader(stream);
5688	websWrite(stream, (char_t *) apply_header);
5689
5690	/* We could probably be more informative here... */
5691	if (ret_code)
5692		websWrite(stream, "Error during upgrade<br>");
5693	else
5694		websWrite(stream, "Upgrade complete. Rebooting...<br>");
5695
5696	websWrite(stream, (char_t *) apply_footer, "firmware.asp");
5697	websFooter(stream);
5698	websDone(stream, 200);
5699
5700	/* Reboot if successful */
5701	if (ret_code == 0)
5702		sys_reboot();
5703}
5704/* Utility function to remove duplicate entries in a space separated list
5705 */
5706
5707static char *
5708remove_dups(char *inlist, int inlist_size)
5709{
5710	char name[IFNAMSIZ], *next=NULL;
5711	char *outlist;
5712
5713	if (!inlist_size)
5714		return NULL;
5715
5716	if (!inlist)
5717		return NULL;
5718
5719	outlist =(char *) malloc(inlist_size);
5720
5721	if (!outlist ) return NULL;
5722
5723	memset(outlist,0,inlist_size);
5724
5725	foreach(name,inlist,next)
5726	{
5727		if (strstr(outlist,name) == NULL)
5728		{
5729			if( strlen(outlist) == 0 )
5730			{
5731				snprintf(outlist,inlist_size,"%s", name);
5732			}
5733			else
5734			{
5735				strncat( outlist, " ", inlist_size - strlen(outlist) );
5736				strncat( outlist, name, inlist_size - strlen(outlist) );
5737			}
5738		}
5739	}
5740
5741	strncpy(inlist,outlist,inlist_size);
5742
5743	free(outlist);
5744	return inlist;
5745
5746}
5747/* This utility routine builds the wl prefixes from wl_unit.
5748 * Input is expected to be a null terminated string
5749 *
5750 * Inputs -prefix: Pointer to prefix buffer
5751 *	  -prefix_size: Size of buffer
5752 *        -Mode flag: If set generates unit.subunit output
5753 *                    if not set generates unit only
5754 *	  -ifname: Optional interface name string
5755 *
5756 *
5757 * Returns - pointer to prefix, NULL if error.
5758 *
5759 *
5760*/
5761static char *
5762make_wl_prefix(char *prefix,int prefix_size, int mode, char *ifname)
5763{
5764	int unit=-1,subunit=-1;
5765	char *wl_unit=NULL;
5766
5767	assert(prefix);
5768	assert(prefix_size);
5769
5770	if (ifname){
5771		assert(*ifname);
5772		wl_unit=ifname;
5773	}else{
5774		wl_unit=nvram_get("wl_unit");
5775
5776		if (!wl_unit)
5777			return NULL;
5778	}
5779
5780	if (get_ifname_unit(wl_unit,&unit,&subunit) < 0 )
5781		return NULL;
5782
5783	if (unit < 0) return NULL;
5784
5785	if  ((mode) && (subunit > 0 ))
5786		snprintf(prefix, prefix_size, "wl%d.%d_", unit,subunit);
5787	else
5788		snprintf(prefix, prefix_size, "wl%d_", unit);
5789
5790	return prefix;
5791}
5792
5793/* Format of the NVRAM text file is as follows
5794 * the following major sections
5795 * Header Block
5796 * Constraint Block
5797 * NVRAM variables
5798 *
5799 * Header consists of :
5800 *	LineCount
5801 *	Checksum
5802 *
5803 * Constraint block consists of :
5804 * Defined by NVRAM_CONSTRAINT_VARS
5805 *
5806 *
5807*/
5808
5809/* Get major os version. The nvram variable gives the whole thing.
5810 * this function avoids the messy parsing.
5811 * Used by NVRAM constraint validation routines.
5812 * The input argument is not used. This is used to maintain
5813 * argument list compatability with nvram_get().
5814 *
5815*/
5816static  char*
5817osversion_get(const char *name)
5818{
5819
5820	static char ret_string[32];
5821
5822	assert(name);
5823
5824 	snprintf(ret_string,sizeof(ret_string),"%d.%d",
5825  			EPI_MAJOR_VERSION,EPI_MINOR_VERSION);
5826
5827
5828	return ret_string;
5829
5830}
5831
5832/* This routine strips the CRLF from the HTTP stream */
5833/* Returns new length or -1 if there is an error*/
5834static int
5835remove_crlf(char *buf, int len)
5836{
5837
5838	int slen;
5839	if (!buf) return -1;
5840	if (!len) return 0;
5841
5842	slen = strlen(buf);
5843	len = len-slen;
5844	if ((buf[slen-1] == '\n' ) && (buf[slen-2] == '\r' )){
5845		buf[slen-1]='\0';
5846		buf[slen-2]='\0';
5847
5848	}
5849	else if ( buf[slen-1] == '\n' ) buf[slen-1]='\0';
5850
5851	return len;
5852}
5853/* Utility routine to add a string from a string buffer.
5854 *
5855 * Routine expects that the buffer is composed of text strings with
5856 * a null as the delimiter.
5857 *
5858 * Input is expected to be a null terminated string
5859 *
5860 * Inputs -Pointer to char buffer
5861 *        -NULL input terminated string
5862 *	  -Offset to end of used area. Including the NULL terminator
5863 *	  -Size of the buffer (to avoid running of the end of the buffer)
5864 *
5865 *
5866 * Returns - Number of bytes occupied including NULL terminator. -1 if error
5867 *
5868 *
5869*/
5870static int
5871add_string(char *buf, char *string, int start, int bufsize)
5872{
5873	int len;
5874
5875	assert(buf);
5876
5877	if (!string) return -1;
5878	if (!*string) return -1;
5879	if (!bufsize) return -1;
5880	if (start >=bufsize) return -1;
5881
5882	len = strlen(string);
5883
5884	if ( (start + len + 1) >= bufsize ) return -1;
5885
5886	strncpy(buf,string,len);
5887
5888	return start + len + 1;
5889}
5890static void
5891do_nvramul_post(char *url, FILE *stream, int len, char *boundary)
5892{
5893	char buf[1024];
5894	int  index,cur_entry;
5895	char *ptr=NULL;
5896	char *name=NULL;
5897	char tmp[NVRAM_MAX_STRINGSIZE];
5898	char file_checksum[NVRAM_SHA1BUFSIZE],checksum[NVRAM_SHA1BUFSIZE];
5899	char key[NVRAM_FILEKEYSIZE];
5900	int  checksum_linenum = NVRAM_CHECKSUM_LINENUM;
5901	char salt[NVRAM_SALTSIZE];
5902	int  numlines=0;
5903	int  entries,offset,slen;
5904	char passphrase[]=NVRAM_PASSPHRASE;
5905	char nvram_file_header[][NVRAM_MAX_STRINGSIZE/2] = NVRAM_FILEHEADER;
5906	upload_constraints constraint_vars [] = NVRAM_CONSTRAINT_VARS;
5907	struct pb {
5908			char header[NVRAM_HEADER_LINECOUNT(nvram_file_header)][NVRAM_MAX_STRINGSIZE];
5909			char buf[NVRAM_SPACE];
5910		 }*tmpbuf=NULL;
5911
5912	assert(stream);
5913
5914	entries = NVRAM_HEADER_LINECOUNT(nvram_file_header);
5915	ret_code = EINVAL;
5916
5917	/* Look for our part */
5918	while (len > 0) {
5919		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
5920			return;
5921
5922		/* Remove LF that fgets()drags in */
5923		len=remove_crlf(buf,len);
5924		/* look for start of attached file header */
5925
5926		if (*buf){
5927		  if (strstr(buf,NVRAM_BEGIN_WEBFILE)) break;
5928		}
5929
5930	}
5931
5932	if (!len) return;
5933
5934	/* loop thru the header lines until we get the blank line
5935	   that signifies the start of file contents */
5936	while (len > 0){
5937	 	if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
5938			return;
5939		/* Remove LF that fgets()drags in */
5940		len=remove_crlf(buf,len);
5941
5942		/* look for the blank line */
5943		if (*buf == NVRAM_END_WEBFILE)  break;
5944	}
5945
5946	if (!len) return;
5947
5948	/* Found start of upload file. Proceed with the upload */
5949	/* Look for start of upload data */
5950	if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
5951			return;
5952
5953	len = len - strlen(buf);
5954
5955	/* Get the number of NVRAM variables */
5956	sprintf(tmp,"%s=%s",nvram_file_header[NVRAM_LINECOUNT_LINENUM],"%d");
5957
5958	if ( (sscanf(buf,tmp,&numlines) != 1) || !len ){
5959		strncpy(posterr_msg,"Invalid NVRAM header<br>",ERR_MSG_SIZE);
5960	 	return ;
5961	}
5962
5963	if ((numlines > NVRAM_MAX_LINES ) || !numlines ){
5964		strncpy(posterr_msg,"Invalid NVRAM header<br>",ERR_MSG_SIZE);
5965	 	return;
5966	}
5967
5968	tmpbuf = (struct pb *) malloc( sizeof(struct pb));
5969	if (!tmpbuf){
5970		strncpy(posterr_msg,"Memory allocation error<br>",ERR_MSG_SIZE);
5971	 	return;
5972	}
5973
5974	memset(tmpbuf,0,sizeof(struct pb));
5975
5976	/* Copy over the first line of the file. Needed for
5977	   proper checksum calculations */
5978
5979	strcpy(tmpbuf->header[0],buf);
5980
5981	/* read in checksum */
5982	if (!fgets(tmpbuf->header[1], MIN(len + 1,NVRAM_MAX_STRINGSIZE), stream))
5983			goto do_nvramul_post_cleanup0;
5984
5985	len = len - strlen(tmpbuf->header[1]);
5986
5987	/* start reading in the rest of the NVRAM contents into memory buffer*/
5988	offset = 0;
5989	for (index = 2 ; (len > 0) &&  (index < numlines); index++){
5990		char filebuf[NVRAM_MAX_STRINGSIZE];
5991
5992	 	if (!fgets(filebuf, MIN(len + 1,NVRAM_MAX_STRINGSIZE), stream))
5993			goto do_nvramul_post_cleanup0;
5994
5995		offset = add_string(&tmpbuf->buf[offset],filebuf,offset,
5996						sizeof(((struct pb *)0)->buf));
5997		if (offset < 0){
5998			snprintf(posterr_msg,ERR_MSG_SIZE,
5999				"Error processing NVRAM variable:%s<br>",filebuf);
6000	 		goto do_nvramul_post_cleanup0;
6001		}
6002		len = len - strlen(filebuf);
6003
6004		/* don't remove the LFs since the we are using  multipart
6005		   MIME encoding that does not touch the contents of the
6006		   uploaded file. LFs are actually part of the NVRAM var lines.
6007		*/
6008	}
6009
6010	/*  Bail if the number of actual lines is less than that
6011	    in the header
6012	*/
6013
6014	if ( !len && (index < numlines) ){
6015		strncpy(posterr_msg,"NVRAM file incomplete<br>",ERR_MSG_SIZE);
6016	 	goto do_nvramul_post_cleanup0;
6017	}
6018
6019	/* Save and decode checksum from file */
6020	ptr = tmpbuf->header[checksum_linenum];
6021
6022	sprintf(tmp,"%s=",nvram_file_header[checksum_linenum]);
6023
6024	if ( !strstr(ptr,tmp) ) {
6025		snprintf(posterr_msg,ERR_MSG_SIZE,
6026			"No checksum present at line %d<br>",checksum_linenum+1);
6027		goto do_nvramul_post_cleanup0 ;
6028	}
6029	ptr = &ptr[strlen(tmp)];
6030
6031	if ( b64_decode(ptr,tmp,NVRAM_MAX_STRINGSIZE) != NVRAM_FILECHKSUM_SIZE){
6032		strncpy(posterr_msg,"Invalid checksum.<br>",ERR_MSG_SIZE);
6033		goto do_nvramul_post_cleanup0 ;
6034	};
6035
6036	memset(file_checksum,0,sizeof(file_checksum));
6037	memcpy(file_checksum,tmp,NVRAM_HASHSIZE);
6038
6039	/* Extract salt value from stored checksum*/
6040	memcpy(salt,&tmp[NVRAM_HASHSIZE],NVRAM_SALTSIZE);
6041
6042	/* Regenerate encryption key */
6043	memset(key,0,NVRAM_FILEKEYSIZE);
6044	fPRF(passphrase,strlen(passphrase),NULL,0,
6045			(unsigned char*)salt,sizeof(salt),key,sizeof(key));
6046
6047	/* Plug in filler for checksum into read buffer*/
6048	memset(tmpbuf->header[checksum_linenum],0,NVRAM_MAX_STRINGSIZE);
6049	snprintf(tmpbuf->header[checksum_linenum],
6050			NVRAM_MAX_STRINGSIZE,"%s\n",NVRAM_CHECKSUM_FILLER);
6051
6052	/* Calculate checksum and compare with stored value*/
6053
6054	memset(checksum,0,sizeof(checksum));
6055	hmac_sha1((unsigned char*)tmpbuf,sizeof(struct pb) ,
6056							key,sizeof(key),checksum);
6057
6058	if (memcmp(checksum,file_checksum,NVRAM_HASHSIZE)){
6059		memcpy(posterr_msg,"File checksum error<br>",ERR_MSG_SIZE);
6060		goto do_nvramul_post_cleanup0;
6061	}
6062
6063	/* Check constraints on the data */
6064
6065	cur_entry = NVRAM_HEADER_LINECOUNT(nvram_file_header);
6066	slen=0;
6067	name = tmpbuf->buf;
6068	for (index = 0  ; *constraint_vars[index].name && *name; index++,cur_entry++,name += slen + 1) {
6069		char *var=NULL,*ptr=NULL;
6070		int comparesize ;
6071
6072		slen = strlen(name);
6073
6074		if (cur_entry > numlines){
6075			memcpy(posterr_msg,
6076				"Constraints mismatch between file and running image<br>",
6077										ERR_MSG_SIZE);
6078			goto do_nvramul_post_cleanup0;
6079		}
6080
6081
6082		var = constraint_vars[index].get(constraint_vars[index].name);
6083
6084		if (!var){
6085			snprintf(posterr_msg,ERR_MSG_SIZE,
6086				"NVRAM variable:%s not found in running image<br>",
6087								constraint_vars[index].name);
6088			goto do_nvramul_post_cleanup0;
6089		}
6090
6091		if (!strstr(name,constraint_vars[index].name)){
6092			snprintf(posterr_msg,ERR_MSG_SIZE,
6093				"NVRAM variable:%s not found in uploaded file<br>",
6094								constraint_vars[index].name);
6095			goto do_nvramul_post_cleanup0;
6096		}
6097
6098		/*Move past separator*/
6099		ptr = &name[strlen(constraint_vars[index].name) + 1] ;
6100
6101		/* Ignore last character which is a \n */
6102		comparesize = strlen(ptr) -1;
6103
6104		/* If the primary match fails try for the secomdary matches */
6105		if (strncmp(ptr,var,comparesize)){
6106		int sec_fail=0;
6107
6108			/* If partial march is defined match altval pattern against
6109			   file and image values*/
6110			if (constraint_vars[index].flags & NVRAM_CONS_PARTIAL_MATCH){
6111				sec_fail=( !strstr(ptr,constraint_vars[index].altval) &&
6112							!strstr(var,constraint_vars[index].altval));
6113			}
6114			else if (constraint_vars[index].flags & NVRAM_CONS_ALT_MATCH){
6115				sec_fail=(strncmp(ptr,constraint_vars[index].altval,comparesize));
6116			}
6117			else sec_fail =1;
6118
6119		if (sec_fail){
6120			snprintf(posterr_msg,ERR_MSG_SIZE,
6121				"NVRAM constraint mismatch FILE:<b>%s=%s</b>  IMAGE:<b>%s=%s</b><br>",
6122					constraint_vars[index].name,ptr,constraint_vars[index].name,var);
6123			goto do_nvramul_post_cleanup0;
6124			}
6125		}
6126
6127	}
6128
6129	/* Process the NVRAM payload
6130	 *
6131	 * Remove the carriage returns at the end of the NVRAM variables
6132	 *
6133	*/
6134
6135	cur_entry = NVRAM_HEADER_LINECOUNT(nvram_file_header) + NVRAM_HEADER_LINECOUNT(constraint_vars);
6136
6137	slen=0;
6138	for (index = cur_entry ;(index < numlines) && *name; index++,name += slen + 1){
6139		int offset;
6140		char *ptr=NULL;
6141		char *varname=NULL;
6142		char *myptr=NULL;
6143		struct variable *v=NULL;
6144
6145		offset = index * NVRAM_MAX_STRINGSIZE;
6146
6147		/* The length of the actual var must be saved here as the subsequent
6148		 * manipulation using strsep() changes the string buffer.
6149		 * This to ensure that the buffer (tmpbuf->buf) is correctly procesed
6150		 * This buffer separates the individual AVPs using a null character
6151		 */
6152
6153		slen =strlen(name);
6154		ptr = name;
6155
6156		/* Remove the CR at the end of the string */
6157		ptr[slen-1] = '\0';
6158
6159		/* Look for tag that indicates that the value is encrypted */
6160		if  (*ptr==NVRAM_ENCTAG){
6161			char buf[NVRAM_MAX_STRINGSIZE];
6162			int bufsize = sizeof(buf);
6163			char *varname=NULL;
6164
6165			varname=strsep(&ptr, "=");
6166
6167			/* Increment pointer to move past tag */
6168			varname++;
6169
6170			if (!decrypt_var(varname,ptr,strlen(ptr),buf,&bufsize,key,sizeof(key))){
6171				snprintf(posterr_msg,ERR_MSG_SIZE,
6172					"Error decrypting value %s at line %d<br>",ptr,index);
6173				goto do_nvramul_post_cleanup0;
6174			}
6175
6176		snprintf(name,NVRAM_MAX_STRINGSIZE,"%s=%s",varname,buf);
6177
6178		}
6179
6180		/*
6181		   Write out NVRAM variables.
6182		*/
6183
6184		myptr = name;
6185		varname=strsep(&myptr, "=");
6186
6187		v=get_var_handle(varname);
6188
6189		/* Restore only those NVRAM vars in the validation table
6190		   Ignore those with the obvious flag set
6191		*/
6192
6193		if (!v)
6194			continue;
6195
6196		if (v->ezc_flags & NVRAM_IGNORE)
6197			continue;
6198
6199		if (nvram_set(varname,myptr))
6200			goto do_nvramul_post_cleanup0;
6201
6202	}
6203
6204	nvram_commit();
6205
6206	/* We are done */
6207	ret_code = 0;
6208
6209do_nvramul_post_cleanup0:
6210	/* Clear up any outstanding stuff */
6211	/* Slurp anything remaining in the request */
6212	while (len--)
6213		(void) fgetc(stream);
6214
6215	if (tmpbuf) free(tmpbuf);
6216
6217	return;
6218}
6219
6220static void
6221do_nvramul_cgi(char *url, FILE *stream)
6222{
6223	assert(stream);
6224	assert(url);
6225
6226	websHeader(stream);
6227	websWrite(stream, (char_t *) apply_header);
6228
6229	if (ret_code){
6230		websWrite(stream, "Error during NVRAM upload<br>");
6231		if (*posterr_msg){
6232			websWrite(stream, posterr_msg);
6233			memset(posterr_msg,0,ERR_MSG_SIZE);
6234		}
6235
6236	} else websWrite(stream, "NVRAM upload complete.<br>Rebooting....<br>");
6237
6238	websWrite(stream, (char_t *) apply_footer, "firmware.asp");
6239	websFooter(stream);
6240	websDone(stream, 200);
6241
6242	/* Reboot if successful */
6243	if (ret_code == 0)
6244		sys_reboot();
6245
6246}
6247
6248/*
6249   This routine validates and formats the NVRAM variable into the file output format.
6250   If the variable is not in the monster V-block or its allowed multi instance variants
6251   it is dropped
6252
6253   Returns number of characters printed or -1 on error
6254*/
6255static int
6256save_nvram_var(char *name, char *var_val,char *buf, int buflen,char *key, int keylen)
6257{
6258	char tmp[NVRAM_MAX_STRINGSIZE];
6259	int len=sizeof(tmp);
6260	int retval=0;
6261	struct variable *v = NULL;
6262
6263	assert(name);
6264	assert(buf);
6265	assert(key);
6266	assert(buflen);
6267	assert(keylen);
6268
6269
6270	/* If var_val is null, this forces the variable to be unset when the file is uploaded
6271	  If the variable is supposed to be encrypted but is null, skip it and do not
6272	  mark the string as encrypted.
6273
6274	  If var_val is null the variable does not exist. Skip and do not save in that case.
6275	*/
6276
6277	v = get_var_handle(name);
6278
6279	if (!v)
6280		return 0;
6281
6282	if (v->ezc_flags & NVRAM_IGNORE)
6283		return 0;
6284
6285	if (var_val) {
6286			if (strlen(var_val) > NVRAM_MAX_STRINGSIZE){
6287				cprintf("get_nvram_var():String too long Len=%d String=%s\n",	strlen(var_val) ,var_val);
6288				return -1;
6289			}
6290
6291			if ( (v->ezc_flags & NVRAM_ENCRYPT) && (*var_val) ){
6292				var_val = encrypt_var(name,var_val,strlen(var_val),tmp,&len,key,keylen);
6293
6294				if (!var_val){
6295					cprintf("get_nvram_var():Error encrypting %s\n",name);
6296					return -1;
6297				}
6298
6299				retval=snprintf(buf,buflen,"%c%s=%s\n",
6300						NVRAM_ENCTAG,
6301						(char_t *)name,
6302						(char_t *)var_val);
6303		    } else retval=snprintf(buf,buflen,"%s=%s\n",
6304						(char_t *)name,
6305						(char_t *)var_val);
6306	}
6307	return retval;
6308}
6309
6310/* This is the cgi handler for the NVRAM download function
6311 * Inputs: -url of the calling file (not used but HTTPD expects this form)
6312 *         -Pointer to the post buffer
6313 *
6314 *
6315 *  Returns: None
6316*/
6317static void
6318do_nvramdl_cgi(char *url, FILE *stream)
6319{
6320	char checksum[NVRAM_SHA1BUFSIZE];
6321	char passphrase[]=NVRAM_PASSPHRASE;
6322	char salt[NVRAM_SALTSIZE];
6323	char key[NVRAM_FILEKEYSIZE];
6324	int entries;
6325	char tmp[NVRAM_MAX_STRINGSIZE],tmp1[NVRAM_MAX_STRINGSIZE];
6326	char tmp_buf[NVRAM_MAX_STRINGSIZE];
6327	char *buf=NULL;
6328	char *var_val=NULL;
6329	char *var_name=NULL;
6330	char *name=NULL;
6331	char *ptr=NULL;
6332	int index;
6333	int retval;
6334	upload_constraints constraint_vars [] = NVRAM_CONSTRAINT_VARS;
6335	char nvram_file_header[][NVRAM_MAX_STRINGSIZE/2] = NVRAM_FILEHEADER;
6336	struct pb {
6337			char header[NVRAM_HEADER_LINECOUNT(nvram_file_header)][NVRAM_MAX_STRINGSIZE];
6338			char buf[NVRAM_SPACE];
6339		 } *post_buf=NULL;
6340
6341	int offset = 0;
6342
6343	assert(stream);
6344
6345	post_buf = (struct pb *)malloc(sizeof (struct pb));
6346
6347	if (!post_buf) {
6348		cprintf("do_nvramdl_cgi():Error allocating %d bytes for post_buf\n",
6349						sizeof (struct pb));
6350		goto do_nvramdl_cgi_error;
6351	}
6352
6353	buf = (char *)malloc(NVRAM_SPACE);
6354
6355	if (!buf) {
6356		cprintf("do_nvramdl_cgi():Error allocating %d bytes for buf\n",
6357						NVRAM_SPACE);
6358		goto do_nvramdl_cgi_error;
6359	}
6360
6361	memset (post_buf,0,sizeof(struct pb));
6362	memset (buf,0,NVRAM_SPACE);
6363
6364	assert(stream);
6365
6366	entries = NVRAM_HEADER_LINECOUNT(nvram_file_header);
6367	memset(tmp_buf,0,sizeof(tmp_buf));
6368
6369	memset(salt,0,sizeof(salt));
6370
6371	srand(time((time_t *)NULL));
6372	for (index = 0 ; index < 30 ; index ++) rand();
6373	index =rand();
6374	memcpy(&salt[sizeof(index)],&index,sizeof(index));
6375	for (index = 0 ; index < 30 ; index ++) rand();
6376	index =rand();
6377	memcpy(&salt,&index,sizeof(index));
6378
6379	/*
6380	   The first entry of the file is the number of variables
6381	   The second entry is the offset to the start of the NVRAM variables
6382	   The third entry is the SHA1 checksum
6383	*/
6384
6385	/* PopulateHeader info */
6386	offset = 0;
6387	for  (index =0 ;*constraint_vars[index].name;index++){
6388		entries++;
6389		var_val=constraint_vars[index].get(constraint_vars[index].name);
6390		snprintf(tmp_buf,NVRAM_MAX_STRINGSIZE,"%s=%s\n",
6391					constraint_vars[index].name,
6392					(var_val) ? var_val : "unknown");
6393		if (!offset) cprintf("Post_buf address = %p\n",&post_buf->buf[offset]);
6394		offset = add_string(&post_buf->buf[offset],tmp_buf,offset,sizeof(struct pb));
6395		if (offset < 0){
6396			cprintf("httpd: Error Adding NVRAM header info.\n");
6397			goto do_nvramdl_cgi_error;
6398		}
6399	};
6400
6401	memset(tmp,0,sizeof(tmp));
6402
6403	fPRF(passphrase,strlen(passphrase),NULL,0,
6404			(unsigned char*)salt,sizeof(salt),key,sizeof(key));
6405
6406	/* Plug in filler for checksum */
6407	snprintf(post_buf->header[NVRAM_CHECKSUM_LINENUM],NVRAM_MAX_STRINGSIZE,"%s\n",NVRAM_CHECKSUM_FILLER);
6408	/* Grab the NVRAM buffer */
6409
6410	nvram_getall(buf, NVRAM_SPACE);
6411
6412	for(name = buf; *name; name += strlen(name) + 1){
6413		var_val =tmp;
6414		strncpy(tmp,name,sizeof(tmp));
6415		var_name=strsep(&var_val,"=");
6416		retval = save_nvram_var(var_name,var_val,tmp_buf,
6417						sizeof(tmp_buf),key,sizeof(key));
6418
6419		if (retval <0){
6420			cprintf("httpd: Error Adding NVRAM variable info.\n");
6421			goto do_nvramdl_cgi_error;
6422		};
6423
6424		if  (retval > 0 ) {
6425			entries++;
6426			offset = add_string(&post_buf->buf[offset],tmp_buf,offset,sizeof(struct pb));
6427			if (offset < 0){
6428				cprintf("httpd: Error Adding NVRAM variable info.\n");
6429				goto do_nvramdl_cgi_error;
6430			}
6431		};
6432
6433		if (offset > NVRAM_SPACE) {
6434			cprintf("httpd: NVRAM_SPACE of %d (%d) exceeded\n",NVRAM_SPACE,offset);
6435			goto do_nvramdl_cgi_error;
6436		};
6437	}
6438
6439
6440	/* Add the header info */
6441	snprintf(post_buf->header[NVRAM_LINECOUNT_LINENUM],NVRAM_MAX_STRINGSIZE,"%s=%d\n",
6442					nvram_file_header[NVRAM_LINECOUNT_LINENUM],entries);
6443
6444	/*Generate the hash */
6445
6446	memset(checksum,0,sizeof(checksum));
6447	hmac_sha1((unsigned char*)post_buf,sizeof(struct pb),key,sizeof(key),checksum);
6448
6449	memcpy(tmp,checksum,NVRAM_HASHSIZE);
6450	memcpy(&tmp[NVRAM_HASHSIZE],salt,NVRAM_SALTSIZE);
6451
6452	ptr = b64_encode(tmp,NVRAM_FILECHKSUM_SIZE, buf, NVRAM_SPACE );
6453
6454	if (!ptr){
6455		cprintf("do_nvramdl_cgi():Error performing base-64 encode of NVRAM checksum.\n");
6456		goto do_nvramdl_cgi_error;
6457	}
6458
6459	strncpy(tmp1,ptr,NVRAM_MAX_STRINGSIZE);
6460
6461	snprintf(post_buf->header[NVRAM_CHECKSUM_LINENUM],NVRAM_MAX_STRINGSIZE,"%s=%s\n",
6462					nvram_file_header[NVRAM_CHECKSUM_LINENUM],tmp1);
6463	/* Write out header */
6464	for (index =0; index < NVRAM_HEADER_LINECOUNT(nvram_file_header) ; index ++)
6465		websWrite(stream, "%s", post_buf->header[index]);
6466
6467	/* Write out rest of file */
6468
6469	for(name = post_buf->buf; *name; name += strlen(name) + 1){
6470		/*cprintf("Val->%s\n",name);*/
6471		websWrite(stream, "%s", name);
6472		};
6473
6474do_nvramdl_cgi_error:
6475
6476	if (post_buf)
6477		free(post_buf);
6478	if (buf)
6479		free(buf);
6480
6481	websDone(stream, 200);
6482
6483	return;
6484}
6485
6486
6487/*
6488 * This routine takes the cipher text ctext and produces the plaintext ptext
6489 * using the provided key.
6490 *
6491 * This routine accepts the cipher text  in the MIME Base64 format.
6492 *
6493 * The plain text is 8 bytes less than the ciphertext
6494 */
6495static char*
6496decrypt_var(char *varname,char *ctext, int ctext_len, char *ptext, int *ptext_len,char *key, int keylen)
6497{
6498	unsigned char tmp[NVRAM_MAX_STRINGSIZE];
6499	int len;
6500	char *end=NULL;
6501
6502	assert(ptext);
6503	assert(ctext);
6504	assert(ptext_len);
6505	assert(key);
6506	if (keylen < 1 ) return NULL;
6507
6508	if (ctext_len > NVRAM_MAX_STRINGSIZE){
6509		cprintf("decrypt_var():Encrypted string is too long MAXSTRINGSIZE=%d Strlen=%d\n",
6510							NVRAM_MAX_STRINGSIZE,ctext_len);
6511	}
6512
6513	/* Cipher text must be more than 8 chars for this aes_unwrap() routine to work*/
6514	if (ctext_len < 8) return NULL;
6515
6516	len=b64_decode(ctext,tmp,NVRAM_MAX_STRINGSIZE);
6517
6518	if (!len) return NULL;
6519
6520	if (aes_unwrap(keylen,key,len,tmp,ptext)) return NULL;
6521
6522	*ptext_len = len - 8;
6523
6524	end = strstr(ptext,varname);
6525
6526	if (end)
6527		(*end)= '\0';
6528	else
6529		return NULL;
6530
6531	return ptext;
6532}
6533/*
6534 * This routine takes the plaintext text ptext and produces the ciphertext ctext
6535 * using the provided key.
6536 *
6537 * It accepts the plaintext in binary form and produces ciphertext in MIME Base64 format.
6538 *
6539 *
6540 */
6541static char*
6542encrypt_var(char *varname,char *ptext, int ptext_len, char *ctext, int *ctext_len,char *key, int keylen)
6543{
6544	unsigned char tmp[NVRAM_MAX_STRINGSIZE];
6545	char *buf=NULL;
6546	int newlen;
6547	int varname_len;
6548
6549	assert(ptext);
6550	assert(ctext);
6551	assert(ctext_len);
6552	assert(key);
6553	if (keylen < 1 ) return NULL;
6554	if (ptext_len < 1) return NULL;
6555
6556	varname_len = strlen (varname);
6557
6558	 /* Include the NULL at the end */
6559	newlen = ptext_len + varname_len + 1;
6560	/* Align the incoming buffer to AES block length boundaries */
6561	if (newlen % AES_BLOCK_LEN)
6562		newlen = (1 + newlen /AES_BLOCK_LEN ) * AES_BLOCK_LEN;
6563
6564	/* Do a string length check. When the binary string is base-64 encoded
6565	   it becomes 30% larger as every 3 bytes are represented by 4 ascii
6566	   characters */
6567
6568	if ( (4*(1+(newlen+8)/3)) > NVRAM_MAX_STRINGSIZE )
6569	{
6570		cprintf("encrypt_var():The encrypted string is too long. MAXSTRINGSIZE=%d Strlen=%d\n",
6571				NVRAM_MAX_STRINGSIZE,(4*(1+(newlen+8)/3)));
6572		return NULL;
6573	}
6574
6575	buf  = malloc (newlen);
6576	if (!buf) return NULL;
6577	memset(buf,0,newlen);
6578	memcpy(buf,ptext,ptext_len);
6579	memcpy(buf + ptext_len,varname,varname_len);
6580
6581	if (aes_wrap(keylen,key,newlen,buf,ctext)){
6582		if (buf) free(buf);
6583	 	return NULL;
6584	};
6585
6586	if (buf) free(buf);
6587
6588	buf = b64_encode(ctext,newlen+8,tmp,NVRAM_MAX_STRINGSIZE-(ptext_len + 1));
6589
6590	if (buf){
6591		strncpy(ctext,buf,NVRAM_MAX_STRINGSIZE);
6592		*ctext_len = strlen(ctext) ;
6593		return ctext;
6594	}else{
6595		cprintf("encrypt_var():base-64 encode error\n");
6596		*ctext_len = 0;
6597		return NULL;
6598	}
6599}
6600
6601
6602static void
6603do_wireless_asp(char *url, FILE *stream)
6604{
6605	char *path=NULL, *query=NULL;
6606
6607	assert(stream);
6608	assert(url);
6609
6610	/* Parse path */
6611	query = url;
6612	path = strsep(&query, "?") ? : url;
6613
6614	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
6615
6616	/* Reset CGI */
6617	init_cgi(NULL);
6618}
6619
6620static void
6621do_security_asp(char *url, FILE *stream)
6622{
6623	char *path=NULL, *query=NULL;
6624
6625	assert(stream);
6626	assert(url);
6627
6628	/* Parse path */
6629	query = url;
6630	path = strsep(&query, "?") ? : url;
6631
6632	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
6633
6634	/* Reset CGI */
6635	init_cgi(NULL);
6636}
6637
6638static void
6639do_internal_asp(char *url, FILE *stream)
6640{
6641	char *path=NULL, *query=NULL;
6642
6643	assert(stream);
6644	assert(url);
6645
6646	/* Parse path */
6647	query = url;
6648	path = strsep(&query, "?") ? : url;
6649
6650	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
6651
6652	/* Reset CGI */
6653	init_cgi(NULL);
6654}
6655
6656#ifdef __CONFIG_NAT__
6657static void
6658do_wan_asp(char *url, FILE *stream)
6659{
6660	char *path=NULL, *query=NULL;
6661
6662	assert(stream);
6663	assert(url);
6664
6665	/* Parse path */
6666	query = url;
6667	path = strsep(&query, "?") ? : url;
6668
6669	wan_asp(stream, NULL, NULL, 0, url, path, query);
6670
6671	/* Reset CGI */
6672	init_cgi(NULL);
6673}
6674#endif	/* __CONFIG_NAT__ */
6675
6676struct mime_handler mime_handlers[] = {
6677#ifdef __CONFIG_NAT__
6678	{ "wan.asp", "text/html", no_cache, do_apply_post, do_wan_asp, do_auth },
6679#endif	/* __CONFIG_NAT__ */
6680	{ "wireless.asp", "text/html", no_cache, do_apply_post, do_wireless_asp, do_auth },
6681	{ "security.asp", "text/html", no_cache, do_apply_post, do_security_asp, do_auth },
6682	{ "internal.asp", "text/html", no_cache, do_apply_post, do_internal_asp, do_auth },
6683#ifdef __CONFIG_EZC__
6684	{ "ezconfig.asp", "text/html", ezc_version, do_apply_ezconfig_post, do_ezconfig_asp, do_auth },
6685#endif /* __CONFIG_EZC__ */
6686	{ "**.asp", "text/html", no_cache, NULL, do_ej, do_auth },
6687	{ "**.css", "text/css", NULL, NULL, do_file, do_auth },
6688	{ "**.gif", "image/gif", NULL, NULL, do_file, do_auth },
6689	{ "**.jpg", "image/jpeg", NULL, NULL, do_file, do_auth },
6690	{ "**.js", "text/javascript", NULL, NULL, do_file, do_auth },
6691	{ "apply.cgi*", "text/html", no_cache, do_apply_post, do_apply_cgi, do_auth },
6692	{ "upgrade.cgi*", "text/html", no_cache, do_upgrade_post, do_upgrade_cgi, do_auth },
6693	/* set MIME type to NULL to override the one built into the webserver. download_hdr
6694	   defines its content type
6695	*/
6696	{ "nvramdl.cgi*", NULL, download_hdr, NULL, do_nvramdl_cgi, do_auth },
6697	{ "nvramul.cgi*", NULL, "text/html", do_nvramul_post,do_nvramul_cgi , do_auth },
6698	{ NULL, NULL, NULL, NULL, NULL, NULL }
6699};
6700
6701struct ej_handler ej_handlers[] = {
6702	{ "nvram_get", ej_nvram_get },
6703	{ "nvram_match", ej_nvram_match },
6704	{ "nvram_invmatch", ej_nvram_invmatch },
6705	{ "nvram_list", ej_nvram_list },
6706	{ "nvram_inlist", ej_nvram_inlist },
6707	{ "nvram_invinlist", ej_nvram_invinlist },
6708#ifdef __CONFIG_NAT__
6709	{ "wan_list", ej_wan_list },
6710	{ "wan_iflist", ej_wan_iflist },
6711	{ "wan_route", ej_wan_route },
6712	{ "wan_link", ej_wan_link },
6713	{ "wan_lease", ej_wan_lease },
6714	{ "filter_client", ej_filter_client },
6715	{ "forward_port", ej_forward_port },
6716	{ "autofw_port", ej_autofw_port },
6717#endif	/*  __CONFIG_NAT__ */
6718	{ "localtime", ej_localtime },
6719	{ "sysuptime", ej_sysuptime },
6720	{ "dumplog", ej_dumplog },
6721	{ "syslog", ej_syslog },
6722	{ "wl_list", ej_wl_list },
6723	{ "wl_guest_ssid", ej_wl_guest_ssid},
6724	{ "wl_phytypes", ej_wl_phytypes },
6725	{ "wl_radioid", ej_wl_radioid },
6726	{ "wl_corerev", ej_wl_corerev },
6727	{ "wl_cur_channel", ej_wl_cur_channel },
6728	{ "wl_cur_phytype", ej_wl_cur_phytype },
6729	{ "wl_cur_country", ej_wl_cur_country },
6730	{ "wl_country_list", ej_wl_country_list },
6731	{ "wl_channel_list", ej_wl_channel_list },
6732	{ "wl_auth_list", ej_wl_auth_list },
6733	{ "wl_mode_list", ej_wl_mode_list },
6734	{ "wl_inlist", ej_wl_inlist },
6735	{ "wl_wds_status", ej_wl_wds_status },
6736	{ "wl_radio_roam_option", ej_wl_radio_roam_option},
6737	{ "wl_radio_roam_option", ej_wl_radio_roam_option},
6738	{ "wl_ure_list", ej_ure_list },
6739	{ "wl_ure_enabled", ej_ure_enabled },
6740	{ "ses_button_display", ej_ses_button_display},
6741	{ "ses_cl_button_display", ej_ses_cl_button_display},
6742	{ "lan_route", ej_lan_route },
6743	{ "lan_guest_iflist", ej_lan_guest_iflist },
6744	{ "lan_leases", ej_lan_leases },
6745	{ "asp_list", ej_asp_list },
6746	{ "wme_match_op", ej_wme_match_op },
6747	{ NULL, NULL }
6748};
6749
6750#endif /* !WEBS */
6751
6752/*
6753 * Country names and abbreviations from ISO 3166
6754 */
6755country_name_t country_names[] = {
6756
6757{"COUNTRY Z1",		 "Z1"},
6758{"COUNTRY Z2",		 "Z2"},
6759{"AFGHANISTAN",		 "AF"},
6760{"ALBANIA",		 "AL"},
6761{"ALGERIA",		 "DZ"},
6762{"AMERICAN SAMOA", 	 "AS"},
6763{"ANDORRA",		 "AD"},
6764{"ANGOLA",		 "AO"},
6765{"ANGUILLA",		 "AI"},
6766{"ANTARCTICA",		 "AQ"},
6767{"ANTIGUA AND BARBUDA",	 "AG"},
6768{"ARGENTINA",		 "AR"},
6769{"ARMENIA",		 "AM"},
6770{"ARUBA",		 "AW"},
6771{"ASCENSION ISLAND",		 "AC"},
6772{"ASHMORE AND BARBUDA",		 "AG"},
6773{"AUSTRALIA",		 "AU"},
6774{"AUSTRIA",		 "AT"},
6775{"AZERBAIJAN",		 "AZ"},
6776{"BAHAMAS",		 "BS"},
6777{"BAHRAIN",		 "BH"},
6778{"BAKER ISLAND",		 "Z2"},
6779{"BANGLADESH",		 "BD"},
6780{"BARBADOS",		 "BB"},
6781{"BELARUS",		 "BY"},
6782{"BELGIUM",		 "BE"},
6783{"BELIZE",		 "BZ"},
6784{"BENIN",		 "BJ"},
6785{"BERMUDA",		 "BM"},
6786{"BHUTAN",		 "BT"},
6787{"BOLIVIA",		 "BO"},
6788{"BOSNIA AND HERZEGOVINA","BA"},
6789{"BOTSWANA",		 "BW"},
6790{"BOUVET ISLAND",	 "BV"},
6791{"BRAZIL",		 "BR"},
6792{"BRITISH INDIAN OCEAN TERRITORY", 	"IO"},
6793{"BRUNEI DARUSSALAM",	 "BN"},
6794{"BULGARIA",		 "BG"},
6795{"BURKINA FASO",	 "BF"},
6796{"BURUNDI",		 "BI"},
6797{"CAMBODIA",		 "KH"},
6798{"CAMEROON",		 "CM"},
6799{"CANADA",		 "CA"},
6800{"CAPE VERDE",		 "CV"},
6801{"CAYMAN ISLANDS",	 "KY"},
6802{"CENTRAL AFRICAN REPUBLIC","CF"},
6803{"CHAD",		 "TD"},
6804{"CHANNEL ISLANDS",		 "Z1"},
6805{"CHILE",		 "CL"},
6806{"CHINA",		 "CN"},
6807{"CHRISTMAS ISLAND",	 "CX"},
6808{"CLIPPERTON ISLAND",	 "CP"},
6809{"COCOS (KEELING) ISLANDS","CC"},
6810{"COLOMBIA",		 "CO"},
6811{"COMOROS",		 "KM"},
6812{"CONGO",		 "CG"},
6813{"CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD"},
6814{"COOK ISLANDS",	 "CK"},
6815{"COSTA RICA",		 "CR"},
6816{"COTE D'IVOIRE",	 "CI"},
6817{"CROATIA",		 "HR"},
6818{"CUBA",		 "CU"},
6819{"CYPRUS",		 "CY"},
6820{"CZECH REPUBLIC",	 "CZ"},
6821{"DENMARK",		 "DK"},
6822{"DJIBOUTI",		 "DJ"},
6823{"DOMINICA",		 "DM"},
6824{"DOMINICAN REPUBLIC", 	 "DO"},
6825{"ECUADOR",		 "EC"},
6826{"EGYPT",		 "EG"},
6827{"EL SALVADOR",		 "SV"},
6828{"EQUATORIAL GUINEA",	 "GQ"},
6829{"ERITREA",		 "ER"},
6830{"ESTONIA",		 "EE"},
6831{"ETHIOPIA",		 "ET"},
6832{"FALKLAND ISLANDS (MALVINAS)",	"FK"},
6833{"FAROE ISLANDS",	 "FO"},
6834{"FIJI",		 "FJ"},
6835{"FINLAND",		 "FI"},
6836{"FRANCE",		 "FR"},
6837{"FRENCH GUIANA",	 "GF"},
6838{"FRENCH POLYNESIA",	 "PF"},
6839{"FRENCH SOUTHERN TERRITORIES",	 "TF"},
6840{"GABON",		 "GA"},
6841{"GAMBIA",		 "GM"},
6842{"GEORGIA",		 "GE"},
6843{"GERMANY",		 "DE"},
6844{"GHANA",		 "GH"},
6845{"GIBRALTAR",		 "GI"},
6846{"GREECE",		 "GR"},
6847{"GREENLAND",		 "GL"},
6848{"GRENADA",		 "GD"},
6849{"GUADELOUPE",		 "GP"},
6850{"GUAM",		 "GU"},
6851{"GUANTANAMO BAY",		 "Z1"},
6852{"GUATEMALA",		 "GT"},
6853{"GUERNSEY",		 "GG"},
6854{"GUINEA",		 "GN"},
6855{"GUINEA-BISSAU",	 "GW"},
6856{"GUYANA",		 "GY"},
6857{"HAITI",		 "HT"},
6858{"HEARD ISLAND AND MCDONALD ISLANDS",	"HM"},
6859{"HOLY SEE (VATICAN CITY STATE)", 	"VA"},
6860{"HONDURAS",		 "HN"},
6861{"HONG KONG",		 "HK"},
6862{"HOWLAND ISLAND",		 "Z2"},
6863{"HUNGARY",		 "HU"},
6864{"ICELAND",		 "IS"},
6865{"INDIA",		 "IN"},
6866{"INDONESIA",		 "ID"},
6867{"IRAN, ISLAMIC REPUBLIC OF",		"IR"},
6868{"IRAQ",		 "IQ"},
6869{"IRELAND",		 "IE"},
6870{"ISRAEL",		 "IL"},
6871{"ITALY",		 "IT"},
6872{"JAMAICA",		 "JM"},
6873{"JAN MAYEN AMAICA",		 "Z1"},
6874{"JAPAN",		 "JP"},
6875{"JAPAN_1",		 "J1"},
6876{"JAPAN_2",		 "J2"},
6877{"JAPAN_3",		 "J3"},
6878{"JAPAN_4",		 "J4"},
6879{"JAPAN_5",		 "J5"},
6880{"JAPAN_6",		 "J6"},
6881{"JAPAN_7",		 "J7"},
6882{"JAPAN_8",		 "J8"},
6883{"JARVIS ISLAND",		 "Z2"},
6884{"JERSEY",		 "JE"},
6885{"JOHNSTON ATOLL",		 "Z2"},
6886{"JORDON",		 "JO"},
6887{"KAZAKHSTAN",		 "KZ"},
6888{"KENYA",		 "KE"},
6889{"KINGMAN REEF",		 "Z2"},
6890{"KIRIBATI",		 "KI"},
6891{"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP"},
6892{"KOREA, REPUBLIC OF",	 "KR"},
6893{"KUWAIT",		 "KW"},
6894{"KYRGYZSTAN",		 "KG"},
6895{"LAO PEOPLE'S DEMOCRATIC REPUBLIC", 	"LA"},
6896{"LATVIA",		 "LV"},
6897{"LEBANON",		 "LB"},
6898{"LESOTHO",		 "LS"},
6899{"LIBERIA",		 "LR"},
6900{"LIBYAN ARAB JAMAHIRIYA","LY"},
6901{"LIECHTENSTEIN",	 "LI"},
6902{"LITHUANIA",		 "LT"},
6903{"LUXEMBOURG",		 "LU"},
6904{"MACAO",		 "MO"},
6905{"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF",	 "MK"},
6906{"MADAGASCAR",		 "MG"},
6907{"MALAWI",		 "MW"},
6908{"MALAYSIA",		 "MY"},
6909{"MALDIVES",		 "MV"},
6910{"MALI",		 "ML"},
6911{"MALTA",		 "MT"},
6912{"MAN, ISLE OF",		 "IM"},
6913{"MARSHALL ISLANDS",	 "MH"},
6914{"MARTINIQUE",		 "MQ"},
6915{"MAURITANIA",		 "MR"},
6916{"MAURITIUS",		 "MU"},
6917{"MAYOTTE",		 "YT"},
6918{"MEXICO",		 "MX"},
6919{"MICRONESIA, FEDERATED STATES OF", 	"FM"},
6920{"MIDWAY ISLANDS", 	"Z2"},
6921{"MOLDOVA, REPUBLIC OF", "MD"},
6922{"MONACO",		 "MC"},
6923{"MONGOLIA",		 "MN"},
6924{"MONTSERRAT",		 "MS"},
6925{"MOROCCO",		 "MA"},
6926{"MOZAMBIQUE",		 "MZ"},
6927{"MYANMAR",		 "MM"},
6928{"NAMIBIA",		 "NA"},
6929{"NAURU",		 "NR"},
6930{"NEPAL",		 "NP"},
6931{"NETHERLANDS",		 "NL"},
6932{"NETHERLANDS ANTILLES", "AN"},
6933{"NEW CALEDONIA",	 "NC"},
6934{"NEW ZEALAND",		 "NZ"},
6935{"NICARAGUA",		 "NI"},
6936{"NIGER",		 "NE"},
6937{"NIGERIA",		 "NG"},
6938{"NIUE",		 "NU"},
6939{"NORFOLK ISLAND",	 "NF"},
6940{"NORTHERN MARIANA ISLANDS","MP"},
6941{"NORWAY",		 "NO"},
6942{"OMAN",		 "OM"},
6943{"PAKISTAN",		 "PK"},
6944{"PALAU",		 "PW"},
6945{"PALESTINIAN TERRITORY, OCCUPIED", 	"PS"},
6946{"PALMYRA ATOLL", 	"Z2"},
6947{"PANAMA",		 "PA"},
6948{"PAPUA NEW GUINEA",	 "PG"},
6949{"PARAGUAY",		 "PY"},
6950{"PERU",		 "PE"},
6951{"PHILIPPINES",		 "PH"},
6952{"PITCAIRN",		 "PN"},
6953{"POLAND",		 "PL"},
6954{"PORTUGAL",		 "PT"},
6955{"PUERTO RICO",		 "PR"},
6956{"QATAR",		 "QA"},
6957{"REUNION",		 "RE"},
6958{"ROMANIA",		 "RO"},
6959{"ROTA ISLAND",		 "Z1"},
6960{"RUSSIAN FEDERATION",	 "RU"},
6961{"RWANDA",		 "RW"},
6962{"SAINT HELENA",	 "SH"},
6963{"SAINT KITTS AND NEVIS","KN"},
6964{"SAINT LUCIA",		 "LC"},
6965{"SAINT PIERRE AND MIQUELON",	 	"PM"},
6966{"SAINT VINCENT AND THE GRENADINES", 	"VC"},
6967{"SAIPAN", 	"Z1"},
6968{"SAMOA",		 "WS"},
6969{"SAN MARINO",		 "SM"},
6970{"SAO TOME AND PRINCIPE","ST"},
6971{"SAUDI ARABIA",	 "SA"},
6972{"SENEGAL",		 "SN"},
6973{"SEYCHELLES",		 "SC"},
6974{"SIERRA LEONE",	 "SL"},
6975{"SINGAPORE",		 "SG"},
6976{"SLOVAKIA",		 "SK"},
6977{"SLOVENIA",		 "SI"},
6978{"SOLOMON ISLANDS",	 "SB"},
6979{"SOMALIA",		 "SO"},
6980{"SOUTH AFRICA",	 "ZA"},
6981{"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS"},
6982{"SPAIN",		 "ES"},
6983{"SRI LANKA",		 "LK"},
6984{"SUDAN",		 "SD"},
6985{"SURINAME",		 "SR"},
6986{"SVALBARD AND JAN MAYEN","SJ"},
6987{"SWAZILAND",		 "SZ"},
6988{"SWEDEN",		 "SE"},
6989{"SWITZERLAND",		 "CH"},
6990{"SYRIAN ARAB REPUBLIC", "SY"},
6991{"TAIWAN, PROVINCE OF CHINA", 		"TW"},
6992{"TAJIKISTAN",		 "TJ"},
6993{"TANZANIA, UNITED REPUBLIC OF",	"TZ"},
6994{"THAILAND",		 "TH"},
6995{"TIMOR-LESTE",		 "TL"},
6996{"TOGO",		 "TG"},
6997{"TOKELAU",		 "TK"},
6998{"TONGA",		 "TO"},
6999{"TRINIDAD AND TOBAGO",	 "TT"},
7000{"TRISTAN DA CUNHA",	 "TA"},
7001{"TUNISIA",		 "TN"},
7002{"TURKEY",		 "TR"},
7003{"TURKMENISTAN",	 "TM"},
7004{"TURKS AND CAICOS ISLANDS",		"TC"},
7005{"TUVALU",		 "TV"},
7006{"UGANDA",		 "UG"},
7007{"UKRAINE",		 "UA"},
7008{"UNITED ARAB EMIRATES", "AE"},
7009{"UNITED KINGDOM",	 "GB"},
7010{"UNITED STATES",	 "US"},
7011{"UNITED STATES MINOR OUTLYING ISLANDS","UM"},
7012{"URUGUAY",		 "UY"},
7013{"UZBEKISTAN",		 "UZ"},
7014{"VANUATU",		 "VU"},
7015{"VENEZUELA",		 "VE"},
7016{"VIET NAM",		 "VN"},
7017{"VIRGIN ISLANDS, BRITISH", "VG"},
7018{"VIRGIN ISLANDS, U.S.", "VI"},
7019{"WALLIS AND FUTUNA",	 "WF"},
7020{"WESTERN SAHARA", 	 "EH"},
7021{"YEMEN",		 "YE"},
7022{"YUGOSLAVIA",		 "YU"},
7023{"ZAMBIA",		 "ZM"},
7024{"ZIMBABWE",		 "ZW"},
7025{"ALL",		 	 "ALL"},
7026{"RADAR CHANNELS",	 "RDR"},
7027{NULL, 			 NULL}
7028};
7029
7030