1/*
2 * Broadcom Home Gateway Reference Design
3 * Web Page Configuration Support Routines
4 *
5 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: broadcom.c 517676 2014-11-26 09:02:04Z $
19 */
20
21#ifdef WEBS
22#include <webs.h>
23#include <uemf.h>
24#include <ej.h>
25#else /* !WEBS */
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30#include <errno.h>
31#include <unistd.h>
32#include <limits.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <netdb.h>
39#include <assert.h>
40#include <httpd.h>
41#endif /* WEBS */
42
43
44/* Required for hash table headers*/
45#if defined(linux) || defined(__NetBSD__)
46/* Use SVID search */
47#define __USE_GNU
48#include <search.h>
49#elif defined(__ECOS)
50#include <search.h>
51#endif
52
53#include <typedefs.h>
54#include <proto/ethernet.h>
55#include <bcmparams.h>
56#include <bcmconfig.h>
57#include <bcmnvram.h>
58#include <bcmutils.h>
59#include <bcmdevs.h>
60#include <shutils.h>
61#include <wlif_utils.h>
62#include <netconf.h>
63#include <nvparse.h>
64#include <wlutils.h>
65#include <bcmcvar.h>
66#include <ezc.h>
67#include <opencrypto.h>
68#include <time.h>
69#include <epivers.h>
70#include "router_version.h"
71#include <proto/802.11.h>
72#include <proto/802.1d.h>
73#include <security_ipc.h>
74#ifdef __CONFIG_WPS__
75#include <wps_ui.h>
76#endif
77#ifdef PLC
78#include <dict.h>
79#endif
80
81
82
83#ifdef __CONFIG_HSPOT__
84#include "passpoint_gui.h"
85#endif /* __CONFIG_HSPOT__ */
86
87#include <etioctl.h>
88#if defined(__CONFIG_TREND_IQOS__) && defined(CONFIG_TREND_IQOS_ENABLED)
89#include "iqos_gui.h"
90#endif /* __CONFIG_TREND_IQOS__ && CONFIG_TREND_IQOS_ENABLED */
91
92#if defined(__CONFIG_VISUALIZATION__) && defined(CONFIG_VISUALIZATION_ENABLED)
93#include "vis_gui.h"
94#endif /* (__CONFIG_VISUALIZATION__) && (CONFIG_VISUALIZATION_ENABLED) */
95
96#define HTTP_ERR_BAD_REQUEST		400
97
98/* FILE-CSTYLED */
99int internal_init(void);
100
101static char * encrypt_var(char *varname, char *ctext, int ctext_len, char *ptext, int *ptext_len,char *key, int keylen);
102static char * decrypt_var(char *varname, char *ptext, int ptext_len, char *ctext, int *ctext_len,char *key, int keylen);
103char * make_wl_prefix(char *prefix,int prefix_size, int mode, char *ifname);
104static char * rfctime(const time_t *timep);
105static char * reltime(unsigned int seconds);
106static char * reltime_short(unsigned int seconds);
107static int wl_phytype_get(webs_t wp, int *phytype);
108#ifdef __CONFIG_WAPI_IAS__
109static int cert_revoke(webs_t wp, char *sn_str);
110#endif
111
112#define WAN_PREFIX(unit, prefix)	snprintf(prefix, sizeof(prefix), "wan%d_", unit)
113
114/* From wlc_rate.[ch] */
115#define MCS_TABLE_SIZE 33
116
117struct mcs_table_info {
118	uint phy_rate_20;
119	uint phy_rate_40;
120};
121
122/* rates are in units of Kbps */
123static const struct mcs_table_info mcs_rate_table[MCS_TABLE_SIZE] = {
124	{6500,   13500},	/* MCS  0 */
125	{13000,  27000},	/* MCS  1 */
126	{19500,  40500},	/* MCS  2 */
127	{26000,  54000},	/* MCS  3 */
128	{39000,  81000},	/* MCS  4 */
129	{52000,  108000},	/* MCS  5 */
130	{58500,  121500},	/* MCS  6 */
131	{65000,  135000},	/* MCS  7 */
132	{13000,  27000},	/* MCS  8 */
133	{26000,  54000},	/* MCS  9 */
134	{39000,  81000},	/* MCS 10 */
135	{52000,  108000},	/* MCS 11 */
136	{78000,  162000},	/* MCS 12 */
137	{104000, 216000},	/* MCS 13 */
138	{117000, 243000},	/* MCS 14 */
139	{130000, 270000},	/* MCS 15 */
140	{19500,  40500},	/* MCS 16 */
141	{39000,  81000},	/* MCS 17 */
142	{58500,  121500},	/* MCS 18 */
143	{78000,  162000},	/* MCS 19 */
144	{117000, 243000},	/* MCS 20 */
145	{156000, 324000},	/* MCS 21 */
146	{175500, 364500},	/* MCS 22 */
147	{195000, 405000},	/* MCS 23 */
148	{26000,  54000},	/* MCS 24 */
149	{52000,  108000},	/* MCS 25 */
150	{78000,  162000},	/* MCS 26 */
151	{104000, 216000},	/* MCS 27 */
152	{156000, 324000},	/* MCS 28 */
153	{208000, 432000},	/* MCS 29 */
154	{234000, 486000},	/* MCS 30 */
155	{260000, 540000},	/* MCS 31 */
156	{0,      6000},		/* MCS 32 */
157};
158
159#define MCS_TABLE_RATE(mcs, _is40) ((_is40)? mcs_rate_table[(mcs)].phy_rate_40: \
160	mcs_rate_table[(mcs)].phy_rate_20)
161
162/*
163 * Country names and abbreviations from ISO 3166
164 */
165typedef struct {
166	char *name;     /* Long name */
167	char *abbrev;   /* Abbreviation */
168} country_name_t;
169country_name_t country_names[];     /* At end of this file */
170
171struct variable variables[];
172extern struct nvram_tuple router_defaults[];
173
174enum {
175	NOTHING,
176	REBOOT,
177	RESTART,
178};
179
180const char * const apply_header =
181"<head>"
182"<title>Broadcom Home Gateway Reference Design: Apply</title>"
183"<meta http-equiv=\"Content-Type\" content=\"application/html; charset=utf-8\">"
184"<style type=\"text/css\">"
185"body { background: white; color: black; font-family: arial, sans-serif; font-size: 9pt }"
186".title	{ font-family: arial, sans-serif; font-size: 13pt; font-weight: bold }"
187".subtitle { font-family: arial, sans-serif; font-size: 11pt }"
188".label { color: #306498; font-family: arial, sans-serif; font-size: 7pt }"
189"</style>"
190"</head>"
191"<body>"
192"<p>"
193"<span class=\"title\">APPLY</span><br>"
194"<span class=\"subtitle\">This screen notifies you of any errors "
195"that were detected while changing the router's settings.</span>"
196"<form method=\"get\" action=\"apply.cgi\">"
197"<p>"
198;
199
200const char * const apply_footer =
201"<p>"
202"<input type=\"button\" name=\"action\" value=\"Continue\" OnClick=\"document.location.href='%s';\">"
203"</form>"
204"<p class=\"label\">&#169;2001-2007 Broadcom Corporation. All rights reserved.</p>"
205"</body>"
206;
207
208int ret_code;
209static char posterr_msg[255];
210static int action = NOTHING;
211
212#ifdef PLC
213static dict_hdl_t BcmPostArgs;
214#endif /* PLC */
215
216#define ERR_MSG_SIZE sizeof(posterr_msg)
217#if defined(linux)
218
219#include <fcntl.h>
220#include <signal.h>
221#include <time.h>
222#include <sys/klog.h>
223#include <sys/wait.h>
224#include <sys/ioctl.h>
225#include <net/if.h>
226
227
228typedef u_int64_t u64;
229typedef u_int32_t u32;
230typedef u_int16_t u16;
231typedef u_int8_t u8;
232#include <linux/types.h>
233#include <linux/ethtool.h>
234#include <linux/sockios.h>
235#include <net/if_arp.h>
236#include <sys/utsname.h>
237
238#define sys_restart() kill(1, SIGHUP)
239/* revised to shut down the radio before reboot */
240//#define sys_reboot() kill(1, SIGTERM)
241inline void sys_reboot(void)
242{
243	eval("wl", "reboot");
244	kill(1, SIGTERM);
245}
246
247#define sys_stats(url) eval("stats", (url))
248
249#define SLEEP(X)	sleep(X)
250#define USLEEP(X)	usleep(X)
251
252#ifndef min
253#define min(a, b)	(((a) < (b)) ? (a) : (b))
254#endif
255
256#ifndef WEBS
257
258#define MIN_BUF_SIZE	4096
259
260static int
261ej_kernel_version(int eid, webs_t wp, int argc, char_t **argv)
262{
263	struct utsname utsn;
264	int ret;
265	char buf[100];
266	char *ptr, *end;
267
268	ret = uname(&utsn);
269	if (ret != 0)
270		return -1;
271
272	strncpy(buf, utsn.release, sizeof(buf)-1);
273	buf[sizeof(buf)-1] = 0;
274
275	ptr = strstr(buf, ".");
276	if (!ptr)
277		return -1;
278
279	ptr = ptr+1;
280	end = strstr(ptr, ".");
281	if (end)
282		*end='\0';
283
284	if (memcmp(buf, "2.4", 3))
285		websWrite(wp,"%s", buf);
286
287	return 0;
288}
289
290
291#if (defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__) || \
292	defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__))
293char *linux_mtd_table[]={LINUX_FIRST, LINUX_SECOND};
294
295static char* get_linux_partition_to_update(int* next)
296{
297	char *target_to_flash;
298
299	/* Second priority: If the LINUX_BOOT_SEQUENCE is not set, we suppose the
300	 * the user wants to disable the dual boot, always return the first one
301	 */
302	char *the_image = nvram_get(IMAGE_BOOT);
303	FILE *fp;
304
305	*next=-1;
306	if(the_image != NULL) {
307		unsigned int current_image = atoi(the_image);
308		unsigned int next_image = -1;
309
310		if(current_image > 1) {
311			cprintf("Image more than 2 is not supported, use default!!\n");
312			goto my_default;
313		}
314		next_image = 1 - current_image;
315
316		/* Test if the linux2 partition exists. User may turn on the IMAGE_BOOT at runtime
317		 * On this time the linux2 is not created until next boot
318		 */
319		if ( (next_image == 1) && (fp = fopen("/proc/mtd", "r"))) {
320			char dev[PATH_MAX];
321
322			while (fgets(dev, sizeof(dev), fp)) {
323				if (strstr(dev, LINUX_SECOND)) {
324					fclose(fp);
325					goto my_continue;
326				}
327			}
328			cprintf("The linux2 does not exists, use default!\n");
329			fclose(fp);
330			goto my_default;
331		}
332my_continue:
333		target_to_flash = linux_mtd_table[next_image];
334		cprintf("\nToggled Linux Partition, next image using: %s\n", target_to_flash);
335		*next= next_image;
336		return target_to_flash;
337	} else {
338		cprintf("%s is not set, use the linux as default\n", IMAGE_BOOT);
339	}
340my_default:
341	return LINUX_FIRST;
342}
343
344/* Upgrade from remote server or socket stream */
345static int
346sys_upgrade(char *url, FILE *stream, int *total)
347{
348	char upload_fifo[] = "/tmp/uploadXXXXXX";
349	FILE *fifo = NULL;
350	//write_argv[2] must be assigned a valid long-lived mtd partition
351	char *write_argv[] = { "write", upload_fifo, NULL, NULL };
352	pid_t pid;
353	char *buf = NULL;
354	int count, ret = 0;
355	long flags = -1;
356	char *target_partition;
357	int the_next=-1;
358
359	assert(stream);
360	assert(total);
361
362	//Assign the target parition first!!
363	target_partition  =  write_argv[2] = get_linux_partition_to_update((int*) &the_next);
364
365	if(target_partition == NULL) {
366		cprintf("!!!! target_partition is NULL\n");
367		goto err;
368	}
369
370	if (url)
371		return eval("write", url, target_partition);
372
373	/* Feed write from a temporary FIFO */
374	if (!mktemp(upload_fifo) ||
375	    mkfifo(upload_fifo, S_IRWXU) < 0||
376	    (ret = _eval(write_argv, NULL, 0, &pid)) ||
377	    !(fifo = fopen(upload_fifo, "w"))) {
378		if (!ret)
379			ret = errno;
380		goto err;
381	}
382
383	/* Set nonblock on the socket so we can timeout */
384	if ((flags = fcntl(fileno(stream), F_GETFL)) < 0 ||
385	    fcntl(fileno(stream), F_SETFL, flags | O_NONBLOCK) < 0) {
386		ret = errno;
387		goto err;
388	}
389
390	/*
391	* The buffer must be at least as big as what the stream file is
392	* using so that it can read all the data that has been buffered
393	* in the stream file. Otherwise it would be out of sync with fn
394	* select specially at the end of the data stream in which case
395	* the select tells there is no more data available but there in
396	* fact is data buffered in the stream file's buffer. Since no
397	* one has changed the default stream file's buffer size, let's
398	* use the constant BUFSIZ until someone changes it.
399	* The code should be as follows
400	* if (size < MIN_BUF_SIZE)
401	*	size = MIN_BUF_SIZE;
402	*/
403
404	if ((buf = malloc(BUFSIZ)) == NULL) {
405		ret = ENOMEM;
406		goto err;
407	}
408
409	/* Pipe the rest to the FIFO */
410	cprintf("Upgrading.\n");
411	while (total && *total) {
412		if (waitfor(fileno(stream), 5) <= 0)
413			break;
414		count = safe_fread(buf, 1, BUFSIZ, stream);
415		if (!count && (ferror(stream) || feof(stream)))
416			break;
417		*total -= count;
418		safe_fwrite(buf, 1, count, fifo);
419		cprintf(".");
420	}
421	fclose(fifo);
422	fifo = NULL;
423
424	/* Wait for write to terminate */
425	waitpid(pid, &ret, 0);
426	cprintf("done\n");
427
428	/* Reset nonblock on the socket */
429	if (fcntl(fileno(stream), F_SETFL, flags) < 0) {
430		ret = errno;
431		goto err;
432	}
433
434	/* Only toggle would set the_next to 0 or 1 */
435	if (!ret && (the_next == 0 || the_next == 1)) {
436		char temp[30];
437		sprintf(temp, "%d", the_next);
438		nvram_set(IMAGE_BOOT, temp);
439		nvram_commit();
440		cprintf("Set %s to %d\n", IMAGE_BOOT, the_next);
441	}
442
443 err:
444	if (buf)
445		free(buf);
446	if (fifo)
447		fclose(fifo);
448	unlink(upload_fifo);
449	return ret;
450}
451#else //__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__
452
453/* Upgrade from remote server or socket stream */
454static int
455sys_upgrade(char *url, FILE *stream, int *total)
456{
457	char upload_fifo[] = "/tmp/uploadXXXXXX";
458	FILE *fifo = NULL;
459	char *write_argv[] = { "write", upload_fifo, "linux", NULL };
460	pid_t pid;
461	char *buf = NULL;
462	int count, ret = 0;
463	long flags = -1;
464	char *cmd = "write";
465	char *boot_partition = "boot";
466	char *target_partition = "linux";
467
468	/* Keep compiler happy */
469	(void) boot_partition;
470
471	assert(stream);
472	assert(total);
473
474
475	if (url)
476		return eval(cmd, url, target_partition);
477
478	/* Feed write from a temporary FIFO */
479	if (!mktemp(upload_fifo) ||
480	    mkfifo(upload_fifo, S_IRWXU) < 0||
481	    (ret = _eval(write_argv, NULL, 0, &pid)) ||
482	    !(fifo = fopen(upload_fifo, "w"))) {
483		if (!ret)
484			ret = errno;
485		goto err;
486	}
487
488	/* Set nonblock on the socket so we can timeout */
489	if ((flags = fcntl(fileno(stream), F_GETFL)) < 0 ||
490	    fcntl(fileno(stream), F_SETFL, flags | O_NONBLOCK) < 0) {
491		ret = errno;
492		goto err;
493	}
494
495	/*
496	* The buffer must be at least as big as what the stream file is
497	* using so that it can read all the data that has been buffered
498	* in the stream file. Otherwise it would be out of sync with fn
499	* select specially at the end of the data stream in which case
500	* the select tells there is no more data available but there in
501	* fact is data buffered in the stream file's buffer. Since no
502	* one has changed the default stream file's buffer size, let's
503	* use the constant BUFSIZ until someone changes it.
504	*
505	* if (size < MIN_BUF_SIZE)
506	*	size = MIN_BUF_SIZE;
507	*/
508
509	if ((buf = malloc(BUFSIZ)) == NULL) {
510		ret = ENOMEM;
511		goto err;
512	}
513
514	/* Pipe the rest to the FIFO */
515	cprintf("Upgrading.\n");
516	while (total && *total) {
517		if (waitfor(fileno(stream), 5) <= 0)
518			break;
519		count = safe_fread(buf, 1, BUFSIZ, stream);
520		if (!count && (ferror(stream) || feof(stream)))
521			break;
522		*total -= count;
523		safe_fwrite(buf, 1, count, fifo);
524		cprintf(".");
525	}
526	fclose(fifo);
527	fifo = NULL;
528
529	/* Wait for write to terminate */
530	waitpid(pid, &ret, 0);
531	cprintf("done\n");
532
533	/* Reset nonblock on the socket */
534	if (fcntl(fileno(stream), F_SETFL, flags) < 0) {
535		ret = errno;
536		goto err;
537	}
538
539 err:
540 	if (buf)
541		free(buf);
542	if (fifo)
543		fclose(fifo);
544	unlink(upload_fifo);
545	return ret;
546}
547#endif //__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__
548
549#endif /* WEBS */
550
551/* Dump firewall log */
552static int
553ej_dumplog(int eid, webs_t wp, int argc, char_t **argv)
554{
555	char buf[4096], *line, *next, *s;
556	int len, ret = 0;
557
558	time_t tm;
559	char *verdict, *src, *dst, *proto, *spt, *dpt;
560
561	if (klogctl(3, buf, 4096) < 0) {
562		websError(wp, 400, "Insufficient memory\n");
563		return -1;
564	}
565
566	for (next = buf; (line = strsep(&next, "\n"));) {
567		if (!strncmp(line, "<4>DROP", 7))
568			verdict = "denied";
569		else if (!strncmp(line, "<4>ACCEPT", 9))
570			verdict = "accepted";
571		else
572			continue;
573
574		/* Parse into tokens */
575		s = line;
576		len = strlen(s);
577		while (strsep(&s, " "));
578
579		/* Initialize token values */
580		time(&tm);
581		src = dst = proto = spt = dpt = "n/a";
582
583		/* Set token values */
584		for (s = line; s < &line[len] && *s; s += strlen(s) + 1) {
585			if (!strncmp(s, "TIME=", 5))
586				tm = strtoul(&s[5], NULL, 10);
587			else if (!strncmp(s, "SRC=", 4))
588				src = &s[4];
589			else if (!strncmp(s, "DST=", 4))
590				dst = &s[4];
591			else if (!strncmp(s, "PROTO=", 6))
592				proto = &s[6];
593			else if (!strncmp(s, "SPT=", 4))
594				spt = &s[4];
595			else if (!strncmp(s, "DPT=", 4))
596				dpt = &s[4];
597		}
598
599		ret += websWrite(wp, "%s %s connection %s to %s:%s from %s:%s\n",
600				 rfctime(&tm), proto, verdict, dst, dpt, src, spt);
601		ret += websWrite(wp, "<br>");
602	}
603
604	return ret;
605}
606
607static int
608ej_syslog(int eid, webs_t wp, int argc, char_t **argv)
609{
610	FILE *fp;
611	char buf[256] = "/sbin/logread > ";
612	char tmp[] = "/tmp/log.XXXXXX";
613	int ret;
614
615	if (!nvram_match("log_ram_enable", "1")) {
616		websError(wp, 400, "\"Syslog in RAM\" is not enabled.\n");
617		return (-1);
618	}
619
620	mktemp(tmp);
621	strcat(buf, tmp);
622	system(buf);
623
624	fp = fopen(tmp, "r");
625
626	unlink(tmp);
627
628	if (fp == NULL) {
629		websError(wp, 400, "logread error\n");
630		return (-1);
631	}
632
633	websWrite(wp, "<pre>");
634
635	ret = 0;
636	while(fgets(buf, sizeof(buf), fp))
637		ret += websWrite(wp, buf);
638
639	ret += websWrite(wp, "</pre>");
640
641	fclose(fp);
642
643	return (ret);
644}
645
646struct lease_t {
647	unsigned char chaddr[16];
648	u_int32_t yiaddr;
649	u_int32_t expires;
650	char hostname[64];
651};
652
653/* Dump leases in <tr><td>hostname</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
654static int
655ej_lan_leases(int eid, webs_t wp, int argc, char_t **argv)
656{
657	FILE *fp = NULL;
658	struct lease_t lease;
659	int i;
660	int index,num_interfaces=0;
661	char buf[128];
662	struct in_addr addr;
663	unsigned long expires = 0;
664	char sigusr1[] = "-XX";
665	int ret = 0;
666
667	/* Write out leases file */
668	sprintf(sigusr1, "-%d", SIGUSR1);
669	eval("killall", sigusr1, "udhcpd");
670
671	/* Count the number of lan and guest interfaces */
672
673	if (nvram_get("lan_ifname"))
674		num_interfaces++;
675
676	if (nvram_get("lan1_ifname"))
677		num_interfaces++;
678
679	for (index =0; index < num_interfaces; index++){
680		snprintf(buf,sizeof(buf),"/tmp/udhcpd%d.leases",index);
681
682		if (!(fp = fopen(buf, "r")))
683			continue;
684
685		while (fread(&lease, sizeof(lease), 1, fp)) {
686			/* Do not display reserved leases */
687			if (ETHER_ISNULLADDR(lease.chaddr))
688				continue;
689			lease.hostname[sizeof(lease.hostname) - 1] = '\0';
690			ret += websWrite(wp, "<tr><td>%s</td><td>", lease.hostname);
691			for (i = 0; i < 6; i++) {
692				ret += websWrite(wp, "%02X", lease.chaddr[i]);
693				if (i != 5) ret += websWrite(wp, ":");
694			}
695			addr.s_addr = lease.yiaddr;
696			ret += websWrite(wp, "</td><td>%s</td><td>", inet_ntoa(addr));
697			expires = ntohl(lease.expires);
698			if (!expires)
699				ret += websWrite(wp, "Expired");
700			else
701				ret += websWrite(wp, "%s", reltime(expires));
702			if(index)
703				ret += websWrite(wp, "</td><td>Guest</td><td>");
704			else
705				ret += websWrite(wp, "</td><td>Internal</td><td>");
706			ret += websWrite(wp, "</td></tr>");
707		}
708
709		fclose(fp);
710	}
711
712	return ret;
713}
714
715/* Renew lease */
716static int
717sys_renew(void)
718{
719	int unit;
720	char tmp[NVRAM_BUFSIZE];
721	char *str = NULL;
722	int pid;
723
724	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
725		unit = 0;
726
727	snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit);
728	if ((str = file2str(tmp))) {
729		pid = atoi(str);
730		free(str);
731		return kill(pid, SIGUSR1);
732	}
733
734	return -1;
735}
736
737/* Release lease */
738static int
739sys_release(void)
740{
741	int unit;
742	char tmp[NVRAM_BUFSIZE];
743	char *str= NULL;
744	int pid;
745
746	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
747		unit = 0;
748
749	snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit);
750	if ((str = file2str(tmp))) {
751		pid = atoi(str);
752		free(str);
753		return kill(pid, SIGUSR2);
754	}
755
756	return -1;
757}
758
759#ifdef __CONFIG_NAT__
760#define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
761
762/* Return WAN link state */
763static int
764ej_wan_link(int eid, webs_t wp, int argc, char_t **argv)
765{
766	char *wan_ifname;
767	int s;
768	struct ifreq ifr;
769	struct ethtool_cmd ecmd;
770	FILE *fp= NULL;
771	int unit;
772	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
773
774	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
775		unit = 0;
776	WAN_PREFIX(unit, prefix);
777
778	/* non-exist and disabled */
779	if (nvram_match(strcat_r(prefix, "proto", tmp), "") ||
780	    nvram_match(strcat_r(prefix, "proto", tmp), "disabled")) {
781		return websWrite(wp, "N/A");
782	}
783	/* PPPoE connection status */
784	else if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) {
785		wan_ifname = nvram_safe_get(strcat_r(prefix, "pppoe_ifname", tmp));
786		if ((fp = fopen(strcat_r("/tmp/ppp/link.", wan_ifname, tmp), "r"))) {
787			fclose(fp);
788			return websWrite(wp, "Connected");
789		} else
790			return websWrite(wp, "Disconnected");
791	}
792	/* Get real interface name */
793	else
794		wan_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
795
796	/* Open socket to kernel */
797	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
798		return websWrite(wp, "N/A");
799
800	/* Check for hardware link */
801	strncpy(ifr.ifr_name, wan_ifname, sizeof(ifr.ifr_name) - 1);
802	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
803
804	ifr.ifr_data = (void *) &ecmd;
805	ecmd.cmd = ETHTOOL_GSET;
806	if (ioctl(s, SIOCETHTOOL, &ifr) < 0) {
807		close(s);
808		return websWrite(wp, "Unknown");
809	}
810	if (!ecmd.speed) {
811		close(s);
812		return websWrite(wp, "Disconnected");
813	}
814
815	/* Check for valid IP address */
816	strncpy(ifr.ifr_name, wan_ifname, sizeof(ifr.ifr_name) - 1);
817	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
818	if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
819		close(s);
820		return websWrite(wp, "Connecting");
821	}
822
823	/* Otherwise we are probably configured */
824	close(s);
825	return websWrite(wp, "Connected");
826}
827
828/* Display IP Address lease */
829static int
830ej_wan_lease(int eid, webs_t wp, int argc, char_t **argv)
831{
832	unsigned long expires = 0;
833	int ret = 0;
834	int unit;
835	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
836
837	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
838		unit = 0;
839	WAN_PREFIX(unit, prefix);
840
841	if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) {
842		char *str;
843		time_t now;
844
845		snprintf(tmp, sizeof(tmp), "/tmp/udhcpc%d.expires", unit);
846		if ((str = file2str(tmp))) {
847			expires = atoi(str);
848			free(str);
849		}
850		time(&now);
851		if (expires <= now)
852			ret += websWrite(wp, "Expired");
853		else
854			ret += websWrite(wp, "%s", reltime(expires - now));
855	} else
856		ret += websWrite(wp, "N/A");
857
858	return ret;
859}
860#endif	/* __CONFIG_NAT__ */
861
862/* Report sys up time */
863static int
864ej_sysuptime(int eid, webs_t wp, int argc, char_t **argv)
865{
866	char *str = file2str("/proc/uptime");
867	if (str) {
868		unsigned int up = atoi(str);
869		free(str);
870		return websWrite(wp, reltime(up));
871	}
872	return websWrite(wp, "N/A");
873}
874
875#ifdef __CONFIG_NAT__
876/* Return a list of wan interfaces (eth0/eth1/eth2/eth3) */
877static int
878ej_wan_iflist(int eid, webs_t wp, int argc, char_t **argv)
879{
880	char name[IFNAMSIZ], *next;
881	int ret = 0;
882	int unit;
883	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
884	char ea[64];
885	int s;
886	struct ifreq ifr;
887
888	/* current unit # */
889	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
890		unit = 0;
891	WAN_PREFIX(unit, prefix);
892
893	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
894		return errno;
895
896	/* build wan interface name list */
897	foreach(name, nvram_safe_get("wan_ifnames"), next) {
898		strncpy(ifr.ifr_name, name, IFNAMSIZ);
899		if (ioctl(s, SIOCGIFHWADDR, &ifr))
900			continue;
901		ret += websWrite(wp, "<option value=\"%s\" %s>%s (%s)</option>", name,
902				 nvram_match(strcat_r(prefix, "ifname", tmp), name) ? "selected" : "",
903				 name, ether_etoa((unsigned char *)ifr.ifr_hwaddr.sa_data, ea));
904	}
905
906	close(s);
907
908	return ret;
909}
910#endif	/* __CONFIG_NAT__ */
911
912
913#elif defined(__NetBSD__)
914
915#include <fcntl.h>
916#include <signal.h>
917#include <time.h>
918#include <sys/wait.h>
919#include <sys/ioctl.h>
920#include <sys/sysctl.h>
921#include <net/if.h>
922#include <proto/wpa.h>
923
924typedef u_int64_t u64;
925typedef u_int32_t u32;
926typedef u_int16_t u16;
927typedef u_int8_t u8;
928#include <sys/sockio.h>
929#include <net/if_arp.h>
930
931#define sys_restart() kill(1, SIGHUP)
932#define sys_reboot() kill(1, SIGTERM)
933#define sys_stats(url) eval("stats", (url))
934
935#define SLEEP(X)	sleep(X)
936#define USLEEP(X)	usleep(X)
937
938void netbsd_random(uint8 *random, int len)
939{
940	int tlen = len;
941	while (tlen--) {
942		*random = (uint8)rand();
943		*random++;
944	}
945	return;
946}
947
948void RAND_bytes(unsigned char *buf, int num)
949{
950	netbsd_random(buf, num);
951}
952
953#ifndef WEBS
954
955#define MIN_BUF_SIZE	4096
956
957/* Upgrade from remote server or socket stream */
958static int
959sys_upgrade(char *url, FILE *stream, int *total)
960{
961	char upload_fifo[] = "/tmp/uploadXXXXXX";
962	FILE *fifo = NULL;
963	char *write_argv[] = { "write", upload_fifo, "linux", NULL };
964	pid_t pid;
965	char *buf = NULL;
966	int count, ret = 0;
967	long flags = -1;
968
969	assert(stream);
970	assert(total);
971
972	if (url)
973		return eval("write", url, "linux");
974
975	/* Feed write from a temporary FIFO */
976	if (!mktemp(upload_fifo) ||
977	    mkfifo(upload_fifo, S_IRWXU) < 0||
978	    (ret = _eval(write_argv, NULL, 0, &pid)) ||
979	    !(fifo = fopen(upload_fifo, "w"))) {
980		if (!ret)
981			ret = errno;
982		goto err;
983	}
984
985	/* Set nonblock on the socket so we can timeout */
986	if ((flags = fcntl(fileno(stream), F_GETFL)) < 0 ||
987	    fcntl(fileno(stream), F_SETFL, flags | O_NONBLOCK) < 0) {
988		ret = errno;
989		goto err;
990	}
991
992	/*
993	* The buffer must be at least as big as what the stream file is
994	* using so that it can read all the data that has been buffered
995	* in the stream file. Otherwise it would be out of sync with fn
996	* select specially at the end of the data stream in which case
997	* the select tells there is no more data available but there in
998	* fact is data buffered in the stream file's buffer. Since no
999	* one has changed the default stream file's buffer size, let's
1000	* use the constant BUFSIZ until someone changes it.
1001	* The code should be as follows
1002	* if (size < MIN_BUF_SIZE)
1003	*	size = MIN_BUF_SIZE;
1004	*/
1005	if ((buf = malloc(BUFSIZ)) == NULL) {
1006		ret = ENOMEM;
1007		goto err;
1008	}
1009
1010	/* Pipe the rest to the FIFO */
1011	cprintf("Upgrading.\n");
1012	while (total && *total) {
1013		if (waitfor(fileno(stream), 5) <= 0)
1014			break;
1015		count = safe_fread(buf, 1, BUFSIZ, stream);
1016		if (!count && (ferror(stream) || feof(stream)))
1017			break;
1018		*total -= count;
1019		safe_fwrite(buf, 1, count, fifo);
1020		cprintf(".");
1021	}
1022	fclose(fifo);
1023	fifo = NULL;
1024
1025	/* Wait for write to terminate */
1026	waitpid(pid, &ret, 0);
1027	cprintf("done\n");
1028
1029	/* Reset nonblock on the socket */
1030	if (fcntl(fileno(stream), F_SETFL, flags) < 0) {
1031		ret = errno;
1032		goto err;
1033	}
1034
1035 err:
1036 	if (buf)
1037		free(buf);
1038	if (fifo)
1039		fclose(fifo);
1040	unlink(upload_fifo);
1041	return ret;
1042}
1043
1044#endif /* WEBS */
1045
1046/* Dump firewall log */
1047static int
1048ej_dumplog(int eid, webs_t wp, int argc, char_t **argv)
1049{
1050	return 0;
1051}
1052
1053static int
1054ej_syslog(int eid, webs_t wp, int argc, char_t **argv)
1055{
1056
1057
1058	return (0);
1059}
1060
1061
1062/* Dump leases in <tr><td>hostname</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
1063static int
1064ej_lan_leases(int eid, webs_t wp, int argc, char_t **argv)
1065{
1066	FILE *fp;
1067	char tmp[100];
1068	char word[100];
1069	char line[100];
1070	int index,num_interfaces=0;
1071	char *cp1, *cp2;
1072	unsigned long expires = 0;
1073	int ret = 0;
1074	time_t tm;
1075
1076	/* Count the number of lan and guest interfaces */
1077	if (nvram_get("lan_ifname"))
1078		num_interfaces++;
1079
1080	if (nvram_get("lan1_ifname"))
1081		num_interfaces++;
1082
1083	for (index =0; index < num_interfaces; index++){
1084		snprintf(word, sizeof(word),"/etc/dhcpd%d.leases",index);
1085
1086		if (!(fp = fopen(word, "r")))
1087			continue;
1088
1089		while (fgets(line, sizeof(line), fp)) {
1090			/* parse lease information */
1091			cp1 = line;
1092			for (cp1 = line, cp2 = cp1; *cp2 && *cp2 != ';'; ++cp2)
1093				;
1094			if (!*cp2)
1095			continue;
1096			*cp2 = '\0';
1097			ret += websWrite(wp, "<tr><td>%s</td><td>", cp1);
1098
1099			/* hardware address */
1100			for (cp1 = cp2+1, cp2 = cp1; *cp2 && *cp2 != ';'; ++cp2)
1101				;
1102			if (!*cp2)
1103			continue;
1104			*cp2 = '\0';
1105			ret += websWrite(wp, "%s", cp1);
1106			/* IP */
1107			for (cp1 = cp2+1, cp2 = cp1; *cp2 && *cp2 != ';'; ++cp2)
1108				;
1109			if (!*cp2)
1110			continue;
1111			*cp2 = '\0';
1112			ret += websWrite(wp, "</td><td>%s</td><td>", cp1);
1113
1114			/* expires */
1115			cp1 = cp2+1;
1116			if (!strcmp(cp1, "never"))
1117				ret += websWrite(wp, "Never");
1118			else {
1119				time(&tm);
1120				expires = atoi(cp1);
1121				expires -= time(&tm);
1122				if (!expires)
1123					ret += websWrite(wp, "Expired");
1124				else
1125					ret += websWrite(wp, "%s", reltime(expires));
1126			}
1127			if(index)
1128				ret += websWrite(wp, "</td><td>Guest</td><td>");
1129			else
1130				ret += websWrite(wp, "</td><td>Internal</td><td>");
1131			ret += websWrite(wp, "</td></tr>");
1132		}
1133
1134		fclose(fp);
1135	}
1136
1137	return ret;
1138}
1139
1140/* Renew lease */
1141static int
1142sys_renew(void)
1143{
1144
1145	return -1;
1146}
1147
1148/* Release lease */
1149static int
1150sys_release(void)
1151{
1152
1153
1154	return -1;
1155}
1156
1157#ifdef __CONFIG_NAT__
1158#define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
1159
1160/* Return WAN link state */
1161static int
1162ej_wan_link(int eid, webs_t wp, int argc, char_t **argv)
1163{
1164
1165	return 0;
1166}
1167
1168/* Display IP Address lease */
1169static int
1170ej_wan_lease(int eid, webs_t wp, int argc, char_t **argv)
1171{
1172
1173
1174	return 0;
1175}
1176#endif	/* __CONFIG_NAT__ */
1177
1178/* Report sys up time */
1179static int
1180ej_sysuptime(int eid, webs_t wp, int argc, char_t **argv)
1181{
1182	int mib[2];
1183	size_t size;
1184	time_t uptime;
1185	struct timeval	boottime;
1186	time_t now;
1187
1188	(void)time(&now);
1189	mib[0] = CTL_KERN;
1190	mib[1] = KERN_BOOTTIME;
1191	size = sizeof(boottime);
1192	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
1193	    boottime.tv_sec != 0) {
1194		uptime = now - boottime.tv_sec;
1195		return websWrite(wp, reltime(uptime));
1196	}
1197	return websWrite(wp, "N/A");
1198}
1199
1200#ifdef __CONFIG_NAT__
1201/* Return a list of wan interfaces (eth0/eth1/eth2/eth3) */
1202static int
1203ej_wan_iflist(int eid, webs_t wp, int argc, char_t **argv)
1204{
1205	char name[IFNAMSIZ], *next;
1206	int ret = 0;
1207	int unit;
1208	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
1209	char ea[64];
1210	int s;
1211	struct ifreq ifr;
1212
1213	/* current unit # */
1214	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
1215		unit = 0;
1216	WAN_PREFIX(unit, prefix);
1217
1218	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
1219		return errno;
1220
1221	/* build wan interface name list */
1222	foreach(name, nvram_safe_get("wan_ifnames"), next) {
1223		strncpy(ifr.ifr_name, name, IFNAMSIZ);
1224		if (ioctl(s, SIOCGIFHWADDR, &ifr))
1225			continue;
1226		ret += websWrite(wp, "<option value=\"%s\" %s>%s (%s)</option>", name,
1227				 nvram_match(strcat_r(prefix, "ifname", tmp), name) ? "selected" : "",
1228				 name, ether_etoa((unsigned char *)ifr.ifr_addr.sa_data, ea));
1229	}
1230
1231	close(s);
1232
1233	return ret;
1234}
1235#endif	/* __CONFIG_NAT__ */
1236
1237
1238static int
1239ej_kernel_version(int eid, webs_t wp, int argc, char_t **argv)
1240{
1241	return 0;
1242}
1243
1244#elif defined(__ECOS)
1245
1246#include <cyg/kernel/kapi.h>
1247#include <cyg/infra/cyg_type.h>
1248#include <cyg/infra/diag.h>
1249#include <typedefs.h>
1250#include <sys/ioctl.h>
1251#include <dhcpc.h>
1252#include <dhcpd.h>
1253
1254#define cprintf(fmt, args...) fprintf(stderr, fmt , ## args)
1255extern void sys_restart(void);
1256extern void sys_reboot(void);
1257
1258#define sys_stats(server) (0)
1259extern int sys_upgrade(char *url, FILE *stream, int *total);
1260extern int wl_ioctl(char *name, int request, void *buf, int len);
1261
1262extern void udelay(int delay);
1263#define SLEEP(n)	cyg_thread_delay(n * 100)
1264#define USLEEP(X)	udelay(X)
1265
1266static int
1267ej_kernel_version(int eid, webs_t wp, int argc, char_t **argv)
1268{
1269	websWrite(wp,"eCos 3.0/");
1270	return 0;
1271}
1272
1273static int
1274sys_renew(void)
1275{
1276	char *wan_ifname;
1277	int unit;
1278	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
1279
1280	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
1281		unit = 0;
1282	WAN_PREFIX(unit, prefix);
1283
1284	if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) {
1285		wan_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1286		dhcpc_renew(wan_ifname);
1287	}
1288
1289	return 0;
1290}
1291
1292static int
1293sys_release(void)
1294{
1295	char *wan_ifname;
1296	int unit;
1297	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
1298
1299	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
1300		unit = 0;
1301	WAN_PREFIX(unit, prefix);
1302
1303	if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) {
1304		wan_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1305		dhcpc_release(wan_ifname);
1306	}
1307
1308	return 0;
1309}
1310
1311/* Dump leases in <tr><td>hostname</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
1312static int
1313ej_lan_leases(int eid, webs_t wp, int argc, char_t **argv)
1314{
1315	int i;
1316	int index, num_interfaces = 0;
1317	int ret = 0;
1318
1319	char *ifname;
1320	struct lease_t *lease, *dump;
1321	int last;
1322
1323	/* Count the number of lan and guest interfaces */
1324	if (nvram_get("lan_ifname"))
1325		num_interfaces++;
1326
1327	if (nvram_get("lan1_ifname"))
1328		num_interfaces++;
1329
1330	for (index = 0; index < num_interfaces; index++){
1331		if (index == 0)
1332			ifname = nvram_get("lan_ifname");
1333		else
1334			ifname = nvram_get("lan1_ifname");
1335		if (!ifname)
1336			continue;
1337
1338		/* dump lease */
1339		dump = lease = dhcpd_lease_dump(ifname);
1340		if (!dump)
1341			return 0;
1342
1343		/* Write HTML until last */
1344		last = 0;
1345		while (last == 0) {
1346			/* Get the last flag for next time qualification */
1347			last = lease->last;
1348
1349			if (lease->flag & RESERVED) {
1350				lease++;
1351				continue;
1352			}
1353
1354			ret += websWrite(wp, "<tr><td>%s</td><td>", lease->hostname);
1355
1356			for (i = 0; i < 6; i++) {
1357				ret += websWrite(wp, "%02X", lease->mac[i]);
1358				if (i != 5) ret += websWrite(wp, ":");
1359			}
1360
1361			ret += websWrite(wp, "</td><td>%s</td><td>", inet_ntoa(lease->ipaddr));
1362
1363			if (lease->expiry < time(0))
1364				ret += websWrite(wp, "Expired");
1365			else
1366				ret += websWrite(wp, "%s",
1367					reltime(lease->expiry-time(0)));
1368
1369			if (index)
1370				ret += websWrite(wp, "</td><td>Guest</td><td>");
1371			else
1372				ret += websWrite(wp, "</td><td>Internal</td><td>");
1373			ret += websWrite(wp, "</td></tr>");
1374
1375			/* Advaince to next */
1376			lease++;
1377		}
1378
1379		/* Free buffer */
1380		free(dump);
1381	}
1382
1383	return ret;
1384}
1385
1386static int
1387ej_dumplog(int eid, webs_t wp, int argc, char_t **argv)
1388{
1389	/* not implemented */
1390	return 0;
1391}
1392
1393extern int syslog_open();
1394extern int syslog_close();
1395extern char *syslog_get();
1396
1397static int
1398ej_syslog(int eid, webs_t wp, int argc, char_t **argv)
1399{
1400	char *buf;
1401	int ret;
1402
1403	syslog_open();
1404
1405	ret = 0;
1406	while((buf = syslog_get()) != NULL) {
1407		ret += websWrite(wp, "<pre>");
1408		ret += websWrite(wp, buf);
1409		ret += websWrite(wp, "</pre>");
1410	}
1411
1412	syslog_close();
1413
1414	return (ret);
1415}
1416
1417#ifdef __CONFIG_NAT__
1418static int
1419ej_wan_link(int eid, webs_t wp, int argc, char_t **argv)
1420{
1421	char *val;
1422
1423	val = nvram_safe_get("wan_connect");
1424	if (strcmp(val, "Connected"))
1425		websWrite(wp, "Connected");
1426	else if (strcmp(val, "Connecting"))
1427		websWrite(wp, "Connecting");
1428	else
1429		websWrite(wp, "Disconnected");
1430	return 0;
1431}
1432
1433static int
1434ej_wan_lease(int eid, webs_t wp, int argc, char_t **argv)
1435{
1436	int ret = 0;
1437	int unit;
1438	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
1439
1440	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
1441		unit = 0;
1442	WAN_PREFIX(unit, prefix);
1443
1444	if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) {
1445		char *value;
1446		unsigned int expires;
1447		time_t now = time(0);
1448
1449		value = nvram_safe_get(strcat_r(prefix, "expiry", tmp));
1450		expires = strtoul(value, NULL, 10);
1451		if (expires == 0)
1452			ret += websWrite(wp, "N/A");
1453		else if (expires <= now)
1454			ret += websWrite(wp, "Expired");
1455		else
1456			ret += websWrite(wp, "%s", reltime(expires - now));
1457	} else
1458		ret += websWrite(wp, "N/A");
1459
1460	return 0;
1461}
1462
1463static int
1464ej_sysuptime(int eid, webs_t wp, int argc, char_t **argv)
1465{
1466	unsigned int up = (unsigned int)(cyg_current_time()/100);
1467
1468	return websWrite(wp, reltime(up));
1469}
1470
1471/* Return a list of wan interfaces (eth0/eth1/eth2/eth3) */
1472static int
1473ej_wan_iflist(int eid, webs_t wp, int argc, char_t **argv)
1474{
1475	char name[IFNAMSIZ], *next;
1476	int ret = 0;
1477	int unit;
1478	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
1479	char ea[64];
1480	int s;
1481	struct ifreq ifr;
1482
1483	/* current unit # */
1484	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
1485		unit = 0;
1486	WAN_PREFIX(unit, prefix);
1487
1488	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
1489		return errno;
1490
1491	/* build wan interface name list */
1492	foreach(name, nvram_safe_get("wan_ifnames"), next) {
1493		strncpy(ifr.ifr_name, name, IFNAMSIZ);
1494		if (ioctl(s, SIOCGIFHWADDR, &ifr))
1495			continue;
1496		ret += websWrite(wp, "<option value=\"%s\" %s>%s (%s)</option>", name,
1497				 nvram_match(strcat_r(prefix, "ifname", tmp), name) ? "selected" : "",
1498				 name, ether_etoa((unsigned char *)ifr.ifr_addr.sa_data, ea));
1499	}
1500
1501	close(s);
1502
1503	return ret;
1504}
1505#endif	/* __CONFIG_NAT__ */
1506
1507
1508#endif /* __ECOS__ */
1509
1510/* Common function */
1511static int
1512wl_phytype_get(webs_t wp, int *phytype)
1513{
1514	char *name =NULL;
1515	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1516
1517	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
1518		websError(wp, 400, "unit number variable doesn't exist\n");
1519		return -1;
1520	}
1521
1522	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1523
1524	/* Get configured phy type */
1525	wl_ioctl(name, WLC_GET_PHYTYPE, phytype, sizeof(int));
1526
1527	return 0;
1528}
1529
1530static int
1531ej_lan_guest_iflist(int eid, webs_t wp, int argc, char_t **argv)
1532{
1533	int ret = 0;
1534	char ifnames[255],name[IFNAMSIZ],os_name[IFNAMSIZ],*next=NULL;
1535	char buf[32],*config_num, *value=NULL;
1536
1537	if (ejArgs(argc, argv, "%s", &config_num) < 1) {
1538		websError(wp, 400, "Insufficient args\n");
1539		return -1;
1540	}
1541
1542	/* Do some of the housekeeping here to remove any leftover invalid NVRAM vars
1543	   prior to display */
1544
1545	snprintf(ifnames, sizeof(ifnames), "%s", nvram_safe_get("unbridged_ifnames"));
1546
1547	snprintf(buf, sizeof(buf), "lan%s_ifname", config_num);
1548
1549	value = nvram_safe_get(buf);
1550
1551
1552	if (!*ifnames)
1553		{
1554			ret += websWrite(wp, "<option value=\"NONE\" selected >NONE</option>");
1555			return ret;
1556		}
1557
1558	if (!remove_dups(ifnames,sizeof(ifnames))){
1559			websError(wp, 400, "Unable to remove duplicate interfaces from ifname list<br>");
1560			return -1;
1561		}
1562
1563	foreach(name, ifnames, next) {
1564
1565
1566		if (nvifname_to_osifname( name, os_name, sizeof(os_name) ) < 0)
1567			continue;
1568
1569		ret += websWrite(wp, "<option value=\"%s\"%s>%s%s</option>",
1570			name, strcmp(name,value) ? "":" selected ",
1571			name, !wl_probe(os_name) ? " (Wireless)" : "");
1572	}
1573
1574	ret += websWrite(wp, "<option value=\"NONE\"%s>NONE</option>",(*value) ? "" : " selected ");
1575
1576	return ret;
1577}
1578
1579
1580static int
1581ej_asp_list(int eid, webs_t wp, int argc, char_t **argv)
1582{
1583	websWrite(wp,
1584	  "<tr>\n"
1585	  "  <td><a href=\"index.asp\"><img border=\"0\" src=\"basic.gif\" alt=\"Basic\"></a></td>\n"
1586	  "  <td><a href=\"lan.asp\"><img border=\"0\" src=\"lan.gif\" alt=\"LAN\"></a></td>\n");
1587#ifdef __CONFIG_NAT__
1588	websWrite(wp,
1589	  "  <td><a href=\"wan.asp\"><img border=\"0\" src=\"wan.gif\" alt=\"WAN\"></a></td>\n");
1590#endif
1591#ifndef	__CONFIG_NETBOOT__
1592	websWrite(wp,
1593	  "  <td><a href=\"status.asp\"><img border=\"0\" src=\"status.gif\" alt=\"Status\"></a></td>\n");
1594#ifdef __CONFIG_NAT__
1595	websWrite(wp,
1596	  "  <td><a href=\"filter.asp\"><img border=\"0\" src=\"filter.gif\" alt=\"Filters\"></a></td>\n"
1597	  "  <td><a href=\"forward.asp\"><img border=\"0\" src=\"forward.gif\" alt=\"Routing\"></a></td>\n");
1598#endif
1599#endif	/* !__CONFIG_NETBOOT__ */
1600#ifdef BCMQOS
1601#if !defined(__CONFIG_TREND_IQOS__) && !defined(CONFIG_TREND_IQOS_ENABLED)
1602	websWrite(wp,
1603	  "  <td><a href=\"qos.asp\"><img border=\"0\" src=\"qos.gif\" alt=\"IQos\"></a></td>\n");
1604#endif /* !defined (__CONFIG_TREND_IQOS__) && !defined (CONFIG_TREND_IQOS_ENABLED) */
1605#endif
1606	websWrite(wp,
1607	  "  <td><a href=\"media.asp\"><img border=\"0\" src=\"media.gif\" alt=\"Media\"></a></td>\n");
1608#ifdef PLC
1609	websWrite(wp, "  <td><a href=\"plc.asp\"><img border=\"0\" src=\"plc.gif\" alt=\"PLC\"></a></td>\n");
1610#endif
1611
1612#if defined(__CONFIG_SAMBA__) || defined(__CONFIG_DLNA_DMS__)
1613	websWrite(wp,
1614	  "  <td><a href=\"storage.asp\"><img border=\"0\" src=\"storage.gif\" alt=\"Storage\"></a></td>\n");
1615#endif
1616	websWrite(wp,
1617	  "  <td><a href=\"radio.asp\"><img border=\"0\" src=\"radio.gif\" alt=\"Wlan I/F\"></a></td>\n"
1618	  "  <td><a href=\"ssid.asp\"><img border=\"0\" src=\"ssid.gif\" alt=\"xyz\"></a></td>\n");
1619#ifdef __CONFIG_HSPOT__
1620	websWrite(wp,
1621	  "  <td><a href=\"passpoint.asp\"><img border=\"0\" src=\"passpoint.gif\" alt=\"Passpoint\"></a></td>\n");
1622#endif /* __CONFIG_HSPOT__ */
1623	websWrite(wp,
1624	  "  <td><a href=\"security.asp\"><img border=\"0\" src=\"security.gif\" alt=\"Security\"></a></td>\n");
1625#ifdef __CONFIG_WAPI_IAS__
1626	websWrite(wp,
1627	  "  <td><a href=\"as.asp\"><img border=\"0\" src=\"as.gif\" alt=\"AS\"></a></td>\n");
1628#endif /* __CONFIG_WAPI_IAS__ */
1629#ifdef __CONFIG_WPS__
1630	websWrite(wp,
1631	  "  <td><a href=\"wps.asp\"><img border=\"0\" src=\"wps.gif\" alt=\"wps\"></a></td>\n");
1632#endif /* __CONFIG_WPS__ */
1633#ifndef __CONFIG_NETBOOT__
1634	websWrite(wp,
1635	  "  <td><a href=\"firmware.asp\"><img border=\"0\" src=\"firmware.gif\" alt=\"Firmware\"></a></td>\n");
1636#else
1637	websWrite(wp,
1638	  "  <td><a href=\"netboot.asp\"><img border=\"0\" src=\"firmware.gif\" alt=\"Firmware\"></a></td>\n");
1639#endif	/* __CONFIG_NETBOOT */
1640#if defined(__CONFIG_VISUALIZATION__) && defined(CONFIG_VISUALIZATION_ENABLED)
1641	websWrite(wp,
1642          "  <td><a href=\"visindex.asp\"><img border=\"0\" src=\"visualization.gif\" alt=\"Visualization\"></a></td>\n");
1643#endif /* (__CONFIG_VISUALIZATION__) && (CONFIG_VISUALIZATION_ENABLED) */
1644#if defined(__CONFIG_TREND_IQOS__) && defined(CONFIG_TREND_IQOS_ENABLED)
1645	websWrite(wp,
1646          "  <td><a href=\"iQoSNetworkSummary.asp\"><img border=\"0\" src=\"iqos.gif\" alt=\"iQoS\"></a></td>\n");
1647#endif /* __CONFIG_TREND_IQOS__ && CONFIG_TREND_IQOS_ENABLED */
1648	websWrite(wp,
1649	  "  <td width=\"100%%\"></td>\n"
1650	  "</tr>\n");
1651	return 0;
1652}
1653
1654static char *
1655rfctime(const time_t *timep)
1656{
1657	static char s[201];
1658	struct tm tm;
1659
1660#if defined(linux) || defined(__NetBSD__)
1661	setenv("TZ", nvram_safe_get("time_zone"), 1);
1662#endif
1663	memcpy(&tm, localtime(timep), sizeof(struct tm));
1664	strftime(s, 200, "%a, %d %b %Y %H:%M:%S %z", &tm);
1665	return s;
1666}
1667
1668static char *
1669reltime(unsigned int seconds)
1670{
1671	static char s[] = "XXXXX days, XX hours, XX minutes, XX seconds";
1672	char *c = s;
1673
1674	if (seconds > 60*60*24) {
1675		c += sprintf(c, "%d days, ", seconds / (60*60*24));
1676		seconds %= 60*60*24;
1677	}
1678	if (seconds > 60*60) {
1679		c += sprintf(c, "%d hours, ", seconds / (60*60));
1680		seconds %= 60*60;
1681	}
1682	if (seconds > 60) {
1683		c += sprintf(c, "%d minutes, ", seconds / 60);
1684		seconds %= 60;
1685	}
1686	c += sprintf(c, "%d seconds", seconds);
1687
1688	return s;
1689}
1690
1691static char *
1692reltime_short(unsigned int seconds)
1693{
1694	static char buf[16];
1695
1696	sprintf(buf, "%02d:%02d:%02d",
1697	        seconds / 3600,
1698	        (seconds % 3600) / 60,
1699	        seconds % 60);
1700
1701	return buf;
1702}
1703
1704
1705/* Report time in RFC-822 format */
1706static int
1707ej_localtime(int eid, webs_t wp, int argc, char_t **argv)
1708{
1709	time_t tm;
1710
1711	time(&tm);
1712	return websWrite(wp, rfctime(&tm));
1713}
1714
1715static int
1716ej_wl_mode_list(int eid, webs_t wp, int argc, char_t **argv)
1717{
1718	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1719	char wl_mode[]="wlXXXXXXXXXX_mode";
1720	char *name=NULL, *next=NULL;
1721	int ap = 0, sta = 0, wet = 0, wds = 0, mac_spoof = 0, psta = 0, psr = 0;
1722	char cap[WLC_IOCTL_SMLEN];
1723	char caps[WLC_IOCTL_MEDLEN];
1724	int mode = 0;
1725	char *wl_bssid = NULL;
1726
1727	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid)))
1728		mode=1;
1729
1730	if (!make_wl_prefix(prefix,sizeof(prefix), mode, NULL)){
1731		websError(wp, 400, "unit number variable doesn't exist\n");
1732		return -1;
1733	}
1734
1735	snprintf(wl_mode,sizeof(wl_mode),"%smode",prefix);
1736
1737	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1738
1739	if(mode) {
1740		/* VIF is being selected , show the mode as AccessPoint, even if
1741		 * VIF is not configured yet */
1742		websWrite(wp, "<option value=\"ap\" selected >Access Point</option>\n" );
1743	}
1744
1745
1746	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
1747		return -1;
1748
1749	foreach(cap, caps, next) {
1750		if (!strcmp(cap, "ap"))
1751			ap = wds = 1;
1752		else if (!strcmp(cap, "sta"))
1753			sta = 1;
1754		else if (!strcmp(cap, "wet"))
1755			wet = 1;
1756		else if (!strcmp(cap, "mac_spoof"))
1757			mac_spoof = 1;
1758		else if (!strcmp(cap, "psta"))
1759			psta = 1;
1760		else if (!strcmp(cap, "psr"))
1761			psr = 1;
1762	}
1763
1764	if (ap)
1765		websWrite(wp, "<option value=\"ap\" %s>Access Point</option>\n",
1766				nvram_match(wl_mode, "ap" ) ? "selected" : "");
1767	if (wds)
1768		websWrite(wp, "<option value=\"wds\" %s>Wireless Bridge</option>\n",
1769				nvram_match(wl_mode, "wds" ) ? "selected" : "");
1770	if (wet)
1771		websWrite(wp, "<option value=\"wet\" %s>Wireless Ethernet</option>\n",
1772			nvram_match(wl_mode, "wet" ) ? "selected" : "");
1773	if (mac_spoof)
1774		websWrite(wp, "<option value=\"mac_spoof\" %s>Wireless Ethernet MAC Spoof</option>\n",
1775			nvram_match(wl_mode, "mac_spoof" ) ? "selected" : "");
1776	if (psta)
1777		websWrite(wp, "<option value=\"psta\" %s>Proxy STA</option>\n",
1778			nvram_match(wl_mode, "psta" ) ? "selected" : "");
1779	if (psr)
1780		websWrite(wp, "<option value=\"psr\" %s>Proxy STA Repeater</option>\n",
1781			nvram_match(wl_mode, "psr" ) ? "selected" : "");
1782	if (sta)
1783		websWrite(wp, "<option value=\"sta\" %s>Station</option>\n",
1784			nvram_match(wl_mode, "sta" ) ? "selected" : "");
1785	return 0;
1786}
1787
1788static int
1789ej_wl_bw_cap_list(int eid, webs_t wp, int argc, char_t **argv)
1790{
1791	int status = 0;
1792	char *name=NULL;
1793	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1794	int cur_phytype;
1795
1796	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
1797		websError(wp, 400, "unit number variable doesn't exist\n");
1798		status = -1;
1799		goto exit;
1800	}
1801
1802	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1803
1804	/* Get configured phy type */
1805	wl_ioctl(name, WLC_GET_PHYTYPE, &cur_phytype, sizeof(cur_phytype));
1806
1807	websWrite(wp, "<option value=\"1\" %s>20 MHz</option>",
1808	          nvram_match("wl_bw_cap", "1") ? "selected" : "");
1809	websWrite(wp, "<option value=\"3\" %s>40 MHz</option>",
1810	          nvram_match("wl_bw_cap", "3") ? "selected" : "");
1811
1812	if (cur_phytype == WLC_PHY_TYPE_AC) {
1813		/* List 80 MHz bandwidth as well */
1814		websWrite(wp, "<option value=\"7\" %s>80 MHz</option>",
1815		          nvram_match("wl_bw_cap", "7") ? "selected" : "");
1816	}
1817
1818exit:
1819	return status;
1820}
1821
1822static char *
1823translate_ssid(char *ssid)
1824{
1825	static char ssid_html[32*5+1]; /* *5 => &#255 */
1826	char *c = NULL, *pssid = ssid_html;;
1827	int len, size = sizeof(ssid_html);
1828
1829	/* Clear static ssid_html */
1830	memset(ssid_html, 0, sizeof(ssid_html));
1831
1832	for (c = ssid; *c; c++) {
1833		if (isprint((int) *c) &&
1834		    *c != '"' && *c != '&' && *c != '<' && *c != '>')
1835			len = snprintf(pssid, size, "%c", *c);
1836		else
1837			len = snprintf(pssid, size, "&#%d;", *c);
1838
1839		size -= len;
1840		pssid += len;
1841	}
1842
1843	return ssid_html;
1844}
1845
1846static int
1847ej_wl_bssid_list(int eid, webs_t wp, int argc, char_t **argv)
1848{
1849	char vif[64];
1850	char prefix[] = "wlXXXXXXXXXX_";
1851	char *bssid = NULL;
1852	char *ssid = NULL;
1853	char i = 0;
1854	char *wl_bssid = NULL;
1855	char bssid_selected = 0;
1856	int mode = 0;
1857	char cap[WLC_IOCTL_SMLEN];
1858	char caps[WLC_IOCTL_MEDLEN];
1859	char *name = NULL;
1860	char *next = NULL;
1861	int max_no_vifs = 1;
1862	char *bss_enabled;
1863
1864	if (!make_wl_prefix(prefix, sizeof(prefix), mode, NULL)) {
1865		websError(wp, 400, "unit number variable doesn't exist\n");
1866		return -1;
1867	}
1868
1869	snprintf(vif, sizeof(vif), "%sssid", prefix);
1870	ssid  = nvram_safe_get(vif);
1871	snprintf(vif, sizeof(vif), "%shwaddr", prefix);
1872	bssid  = nvram_get(vif);
1873
1874	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)))
1875		bssid_selected = atoi(wl_bssid);
1876	snprintf(vif, sizeof(vif), "%sbss_enabled", prefix);
1877	bss_enabled = nvram_safe_get(vif);
1878
1879	/* show primary interface  */
1880	websWrite(wp, "<option value=%x %s > %s (%s %sabled) </option>\n", i,
1881		(bssid_selected == i) ? "selected" : "", bssid, translate_ssid(ssid),
1882		(bss_enabled[0] == '1') ? "en" : "dis");
1883
1884	/* Get the no of VIFS to be dispalyed */
1885	name = nvram_safe_get(strcat_r(prefix, "ifname",vif));
1886
1887	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
1888		return -1;
1889
1890	foreach(cap, caps, next) {
1891		if (!strcmp(cap, "mbss16"))
1892			max_no_vifs = 16;
1893		else if (!strcmp(cap, "mbss8"))
1894			max_no_vifs = 8;
1895		else if (!strcmp(cap, "mbss4"))
1896			max_no_vifs = 4;
1897	}
1898
1899	if ((!atoi (nvram_safe_get("ure_disable"))) ||
1900	    (!strcmp ("psr", nvram_safe_get(strcat_r(prefix, "mode", vif)))))
1901		max_no_vifs = 2;
1902
1903	/* show all virtual interface  */
1904	for (i = 1; i < max_no_vifs ; i++) {
1905		snprintf(vif, sizeof(vif), "%c%c%c.%d_ssid", prefix[0], prefix[1], prefix[2], i);
1906		ssid  = nvram_safe_get(vif);
1907		snprintf(vif, sizeof(vif), "%c%c%c.%d_hwaddr", prefix[0], prefix[1], prefix[2], i);
1908		bssid  = nvram_get(vif);
1909		if (!bssid){
1910			bssid = "virtual_bssid";
1911		}
1912		snprintf(vif, sizeof(vif), "%c%c%c.%d_bss_enabled", prefix[0], prefix[1],
1913			prefix[2], i);
1914		bss_enabled = nvram_safe_get(vif);
1915		websWrite(wp, "<option value=%d %s > %s (%s %sabled)</option>\n", i,
1916			  (bssid_selected == i) ? "selected" : "", bssid, translate_ssid(ssid),
1917			  (bss_enabled[0] == '1') ? "en" : "dis");
1918	}
1919	return 0;
1920
1921}
1922
1923static int
1924ej_wl_inlist(int eid, webs_t wp, int argc, char_t **argv)
1925{
1926	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1927	char *name=NULL, *next=NULL;
1928	char cap[WLC_IOCTL_SMLEN];
1929	char caps[WLC_IOCTL_MEDLEN];
1930	char *var=NULL, *item=NULL;
1931
1932	if (ejArgs(argc, argv, "%s %s", &var, &item) < 2) {
1933		websError(wp, 400, "Insufficient args\n");
1934		return -1;
1935	}
1936
1937	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
1938		websError(wp, 400, "unit number variable doesn't exist\n");
1939		return -1;
1940	}
1941
1942	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1943
1944	if (wl_iovar_get(name, var, (void *)caps, sizeof(caps)))
1945		return -1;
1946
1947	foreach(cap, caps, next) {
1948		if (!strcmp(cap, item))
1949			return websWrite(wp, "1");
1950	}
1951
1952	return websWrite(wp, "0");
1953}
1954
1955static int
1956ej_wl_wds_status(int eid, webs_t wp, int argc, char_t **argv)
1957{
1958	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
1959	char *macs=NULL, *next=NULL, *name=NULL;
1960	char mac[100];
1961	int i=0, len=0;
1962	sta_info_t *sta=NULL;
1963	char buf[sizeof(sta_info_t)];
1964
1965	if (ejArgs(argc, argv, "%d", &i) < 1) {
1966		websError(wp, 400, "Insufficient args\n");
1967		return -1;
1968	}
1969
1970	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
1971		websError(wp, 400, "Insufficient args\n");
1972		return -1;
1973	}
1974
1975	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1976	macs = nvram_safe_get(strcat_r(prefix, "wds", tmp));
1977
1978	foreach(mac, macs, next) {
1979		if (i-- == 0) {
1980			len = sprintf(buf, "sta_info");
1981			ether_atoe(mac, (unsigned char *)&buf[len + 1]);
1982			if (atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp))) &&
1983			    !wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))) {
1984				sta = (sta_info_t *)buf;
1985				return websWrite(wp, "%s", (sta->flags & WL_STA_WDS_LINKUP) ? "up" : "down");
1986			}
1987			else
1988				return websWrite(wp, "%s", "unknown");
1989		}
1990	}
1991
1992	return 0;
1993}
1994
1995static int
1996ej_ses_button_display(int eid, webs_t wp, int argc, char_t **argv)
1997{
1998
1999	return 1;
2000}
2001
2002
2003static int
2004ej_ses_cl_button_display(int eid, webs_t wp, int argc, char_t **argv)
2005{
2006
2007	return 1;
2008}
2009
2010static int
2011ej_wl_auth_display(int eid, webs_t wp, int argc, char_t **argv)
2012{
2013	if (!nvram_match("wl_mode", "ap"))
2014		websWrite(wp, "<option value=\"2\" %s>Auto</option>",
2015		          nvram_match("wl_auth", "2") ? "selected" : "");
2016	websWrite(wp, "<option value=\"1\" %s>Shared</option>",
2017	          nvram_match("wl_auth", "1") ? "selected" : "");
2018	websWrite(wp, "<option value=\"0\" %s>Open</option>",
2019	          nvram_match("wl_auth", "0") ? "selected" : "");
2020
2021	return 1;
2022}
2023
2024static int
2025ej_emf_enable_display(int eid, webs_t wp, int argc, char_t **argv)
2026{
2027#ifdef __CONFIG_EMF__
2028	websWrite(wp, "<p>\n");
2029	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
2030	websWrite(wp, "<tr>\n");
2031	websWrite(wp, "<th width=\"310\"\n");
2032	websWrite(wp, "onMouseOver=\"return overlib(\'Enables/Disables Efficient Multicast Forwarding feature\', LEFT);\"\n");
2033	websWrite(wp, "onMouseOut=\"return nd();\">\n");
2034	websWrite(wp, "EMF:&nbsp;&nbsp;\n");
2035	websWrite(wp, "</th>\n");
2036	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2037	websWrite(wp, "<td>\n");
2038	websWrite(wp, "<select name=\"emf_enable\">\n");
2039	websWrite(wp, "<option value=\"1\" %s>Enabled</option>", nvram_match("emf_enable", "1") ? "selected": "\n");
2040	websWrite(wp, "<option value=\"0\" %s>Disabled</option>", nvram_match("emf_enable", "0") ? "selected": "\n");
2041	websWrite(wp, "</select>\n");
2042	websWrite(wp, "</td>\n");
2043	websWrite(wp, "</tr>\n");
2044	websWrite(wp, "</table>\n");
2045#endif /* __CONFIG_EMF__ */
2046
2047	return 1;
2048}
2049
2050#ifdef __CONFIG_EMF__
2051/*
2052 * Example:
2053 * emf_entry=225.0.0.1:wds0.1 225.0.0.2:wds0.2 ...
2054 * get_emf_entry("mgrp", 0) : produces "225.0.0.1"
2055 * get_emf_entry("if", 0) : produces "wds0.1"
2056 */
2057void
2058get_emf_entry(char *arg, int entry, char *output)
2059{
2060	char word[256], *next;
2061	char *mgrp, *ifname;
2062
2063	foreach(word, nvram_safe_get("emf_entry"), next) {
2064		if (entry-- == 0) {
2065			ifname = word;
2066			mgrp = strsep(&ifname, ":");
2067			if (!mgrp || !ifname)
2068				continue;
2069			if (!strcmp(arg, "mgrp")) {
2070				strcpy(output, mgrp);
2071				return;
2072			}
2073			else if (!strcmp(arg, "if")) {
2074				strcpy(output, ifname);
2075				return;
2076			}
2077		}
2078	}
2079
2080	strcpy(output, "");
2081
2082	return;
2083}
2084#endif /* __CONFIG_EMF__ */
2085
2086static int
2087ej_emf_entries_display(int eid, webs_t wp, int argc, char_t **argv)
2088{
2089#ifdef __CONFIG_EMF__
2090	char value[32];
2091
2092	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
2093	websWrite(wp, "<tr>\n");
2094    	websWrite(wp, "<th width=\"310\" valign=\"top\" rowspan=\"6\"\n");
2095	websWrite(wp, "onMouseOver=\"return overlib(\'Add/Delete static forwarding entries for the multicast groups.\', LEFT);\"\n");
2096	websWrite(wp, "onMouseOut=\"return nd();\">\n");
2097	websWrite(wp, "<input type=\"hidden\" name=\"emf_entry\" value=\"5\">\n");
2098	websWrite(wp, "Static Multicast Forwarding Entries:&nbsp;&nbsp;\n");
2099    	websWrite(wp, "</th>\n");
2100    	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2101    	websWrite(wp, "<td class=\"label\">Multicast IP Address</td>\n");
2102    	websWrite(wp, "<td></td>\n");
2103    	websWrite(wp, "<td class=\"label\">Interface</td>\n");
2104  	websWrite(wp, "</tr>\n");
2105	websWrite(wp, "<tr>\n");
2106	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2107	get_emf_entry("mgrp", 0, value);
2108	websWrite(wp, "<td><input name=\"emf_entry_mgrp0\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2109	websWrite(wp, "<td>&nbsp;</td>\n");
2110	get_emf_entry("if", 0, value);
2111	websWrite(wp, "<td><input name=\"emf_entry_if0\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2112	websWrite(wp, "</tr>\n");
2113	websWrite(wp, "<tr>\n");
2114	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2115	get_emf_entry("mgrp", 1, value);
2116	websWrite(wp, "<td><input name=\"emf_entry_mgrp1\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2117	websWrite(wp, "<td>&nbsp;</td>\n");
2118	get_emf_entry("if", 1, value);
2119	websWrite(wp, "<td><input name=\"emf_entry_if1\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2120	websWrite(wp, "</tr>\n");
2121	websWrite(wp, "<tr>\n");
2122	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2123	get_emf_entry("mgrp", 2, value);
2124	websWrite(wp, "<td><input name=\"emf_entry_mgrp2\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2125	websWrite(wp, "<td>&nbsp;</td>\n");
2126	get_emf_entry("if", 2, value);
2127	websWrite(wp, "<td><input name=\"emf_entry_if2\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2128	websWrite(wp, "</tr>\n");
2129	websWrite(wp, "<tr>\n");
2130	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2131	get_emf_entry("mgrp", 3, value);
2132	websWrite(wp, "<td><input name=\"emf_entry_mgrp3\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2133	websWrite(wp, "<td>&nbsp;</td>\n");
2134	get_emf_entry("if", 3, value);
2135	websWrite(wp, "<td><input name=\"emf_entry_if3\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2136	websWrite(wp, "</tr>\n");
2137	websWrite(wp, "<tr>\n");
2138	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2139	get_emf_entry("mgrp", 4, value);
2140	websWrite(wp, "<td><input name=\"emf_entry_mgrp4\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2141	websWrite(wp, "<td>&nbsp;</td>\n");
2142	get_emf_entry("if", 4, value);
2143	websWrite(wp, "<td><input name=\"emf_entry_if4\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2144	websWrite(wp, "</tr>\n");
2145	websWrite(wp, "</table>\n");
2146#endif /* __CONFIG_EMF__ */
2147
2148	return 1;
2149}
2150
2151#ifdef __CONFIG_EMF__
2152/*
2153 * Example:
2154 * emf_uffp_entry=wds0.1 wds0.2 ...
2155 * get_emf_uffp_entry("if", 0) : produces "wds0.1"
2156 * get_emf_uffp_entry("if", 1) : produces "wds0.2"
2157 */
2158void
2159get_emf_uffp_entry(char *arg, int entry, char *output)
2160{
2161	char word[256], *next;
2162	char *ifname;
2163
2164	foreach(word, nvram_safe_get("emf_uffp_entry"), next) {
2165		if (entry-- == 0) {
2166			ifname = word;
2167			if (ifname[0] == '\0')
2168				continue;
2169			if (!strcmp(arg, "if")) {
2170				strcpy(output, ifname);
2171				return;
2172			}
2173		}
2174	}
2175
2176	strcpy(output, "");
2177
2178	return;
2179}
2180
2181/*
2182 * Example:
2183 * emf_rtport_entry=wds0.1 wds0.2 ...
2184 * get_emf_rtport_entry("if", 0) : produces "wds0.1"
2185 * get_emf_rtport_entry("if", 1) : produces "wds0.2"
2186 */
2187void
2188get_emf_rtport_entry(char *arg, int entry, char *output)
2189{
2190	char word[256], *next;
2191	char *ifname;
2192
2193	foreach(word, nvram_safe_get("emf_rtport_entry"), next) {
2194		if (entry-- == 0) {
2195			ifname = word;
2196			if (ifname[0] == '\0')
2197				continue;
2198			if (!strcmp(arg, "if")) {
2199				strcpy(output, ifname);
2200				return;
2201			}
2202		}
2203	}
2204
2205	strcpy(output, "");
2206
2207	return;
2208}
2209#endif /* __CONFIG_EMF__ */
2210
2211static int
2212ej_emf_uffp_entries_display(int eid, webs_t wp, int argc, char_t **argv)
2213{
2214#ifdef __CONFIG_EMF__
2215	char value[32];
2216
2217	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
2218	websWrite(wp, "<tr>\n");
2219    	websWrite(wp, "<th width=\"310\" valign=\"top\" rowspan=\"6\"\n");
2220	websWrite(wp, "onMouseOver=\"return overlib(\'Add/Delete unregistered multicast data frames forwarding port entries. Multicast data frames that fail MFDB lookup will be flooded on to these ports.\', LEFT);\"\n");
2221	websWrite(wp, "onMouseOut=\"return nd();\">\n");
2222	websWrite(wp, "<input type=\"hidden\" name=\"emf_uffp_entry\" value=\"5\">\n");
2223	websWrite(wp, "Unregistered Multicast Frames Forwarding Ports:&nbsp;&nbsp;\n");
2224    	websWrite(wp, "</th>\n");
2225    	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2226    	websWrite(wp, "<td class=\"label\">Interface</td>\n");
2227    	websWrite(wp, "<td></td>\n");
2228  	websWrite(wp, "</tr>\n");
2229	websWrite(wp, "<tr>\n");
2230	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2231	get_emf_uffp_entry("if", 0, value);
2232	websWrite(wp, "<td><input name=\"emf_uffp_entry_if0\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2233	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2234    	websWrite(wp, "<td></td>\n");
2235	websWrite(wp, "</tr>\n");
2236	websWrite(wp, "<tr>\n");
2237	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2238	get_emf_uffp_entry("if", 1, value);
2239	websWrite(wp, "<td><input name=\"emf_uffp_entry_if1\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2240	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2241    	websWrite(wp, "<td></td>\n");
2242	websWrite(wp, "</tr>\n");
2243	websWrite(wp, "<tr>\n");
2244	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2245	get_emf_uffp_entry("if", 2, value);
2246	websWrite(wp, "<td><input name=\"emf_uffp_entry_if2\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2247	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2248    	websWrite(wp, "<td></td>\n");
2249	websWrite(wp, "</tr>\n");
2250	websWrite(wp, "<tr>\n");
2251	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2252	get_emf_uffp_entry("if", 3, value);
2253	websWrite(wp, "<td><input name=\"emf_uffp_entry_if3\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2254	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2255    	websWrite(wp, "<td></td>\n");
2256	websWrite(wp, "</tr>\n");
2257	websWrite(wp, "<tr>\n");
2258	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2259	get_emf_uffp_entry("if", 4, value);
2260	websWrite(wp, "<td><input name=\"emf_uffp_entry_if4\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2261	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2262    	websWrite(wp, "<td></td>\n");
2263	websWrite(wp, "</tr>\n");
2264	websWrite(wp, "</table>\n");
2265#endif /* __CONFIG_EMF__ */
2266
2267	return 1;
2268}
2269
2270static int
2271ej_emf_rtport_entries_display(int eid, webs_t wp, int argc, char_t **argv)
2272{
2273#ifdef __CONFIG_EMF__
2274	char value[32];
2275
2276	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
2277	websWrite(wp, "<tr>\n");
2278    	websWrite(wp, "<th width=\"310\" valign=\"top\" rowspan=\"6\"\n");
2279	websWrite(wp, "onMouseOver=\"return overlib(\'These are the LAN interfaces on which multicast routers are present. IGMP Report frames are forwared to these ports.\', LEFT);\"\n");
2280	websWrite(wp, "onMouseOut=\"return nd();\">\n");
2281	websWrite(wp, "<input type=\"hidden\" name=\"emf_rtport_entry\" value=\"5\">\n");
2282	websWrite(wp, "Multicast Router / IGMP Forwarding Ports:&nbsp;&nbsp;\n");
2283    	websWrite(wp, "</th>\n");
2284    	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2285    	websWrite(wp, "<td class=\"label\">Interface</td>\n");
2286    	websWrite(wp, "<td></td>\n");
2287  	websWrite(wp, "</tr>\n");
2288	websWrite(wp, "<tr>\n");
2289	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2290	get_emf_rtport_entry("if", 0, value);
2291	websWrite(wp, "<td><input name=\"emf_rtport_entry_if0\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2292	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2293    	websWrite(wp, "<td></td>\n");
2294	websWrite(wp, "</tr>\n");
2295	websWrite(wp, "<tr>\n");
2296	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2297	get_emf_rtport_entry("if", 1, value);
2298	websWrite(wp, "<td><input name=\"emf_rtport_entry_if1\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2299	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2300    	websWrite(wp, "<td></td>\n");
2301	websWrite(wp, "</tr>\n");
2302	websWrite(wp, "<tr>\n");
2303	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2304	get_emf_rtport_entry("if", 2, value);
2305	websWrite(wp, "<td><input name=\"emf_rtport_entry_if2\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2306	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2307    	websWrite(wp, "<td></td>\n");
2308	websWrite(wp, "</tr>\n");
2309	websWrite(wp, "<tr>\n");
2310	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2311	get_emf_rtport_entry("if", 3, value);
2312	websWrite(wp, "<td><input name=\"emf_rtport_entry_if3\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2313	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2314    	websWrite(wp, "<td></td>\n");
2315	websWrite(wp, "</tr>\n");
2316	websWrite(wp, "<tr>\n");
2317	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2318	get_emf_rtport_entry("if", 4, value);
2319	websWrite(wp, "<td><input name=\"emf_rtport_entry_if4\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>\n", value);
2320	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2321    	websWrite(wp, "<td></td>\n");
2322	websWrite(wp, "</tr>\n");
2323	websWrite(wp, "</table>\n");
2324#endif /* __CONFIG_EMF__ */
2325
2326	return 1;
2327}
2328
2329static int
2330ej_ses_wds_mode_list(int eid, webs_t wp, int argc, char_t **argv)
2331{
2332	websWrite(wp, "<option value=\"0\" %s>Disabled</option>\n",
2333						nvram_match("ses_wds_mode", "0") ? "selected" : "" );
2334	websWrite(wp, "<option value=\"1\" %s>Auto</option>\n",
2335						nvram_match("ses_wds_mode", "1") ? "selected" : "" );
2336	websWrite(wp, "<option value=\"2\" %s>Configurator(Reg+WDS)</option>\n",
2337						nvram_match("ses_wds_mode", "2") ? "selected" : "" );
2338	websWrite(wp, "<option value=\"3\" %s>Configurator(WDS only)</option>\n",
2339						nvram_match("ses_wds_mode", "3") ? "selected" : "" );
2340	if( !nvram_match( "ses_cl_enable", "0" ))
2341		websWrite(wp, "<option value=\"4\" %s>Client</option>\n",
2342							nvram_match("ses_wds_mode", "4") ? "selected" : "" );
2343	return 1;
2344}
2345
2346static int
2347ej_wl_radio_roam_option(int eid, webs_t wp, int argc, char_t **argv)
2348{
2349	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
2350	char *name=NULL;
2351	int radio_status = 0;
2352
2353	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
2354		websError(wp, 400, "unit number variable doesn't exist\n");
2355		return -1;
2356	}
2357	name = nvram_get(strcat_r(prefix, "ifname", tmp));
2358
2359	if (!name){
2360		websError(wp, 400, "Could not find: %s\n",strcat_r(prefix, "ifname", tmp));
2361		return -1;
2362	}
2363
2364	wl_ioctl(name, WLC_GET_RADIO, &radio_status, sizeof (radio_status));
2365	radio_status &= WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE;
2366
2367	if (!radio_status) /* Radio on*/
2368		websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"RadioOff\" >");
2369	else /* Radio Off */
2370		websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"RadioOn\" >");
2371
2372	return 1;
2373
2374
2375}
2376
2377static int
2378ej_wet_tunnel_display(int eid, webs_t wp, int argc, char_t **argv)
2379{
2380	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
2381	char cap[WLC_IOCTL_SMLEN];
2382	char caps[WLC_IOCTL_MEDLEN];
2383	char *name = NULL;
2384	char *next = NULL;
2385	int wet_tunnel_cap = 0;
2386
2387	if (!make_wl_prefix(prefix, sizeof(prefix), 0, NULL)) {
2388		websError(wp, 400, "unit number variable doesn't exist\n");
2389		return -1;
2390	}
2391
2392	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
2393	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
2394		return -1;
2395
2396	foreach(cap, caps, next) {
2397		if (!strcmp(cap, "wet_tunnel")) {
2398			wet_tunnel_cap = 1;
2399			break;
2400		}
2401	}
2402	if (wet_tunnel_cap == 0)
2403		return -1;
2404
2405	websWrite(wp, "<p>\n");
2406	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
2407	websWrite(wp, "<tr>\n");
2408	websWrite(wp, "<th width=\"310\"\n");
2409	websWrite(wp, "onMouseOver=\"return overlib(\'Enable/Disable WET tunnel\', LEFT);\"\n");
2410	websWrite(wp, "onMouseOut=\"return nd();\">\n");
2411	websWrite(wp, "WET Tunnel:&nbsp;&nbsp;\n");
2412	websWrite(wp, "</th>\n");
2413	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2414	websWrite(wp, "<td>\n");
2415	websWrite(wp, "<select name=\"wl_wet_tunnel\">\n");
2416	websWrite(wp, "<option value=\"1\" %s>Enabled</option>", nvram_match("wl_wet_tunnel", "1") ? "selected": "\n");
2417	websWrite(wp, "<option value=\"0\" %s>Disabled</option>", nvram_match("wl_wet_tunnel", "0") ? "selected": "\n");
2418	websWrite(wp, "</select>\n");
2419	websWrite(wp, "</td>\n");
2420	websWrite(wp, "</tr>\n");
2421	websWrite(wp, "</table>\n");
2422
2423	return 1;
2424}
2425
2426#ifdef TRAFFIC_MGMT_RSSI_POLICY
2427static int
2428ej_trf_mgmt_rssi_policy_display(int eid, webs_t wp, int argc, char_t **argv)
2429{
2430	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
2431	char cap[WLC_IOCTL_SMLEN];
2432	char caps[WLC_IOCTL_MEDLEN];
2433	char *name = NULL;
2434	char *next = NULL;
2435	int trf_mgmt_cap = 0;
2436
2437	if (!make_wl_prefix(prefix, sizeof(prefix), 0, NULL)) {
2438		websError(wp, 400, "unit number variable doesn't exist\n");
2439		return -1;
2440	}
2441
2442	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
2443	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
2444		return -1;
2445
2446	foreach(cap, caps, next) {
2447		if (!strcmp(cap, "traffic-mgmt")) {
2448			trf_mgmt_cap = 1;
2449			break;
2450		}
2451	}
2452	if (trf_mgmt_cap == 0)
2453		return -1;
2454
2455	websWrite(wp, "<p>\n");
2456	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
2457	websWrite(wp, "<tr>\n");
2458	websWrite(wp, "<th width=\"310\"\n");
2459	websWrite(wp, "onMouseOver=\"return overlib(\'Set to map lowest RSSI STA to low priority(BE) or disable.\', LEFT);\"\n");
2460	websWrite(wp, "onMouseOut=\"return nd();\">\n");
2461	websWrite(wp, "Traffic Management RSSI Policy:&nbsp;&nbsp;\n");
2462	websWrite(wp, "</th>\n");
2463	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
2464	websWrite(wp, "<td>\n");
2465	websWrite(wp, "<select name=\"wl_trf_mgmt_rssi_policy\">\n");
2466	websWrite(wp, "<option value=\"0\" %s>None</option>", nvram_match("wl_trf_mgmt_rssi_policy", "0") ? "selected": "\n");
2467	websWrite(wp, "<option value=\"1\" %s>Lowest RSSI</option>", nvram_match("wl_trf_mgmt_rssi_policy", "1") ? "selected": "\n");
2468	websWrite(wp, "</select>\n");
2469	websWrite(wp, "</td>\n");
2470	websWrite(wp, "</tr>\n");
2471	websWrite(wp, "</table>\n");
2472
2473	return 1;
2474}
2475#endif /* TRAFFIC_MGMT_RSSI_POLICY */
2476
2477#if defined(__CONFIG_DLNA_DMS__)
2478#ifdef LINUX26
2479static char *mntdir = "/media";
2480#else
2481static char *mntdir = "/mnt";
2482#endif
2483#endif
2484
2485
2486#if defined(__CONFIG_DLNA_DMS__)
2487static int
2488ej_get_mnt_path(int eid, webs_t wp, int argc, char_t **argv)
2489{
2490	char mntpath[128] = {0};
2491	char devpath[128] = {0};
2492	FILE *fp;
2493	char buf[256];
2494
2495	memset(mntpath, 0, sizeof(mntpath));
2496	memset(devpath, 0, sizeof(devpath));
2497
2498	if ((fp = fopen("/proc/mounts", "r")) != NULL) {
2499		while (fgets(buf, sizeof(buf), fp) != NULL) {
2500			if (strstr(buf, mntdir) != NULL) {
2501				sscanf(buf, "%s %s", devpath, mntpath);
2502				break;
2503			}
2504		}
2505		fclose(fp);
2506	}
2507
2508	return websWrite(wp, mntpath);
2509}
2510#endif /* __CONFIG_DLNA_DMS__ */
2511
2512#ifdef __CONFIG_WPS__
2513/* WPS ENR mode APIs */
2514typedef struct wps_ap_list_info
2515{
2516	bool        used;
2517	uint8       ssid[33];
2518	uint8       ssidLen;
2519	uint8       BSSID[6];
2520	uint8       *ie_buf;
2521	uint32      ie_buflen;
2522	uint8       channel;
2523	uint8       wep;
2524	bool	    scstate;
2525} wps_ap_list_info_t;
2526
2527#define WPS_ENR_DUMP_BUF_LEN (32 * 1024)
2528#define WPS_ENR_MAX_AP_SCAN_LIST_LEN 50
2529#define WPS_ENR_SCAN_RETRY_TIMES	5
2530
2531static wps_ap_list_info_t ap_list[WPS_ENR_MAX_AP_SCAN_LIST_LEN];
2532static char scan_result[WPS_ENR_DUMP_BUF_LEN];
2533static int scanned = 0, wps_ap_num = 0;
2534wps_ap_list_info_t *selected_ap = NULL;
2535
2536static int ej_wps_process(int eid, webs_t wp, int argc, char_t **argv);
2537static int ej_wps_current_mode(int eid, webs_t wp, int argc, char_t **argv, int wps_sta);
2538static int ej_wps_start(int eid, webs_t wp, int argc, char_t **argv, int wps_sta);
2539static int ej_wps_credentials(int eid, webs_t wp, int argc, char_t **argv, int wps_sta);
2540static int ej_wps_enr_scan_result(int eid, webs_t wp, int argc, char_t **argv);
2541static int ej_wps_enr_process(int eid, webs_t wp, int argc, char_t **argv);
2542static int wps_gen_ssid(char *ssid, int ssid_len);
2543static int wps_gen_key(char *key, int key_len);
2544static wps_ap_list_info_t *wps_enr_create_aplist();
2545static int wps_enr_get_aplist(wps_ap_list_info_t *list_in, wps_ap_list_info_t *list_out );
2546
2547#define MACLIST_MAX_NUM	16
2548
2549static int wps_config_command;
2550static int wps_action = 0;
2551static int wps_method;
2552static char wps_autho_sta_mac[sizeof("00:00:00:00:00:00")];
2553static char wps_uuid[36];
2554static char wps_unit[32];
2555static int ssid_update = 0;
2556static char random_ssid[33] = {0};
2557static char random_psk[65] = {0};
2558#ifdef __CONFIG_NFC__
2559static int wps_nfc_dm_status;
2560static int wps_nfc_err_code;
2561#endif
2562static int get_wps_env();
2563
2564static int wps_get_lan_idx();
2565static int wps_is_reg();
2566static int wps_is_oob();
2567static void wps_disable_oob();
2568static int wps_get_oob_name(char *name, int lan);
2569
2570static void
2571wl_wpsPinGen(char *devPwd)
2572{
2573	unsigned long PIN;
2574	unsigned long int accum = 0;
2575	int digit;
2576
2577	srand(time((time_t *)NULL));
2578	PIN = rand();
2579	sprintf(devPwd, "%08u", (unsigned int)PIN);
2580	devPwd[7] = '\0';
2581
2582	PIN = strtoul( devPwd, NULL, 10 );
2583
2584	PIN *= 10;
2585	accum += 3 * ((PIN / 10000000) % 10);
2586	accum += 1 * ((PIN / 1000000) % 10);
2587	accum += 3 * ((PIN / 100000) % 10);
2588	accum += 1 * ((PIN / 10000) % 10);
2589	accum += 3 * ((PIN / 1000) % 10);
2590	accum += 1 * ((PIN / 100) % 10);
2591	accum += 3 * ((PIN / 10) % 10);
2592
2593	digit = (accum % 10);
2594	accum = (10 - digit) % 10;
2595
2596	PIN += accum;
2597	sprintf(devPwd, "%u", (unsigned int)PIN);
2598	devPwd[8] = '\0';
2599
2600	printf("Generate WPS PIN = %s\n", devPwd);
2601	return;
2602}
2603
2604static int
2605wl_wpsPincheck(char *pin_string)
2606{
2607	unsigned long PIN = strtoul(pin_string, NULL, 10);
2608	unsigned long int accum = 0;
2609	unsigned int len = strlen(pin_string);
2610
2611	if (len != 4 && len != 8)
2612		return 	-1;
2613
2614	if (len == 8) {
2615		accum += 3 * ((PIN / 10000000) % 10);
2616		accum += 1 * ((PIN / 1000000) % 10);
2617		accum += 3 * ((PIN / 100000) % 10);
2618		accum += 1 * ((PIN / 10000) % 10);
2619		accum += 3 * ((PIN / 1000) % 10);
2620		accum += 1 * ((PIN / 100) % 10);
2621		accum += 3 * ((PIN / 10) % 10);
2622		accum += 1 * ((PIN / 1) % 10);
2623
2624		if (0 == (accum % 10))
2625			return 0;
2626	}
2627	else if (len == 4)
2628		return 0;
2629
2630	return -1;
2631}
2632
2633#ifdef __CONFIG_NFC__
2634static int
2635ej_wps_nfc_dm_status(int eid, webs_t wp, int argc, char_t **argv)
2636{
2637
2638	char *status;
2639
2640	if (!nvram_match( "wl_wps_mode", "enabled" ))
2641		return 0;
2642
2643	switch (wps_nfc_dm_status) {
2644	case WPS_UI_NFC_STATUS_INITED:
2645		websWrite(wp, "Successful Initiated");
2646		break;
2647	case WPS_UI_NFC_STATUS_INITING:
2648		websWrite(wp, "Initiating");
2649		break;
2650	default:
2651		websWrite(wp, "Error: code %d\n", wps_nfc_dm_status);
2652		break;
2653	}
2654
2655	return 0;
2656}
2657#endif /* __CONFIG_NFC__ */
2658#endif /* __CONFIG_WPS__ */
2659
2660
2661/* Always have following ej_wps_xxx functions */
2662static int
2663ej_wps_display(int eid, webs_t wp, int argc, char_t **argv)
2664{
2665#ifdef __CONFIG_WPS__
2666	/* We need to separate STA and AP */
2667	char *str;
2668	int wps_sta = 0;
2669	char prefix[] = "wlXXXXXXXXXX_";
2670	char wl_mode[]="wlXXXXXXXXXX_mode";
2671	char wps_mode[100];
2672	char *value;
2673	char tmp[100] = {0};
2674
2675	if ((value = websGetVar(wp, "wl_unit", NULL))) {
2676		printf("ej_wps_display: wl_unit=%s\n", value);
2677		nvram_set("wl_unit", value);
2678	}
2679
2680	if (!make_wl_prefix(prefix,sizeof(prefix), 1, NULL)) {
2681		websError(wp, 400, "unit number variable doesn't exist\n");
2682		return EINVAL;
2683	}
2684
2685	snprintf(wl_mode,sizeof(wl_mode),"%smode",prefix);
2686	value = nvram_safe_get(wl_mode);
2687	if (!strcmp(value, "wet") ||
2688		!strcmp(value, "sta") ||
2689		!strcmp(value, "psr") ||
2690		!strcmp(value, "psta") ||
2691		!strcmp(value, "mac_spoof")) {
2692		wps_sta = 1;
2693	}
2694
2695	if ((value = websGetVar(wp, "wps_action", NULL))) {
2696		if (!strcmp(value, "AddEnrollee"))
2697			wps_action = WPS_UI_ACT_ADDENROLLEE;
2698		else if (!strcmp(value, "Enroll"))
2699			wps_action = WPS_UI_ACT_ENROLL;
2700		else if (!strcmp(value, "ConfigAP"))
2701			wps_action = WPS_UI_ACT_STA_CONFIGAP;
2702		else if (!strcmp(value, "GetAPConfig"))
2703			wps_action = WPS_UI_ACT_STA_GETAPCONFIG;
2704	}
2705
2706	if (!wps_sta) {
2707		if (wps_action != WPS_UI_ACT_ADDENROLLEE )
2708			wps_action = WPS_UI_ACT_ADDENROLLEE;
2709	}
2710	else {
2711		if (wps_action == WPS_UI_ACT_NONE ||
2712		    wps_action == WPS_UI_ACT_ADDENROLLEE ){
2713			wps_action = WPS_UI_ACT_ENROLL;
2714		}
2715	}
2716
2717	/* Parse WPS method */
2718	if (wps_action == WPS_UI_ACT_ENROLL) {
2719		if ((value = websGetVar(wp, "wps_method", NULL))) {
2720			if (!strcmp(value, "PIN"))
2721				wps_method = WPS_UI_METHOD_PIN;
2722			else
2723				wps_method = WPS_UI_METHOD_PBC;
2724		}
2725		snprintf(tmp, sizeof(tmp), "%d", wps_method);
2726		nvram_set("wps_method", tmp);
2727	}
2728
2729	websWrite(wp,"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
2730
2731	websWrite(wp, "<tr>"
2732		  "<th width=\"310\""
2733		  "onMouseOver=\"return overlib('WPS current mode', LEFT);\""
2734		  "onMouseOut=\"return nd();\">"
2735		  "WPS Current Mode:&nbsp;&nbsp;"
2736		  "</th>"
2737		  "<td>&nbsp;&nbsp;</td>"
2738		  "<td>");
2739
2740	ej_wps_current_mode(eid, wp, argc, argv, wps_sta);
2741	websWrite(wp, "</td> </tr>");
2742	websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td><td></td></tr>\n");
2743
2744	websWrite(wp, "<tr>"
2745	          "<th width=\"310\""
2746	          "onMouseOver=\"return overlib('Selects WiFi Simple Config mode.', LEFT);\""
2747	          "onMouseOut=\"return nd();\">"
2748	          "WPS Configuration:&nbsp;&nbsp;"
2749	          "</th>"
2750	          "<td>&nbsp;&nbsp;</td>\n"
2751	          "<td>" );
2752	websWrite(wp,"<select name=\"wl_wps_mode\" onChange=\"wps_config_change();\">");
2753
2754	sprintf(wps_mode, "%swps_mode", prefix);
2755	if (nvram_match(wps_mode, "enabled")) {
2756		websWrite(wp, "<option value=\"enabled\" selected>Enabled</option>");
2757		websWrite(wp, "<option value=\"disabled\">Disabled</option>");
2758	}
2759	else {
2760		websWrite(wp, "<option value=\"enabled\">Enabled</option>");
2761		websWrite(wp, "<option value=\"disabled\" selected>Disabled</option>");
2762	}
2763
2764	websWrite(wp, "</select> </td> </tr>\n");
2765
2766	/* If WPS is disabled, don't show any configurations util wps_mode is enabled */
2767	if (nvram_invmatch(wps_mode, "enabled")) {
2768		websWrite(wp, "</table>\n");
2769		goto out;
2770	}
2771
2772	/* show Device UUID */
2773	websWrite(wp,"<tr>"
2774	          "<th width=\"310\""
2775	          "onMouseOver=\"return overlib('A WPS UUID number of this device.', LEFT);\""
2776	          "onMouseOut=\"return nd();\">"
2777	          "Device WPS UUID:&nbsp;&nbsp;"
2778	          "</th>"
2779	          "<td>&nbsp;&nbsp;</td>\n");
2780	str = wps_uuid;
2781	websWrite(wp,"<td>%s</td><td>&nbsp;&nbsp;",str);
2782	websWrite(wp, "</td></tr>\n");
2783
2784	/* show Device PIN */
2785	websWrite(wp,"<tr>"
2786	          "<th width=\"310\""
2787	          "onMouseOver=\"return overlib('A PIN number of this device.', LEFT);\""
2788	          "onMouseOut=\"return nd();\">"
2789	          "Device PIN:&nbsp;&nbsp;"
2790	          "</th>"
2791	          "<td>&nbsp;&nbsp;</td>");
2792	str = nvram_get("wps_device_pin");
2793	websWrite(wp,"<td>%s",str);
2794
2795	/* show Generate button */
2796	if (wps_config_command != WPS_UI_CMD_START)
2797		websWrite(wp, "&nbsp;&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Generate\">");
2798
2799	websWrite(wp,"</td></tr>\n");
2800	if (!wps_sta) {
2801		/* show allow/deny Wireless External Registrar Get/Configure AP securit */
2802		websWrite(wp, "<tr>"
2803		          "<th width=\"310\""
2804		          "onMouseOver=\"return overlib('Set allow/deny Wireless External Registrar get/configure AP security through AP PIN', LEFT);\""
2805		          "onMouseOut=\"return nd();\">"
2806		          "Configure by External Registrar:&nbsp;&nbsp;"
2807		          "</th>"
2808		          "<td>&nbsp;&nbsp;</td>\n"
2809		          "<td>");
2810		websWrite(wp, "<select name=\"wps_wer_mode\">");
2811		if (nvram_match("wps_wer_mode", "allow")) {
2812			websWrite(wp, "<option value=\"allow\" selected>Allow</option>");
2813			websWrite(wp, "<option value=\"deny\" >Deny</option>");
2814		}
2815		else {
2816			websWrite(wp, "<option value=\"allow\" >Allow</option>");
2817			websWrite(wp, "<option value=\"deny\" selected>Deny</option>");
2818		}
2819		websWrite(wp, "</select> </td> </tr>\n");
2820
2821		/* show empty column */
2822		websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td><td></td></tr>\n");
2823
2824	} /* !wps_sta */
2825
2826	if (wps_sta) {
2827
2828		/* WPS AP list */
2829		websWrite(wp,"<tr>"
2830		          "<th width=\"310\""
2831		          "onMouseOver=\"return overlib('WPS support AP list.', LEFT);\""
2832		          "onMouseOut=\"return nd();\">"
2833		          "WPS AP List:&nbsp;&nbsp;"
2834		          "</th>"
2835		          "<td>&nbsp;&nbsp;</td>"
2836		          "<td>");
2837		websWrite(wp, "<select name=\"wps_ap_list\">");
2838		ej_wps_enr_scan_result(eid, wp, argc, argv);
2839		websWrite(wp, "</select>");
2840		if (wps_config_command != WPS_UI_CMD_START)
2841			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Rescan\">");
2842		websWrite(wp, "</td></tr>\n");
2843	}
2844
2845	if (wps_config_command == WPS_UI_CMD_NONE) {
2846		/* show wps_action */
2847		if (wps_sta) {
2848			/* show wps-action */
2849			websWrite(wp, "<tr>"
2850				  "<th width=\"310\""
2851				  "onMouseOver=\"return overlib('The action for wps running later', LEFT);\""
2852				  "onMouseOut=\"return nd();\">"
2853				  "WPS Action:&nbsp;&nbsp;"
2854				  "</th>"
2855				  "<td>&nbsp;&nbsp;</td>\n"
2856				  "<td>");
2857			websWrite(wp, "<select name=\"wps_action\" onChange=\"submit();\">");
2858			websWrite(wp, "<option value=\"Enroll\"%s>Enroll</option>",
2859				(wps_action == WPS_UI_ACT_ENROLL) ? " selected":"");
2860			websWrite(wp, "<option value=\"ConfigAP\"%s >Config AP</option>",
2861				(wps_action == WPS_UI_ACT_STA_CONFIGAP) ? " selected":"");
2862			websWrite(wp, "<option value=\"GetAPConfig\" %s>Get AP Config</option>",
2863				(wps_action == WPS_UI_ACT_STA_GETAPCONFIG) ? " selected":"");
2864			/* show empty column */
2865			websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td><td></td></tr>\n");
2866		}
2867		else {
2868			/* AP always act as AddEnrollee */
2869			websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td>"
2870				      "<td><input type=\"hidden\" name=\"wps_action\""
2871				      " value=\"AddEnrollee\"></td></tr>\n");
2872		}
2873
2874		/* Show WPS credentials */
2875		ej_wps_credentials(eid, wp, argc, argv, wps_sta);
2876
2877		/* show empty column */
2878		websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td><td></td></tr>\n");
2879
2880		if (wps_action == WPS_UI_ACT_ENROLL) {
2881			/* show wps method */
2882			websWrite(wp, "<tr>"
2883				  "<th width=\"310\""
2884				  "onMouseOver=\"return overlib('The grant for wps exchange data', LEFT);\""
2885				  "onMouseOut=\"return nd();\">"
2886				  "WPS Method:&nbsp;&nbsp;"
2887				  "</th>"
2888				  "<td>&nbsp;&nbsp;</td>\n"
2889				  "<td>");
2890			websWrite(wp, "<select name=\"wps_method\">");
2891			if (wps_action == WPS_UI_ACT_ENROLL) {
2892				websWrite(wp, "<option value=\"PBC\"%s>PBC</option>",
2893					(wps_method == WPS_UI_METHOD_PBC)? " selected":"");
2894			}
2895			websWrite(wp, "<option value=\"PIN\" %s>PIN</option>",
2896				(wps_method == WPS_UI_METHOD_PIN)? " selected":"");
2897#ifdef __CONFIG_NFC__
2898			/* NFC password token.  When we are WPS_UI_ACT_ENROLL */
2899			websWrite(wp, "<option value=\"NFC\" %s>NFC</option>",
2900				(wps_method == WPS_UI_METHOD_NFC_PW)? " selected":"");
2901#endif
2902			if (wps_action == WPS_UI_ACT_ENROLL) {
2903				websWrite(wp, "</select>&nbsp;&nbsp;If PIN is selected, please set PIN \"%s\" to the WPS AP or registrar.</td> </tr>\n",
2904					nvram_get("wps_device_pin"));
2905			}
2906		}
2907		if (wps_action == WPS_UI_ACT_ADDENROLLEE) {
2908			/* show pin field */
2909			websWrite(wp,"<tr>"
2910				  "<th width=\"310\""
2911				  "onMouseOver=\"return overlib('Station pin for verify the station is what we expect.', LEFT);\""
2912				  "onMouseOut=\"return nd();\">"
2913				  "Station PIN:&nbsp;&nbsp;"
2914				  "</th>"
2915				  "<td>&nbsp;&nbsp;</td>\n");
2916			websWrite(wp,"<td><input name=\"wps_sta_pin\" value=\"\" size=\"9\" maxlength=\"9\"> Note: Empty for PBC method.");
2917			websWrite(wp, "</td></tr>\n");
2918
2919			/* show authorized mac field */
2920			websWrite(wp,"<tr>"
2921				  "<th width=\"310\""
2922				  "onMouseOver=\"return overlib('Authorized Station MAC.', LEFT);\""
2923				  "onMouseOut=\"return nd();\">"
2924				  "Authorized Station MAC:&nbsp;&nbsp;"
2925				  "</th>"
2926				  "<td>&nbsp;&nbsp;</td>\n");
2927			websWrite(wp,"<td><input name=\"wps_autho_sta_mac\" value=\"\" size=\"17\" maxlength=\"17\">");
2928		}
2929		if (wps_action == WPS_UI_ACT_STA_GETAPCONFIG || wps_action == WPS_UI_ACT_STA_CONFIGAP) {
2930			/* AP pin field */
2931			websWrite(wp, "<tr>"
2932				  "<th width=\"310\""
2933				  "onMouseOver=\"return overlib('PIN of AP.', LEFT);\""
2934				  "onMouseOut=\"return nd();\">"
2935				  "AP PIN:&nbsp;&nbsp;"
2936				  "</th>"
2937				  "<td>&nbsp;&nbsp;</td>\n");
2938			websWrite(wp,"<td><input name=\"wps_ap_pin\" value=\"\" size=\"9\" maxlength=\"9\">");
2939			websWrite(wp, "</td> </tr>\n");
2940#ifdef __CONFIG_NFC__
2941			/* Show wps method */
2942			websWrite(wp, "<tr>"
2943				  "<th width=\"310\""
2944				  "onMouseOver=\"return overlib('The grant for wps exchange data', LEFT);\""
2945				  "onMouseOut=\"return nd();\">"
2946				  "WPS Method:&nbsp;&nbsp;"
2947				  "</th>"
2948				  "<td>&nbsp;&nbsp;</td>\n"
2949				  "<td>");
2950			websWrite(wp, "<select name=\"wps_method\">");
2951			websWrite(wp, "<option value=\"PIN\" %s>PIN</option>",
2952				(wps_method == WPS_UI_METHOD_PIN)? " selected":"");
2953			/* NFC password token.  When we are WPS_UI_ACT_ENROLL */
2954			websWrite(wp, "<option value=\"NFC\" %s>NFC</option>",
2955				(wps_method == WPS_UI_METHOD_NFC_PW)? " selected":"");
2956#endif /* __CONFIG_NFC__ */
2957		}
2958		websWrite(wp, "&nbsp;&nbsp;");
2959		/* show trigger button */
2960		ej_wps_start(eid, wp, argc, argv, wps_sta);
2961	}
2962
2963	/* show last attempted enrollee information */
2964	if (!wps_sta) {
2965		char *err_state = nvram_safe_get("wps_pinfail_state");
2966		char tmp[256], devPwd[12], *warning_msg = "";
2967
2968		if (strcmp(err_state, "M4") == 0 ||
2969		    strcmp(err_state, "M6") == 0) {
2970			/* show empty column */
2971			websWrite(wp, "<tr>"
2972			          "<th width=\"310\">"
2973			          "</th>"
2974			          "<td>&nbsp;&nbsp;</td>"
2975			          "<td></td></tr>\n ");
2976
2977			/* MAC */
2978			websWrite(wp, "<tr>");
2979			websWrite(wp, "<th width=\"310\">"
2980				"Last Enrollee MAC:&nbsp;&nbsp;</th>"
2981				"<td>&nbsp;&nbsp;</td>\n");
2982			websWrite(wp, "<td>%s</td>\n", nvram_safe_get("wps_pinfail_mac"));
2983
2984			/* Device Name*/
2985			websWrite(wp, "<tr>");
2986			websWrite(wp, "<th width=\"310\">"
2987				"Last Enrollee Name:&nbsp;&nbsp;</th>"
2988				"<td>&nbsp;&nbsp;</td>\n");
2989			websWrite(wp, "<td>%s</td>\n", nvram_safe_get("wps_pinfail_name"));
2990
2991			/* Attacker warnng */
2992			if (strcmp(err_state, "M4") == 0)
2993				warning_msg = "Station PIN registration failed (first half), "
2994					"be aware a brute force offline attacker "
2995					"(Eavesdropped Enrollee).";
2996			else {
2997				wl_wpsPinGen(devPwd);
2998				sprintf(tmp,
2999					"Station PIN registration failed (second half), be aware a "
3000					"brute force offline attacker (Eavesdropped Enrollee).<br>"
3001					"Please input new Station PIN %s on both AP and Station",
3002					devPwd);
3003				warning_msg = tmp;
3004			}
3005
3006			websWrite(wp, "<tr>");
3007			websWrite(wp, "<th width=\"310\">&nbsp;&nbsp;</th><td>&nbsp;&nbsp;</td>\n");
3008			websWrite(wp, "<td><b>ATTACKER WARNING<br>%s</b></td>\n", warning_msg);
3009		}
3010	}
3011
3012	/* show empty column */
3013	websWrite(wp, "<tr>"
3014	          "<th width=\"310\">"
3015	          "</th>"
3016	          "<td>&nbsp;&nbsp;</td>"
3017	          "<td></td></tr>\n ");
3018
3019	/* show Current Status */
3020	websWrite(wp, "<tr>"
3021	          "<th width=\"310\""
3022	          "onMouseOver=\"return overlib('WPS process status', LEFT);\""
3023	          "onMouseOut=\"return nd();\">"
3024	          "WPS Current Status:&nbsp;&nbsp;"
3025	          "</th>"
3026	          "<td>&nbsp;&nbsp;</td>\n"
3027	          "<td>");
3028	if (!wps_sta)
3029		ej_wps_process(eid, wp, argc, argv);
3030	else
3031		ej_wps_enr_process(eid, wp, argc, argv);
3032
3033	websWrite(wp, "</td> </tr>\n");
3034	websWrite(wp, "</table>\n");
3035
3036#ifdef __CONFIG_NFC__
3037	/* Show NFC stuffs */
3038	if (wps_config_command == WPS_UI_CMD_NONE) {
3039		websWrite(wp, "<p>\n");
3040		websWrite(wp,"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
3041
3042		if (wps_action == WPS_UI_ACT_ADDENROLLEE) {
3043			/* show NFC write/read Configuration token */
3044			websWrite(wp,"<tr>"
3045				  "<th width=\"310\""
3046				  "onMouseOver=\"return overlib('Write the AP security to NFC tag and use it to configure other devices. "
3047				  "Read the configuration from the NFC tag and apply to AP system', LEFT);\""
3048				  "onMouseOut=\"return nd();\">"
3049				  "NFC Configuration Token:&nbsp;&nbsp;"
3050				  "</th>"
3051				  "<td>&nbsp;&nbsp;</td>\n");
3052			websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Write Configuration\">&nbsp;&nbsp");
3053			websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"NFC Read Configuration\">");
3054			websWrite(wp, "</td></tr>\n");
3055		}
3056
3057		if (wps_action == WPS_UI_ACT_STA_GETAPCONFIG || wps_action == WPS_UI_ACT_STA_CONFIGAP) {
3058			if (wps_action == WPS_UI_ACT_STA_GETAPCONFIG) {
3059				/* show NFC read Configuration token */
3060				websWrite(wp,"<tr>"
3061					  "<th width=\"310\""
3062					  "onMouseOver=\"return overlib('Read the configuration from the NFC tag and apply to the station', LEFT);\""
3063					  "onMouseOut=\"return nd();\">"
3064					  "NFC Configuration Token:&nbsp;&nbsp;"
3065					  "</th>"
3066					  "<td>&nbsp;&nbsp;</td>\n");
3067				websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Read Configuration\">");
3068			}
3069			else {
3070				/* show NFC write Configuration token, need take care the "new credentials" on the GUI */
3071				websWrite(wp,"<tr>"
3072					  "<th width=\"310\""
3073					  "onMouseOver=\"return overlib('Write the station security to NFC tag and use it to configure AP or other stations.', LEFT);\""
3074					  "onMouseOut=\"return nd();\">"
3075					  "NFC Configuration Token:&nbsp;&nbsp;"
3076					  "</th>"
3077					  "<td>&nbsp;&nbsp;</td>\n");
3078				websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Write Configuration\">");
3079			}
3080			websWrite(wp, "</td></tr>\n");
3081		}
3082
3083		/* Show NFC Password token */
3084		if (!wps_sta) {
3085			websWrite(wp,"<tr>"
3086			  "<th width=\"310\""
3087			  "onMouseOver=\"return overlib('Write the AP security to NFC tag and use it to configure other devices. "
3088			  "Read the configuration from the NFC tag and apply to AP system', LEFT);\""
3089			  "onMouseOut=\"return nd();\">"
3090			  "NFC Password Token:&nbsp;&nbsp;"
3091			  "</th>"
3092			  "<td>&nbsp;&nbsp;</td>\n");
3093			websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Add Enrollee\">&nbsp;&nbsp");
3094			websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"NFC Config AP\">");
3095			websWrite(wp, "</td></tr>\n");
3096		}
3097
3098		/* Show NFC Hand Over Selector/Requester */
3099		if (wps_action == WPS_UI_ACT_ADDENROLLEE) {
3100			/* show NFC write/read Configuration token */
3101			websWrite(wp,"<tr>"
3102			  "<th width=\"310\""
3103			  "onMouseOver=\"return overlib('Selector provide the Configuration to Requester. Requester get Configuration from Selector.', LEFT);\""
3104			  "onMouseOut=\"return nd();\">"
3105			  "NFC Hand Over:&nbsp;&nbsp;"
3106			  "</th>"
3107			  "<td>&nbsp;&nbsp;</td>\n");
3108			websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Hand Over As Selecotr\">&nbsp;&nbsp");
3109			websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"NFC Hand Over As Requester\">");
3110			websWrite(wp, "</td></tr>\n");
3111		}
3112
3113		if (wps_action == WPS_UI_ACT_STA_GETAPCONFIG || wps_action == WPS_UI_ACT_STA_CONFIGAP ||
3114		    wps_action == WPS_UI_ACT_ENROLL) {
3115			if (wps_action == WPS_UI_ACT_STA_GETAPCONFIG) {
3116				/* show NFC Hand Over as Requester */
3117				websWrite(wp,"<tr>"
3118				  "<th width=\"310\""
3119				  "onMouseOver=\"return overlib('As a Requester get Configuration from Selector.', LEFT);\""
3120				  "onMouseOut=\"return nd();\">"
3121				  "NFC Hand Over:&nbsp;&nbsp;"
3122				  "</th>"
3123				  "<td>&nbsp;&nbsp;</td>\n");
3124				websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Hand Over As Requester\">");
3125			}
3126			else if (wps_action == WPS_UI_ACT_STA_CONFIGAP) {
3127				/* show NFC Hand Over as Selector, need take care the "new credentials" on the GUI */
3128				websWrite(wp,"<tr>"
3129				  "<th width=\"310\""
3130			 	  "onMouseOver=\"return overlib('As a Selector provide the Configuration to Requester.', LEFT);\""
3131				  "onMouseOut=\"return nd();\">"
3132				  "NFC Hand Over:&nbsp;&nbsp;"
3133				  "</th>"
3134				  "<td>&nbsp;&nbsp;</td>\n");
3135				websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Hand Over As Selecotr\">");
3136			}
3137			else {
3138				/* show NFC Hand Over as Requester/Selector */
3139				websWrite(wp,"<tr>"
3140				  "<th width=\"310\""
3141				  "onMouseOver=\"return overlib('As a Requester get Configuration from Selector or as a Selector provide the Configuration to Requester.', LEFT);\""
3142				  "onMouseOut=\"return nd();\">"
3143				  "NFC Hand Over:&nbsp;&nbsp;"
3144				  "</th>"
3145				  "<td>&nbsp;&nbsp;</td>\n");
3146				websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Hand Over As Selecotr\">&nbsp;&nbsp");
3147				websWrite(wp,"<td><input type=\"submit\" name=\"action\" value=\"NFC Hand Over As Requester\">");
3148			}
3149			websWrite(wp, "</td></tr>\n");
3150		}
3151
3152
3153		/* show NFC Device Manager status */
3154		websWrite(wp, "<tr>"
3155		          "<th width=\"310\""
3156		          "onMouseOver=\"return overlib('NFC Device Management Status', LEFT);\""
3157		          "onMouseOut=\"return nd();\">"
3158		          "NFC Device Management Status:&nbsp;&nbsp;"
3159		          "</th>"
3160		          "<td>&nbsp;&nbsp;</td>\n"
3161		          "<td>");
3162		ej_wps_nfc_dm_status(eid, wp, argc, argv);
3163
3164		websWrite(wp, "</table>");
3165	}
3166#endif /* __CONFIG_NFC__ */
3167
3168#ifdef WFA_WPS_20_TESTBED
3169	/* For PlugFest testing only */
3170	websWrite(wp, "<p>\n");
3171
3172	websWrite(wp,"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
3173
3174	/* WPS version */
3175	websWrite(wp, "<tr>\n"
3176	          "<th width=\"310\"\n"
3177	          "onMouseOver=\"return overlib('Selects WPS version.', LEFT);\"\n"
3178	          "onMouseOut=\"return nd();\">\n"
3179	          "WPS Version:&nbsp;&nbsp;\n"
3180	          "</th>\n"
3181	          "<td>&nbsp;&nbsp;</td>\n"
3182	          "<td>\n");
3183	websWrite(wp, "<select name=\"wps_version2\" onChange=\"wps_version2_change();\">\n");
3184	if (nvram_match("wps_version2", "enabled")) {
3185		websWrite(wp, "<option value=\"enabled\" selected>V2</option>\n");
3186		websWrite(wp, "<option value=\"disabled\">V1</option>\n");
3187	}
3188	else {
3189		websWrite(wp, "<option value=\"enabled\">V2</option>\n");
3190		websWrite(wp, "<option value=\"disabled\" selected>V1</option>\n");
3191	}
3192	websWrite(wp, "</select> </td> </tr>\n");
3193
3194	/* WPS version number */
3195	websWrite(wp,"<tr>\n"
3196	          "<th width=\"310\"\n"
3197	          "onMouseOver=\"return overlib('WPS version2 number 0 ~ 255.', LEFT);\"\n"
3198	          "onMouseOut=\"return nd();\">\n"
3199	          "WPS version2 number:&nbsp;&nbsp;\n"
3200	          "</th>\n"
3201	          "<td>&nbsp;&nbsp;</td>\n");
3202	str = nvram_get("wps_version2_num");
3203	websWrite(wp,"<td><input name=\"wps_version2_num\" value=\"%s\" size=\"2\" maxlength=\"2\">\n",
3204		str ? str : "");
3205	websWrite(wp, "</td> </tr>\n");
3206
3207	/* WPS IE fragment threshold */
3208	websWrite(wp,"<tr>\n"
3209	          "<th width=\"310\"\n"
3210	          "onMouseOver=\"return overlib('WPS version2 IE fragment threshold 72 ~ 228.', LEFT);\"\n"
3211	          "onMouseOut=\"return nd();\">\n"
3212	          "WPS IE fragment threshold:&nbsp;&nbsp;\n"
3213	          "</th>\n"
3214	          "<td>&nbsp;&nbsp;</td>\n");
3215	str = nvram_get("wps_ie_frag");
3216	websWrite(wp,"<td><input name=\"wps_ie_frag\" value=\"%s\" size=\"4\" maxlength=\"4\">\n",
3217		str ? str : "");
3218	websWrite(wp, "</td> </tr>\n");
3219
3220	/* WPS EAP fragment threshold */
3221	websWrite(wp,"<tr>\n"
3222	          "<th width=\"310\"\n"
3223	          "onMouseOver=\"return overlib('WPS version2 EAP fragment threshold 100 ~ 1398.', LEFT);\"\n"
3224	          "onMouseOut=\"return nd();\">\n"
3225	          "WPS EAP fragment threshold:&nbsp;&nbsp;\n"
3226	          "</th>\n"
3227	          "<td>&nbsp;&nbsp;</td>\n");
3228	str = nvram_get("wps_eap_frag");
3229	websWrite(wp,"<td><input name=\"wps_eap_frag\" value=\"%s\" size=\"4\" maxlength=\"4\">\n",
3230		str ? str : "");
3231	websWrite(wp, "</td> </tr>\n");
3232
3233	/* Append new attribute */
3234	websWrite(wp, "<tr>\n"
3235	          "<th width=\"310\"\n"
3236	          "onMouseOver=\"return overlib('Append new attribute.', LEFT);\"\n"
3237	          "onMouseOut=\"return nd();\">\n"
3238	          "WPS New Attribute Append:&nbsp;&nbsp;\n"
3239	          "</th>\n"
3240	          "<td>&nbsp;&nbsp;</td>\n");
3241	str = nvram_get("wps_nattr");
3242	websWrite(wp,"<td><input name=\"wps_nattr\" value=\"%s\" size=\"32\" maxlength=\"127\">\n",
3243		str ? str : "");
3244	websWrite(wp, "</td> </tr>\n");
3245
3246	/* Enable zero padding */
3247	websWrite(wp, "<tr>\n"
3248	          "<th width=\"310\"\n"
3249	          "onMouseOver=\"return overlib('Enabled Zero Padding.', LEFT);\"\n"
3250	          "onMouseOut=\"return nd();\">\n"
3251	          "WPS Zero Padding:&nbsp;&nbsp;\n"
3252	          "</th>\n"
3253	          "<td>&nbsp;&nbsp;</td>\n"
3254	          "<td>\n");
3255	websWrite(wp, "<select name=\"wps_zpadding\">\n");
3256	if (nvram_match("wps_zpadding", "1")) {
3257		websWrite(wp, "<option value=\"1\" selected>YES</option>\n");
3258		websWrite(wp, "<option value=\"0\">NO</option>\n");
3259	}
3260	else {
3261		websWrite(wp, "<option value=\"1\">YES</option>\n");
3262		websWrite(wp, "<option value=\"0\" selected>NO</option>\n");
3263	}
3264	websWrite(wp, "</select> </td> </tr>\n");
3265
3266	/* Multiple Credential Attribute */
3267	websWrite(wp, "<tr>\n"
3268	          "<th width=\"310\"\n"
3269	          "onMouseOver=\"return overlib('Enabled Multiple Credential Attribute.', LEFT);\"\n"
3270	          "onMouseOut=\"return nd();\">\n"
3271	          "WPS Multiple Credential Attribute:&nbsp;&nbsp;\n"
3272	          "</th>\n"
3273	          "<td>&nbsp;&nbsp;</td>\n"
3274	          "<td>\n");
3275	websWrite(wp, "<select name=\"wps_mca\">\n");
3276	if (nvram_match("wps_mca", "1")) {
3277		websWrite(wp, "<option value=\"1\" selected>YES</option>\n");
3278		websWrite(wp, "<option value=\"0\">NO</option>\n");
3279	}
3280	else {
3281		websWrite(wp, "<option value=\"1\">YES</option>\n");
3282		websWrite(wp, "<option value=\"0\" selected>NO</option>\n");
3283	}
3284	websWrite(wp, "</select> </td> </tr>\n");
3285
3286	/* EAP fregmant threshold */
3287
3288	websWrite(wp, "</table>");
3289#endif /* WFA_WPS_20_TESTBED */
3290
3291out:
3292#endif /* __CONFIG_WPS__ */
3293
3294	return 1;
3295}
3296
3297static int
3298ej_wps_config_change_display(int eid, webs_t wp, int argc, char_t **argv)
3299{
3300#ifdef __CONFIG_WPS__
3301	int wps_sta = 0;
3302	char prefix[] = "wlXXXXXXXXXX_";
3303	char tmp[] = "wlXXXXXXXXXX_mode";
3304	char *mode;
3305	char *closed;
3306
3307	if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
3308		websError(wp, 400, "unit number variable doesn't exist\n");
3309		return EINVAL;
3310	}
3311
3312	/* Get wl_mode */
3313	snprintf(tmp, sizeof(tmp), "%smode", tmp);
3314	mode = nvram_safe_get(tmp);
3315	if (!strcmp(mode, "wet") ||
3316		!strcmp(mode, "sta") ||
3317		!strcmp(mode, "psr") ||
3318		!strcmp(mode, "psta") ||
3319		!strcmp(mode, "mac_spoof")) {
3320
3321		wps_sta = 1;
3322	}
3323
3324	/* Get wl_closed */
3325	snprintf(tmp, sizeof(tmp), "%sclosed", prefix);
3326	closed = nvram_safe_get(tmp);
3327
3328	websWrite(wp,"    var wps_sta = \"%d\";\n", wps_sta);
3329	websWrite(wp,"    var wl_closed = \"%s\";\n", closed);
3330	websWrite(wp,"    var msg = \"Enable WPS will change the SSID Network Type to Open, Are you sure?\";\n");
3331
3332	websWrite(wp,"    if ((wps_sta == \"0\") && (wl_closed == \"1\") &&\n");
3333	websWrite(wp,"        (document.forms[0].wl_wps_mode.value == \"enabled\") && !confirm(msg)) {\n");
3334	websWrite(wp,"        document.forms[0].wl_wps_mode.value = \"disabled\";\n");
3335	websWrite(wp,"    }\n");
3336#endif /* __CONFIG_WPS__ */
3337
3338	return 1;
3339}
3340
3341static int
3342ej_wps_current_psk_window_display(int eid, webs_t wp, int argc, char_t **argv)
3343{
3344#ifdef __CONFIG_WPS__
3345	char prefix[] = "wlXXXXXXXXXX_";
3346	char tmp[100];
3347	char *value;
3348
3349	if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
3350		websError(wp, 400, "unit number variable doesn't exist\n");
3351		return -1;
3352	}
3353	snprintf(tmp, sizeof(tmp), "%swpa_psk", prefix);
3354	value = nvram_safe_get(tmp);
3355
3356	websWrite(wp,"	var psk_window = window.open(\"\", \"\", \"toolbar=no,scrollbars=yes,width=400,height=100\");\n");
3357	websWrite(wp,"	psk_window.document.write(\"The WPA passphrase is %s\");\n", value);
3358	websWrite(wp,"	psk_window.document.close();\n");
3359#endif /* __CONFIG_WPS__ */
3360	return 1;
3361}
3362
3363static int
3364ej_wps_psk_window_display(int eid, webs_t wp, int argc, char_t **argv)
3365{
3366#ifdef __CONFIG_WPS__
3367	char prefix[] = "wlXXXXXXXXXX_";
3368	char tmp[100], psk[65];
3369	char *value;
3370	int oob = wps_is_oob();
3371
3372	if (oob) {
3373		if ((value  = nvram_get("wps_randomkey"))) {
3374			strncpy(random_psk, value, sizeof(random_psk));
3375			random_psk[sizeof(random_psk)-1] = '\0';
3376		}
3377		else if (random_psk[0] == 0)
3378			wps_gen_key(random_psk, sizeof(random_psk));
3379		strcpy(psk, random_psk);
3380	}
3381	else {
3382		if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
3383			websError(wp, 400, "unit number variable doesn't exist\n");
3384			return -1;
3385		}
3386		snprintf(tmp, sizeof(tmp), "%swpa_psk", prefix);
3387		value = nvram_safe_get(tmp);
3388		strncpy(psk, value, sizeof(psk));
3389		psk[sizeof(psk)-1] = '\0';
3390	}
3391	websWrite(wp,"	var psk_window = window.open(\"\", \"\", \"toolbar=no,scrollbars=yes,width=400,height=100\");\n");
3392	websWrite(wp,"	psk_window.document.write(\"The WPA passphrase is %s\");\n", psk);
3393	websWrite(wp,"	psk_window.document.close();\n");
3394#endif /* __CONFIG_WPS__ */
3395	return 1;
3396}
3397
3398static int
3399ej_wps_closed_check_display(int eid, webs_t wp, int argc, char_t **argv)
3400{
3401#ifdef __CONFIG_WPS__
3402	if (nvram_match("wl_wps_mode", "enabled")) {
3403		websWrite(wp,"    var msg = \"Selecting Closed hides the network will disable the WPS, Are you sure?\";\n\n");
3404
3405		websWrite(wp,"    if (document.forms[0].wl_closed.value == \"1\" && !confirm(msg))\n");
3406		websWrite(wp,"        document.forms[0].wl_closed.value = \"0\";\n");
3407	}
3408#endif /* __CONFIG_WPS__ */
3409
3410	return 1;
3411}
3412
3413
3414static int
3415ej_wps_wep_change_display(int eid, webs_t wp, int argc, char_t **argv)
3416{
3417#ifdef __CONFIG_WPS__
3418	websWrite(wp,"    var mode = document.forms[0].wl_auth_mode[document.forms[0].wl_auth_mode.selectedIndex].value;\n");
3419	websWrite(wp,"    var wep = document.forms[0].wl_wep[document.forms[0].wl_wep.selectedIndex].value;\n");
3420	websWrite(wp,"    var wpa = document.forms[0].wl_akm_wpa[document.forms[0].wl_akm_wpa.selectedIndex].value;\n");
3421	websWrite(wp,"    var psk = document.forms[0].wl_akm_psk[document.forms[0].wl_akm_psk.selectedIndex].value;\n");
3422	websWrite(wp,"    var wpa2 = document.forms[0].wl_akm_wpa2[document.forms[0].wl_akm_wpa2.selectedIndex].value;\n");
3423	websWrite(wp,"    var psk2 = document.forms[0].wl_akm_psk2[document.forms[0].wl_akm_psk2.selectedIndex].value;\n");
3424	websWrite(wp,"    var brcm_psk = document.forms[0].wl_akm_brcm_psk[document.forms[0].wl_akm_brcm_psk.selectedIndex].value;\n");
3425	websWrite(wp,"    var wps_mode = document.forms[0].wl_wps_mode.value;\n");
3426	websWrite(wp,"    var msg = \"Selecting WEP Encryption will disable the WPS, Are you sure?\";\n\n");
3427
3428	if (nvram_match("wps_version2", "enabled")) {
3429		websWrite(wp,"    if (wep == \"enabled\" && wps_mode == \"enabled\" &&\n");
3430		websWrite(wp,"        wpa != \"enabled\" && psk != \"enabled\" &&\n");
3431		websWrite(wp,"        wpa2 != \"enabled\" && psk2 != \"enabled\" &&\n");
3432		websWrite(wp,"        brcm_psk != \"enabled\" && mode != \"radius\") {\n");
3433		websWrite(wp,"        if (confirm(msg))\n");
3434		websWrite(wp,"            document.forms[0].wl_wps_mode.value = \"disabled\";\n");
3435		websWrite(wp,"        else\n");
3436		websWrite(wp,"            document.forms[0].wl_wep.selectedIndex = 1;\n");
3437		websWrite(wp,"    }\n");
3438	}
3439#endif /* __CONFIG_WPS__ */
3440
3441	return 1;
3442}
3443
3444static int
3445ej_wps_get_ap_config_submit_display(int eid, webs_t wp, int argc, char_t **argv)
3446{
3447#ifdef __CONFIG_WPS__
3448	int i = 0, buf_len;
3449	char buf[256] = {0};
3450	wps_ap_list_info_t *wpsaplist, *ap;
3451
3452	if (!scanned && nvram_match( "wl_wps_mode", "disabled" )) {
3453		wps_ap_num = 0;
3454		return 0;
3455	}
3456	else if (!scanned)
3457		wps_enr_create_aplist();
3458
3459	websWrite(wp,"    var unconfig, i;\n");
3460	websWrite(wp,"    var ap_index=document.forms[0].wps_ap_list.selectedIndex;\n");
3461	websWrite(wp,"    var str = \"Selected AP is UNCONFIGURED! Do you want to configure it using random credential?\";\n\n");
3462
3463	wpsaplist = ap_list;
3464	wps_enr_get_aplist(wpsaplist, wpsaplist);
3465
3466	ap = wpsaplist;
3467	while(ap->used == TRUE ) {
3468		if (ap->scstate == FALSE) {
3469			buf_len = strlen(buf);
3470			if (buf_len)
3471				sprintf(buf+buf_len, ", \"%d\"",  i);
3472			else
3473				sprintf(buf+buf_len, "\"%d\"",  i);
3474		}
3475		ap++;
3476		i++;
3477	}
3478	websWrite(wp,"    unconfig = new Array(%s);\n", buf);
3479
3480	websWrite(wp,"    for (var i in unconfig) {\n");
3481	websWrite(wp,"        if (unconfig[i] == ap_index)\n");
3482	websWrite(wp,"            return confirm(str);\n");
3483	websWrite(wp,"    };\n");
3484	websWrite(wp,"    return 1;\n");
3485#endif /* __CONFIG_WPS__ */
3486
3487	return 1;
3488}
3489
3490static int
3491ej_wps_akm_change_display(int eid, webs_t wp, int argc, char_t **argv)
3492{
3493#ifdef __CONFIG_WPS__
3494	if (wps_config_command == WPS_UI_CMD_NONE) {
3495		websWrite(wp,"    var akm = document.forms[0].wps_akm[document.forms[0].wps_akm.selectedIndex].value;\n");
3496		websWrite(wp,"    var action = document.forms[0].wps_action.value;\n");
3497
3498		websWrite(wp,"    if (action == \"ConfigAP\" || action == \"AddEnrollee\") {\n");
3499		websWrite(wp,"        if (akm ==\"0\") {\n");
3500		websWrite(wp,"            document.forms[0].wps_crypto.disabled = 1;\n");
3501		websWrite(wp,"            document.forms[0].wps_crypto.value = \"0\";\n");
3502		websWrite(wp,"            document.forms[0].wps_psk.disabled = 1;\n");
3503		websWrite(wp,"        }\n");
3504		websWrite(wp,"        else {\n");
3505		websWrite(wp,"            document.forms[0].wps_crypto.disabled = 0;\n");
3506		websWrite(wp,"            document.forms[0].wps_psk.disabled = 0;\n");
3507		websWrite(wp,"        }\n");
3508		websWrite(wp,"    }\n");
3509	}
3510#endif /* __CONFIG_WPS__ */
3511	return 1;
3512}
3513
3514static int
3515ej_wps_refresh(int eid, webs_t wp, int argc, char_t **argv)
3516{
3517#ifdef __CONFIG_WPS__
3518	if (wps_config_command == WPS_UI_CMD_NONE)
3519		websWrite(wp, "0");
3520	else {
3521		int interval = 3;
3522		char *value = nvram_get("wps_refresh_interval");
3523
3524		if (value)
3525			interval = atoi(value);
3526		websWrite(wp, "%d", interval);
3527	}
3528#endif
3529	return 1;
3530}
3531
3532static int
3533ej_wps_security_pre_submit_display(int eid, webs_t wp, int argc, char_t **argv)
3534{
3535#ifdef __CONFIG_WPS__
3536	websWrite(wp,"    var auth = document.forms[0].wl_auth[document.forms[0].wl_auth.selectedIndex].value;\n");
3537	websWrite(wp,"    var mode = document.forms[0].wl_auth_mode[document.forms[0].wl_auth_mode.selectedIndex].value;\n");
3538	websWrite(wp,"    var wep = document.forms[0].wl_wep[document.forms[0].wl_wep.selectedIndex].value;\n");
3539	websWrite(wp,"    var wpa = document.forms[0].wl_akm_wpa[document.forms[0].wl_akm_wpa.selectedIndex].value;\n");
3540	websWrite(wp,"    var psk = document.forms[0].wl_akm_psk[document.forms[0].wl_akm_psk.selectedIndex].value;\n");
3541	websWrite(wp,"    var wpa2 = document.forms[0].wl_akm_wpa2[document.forms[0].wl_akm_wpa2.selectedIndex].value;\n");
3542	websWrite(wp,"    var psk2 = document.forms[0].wl_akm_psk2[document.forms[0].wl_akm_psk2.selectedIndex].value;\n");
3543	websWrite(wp,"    var brcm_psk = document.forms[0].wl_akm_brcm_psk[document.forms[0].wl_akm_brcm_psk.selectedIndex].value;\n");
3544	websWrite(wp,"    var wps_mode = document.forms[0].wl_wps_mode.value;\n");
3545	websWrite(wp,"    var crypto = document.forms[0].wl_crypto[document.forms[0].wl_crypto.selectedIndex].value;\n");
3546	websWrite(wp,"    var open_str = \"Are you sure to configure WPS in Open security?\";\n");
3547	websWrite(wp,"    var shared_str = \"WPS dose not support Shared 802.11 authentication.  Are you sure to configure WPS in Shared authentication? Yes will force disable WPS.\";\n");
3548	websWrite(wp,"    var psk2_str = \"WPS only support WPA2-PSK or WPA2-PSK+WPA-PSK mixed mode authentication key management.  Are you sure your settings are correct? Yes will force disable WPS.\";\n");
3549	websWrite(wp,"    var tkip_str = \"WPS does not support TKIP only WPA encryption.  Are you sure your settings are correct? Yes will force disable WPS.\";\n");
3550	websWrite(wp,"    var wep_str = \"WPS dose not support WEP encryptipon.  Are you sure to configure WPS in WEP mode? Yes will force disable WPS.\";\n\n");
3551
3552	if (nvram_match("wps_version2", "enabled")) {
3553		websWrite(wp,"    if (wps_mode == \"enabled\") {\n");
3554		/* 1. Check WPS in OPEN security */
3555		websWrite(wp,"        if (auth == \"0\" && wep == \"disabled\" &&\n");
3556		websWrite(wp,"            wpa == \"disabled\" && psk == \"disabled\" &&\n");
3557		websWrite(wp,"            wpa2 == \"disabled\" && psk2 == \"disabled\" &&\n");
3558		websWrite(wp,"            brcm_psk != \"enabled\" && mode != \"radius\")\n");
3559		websWrite(wp,"            return confirm(open_str);\n");
3560
3561		/* Check Auth, deprecated "Shared" mode */
3562		websWrite(wp,"        if (auth == \"1\")\n");
3563		websWrite(wp,"            return confirm(shared_str);\n");
3564
3565		/* AKM enabled checking */
3566		websWrite(wp,"        if (wpa == \"enabled\" || psk == \"enabled\" || wpa2 == \"enabled\" ||psk2 == \"enabled\") {\n");
3567		websWrite(wp,"            if (psk2 != \"enabled\")\n");
3568		websWrite(wp,"                return confirm(psk2_str);\n");
3569					/* WSC 2.0, Encryption type check */
3570		websWrite(wp,"            if (crypto == \"tkip\")\n");
3571		websWrite(wp,"                return confirm(tkip_str);\n");
3572		websWrite(wp,"        }\n");
3573		websWrite(wp,"        else {\n");
3574					/* Check WEP */
3575		websWrite(wp,"            if (wep == \"enabled\" &&\n");
3576		websWrite(wp,"                wpa != \"enabled\" && psk != \"enabled\" &&\n");
3577		websWrite(wp,"                wpa2 != \"enabled\" && psk2 != \"enabled\" &&\n");
3578		websWrite(wp,"                brcm_psk != \"enabled\" && mode != \"radius\")\n");
3579		websWrite(wp,"                return confirm(wep_str);\n");
3580		websWrite(wp,"        }\n");
3581		websWrite(wp,"    }\n");
3582	}
3583#endif /* __CONFIG_WPS__ */
3584
3585	return 1;
3586}
3587
3588static int
3589wl_radio_onoff(webs_t wp, int disable)
3590{
3591	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
3592	char *name=NULL;
3593	char *interface_status=NULL;
3594	uint radiomaskval = 0;
3595
3596	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
3597		websError(wp, 400, "unit number variable doesn't exist\n");
3598		return -1;
3599	}
3600
3601	interface_status = nvram_get(strcat_r(prefix, "radio", tmp));
3602
3603	if (interface_status != NULL) {
3604		if (!strcmp(interface_status, "1")) {
3605			name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
3606			radiomaskval = WL_RADIO_SW_DISABLE << 16 | disable;
3607			wl_ioctl(name, WLC_SET_RADIO, &radiomaskval, sizeof (disable));
3608		}
3609		else {
3610			websWrite(wp, "Interface is not Enabled...");
3611			return 0;
3612		}
3613	}
3614	else {
3615		websWrite(wp, "Interface  status UnKnown...");
3616		return 0;
3617	}
3618
3619
3620	return 0;
3621
3622}
3623
3624/*
3625 * Example:
3626 * lan_ipaddr=192.168.1.1
3627 * <% nvram_get("lan_ipaddr"); %> produces "192.168.1.1"
3628 * <% nvram_get("undefined"); %> produces ""
3629 */
3630static int
3631ej_nvram_get(int eid, webs_t wp, int argc, char_t **argv)
3632{
3633	char *name=NULL, *c=NULL;
3634	int ret = 0;
3635
3636	if (ejArgs(argc, argv, "%s", &name) < 1) {
3637		websError(wp, 400, "Insufficient args\n");
3638		return -1;
3639	}
3640
3641	assert(name);
3642
3643	for (c = nvram_safe_get(name); *c; c++) {
3644		if (isprint((int) *c) &&
3645		    *c != '"' && *c != '&' && *c != '<' && *c != '>')
3646			ret += websWrite(wp, "%c", *c);
3647		else
3648			ret += websWrite(wp, "&#%d;", *c);
3649	}
3650
3651	return ret;
3652}
3653
3654#define MAX_BRIDGE_PREFIX_LEN 14
3655static int
3656ej_wl_get_bridge(int eid, webs_t wp, int argc, char_t **argv)
3657{
3658	int mode=0;
3659	char vif[MAX_BRIDGE_PREFIX_LEN];
3660	char *wl_bssid = NULL;
3661	char prefix[MAX_BRIDGE_PREFIX_LEN] = "wlXXXXXXXXXX_";
3662	unsigned int len;
3663	char name[IFNAMSIZ], *next = NULL;
3664	int found = 0;
3665	/* Get the interface name */
3666	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid)))
3667		mode=1;
3668
3669	/* In case of primary interfacae, it is always LAN */
3670	if(!mode) {
3671		websWrite(wp, "<option value=%s selected >LAN </option>\n","0" );
3672		websWrite(wp, "<option value=%s          >Guest</option>\n","1" );
3673		return 0;
3674
3675	}
3676
3677	if (!make_wl_prefix(prefix, sizeof(prefix), mode, NULL)) {
3678		websError(wp, 400, "unit number variable doesn't exist\n");
3679		return -1;
3680	}
3681
3682	/* interface name is prefix less the trailing '_' */
3683	strncpy(vif, prefix,MAX_BRIDGE_PREFIX_LEN-1);
3684	vif[MAX_BRIDGE_PREFIX_LEN - 1] = '\0';
3685	len = strlen(vif);
3686	len--;
3687	vif[len] = 0;
3688
3689	foreach(name, nvram_get("lan_ifnames"), next) {
3690		if (!strcmp(name, vif)) {
3691			found = 1;
3692			break;
3693		}
3694	}
3695
3696	if(found) {
3697		websWrite(wp, "<option value=%s selected >LAN </option>\n","0" );
3698		websWrite(wp, "<option value=%s          >Guest</option>\n","1" );
3699	}
3700	else {
3701		websWrite(wp, "<option value=%s          >LAN </option>\n","0" );
3702		websWrite(wp, "<option value=%s selected >Guest</option>\n","1" );
3703	}
3704
3705	return 0;
3706}
3707
3708/*
3709 * Example:
3710 * wan_proto=dhcp
3711 * <% nvram_match("wan_proto", "dhcp", "selected"); %> produces "selected"
3712 * <% nvram_match("wan_proto", "static", "selected"); %> produces ""
3713 */
3714static int
3715ej_nvram_match(int eid, webs_t wp, int argc, char_t **argv)
3716{
3717	char *name=NULL, *match=NULL, *output=NULL;
3718
3719	if (ejArgs(argc, argv, "%s %s %s", &name, &match, &output) < 3) {
3720		websError(wp, 400, "Insufficient args\n");
3721		return -1;
3722	}
3723
3724	assert(name);
3725	assert(match);
3726	assert(output);
3727
3728	if (nvram_match(name, match))
3729		return websWrite(wp, output);
3730
3731	return 0;
3732}
3733
3734/*
3735 * Example:
3736 * wl_u11en=0
3737 * <% nvram_match_bitflag("wl_hsflag", 2, "0", "selected"); %> produces "selected"
3738 * <% nvram_match_bitflag("wl_hsflag", 2, "1", "selected"); %> produces ""
3739 */
3740static int
3741ej_nvram_match_bitflag(int eid, webs_t wp, int argc, char_t **argv)
3742{
3743	char *name=NULL, *match=NULL, *output=NULL;
3744	int bit = 0;
3745
3746	if (ejArgs(argc, argv, "%s %d %s %s", &name, &bit, &match, &output) < 4) {
3747		websError(wp, HTTP_ERR_BAD_REQUEST, "Insufficient args\n");
3748		return -1;
3749	}
3750
3751	assert(name);
3752	assert(match);
3753	assert(output);
3754
3755	if (nvram_match_bitflag(name, bit, match))
3756		return websWrite(wp, output);
3757
3758	return 0;
3759}
3760
3761/*
3762 * Example:
3763 * wl_u11en=0
3764 * <% nvram_get_bitflag("wl_hsflag", 1); %> produces "1"
3765 * <% nvram_get_bitflag("wl_hsflag", 0); %> produces ""
3766 */
3767static int
3768ej_nvram_get_bitflag(int eid, webs_t wp, int argc, char_t ** argv)
3769{
3770	char *name = NULL;
3771	char *ptr = NULL;
3772	int bit = 0, ret = 0;
3773
3774	if (ejArgs(argc, argv, "%s %d", &name, &bit) < 2) {
3775		websError(wp, HTTP_ERR_BAD_REQUEST, "Insufficient args\n");
3776		return -1;
3777	}
3778
3779	assert(name);
3780	ptr = nvram_get_bitflag(name, bit);
3781	ret += websWrite(wp, (ptr ? ptr : "0"));
3782	return ret;
3783}
3784
3785static int
3786wl_print_chanspec_list(webs_t wp, char *name, char *abbrev, int band, int bw)
3787{
3788	chanspec_t c = 0, *chanspec;
3789	char *buf = (char *)malloc(WLC_IOCTL_MAXLEN);
3790	int buflen;
3791	wl_uint32_list_t *list;
3792	int ret = 0, i = 0;
3793	uint16 bandwidth = 0;
3794
3795	if (buf == NULL) {
3796		ret = -1;
3797		goto exit;
3798	}
3799
3800	strcpy(buf, "chanspecs");
3801	buflen = strlen(buf) + 1;
3802
3803	if (band == WLC_BAND_5G)
3804		c |= WL_CHANSPEC_BAND_5G;
3805	else
3806		c |= WL_CHANSPEC_BAND_2G;
3807
3808	if (bw == 80) {
3809		c |= WL_CHANSPEC_BW_80;
3810		bandwidth = WL_CHANSPEC_BW_80;
3811	} else if (bw == 40) {
3812		c |= WL_CHANSPEC_BW_40;
3813		bandwidth = WL_CHANSPEC_BW_40;
3814	} else {
3815		c |= WL_CHANSPEC_BW_20;
3816		bandwidth = WL_CHANSPEC_BW_20;
3817	}
3818
3819	chanspec = (chanspec_t *)(buf + buflen);
3820	*chanspec = c;
3821	buflen += (sizeof(chanspec_t));
3822	strncpy(buf + buflen, abbrev, WLC_CNTRY_BUF_SZ);
3823	buflen += WLC_CNTRY_BUF_SZ;
3824
3825	/* Add list */
3826	list = (wl_uint32_list_t *)(buf + buflen);
3827	list->count = WL_NUMCHANSPECS;
3828	buflen += sizeof(uint32)*(WL_NUMCHANSPECS + 1);
3829
3830	ret = wl_ioctl(name, WLC_GET_VAR, buf, buflen);
3831	if (ret < 0) {
3832		goto exit;
3833	}
3834
3835	list = (wl_uint32_list_t *)buf;
3836
3837	if (list->count > 0) {
3838		websWrite(wp, "\t\tif (country == \"%s\")\n\t\t\tchanspecs = new Array(\"0\"", abbrev);
3839		for (i = 0; i < list->count; i++) {
3840			char chanbuf[CHANSPEC_STR_LEN];
3841
3842			c = (chanspec_t) list->element[i];
3843
3844			if (bandwidth && CHSPEC_BW(c) != bandwidth)
3845				continue;
3846
3847			websWrite(wp, ", \"%s\"", wf_chspec_ntoa(c, chanbuf));
3848		}
3849		websWrite(wp, ");\n");
3850	} else {
3851		websWrite(wp, "\t\tif (country == \"%s\")\n\t\t\tchanspecs = new Array(\"N/A\");\n", abbrev);
3852	}
3853
3854exit:
3855	if (buf)
3856		free(buf);
3857
3858	return ret;
3859}
3860
3861static int
3862ej_wl_country_list(int eid, webs_t wp, int argc, char_t **argv)
3863{
3864	int i =0, status = 0;
3865	char *name =NULL;
3866	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
3867	char *phytype = NULL;
3868	wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN);
3869	country_name_t *cntry=NULL;
3870	char *abbrev=NULL;
3871	int band = WLC_BAND_ALL, cur_phytype;
3872
3873	if (!cl) {
3874		status = -1;
3875		goto exit;
3876	}
3877
3878	if (ejArgs(argc, argv, "%s %d", &phytype, &band) < 1) {
3879		websError(wp, 400, "Insufficient args\n");
3880		status = -1;
3881		goto exit;
3882	}
3883
3884	assert(phytype);
3885	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
3886		websError(wp, 400, "unit number variable doesn't exist\n");
3887		status = -1;
3888		goto exit;
3889	}
3890
3891	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
3892
3893	/* Get configured phy type */
3894	wl_ioctl(name, WLC_GET_PHYTYPE, &cur_phytype, sizeof(cur_phytype));
3895
3896	cl->buflen = WLC_IOCTL_MAXLEN;
3897	cl->band_set = TRUE;
3898
3899	if (!strcmp(phytype, "a") &&
3900	    (cur_phytype != WLC_PHY_TYPE_N) && (cur_phytype != WLC_PHY_TYPE_SSN) &&
3901	    (cur_phytype != WLC_PHY_TYPE_LCN) && (cur_phytype != WLC_PHY_TYPE_HT) &&
3902	    (cur_phytype != WLC_PHY_TYPE_AC)) {
3903		cl->band = WLC_BAND_5G;
3904	} else if (((!strcmp(phytype, "b")) || (!strcmp(phytype, "g"))) &&
3905	           (cur_phytype != WLC_PHY_TYPE_N) && (cur_phytype != WLC_PHY_TYPE_SSN) &&
3906	           (cur_phytype != WLC_PHY_TYPE_LCN) && (cur_phytype != WLC_PHY_TYPE_HT) &&
3907	           (cur_phytype != WLC_PHY_TYPE_AC)) {
3908		cl->band = WLC_BAND_2G;
3909	} else if ((!strcmp(phytype, "n") || !strcmp(phytype, "s") || !strcmp(phytype, "h") || !strcmp(phytype, "v")) &&
3910	           ((cur_phytype == WLC_PHY_TYPE_N) || (cur_phytype == WLC_PHY_TYPE_SSN) ||
3911	            (cur_phytype == WLC_PHY_TYPE_LCN) || (cur_phytype == WLC_PHY_TYPE_HT) ||
3912	            (cur_phytype == WLC_PHY_TYPE_AC))) {
3913		/* Need to have additional argument of the band */
3914		if (argc < 2 || (band != WLC_BAND_2G && band != WLC_BAND_5G)) {
3915			status = -1;
3916			goto exit;
3917		}
3918		cl->band = band;
3919	} else if ((!strcmp(phytype, "l")) && (cur_phytype == WLC_PHY_TYPE_LP)) {
3920		wl_ioctl(name, WLC_GET_BAND, &band, sizeof(band));
3921		cl->band = band;
3922	} else {
3923		status = -1;
3924		goto exit;
3925	}
3926
3927	if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) {
3928		websWrite(wp, "\t\tvar countries = new Array(");
3929		for(i = 0; i < cl->count; i++) {
3930			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
3931			websWrite(wp, "\"%s\"", abbrev);
3932			if (i != (cl->count - 1))
3933				websWrite(wp, ", ");
3934		}
3935		websWrite(wp, ");\n");
3936		for(i = 0; i < cl->count; i++) {
3937			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
3938			for(cntry = country_names;
3939				cntry->name && strcmp(abbrev, cntry->abbrev);
3940				cntry++);
3941			websWrite(wp, "\t\tdocument.forms[0].wl_country_code[%d] = new Option(\"%s\", \"%s\");\n",
3942				i, cntry->name ? cntry->name : abbrev, abbrev);
3943		}
3944	}
3945
3946exit:
3947	if (cl)
3948		free((void *)cl);
3949	return status;
3950}
3951
3952static int
3953wl_print_country_rev_list(webs_t wp, char *name, char *abbrev)
3954{
3955	char *buf = (char *)malloc(WLC_IOCTL_MAXLEN);
3956	int buflen;
3957	wl_uint32_list_t *list;
3958	int ret = 0, i = 0, c = 0;
3959
3960	if (buf == NULL)
3961		return -1;
3962
3963	strcpy(buf, "country_rev");
3964	buflen = strlen(buf) + 1;
3965
3966	strncpy(buf + buflen, abbrev, WLC_CNTRY_BUF_SZ);
3967	buflen += WLC_CNTRY_BUF_SZ;
3968
3969	/* Add list */
3970	list = (wl_uint32_list_t *)(buf + buflen);
3971	list->count = WLC_IOCTL_SMLEN;
3972	buflen += sizeof(uint32)*(WLC_IOCTL_SMLEN + 1);
3973
3974	ret = wl_ioctl(name, WLC_GET_VAR, buf, buflen);
3975	if (ret < 0)
3976		goto exit;
3977
3978	list = (wl_uint32_list_t *)buf;
3979
3980	if (list->count == 0) {
3981		ret = 0;
3982		goto exit;
3983	}
3984
3985	websWrite(wp, "\t\tif (country == \"%s\")\n\t\t\tcountry_revs = new Array(",
3986	          abbrev);
3987	for (i = 0; i < list->count; i++) {
3988		c = list->element[i];
3989		websWrite(wp, "\"%d\"", c);
3990		if (i != (list->count - 1))
3991			websWrite(wp, ", ");
3992	}
3993	websWrite(wp,");\n");
3994
3995exit:
3996	free((void *)buf);
3997	return ret;
3998}
3999
4000static int
4001ej_wl_country_rev_list(int eid, webs_t wp, int argc, char_t **argv)
4002{
4003	/* country_rev from 0 to 99 */
4004	int i =0, status = 0;
4005	char *name =NULL;
4006	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
4007	char *phytype = NULL;
4008	wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN);
4009	char *abbrev=NULL;
4010	int band = WLC_BAND_ALL, cur_phytype;
4011
4012	if (!cl) {
4013		status = -1;
4014		goto exit;
4015	}
4016
4017	if (ejArgs(argc, argv, "%s %d", &phytype, &band) < 1) {
4018		websError(wp, 400, "Insufficient args\n");
4019		status = -1;
4020		goto exit;
4021	}
4022
4023	assert(phytype);
4024	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
4025		websError(wp, 400, "unit number variable doesn't exist\n");
4026		status = -1;
4027		goto exit;
4028	}
4029
4030	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
4031
4032	/* Get configured phy type */
4033	wl_ioctl(name, WLC_GET_PHYTYPE, &cur_phytype, sizeof(cur_phytype));
4034
4035	cl->buflen = WLC_IOCTL_MAXLEN;
4036	cl->band_set = TRUE;
4037
4038	if (!strcmp(phytype, "a") &&
4039	    (cur_phytype != WLC_PHY_TYPE_N) && (cur_phytype != WLC_PHY_TYPE_SSN) &&
4040	    (cur_phytype != WLC_PHY_TYPE_LCN) && (cur_phytype != WLC_PHY_TYPE_HT) &&
4041	    (cur_phytype != WLC_PHY_TYPE_AC)) {
4042		cl->band = WLC_BAND_5G;
4043	} else if (((!strcmp(phytype, "b")) || (!strcmp(phytype, "g"))) &&
4044	           (cur_phytype != WLC_PHY_TYPE_N) && (cur_phytype != WLC_PHY_TYPE_SSN) &&
4045	           (cur_phytype != WLC_PHY_TYPE_LCN) && (cur_phytype != WLC_PHY_TYPE_HT) &&
4046	           (cur_phytype != WLC_PHY_TYPE_AC)) {
4047		cl->band = WLC_BAND_2G;
4048	} else if ((!strcmp(phytype, "n") || !strcmp(phytype, "s") || !strcmp(phytype, "h") ||
4049	            !strcmp(phytype, "v")) &&
4050	           ((cur_phytype == WLC_PHY_TYPE_N) || (cur_phytype == WLC_PHY_TYPE_SSN) ||
4051	            (cur_phytype == WLC_PHY_TYPE_LCN) || (cur_phytype == WLC_PHY_TYPE_HT) ||
4052	            (cur_phytype == WLC_PHY_TYPE_AC))) {
4053		/* Need to have additional argument of the band */
4054		if (argc < 2 || (band != WLC_BAND_2G && band != WLC_BAND_5G)) {
4055			status = -1;
4056			goto exit;
4057		}
4058		cl->band = band;
4059	} else if ((!strcmp(phytype, "l")) && (cur_phytype == WLC_PHY_TYPE_LP)) {
4060		wl_ioctl(name, WLC_GET_BAND, &band, sizeof(band));
4061		cl->band = band;
4062	} else {
4063		status = -1;
4064		goto exit;
4065	}
4066
4067	if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) {
4068		for(i = 0; i < cl->count; i++) {
4069			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
4070			wl_print_country_rev_list(wp, name, abbrev);
4071		}
4072	}
4073
4074exit:
4075	if (cl)
4076		free((void *)cl);
4077	return status;
4078
4079}
4080
4081static int
4082ej_wl_chanspec_list(int eid, webs_t wp, int argc, char_t **argv)
4083{
4084	int  i, status = 0;
4085	char *name=NULL;
4086	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
4087	char *phytype = NULL;
4088	int cur_phytype;
4089	wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN);
4090	char *abbrev=NULL;
4091	int band = WLC_BAND_ALL;
4092	int bw = 0;
4093
4094	if (!cl) {
4095		status = -1;
4096		goto exit;
4097	}
4098
4099	if (ejArgs(argc, argv, "%s %d %d", &phytype, &band, &bw) < 1) {
4100		websError(wp, 400, "Insufficient args\n");
4101		status = -1;
4102		goto exit;
4103	}
4104
4105	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
4106		websError(wp, 400, "unit number variable doesn't exist\n");
4107		status = -1;
4108		goto exit;
4109	}
4110
4111	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
4112
4113	/* Get configured phy type */
4114	wl_ioctl(name, WLC_GET_PHYTYPE, &cur_phytype, sizeof(cur_phytype));
4115
4116	cl->buflen = WLC_IOCTL_MAXLEN;
4117	cl->band_set = TRUE;
4118
4119	if (!strcmp(phytype, "a") &&
4120	    (cur_phytype != WLC_PHY_TYPE_N) && (cur_phytype != WLC_PHY_TYPE_SSN) &&
4121	    (cur_phytype != WLC_PHY_TYPE_LCN) && (cur_phytype != WLC_PHY_TYPE_HT) &&
4122	    (cur_phytype != WLC_PHY_TYPE_AC)) {
4123		cl->band = WLC_BAND_5G;
4124	} else if (((!strcmp(phytype, "b")) || (!strcmp(phytype, "g"))) &&
4125	           (cur_phytype != WLC_PHY_TYPE_N) && (cur_phytype != WLC_PHY_TYPE_SSN) &&
4126	           (cur_phytype != WLC_PHY_TYPE_LCN) && (cur_phytype != WLC_PHY_TYPE_HT) &&
4127	           (cur_phytype != WLC_PHY_TYPE_AC)) {
4128		cl->band = WLC_BAND_2G;
4129	} else if ((!strcmp(phytype, "l")) && (cur_phytype == WLC_PHY_TYPE_LP)) {
4130		wl_ioctl(name, WLC_GET_BAND, &band, sizeof(band));
4131		cl->band = band;
4132	} else if ((!strcmp(phytype, "n") || !strcmp(phytype, "s") || !strcmp(phytype, "h") || !strcmp(phytype, "v")) &&
4133	           ((cur_phytype == WLC_PHY_TYPE_N) || (cur_phytype == WLC_PHY_TYPE_SSN) ||
4134	            (cur_phytype == WLC_PHY_TYPE_LCN) || (cur_phytype == WLC_PHY_TYPE_HT) ||
4135	            (cur_phytype == WLC_PHY_TYPE_AC))) {
4136		/* Need to have additional argument of the band */
4137		if (argc < 2 || (band != WLC_BAND_2G && band != WLC_BAND_5G)) {
4138			status = -1;
4139			goto exit;
4140		}
4141		cl->band = band;
4142	} else {
4143		status = -1;
4144		goto exit;
4145	}
4146
4147	band = cl->band;
4148
4149	if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) {
4150		for (i = 0; i < cl->count; i++) {
4151			abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
4152			wl_print_chanspec_list(wp, name, abbrev, band, bw);
4153		}
4154	}
4155
4156exit:
4157	if (cl)
4158		free(cl);
4159
4160	return status;
4161}
4162
4163/* Output one row of the HTML authenticated STA list table */
4164static void
4165auth_list_sta(webs_t wp, char *name, struct ether_addr *ea)
4166{
4167	char buf[sizeof(sta_info_t)];
4168
4169	assert(sizeof (buf) >= sizeof (sta_info_t));
4170	strcpy(buf, "sta_info");
4171	memcpy(buf + strlen(buf) + 1, (unsigned char *)ea, ETHER_ADDR_LEN);
4172
4173	if (!wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))) {
4174		char ea_str[ETHER_ADDR_STR_LEN];
4175		sta_info_t *sta = (sta_info_t *)buf;
4176		uint32 f = sta->flags;
4177
4178		websWrite(wp, "<td>%s</td>", ether_etoa((unsigned char *)ea, ea_str));
4179		websWrite(wp, "<td>%s</td>", (f & WL_STA_ASSOC) ? reltime_short(sta->in) : "-");
4180		websWrite(wp, "<td>%s</td>", (f & WL_STA_AUTHO) ? "Yes" : "No");
4181		websWrite(wp, "<td>%s</td>", (f & WL_STA_WME) ? "Yes" : "No");
4182		websWrite(wp, "<td>%s</td>", (f & WL_STA_PS) ? "Yes" : "No");
4183		websWrite(wp, "<td>%s%s%s%s&nbsp;</td>",
4184		          (f & WL_STA_APSD_BE) ? "BE " : "",
4185		          (f & WL_STA_APSD_BK) ? "BK " : "",
4186		          (f & WL_STA_APSD_VI) ? "VI " : "",
4187		          (f & WL_STA_APSD_VO) ? "VO " : "");
4188	}
4189}
4190
4191static int
4192ej_wl_auth_list(int eid, webs_t wp, int argc, char_t **argv)
4193{
4194	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
4195	char *name;
4196	struct maclist *mac_list;
4197	int mac_list_size;
4198	int i;
4199	char *wl_bssid = NULL;
4200	int mode = 0;
4201
4202	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid)))
4203		mode=1;
4204
4205	if (!make_wl_prefix(prefix, sizeof(prefix), mode, NULL)) {
4206		websError(wp, 400, "unit number variable doesn't exist\n");
4207		return -1;
4208	}
4209
4210	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
4211
4212	/* buffers and length */
4213	mac_list_size = sizeof(mac_list->count) + MAX_STA_COUNT * sizeof(struct ether_addr);
4214	mac_list = malloc(mac_list_size);
4215
4216	if (!mac_list)
4217		return -1;
4218
4219	/* query wl for authenticated sta list */
4220#ifndef __NetBSD__
4221	strcpy((char*)mac_list, "authe_sta_list");
4222	if (wl_ioctl(name, WLC_GET_VAR, mac_list, mac_list_size)) {
4223		free(mac_list);
4224		return -1;
4225	}
4226#else
4227	/* NetBSD TBD... */
4228	mac_list->count=0;
4229#endif
4230
4231	/* query sta_info for each STA and output one table row each */
4232	for (i = 0; i < mac_list->count; i++) {
4233		websWrite(wp, "<tr align=\"center\">");
4234		auth_list_sta(wp, name, &mac_list->ea[i]);
4235		websWrite(wp, "</tr>");
4236	}
4237
4238	free(mac_list);
4239
4240	return 0;
4241}
4242
4243/*
4244 * Example:
4245 * wan_proto=dhcp
4246 * <% nvram_invmatch("wan_proto", "dhcp", "disabled"); %> produces ""
4247 * <% nvram_invmatch("wan_proto", "static", "disabled"); %> produces "disabled"
4248 */
4249static int
4250ej_nvram_invmatch(int eid, webs_t wp, int argc, char_t **argv)
4251{
4252	char *name=NULL, *invmatch=NULL, *output=NULL;
4253
4254	if (ejArgs(argc, argv, "%s %s %s", &name, &invmatch, &output) < 3) {
4255		websError(wp, 400, "Insufficient args\n");
4256		return -1;
4257	}
4258
4259	assert(name);
4260	assert(invmatch);
4261	assert(output);
4262
4263	if (nvram_invmatch(name, invmatch))
4264		return websWrite(wp, output);
4265
4266	return 0;
4267}
4268
4269/*
4270 * Example:
4271 * filter_maclist=00:12:34:56:78:00 00:87:65:43:21:00
4272 * <% nvram_list("filter_maclist", 1); %> produces "00:87:65:43:21:00"
4273 * <% nvram_list("filter_maclist", 100); %> produces ""
4274 */
4275static int
4276ej_nvram_list(int eid, webs_t wp, int argc, char_t **argv)
4277{
4278	char *name=NULL;
4279	int which=0;
4280	char word[256], *next=NULL;
4281
4282	if (ejArgs(argc, argv, "%s %d", &name, &which) < 2) {
4283		websError(wp, 400, "Insufficient args\n");
4284		return -1;
4285	}
4286
4287	foreach(word, nvram_safe_get(name), next) {
4288		if (which-- == 0)
4289			return websWrite(wp, word);
4290	}
4291
4292	return 0;
4293}
4294
4295static int
4296ej_nvram_inlist(int eid, webs_t wp, int argc, char_t **argv)
4297{
4298	char *name, *item, *output;
4299	char word[256], *next;
4300
4301	if (ejArgs(argc, argv, "%s %s %s", &name, &item, &output) < 3) {
4302		websError(wp, 400, "Insufficient args\n");
4303		return -1;
4304	}
4305
4306	foreach(word, nvram_safe_get(name), next) {
4307		if (!strcmp(word, item))
4308			return websWrite(wp, output);
4309	}
4310
4311	return 0;
4312}
4313
4314static int
4315ej_nvram_invinlist(int eid, webs_t wp, int argc, char_t **argv)
4316{
4317	char *name, *item, *output;
4318	char word[256], *next;
4319
4320	if (ejArgs(argc, argv, "%s %s %s", &name, &item, &output) < 3) {
4321		websError(wp, 400, "Insufficient args\n");
4322		return -1;
4323	}
4324
4325	foreach(word, nvram_safe_get(name), next) {
4326		if (!strcmp(word, item))
4327			return 0;
4328	}
4329
4330	return websWrite(wp, output);
4331}
4332
4333/*
4334 * Example:
4335 * wme_ap_bk=15 1023 7 0 0 on off
4336 * <% nvram_indexmatch("wme_ap_bk", 5, "on", "selected"); %> produces "selected"
4337 * <% nvram_indexmatch("wme_ap_bk", 6, "on", "selected"); %> produces ""
4338 */
4339static int
4340ej_nvram_indexmatch(int eid, webs_t wp, int argc, char_t **argv)
4341{
4342	char *name = NULL, *match = NULL, *output = NULL;
4343	char word[256], *next;
4344	int index;
4345
4346	if (ejArgs(argc, argv, "%s %d %s %s", &name, &index, &match, &output) < 3) {
4347		websError(wp, 400, "Insufficient args\n");
4348		return -1;
4349	}
4350
4351	assert(name);
4352	assert(match);
4353	assert(output);
4354
4355	foreach(word, nvram_safe_get(name), next)
4356	        if (index-- == 0 && !strcmp(word, match))
4357			return websWrite(wp, output);
4358
4359	return 0;
4360}
4361
4362#ifdef __CONFIG_NAT__
4363/*
4364 * Example:
4365 * <% filter_client(1, 10); %> produces a table of the first 10 client filter entries
4366 */
4367static int
4368ej_filter_client(int eid, webs_t wp, int argc, char_t **argv)
4369{
4370	int i, n, j, ret = 0;
4371	netconf_filter_t start, end;
4372	bool valid;
4373	char port[] = "XXXXX";
4374	char *days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
4375	char *hours[] = {
4376		"12:00 AM", "1:00 AM", "2:00 AM", "3:00 AM", "4:00 AM", "5:00 AM",
4377		"6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM",
4378		"12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM",
4379		"6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM"
4380	};
4381
4382	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
4383		websError(wp, 400, "Insufficient args\n");
4384		return -1;
4385	}
4386
4387	for (; i <= n; i++) {
4388		valid = get_filter_client(i, &start, &end);
4389
4390		ret += websWrite(wp, "<tr>");
4391		ret += websWrite(wp, "<td></td>");
4392
4393		/* Print address range */
4394		ret += websWrite(wp, "<td><input name=\"filter_client_from_start%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
4395				 i, valid ? inet_ntoa(start.match.src.ipaddr) : "");
4396		ret += websWrite(wp, "<td>-</td>");
4397		ret += websWrite(wp, "<td><input name=\"filter_client_from_end%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
4398				 i, valid ? inet_ntoa(end.match.src.ipaddr) : "");
4399		ret += websWrite(wp, "<td></td>");
4400
4401		/* Print protocol */
4402		ret += websWrite(wp, "<td>");
4403		ret += websWrite(wp, "<select name=\"filter_client_proto%d\">", i);
4404		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
4405				 valid && start.match.ipproto == IPPROTO_TCP ? "selected" : "");
4406		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
4407				 valid && start.match.ipproto == IPPROTO_UDP ? "selected" : "");
4408		ret += websWrite(wp, "</select>");
4409		ret += websWrite(wp, "</td>");
4410		ret += websWrite(wp, "<td></td>");
4411
4412		/* Print port range */
4413		if (valid)
4414			snprintf(port, sizeof(port), "%d", ntohs(start.match.dst.ports[0]));
4415		else
4416			*port = '\0';
4417		ret += websWrite(wp, "<td><input name=\"filter_client_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4418				 i, port);
4419		ret += websWrite(wp, "<td>-</td>");
4420		if (valid)
4421			snprintf(port, sizeof(port), "%d", ntohs(start.match.dst.ports[1]));
4422		else
4423			*port = '\0';
4424		ret += websWrite(wp, "<td><input name=\"filter_client_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4425				 i, port);
4426		ret += websWrite(wp, "<td></td>");
4427
4428		/* Print day range */
4429		ret += websWrite(wp, "<td>");
4430		ret += websWrite(wp, "<select name=\"filter_client_from_day%d\">", i);
4431		for (j = 0; j < ARRAYSIZE(days); j++)
4432			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
4433					 j, valid && start.match.days[0] == j ? "selected" : "", days[j]);
4434		ret += websWrite(wp, "</select>");
4435		ret += websWrite(wp, "</td>");
4436		ret += websWrite(wp, "<td>-</td>");
4437		ret += websWrite(wp, "<td>");
4438		ret += websWrite(wp, "<select name=\"filter_client_to_day%d\">", i);
4439		for (j = 0; j < ARRAYSIZE(days); j++)
4440			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
4441					 j, valid && start.match.days[1] == j ? "selected" : "", days[j]);
4442		ret += websWrite(wp, "</select>");
4443		ret += websWrite(wp, "</td>");
4444		ret += websWrite(wp, "<td></td>");
4445
4446		/* Print time range */
4447		ret += websWrite(wp, "<td>");
4448		ret += websWrite(wp, "<select name=\"filter_client_from_sec%d\">", i);
4449		for (j = 0; j < ARRAYSIZE(hours); j++)
4450			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
4451					 j * 3600, valid && start.match.secs[0] == (j * 3600) ? "selected" : "", hours[j]);
4452		ret += websWrite(wp, "</select>");
4453		ret += websWrite(wp, "</td>");
4454		ret += websWrite(wp, "<td>-</td>");
4455
4456		ret += websWrite(wp, "<td>");
4457		ret += websWrite(wp, "<select name=\"filter_client_to_sec%d\">", i);
4458		for (j = 0; j < ARRAYSIZE(hours); j++)
4459			ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>",
4460					 j * 3600, valid && start.match.secs[1] == (j * 3600) ? "selected" : "", hours[j]);
4461		/* Special case for 11:59:59 PM */
4462		ret += websWrite(wp, "<option value=\"%d\" %s>12:00 AM</option>",
4463				 24 * 3600 - 1, valid && start.match.secs[1] == (24 * 3600 - 1) ? "selected" : "");
4464		ret += websWrite(wp, "</select>");
4465		ret += websWrite(wp, "</td>");
4466		ret += websWrite(wp, "<td></td>");
4467
4468		/* Print enable */
4469		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"filter_client_enable%d\" %s></td>",
4470				 i, valid && !(start.match.flags & NETCONF_DISABLED) ? "checked" : "");
4471
4472		ret += websWrite(wp, "</tr>");
4473	}
4474
4475	return ret;
4476}
4477
4478/*
4479 * Example:
4480 * <% filter_url(1, 10); %> produces a table of the first 10 client filter entries
4481 */
4482static int
4483ej_filter_url(int eid, webs_t wp, int argc, char_t **argv)
4484{
4485	int ret = 0;
4486
4487#ifdef __CONFIG_URLFILTER__
4488	int i, n;
4489	netconf_urlfilter_t start, end;
4490	bool valid;
4491
4492	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
4493		websError(wp, 400, "Insufficient args\n");
4494		return -1;
4495	}
4496
4497	/* Start of table */
4498	ret += websWrite(wp, "<p>");
4499	ret += websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
4500	ret += websWrite(wp, "<tr>");
4501	ret += websWrite(wp, "<th width=\"310\" valign=\"top\" rowspan=\"11\" ");
4502	ret += websWrite(wp, "onMouseOver=");
4503	ret += websWrite(wp,
4504	"\"return overlib('Filter packets from IP addresses destined to certain URL.', LEFT);\" ");
4505	ret += websWrite(wp, "onMouseOut=\"return nd();\">");
4506	ret += websWrite(wp, "<input type=\"hidden\" name=\"filter_url\" value=\"10\">");
4507	ret += websWrite(wp, "URL Filters:&nbsp;&nbsp;");
4508	ret += websWrite(wp, "</th>");
4509	ret += websWrite(wp, "<td>&nbsp;&nbsp;</td>");
4510	ret += websWrite(wp, "<td class=\"label\" colspan=\"3\">LAN IP Address Range</td>");
4511	ret += websWrite(wp, "<td>&nbsp;</td>");
4512	ret += websWrite(wp, "<td class=\"label\">URL filter string</td>");
4513	ret += websWrite(wp, "<td class=\"label\">Enabled</td>");
4514	ret += websWrite(wp, "</tr>");
4515
4516	/* Entries */
4517	for (; i <= n; i++) {
4518		valid = get_filter_url(i, &start, &end);
4519
4520		ret += websWrite(wp, "<tr>");
4521		ret += websWrite(wp, "<td></td>");
4522
4523		/* Print address range */
4524		ret += websWrite(wp, "<td><input name=\"filter_url_from_start%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
4525				 i, valid ? inet_ntoa(start.match.src.ipaddr) : "");
4526		ret += websWrite(wp, "<td>-</td>");
4527		ret += websWrite(wp, "<td><input name=\"filter_url_from_end%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
4528				 i, valid ? inet_ntoa(end.match.src.ipaddr) : "");
4529		ret += websWrite(wp, "<td></td>");
4530
4531		/* Print URL string */
4532		ret += websWrite(wp, "<td><input name=\"filter_url_addr%d\" value=\"%s\" size=\"40\" maxlength=\"128\"></td>",
4533				 i, valid ?  start.url : "");
4534
4535		/* Print enable */
4536		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"filter_url_enable%d\" %s></td>",
4537				 i, valid && !(start.match.flags & NETCONF_DISABLED) ? "checked" : "");
4538
4539		ret += websWrite(wp, "</tr>");
4540	}
4541
4542	/* End of table */
4543	ret += websWrite(wp, "</table>");
4544#endif /* __CONFIG_URLFILTER__ */
4545
4546	return ret;
4547}
4548
4549/*
4550 * Example:
4551 * <% forward_port(1, 10); %> produces a table of the first 10 port forward entries
4552 */
4553static int
4554ej_forward_port(int eid, webs_t wp, int argc, char_t **argv)
4555{
4556	int i, n, ret = 0;
4557	netconf_nat_t nat;
4558	bool valid;
4559	char port[] = "XXXXX";
4560
4561	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
4562		websError(wp, 400, "Insufficient args\n");
4563		return -1;
4564	}
4565
4566	for (; i <= n; i++) {
4567		valid = get_forward_port(i, &nat);
4568
4569		ret += websWrite(wp, "<tr>");
4570		ret += websWrite(wp, "<td></td>");
4571
4572		/* Print protocol */
4573		ret += websWrite(wp, "<td>");
4574		ret += websWrite(wp, "<select name=\"forward_port_proto%d\">", i);
4575		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
4576				 valid && nat.match.ipproto == IPPROTO_TCP ? "selected" : "");
4577		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
4578				 valid && nat.match.ipproto == IPPROTO_UDP ? "selected" : "");
4579		ret += websWrite(wp, "</select>");
4580		ret += websWrite(wp, "</td>");
4581		ret += websWrite(wp, "<td></td>");
4582
4583		/* Print WAN destination port range */
4584		if (valid)
4585			snprintf(port, sizeof(port), "%d", ntohs(nat.match.dst.ports[0]));
4586		else
4587			*port = '\0';
4588		ret += websWrite(wp, "<td><input name=\"forward_port_from_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4589				 i, port);
4590		ret += websWrite(wp, "<td>-</td>");
4591		if (valid)
4592			snprintf(port, sizeof(port), "%d", ntohs(nat.match.dst.ports[1]));
4593		else
4594			*port = '\0';
4595		ret += websWrite(wp, "<td><input name=\"forward_port_from_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4596				 i, port);
4597		ret += websWrite(wp, "<td>></td>");
4598
4599		/* Print address range */
4600		ret += websWrite(wp, "<td><input name=\"forward_port_to_ip%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>",
4601				 i, valid ? inet_ntoa(nat.ipaddr) : "");
4602		ret += websWrite(wp, "<td>:</td>");
4603
4604		/* Print LAN destination port range */
4605		if (valid)
4606			snprintf(port, sizeof(port), "%d", ntohs(nat.ports[0]));
4607		else
4608			*port = '\0';
4609		ret += websWrite(wp, "<td><input name=\"forward_port_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4610				 i, port);
4611		ret += websWrite(wp, "<td>-</td>");
4612		if (valid)
4613			snprintf(port, sizeof(port), "%d", ntohs(nat.ports[1]));
4614		else
4615			*port = '\0';
4616		ret += websWrite(wp, "<td><input name=\"forward_port_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4617				 i, port);
4618		ret += websWrite(wp, "<td></td>");
4619
4620		/* Print enable */
4621		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"forward_port_enable%d\" %s></td>",
4622				 i, valid && !(nat.match.flags & NETCONF_DISABLED) ? "checked" : "");
4623
4624		ret += websWrite(wp, "</tr>");
4625	}
4626
4627	return ret;
4628}
4629
4630static int
4631ej_autofw_port_display(int eid, webs_t wp, int argc, char_t **argv)
4632{
4633	int ret = 0;
4634
4635#if !defined(AUTOFW_PORT_DEPRECATED)
4636	int i, n;
4637	netconf_app_t app;
4638	bool valid;
4639	char port[] = "XXXXX";
4640
4641	if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) {
4642		websError(wp, 400, "Insufficient args\n");
4643		return -1;
4644	}
4645
4646	/* Display table layout */
4647	ret += websWrite(wp, "<p>\n");
4648	ret += websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
4649	ret += websWrite(wp, "<tr>\n");
4650	ret += websWrite(wp, "<th width=\"310\" valign=\"top\" rowspan=\"11\" onMouseOver=\"return overlib('Automatically forward connections.', LEFT);\" onMouseOut=\"return nd();\">\n");
4651	ret += websWrite(wp, "<input type=\"hidden\" name=\"autofw_port\" value=\"5\">Application Specific Port Forwards:&nbsp;&nbsp;\n");
4652	ret += websWrite(wp, "</th>\n");
4653	ret += websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
4654	ret += websWrite(wp, "<td class=\"label\">Outbound<br>Protocol</td>\n");
4655	ret += websWrite(wp, "<td>&nbsp;</td>\n");
4656	ret += websWrite(wp, "<td class=\"label\">Outbound<br>Port Start</td>\n");
4657	ret += websWrite(wp, "<td>&nbsp;</td>\n");
4658	ret += websWrite(wp, "<td class=\"label\">Outbound<br>Port End</td>\n");
4659	ret += websWrite(wp, "<td>&nbsp;</td>\n");
4660	ret += websWrite(wp, "<td class=\"label\">Inbound<br>Protocol</td>\n");
4661	ret += websWrite(wp, "<td>&nbsp;</td>\n");
4662	ret += websWrite(wp, "<td class=\"label\">Inbound<br>Port Start</td>\n");
4663	ret += websWrite(wp, "<td></td>\n");
4664	ret += websWrite(wp, "<td class=\"label\">Inbound<br>Port End</td>\n");
4665	ret += websWrite(wp, "<td>&nbsp;</td>\n");
4666	ret += websWrite(wp, "<td class=\"label\">To<br>Port Start</td>\n");
4667	ret += websWrite(wp, "<td></td>\n");
4668	ret += websWrite(wp, "<td class=\"label\">To<br>Port End</td>\n");
4669	ret += websWrite(wp, "<td>&nbsp;</td>\n");
4670	ret += websWrite(wp, "<td class=\"label\">Enabled</td>\n");
4671	ret += websWrite(wp, "</tr>\n");
4672
4673	for (; i <= n; i++) {
4674		valid = get_autofw_port(i, &app);
4675
4676		/* Parse out_proto:out_port,in_proto:in_start-in_end>to_start-to_end,enable,desc */
4677		ret += websWrite(wp, "<tr>");
4678		ret += websWrite(wp, "<td></td>");
4679
4680		/* Print outbound protocol */
4681		ret += websWrite(wp, "<td>");
4682		ret += websWrite(wp, "<select name=\"autofw_port_out_proto%d\">", i);
4683		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
4684				 valid && app.match.ipproto == IPPROTO_TCP ? "selected" : "");
4685		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
4686				 valid && app.match.ipproto == IPPROTO_UDP ? "selected" : "");
4687		ret += websWrite(wp, "</select>");
4688		ret += websWrite(wp, "</td>");
4689		ret += websWrite(wp, "<td></td>");
4690
4691		/* Print outbound port */
4692		if (valid)
4693			snprintf(port, sizeof(port), "%d", ntohs(app.match.dst.ports[0]));
4694		else
4695			*port = '\0';
4696		ret += websWrite(wp, "<td><input name=\"autofw_port_out_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4697				 i, port);
4698		ret += websWrite(wp, "<td>-</td>");
4699		if (valid)
4700			snprintf(port, sizeof(port), "%d", ntohs(app.match.dst.ports[1]));
4701		else
4702			*port = '\0';
4703		ret += websWrite(wp, "<td><input name=\"autofw_port_out_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4704				 i, port);
4705		ret += websWrite(wp, "<td></td>");
4706
4707		/* Print related protocol */
4708		ret += websWrite(wp, "<td>");
4709		ret += websWrite(wp, "<select name=\"autofw_port_in_proto%d\">", i);
4710		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
4711				 valid && app.proto == IPPROTO_TCP ? "selected" : "");
4712		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
4713				 valid && app.proto == IPPROTO_UDP ? "selected" : "");
4714		ret += websWrite(wp, "</select>");
4715		ret += websWrite(wp, "</td>");
4716		ret += websWrite(wp, "<td></td>");
4717
4718		/* Print related destination port range */
4719		if (valid)
4720			snprintf(port, sizeof(port), "%d", ntohs(app.dport[0]));
4721		else
4722			*port = '\0';
4723		ret += websWrite(wp, "<td><input name=\"autofw_port_in_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4724				 i, port);
4725		ret += websWrite(wp, "<td>-</td>");
4726		if (valid)
4727			snprintf(port, sizeof(port), "%d", ntohs(app.dport[1]));
4728		else
4729			*port = '\0';
4730		ret += websWrite(wp, "<td><input name=\"autofw_port_in_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4731				 i, port);
4732		ret += websWrite(wp, "<td></td>");
4733
4734		/* Print mapped destination port range */
4735		if (valid)
4736			snprintf(port, sizeof(port), "%d", ntohs(app.to[0]));
4737		else
4738			*port = '\0';
4739		ret += websWrite(wp, "<td><input name=\"autofw_port_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4740				 i, port);
4741		ret += websWrite(wp, "<td>-</td>");
4742		if (valid)
4743			snprintf(port, sizeof(port), "%d", ntohs(app.to[1]));
4744		else
4745			*port = '\0';
4746		ret += websWrite(wp, "<td><input name=\"autofw_port_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
4747				 i, port);
4748		ret += websWrite(wp, "<td></td>");
4749
4750		/* Print enable */
4751		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"autofw_port_enable%d\" %s></td>",
4752				 i, valid && !(app.match.flags & NETCONF_DISABLED) ? "checked" : "");
4753
4754		ret += websWrite(wp, "</tr>");
4755	}
4756
4757	ret += websWrite(wp, "</table>\n");
4758
4759#endif /* !AUTOFW_PORT_DEPRECATE */
4760
4761	return ret;
4762}
4763#endif	/* __CONFIG_NAT__ */
4764
4765/*
4766 * Example:
4767 * lan_route=192.168.2.0:255.255.255.0:192.168.2.1:1
4768 * <% lan_route("ipaddr", 0); %> produces "192.168.2.0"
4769 */
4770static int
4771ej_lan_route(int eid, webs_t wp, int argc, char_t **argv)
4772{
4773	char *arg;
4774	int which;
4775	char word[256], *next;
4776	char *ipaddr, *netmask, *gateway, *metric;
4777
4778	if (ejArgs(argc, argv, "%s %d", &arg, &which) < 2) {
4779		websError(wp, 400, "Insufficient args\n");
4780		return -1;
4781	}
4782
4783	foreach(word, nvram_safe_get("lan_route"), next) {
4784		if (which-- == 0) {
4785			netmask = word;
4786			ipaddr = strsep(&netmask, ":");
4787			if (!ipaddr || !netmask)
4788				continue;
4789			gateway = netmask;
4790			netmask = strsep(&gateway, ":");
4791			if (!netmask || !gateway)
4792				continue;
4793			metric = gateway;
4794			gateway = strsep(&metric, ":");
4795			if (!gateway || !metric)
4796				continue;
4797			if (!strcmp(arg, "ipaddr"))
4798				return websWrite(wp, ipaddr);
4799			else if (!strcmp(arg, "netmask"))
4800				return websWrite(wp, netmask);
4801			else if (!strcmp(arg, "gateway"))
4802				return websWrite(wp, gateway);
4803			else if (!strcmp(arg, "metric"))
4804				return websWrite(wp, metric);
4805		}
4806	}
4807
4808	return 0;
4809}
4810
4811#ifdef __CONFIG_NAT__
4812/*
4813 * Example:
4814 * wan_route=192.168.10.0:255.255.255.0:192.168.10.1:1
4815 * <% wan_route("ipaddr", 0); %> produces "192.168.10.0"
4816 */
4817static int
4818ej_wan_route(int eid, webs_t wp, int argc, char_t **argv)
4819{
4820	char *arg;
4821	int which;
4822	char word[256], *next;
4823	char *ipaddr, *netmask, *gateway, *metric;
4824	int unit;
4825	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
4826
4827
4828	if (ejArgs(argc, argv, "%s %d", &arg, &which) < 2) {
4829		websError(wp, 400, "Insufficient args\n");
4830		return -1;
4831	}
4832
4833	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
4834		unit = 0;
4835	WAN_PREFIX(unit, prefix);
4836
4837	foreach(word, nvram_safe_get(strcat_r(prefix, "route", tmp)), next) {
4838		if (which-- == 0) {
4839			netmask = word;
4840			ipaddr = strsep(&netmask, ":");
4841			if (!ipaddr || !netmask)
4842				continue;
4843			gateway = netmask;
4844			netmask = strsep(&gateway, ":");
4845			if (!netmask || !gateway)
4846				continue;
4847			metric = gateway;
4848			gateway = strsep(&metric, ":");
4849			if (!gateway || !metric)
4850				continue;
4851			if (!strcmp(arg, "ipaddr"))
4852				return websWrite(wp, ipaddr);
4853			else if (!strcmp(arg, "netmask"))
4854				return websWrite(wp, netmask);
4855			else if (!strcmp(arg, "gateway"))
4856				return websWrite(wp, gateway);
4857			else if (!strcmp(arg, "metric"))
4858				return websWrite(wp, metric);
4859		}
4860	}
4861
4862	return 0;
4863}
4864#endif	/* __CONFIG_NAT__ */
4865
4866#ifdef PLC
4867static void cgi(webs_t wp, const char * const cmd)
4868{
4869  static char line[512];
4870  FILE *f;
4871
4872  snprintf(line, sizeof line,
4873      "/usr/sbin/gigle_util cgi %s", cmd);
4874
4875  system(line);
4876  f = fopen("/tmp/cgi.out", "rt");
4877  if (f)
4878  {
4879    while (fgets(line, sizeof line, f))
4880    {
4881      websWrite(wp, "%s", line);
4882    }
4883    fclose(f);
4884  }
4885  unlink("/tmp/cgi.out");
4886}
4887
4888static int
4889ej_ggl_plc_get_autoconf_root(int eid, webs_t wp, int argc, char_t **argv)
4890{
4891  cgi(wp, "get plc_cfg_root");
4892  return 0;
4893}
4894
4895static int
4896ej_ggl_plc_get_info(int eid, webs_t wp, int argc, char_t **argv)
4897{
4898  cgi(wp, "get info");
4899  return 0;
4900}
4901
4902static int
4903ej_ggl_plc_get_mac(int eid, webs_t wp, int argc, char_t **argv)
4904{
4905  cgi(wp, "get mac");
4906  return 0;
4907}
4908
4909static int
4910ej_ggl_plc_get_nets(int eid, webs_t wp, int argc, char_t **argv)
4911{
4912  cgi(wp, "get nw_info");
4913  return 0;
4914}
4915
4916static int
4917ej_ggl_plc_get_nick(int eid, webs_t wp, int argc, char_t **argv)
4918{
4919  cgi(wp, "get nick");
4920  return 0;
4921}
4922
4923static int
4924ej_ggl_plc_get_role(int eid, webs_t wp, int argc, char_t **argv)
4925{
4926  cgi(wp, "get role");
4927  return 0;
4928}
4929
4930static int
4931ej_ggl_plc_get_stas(int eid, webs_t wp, int argc, char_t **argv)
4932{
4933  cgi(wp, "get stas");
4934  return 0;
4935}
4936
4937static int
4938ej_ggl_plc_get_uptime(int eid, webs_t wp, int argc, char_t **argv)
4939{
4940  cgi(wp, "get uptime");
4941  return 0;
4942}
4943
4944static int
4945ej_ggl_cgi_version(int eid, webs_t wp, int argc, char_t **argv)
4946{
4947  cgi(wp, "get version");
4948  return 0;
4949}
4950
4951static int
4952ej_ggl_get_avln_list(int eid, webs_t wp, int argc, char_t **argv)
4953{
4954  int i;
4955  char mac[] = "00:1F:84:00:00:00";
4956  char nid[] = "00 11 22 33 44 55";
4957
4958  printf("ej_ggl_get_avln_list()\n");
4959
4960  // TODO: Query apcm_get_newsta
4961
4962  for (i = 0; i<4; i++) {
4963    websWrite(wp, "<tr align=\"center\">");
4964    websWrite(wp, "<td>%s</td>", mac);
4965    websWrite(wp, "<td>%s</td>", nid);
4966    websWrite(wp, "<td>%u</td>", 5);
4967    websWrite(wp, "</tr>");
4968  }
4969  return 0;
4970}
4971
4972/**************************************************
4973 * Function name : static void do_plc_cgi_restart(char *url, FILE *stream)
4974 * Created by    : Toni Homedes i Saun
4975 * Date created  : 06-10-2010
4976 * Notes         : Public function
4977 *                 Restrictions (pre-conditions)
4978 *                 Odd modes (post-conditions)
4979 **************************************************/
4980/** \brief Restarts the modem
4981 *
4982 *  \param[in] url      unused
4983 *  \param[in] stream   socket to write to
4984 *
4985 **************************************************/
4986static void do_plc_cgi_restart(char *url, FILE *stream)
4987{
4988  assert(url);
4989  assert(stream);
4990
4991  DictFree(BcmPostArgs);  /* Ignoring any argument */
4992
4993  websHeader(stream);
4994  websWrite(stream, (char_t *) apply_header);
4995
4996  cgi(stream, "restart");
4997
4998  websWrite(stream, (char_t *) apply_footer, "plc.asp");
4999  websFooter(stream);
5000  websDone(stream, 200);
5001}
5002
5003/**************************************************
5004 * Function name : static void do_plc_cgi(char *url, FILE *stream)
5005 * Created by    : Toni Homedes i Saun
5006 * Date created  : 06-10-2010
5007 * Notes         : Public function
5008 *                 Restrictions (pre-conditions)
5009 *                 Odd modes (post-conditions)
5010 **************************************************/
5011/** \brief Generates the plc.cgi page
5012 *
5013 *  \param[in] url      unused
5014 *  \param[in] stream   socket to write to
5015 *
5016 **************************************************/
5017static void do_plc_cgi(char *url, FILE *stream)
5018{
5019  dict_iterator_t iterator = DictIteratorNew(BcmPostArgs);
5020
5021  assert(url);
5022  assert(stream);
5023
5024  websHeader(stream);
5025  websWrite(stream, (char_t *) apply_header);
5026
5027  websWrite(stream, "\n<p>Processing the following values:</p>");
5028
5029  websWrite(stream, "<table border=\"1\" cellpadding=\"2\">\n");
5030  do
5031  {
5032    char command[512];
5033    const char *key = DictIteratorKey(iterator);
5034    if (key)
5035    {
5036      const char *value = DictGet(BcmPostArgs, key);
5037
5038      websWrite(stream, "  <tr><td>%s</td><td>%s</td><td>", key, value);
5039      sprintf(command, "set \"%s\" \"%s\"", key, value);
5040      cgi(stream, command);
5041      websWrite(stream, "</td></tr>\n");
5042    }
5043  }
5044  while (DictIteratorAdvance(iterator));
5045
5046  websWrite(stream, "</table>\n");
5047
5048  websWrite(stream, (char_t *) apply_footer, "plc.asp");
5049  websFooter(stream);
5050  websDone(stream, 200);
5051  DictIteratorFree(iterator);
5052  DictFree(BcmPostArgs);
5053
5054  sleep(1);
5055}
5056#endif
5057
5058/* Return a list of the currently present wireless interfaces */
5059static int
5060ej_wl_list(int eid, webs_t wp, int argc, char_t **argv)
5061{
5062	char name[IFNAMSIZ], *next=NULL;
5063	char wl_name[IFNAMSIZ],os_name[IFNAMSIZ];
5064	int unit=-1,subunit=-1, ret = 0;
5065	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5066	char unit_str[]="000000";
5067	char *hwaddr=NULL, *ssid=NULL, *virtual=NULL;
5068	char ifnames[256];
5069	char *str_to_compare=NULL;
5070	char *is_ssid_required=NULL;
5071
5072	if (ejArgs(argc, argv, "%s %s", &is_ssid_required, &virtual)  > 0) {
5073		if (strcmp(virtual,"INCLUDE_VIFS")){
5074			websError(wp, 400, "Unknown argument %s\n",virtual);
5075			return -1;
5076		}
5077	}
5078
5079
5080	snprintf(ifnames, sizeof(ifnames), "%s %s %s",
5081		nvram_safe_get("lan_ifnames"),
5082		nvram_safe_get("wan_ifnames"),
5083		nvram_safe_get("lan1_ifnames"));
5084
5085	if (!remove_dups(ifnames,sizeof(ifnames))){
5086		websError(wp, 400, "Unable to remove duplicate interfaces from ifname list<br>");
5087		return -1;
5088	}
5089
5090	foreach(name, ifnames, next) {
5091
5092		if ( nvifname_to_osifname( name, os_name, sizeof(os_name) ) < 0 )
5093			continue;
5094
5095		if (wl_probe(os_name) ||
5096		    wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
5097			continue;
5098
5099		/* Convert eth name to wl name */
5100
5101		if( osifname_to_nvifname( name, wl_name, sizeof(wl_name) ) != 0 )
5102		{
5103			websError(wp, 400, "wl name for interface:%s not found\n",name);
5104			return -1;
5105		}
5106
5107		/* Get configured ethernet MAC address */
5108		snprintf(prefix, sizeof(prefix), "wl%d_", unit);
5109
5110		/* Slave intefaces have a '.' in the name. assume the MAC address
5111		   is the same as the primary interface*/
5112		if (strchr(wl_name,'.')) {
5113			/* If Physical interfaces are specified do not
5114			   process the slave interfaces skip writing out the info
5115			  */
5116			if (virtual)
5117				snprintf(prefix, sizeof(prefix),"%s_",wl_name);
5118			else
5119				continue;
5120		}
5121
5122		if (get_ifname_unit(wl_name,&unit,&subunit) < 0) {
5123			websError(wp, 400, "Error extracting unit and subunit name from %s\n",wl_name);
5124			return -1;
5125		}
5126
5127		hwaddr = nvram_get(strcat_r(prefix, "hwaddr", tmp));
5128
5129		/* Should not need to test if pysical interfaces flag is set,
5130		   since that the code above will skip this portion. However
5131		   it guards against future problems if this gets reworked
5132		   in the future as the explicit checks here prevent any
5133		   ambiguity
5134		*/
5135
5136		if ((subunit > 0 ) && (virtual) )
5137			snprintf(unit_str,sizeof(unit_str),"%d.%d",unit,subunit);
5138		else
5139			snprintf(unit_str,sizeof(unit_str),"%d",unit);
5140
5141		ssid = nvram_get(strcat_r(prefix, "ssid", tmp));
5142
5143		if (!hwaddr || !*hwaddr || !ssid || !*ssid)
5144			continue;
5145
5146		/* The following code is for ssid.asp , used to highlight the physical interface */
5147		if (websGetVar(wp, "wl_bssid", NULL)) {
5148			str_to_compare  = websGetVar(wp, "wl_unit", NULL);
5149		}
5150		else {
5151			str_to_compare  =  nvram_safe_get("wl_unit");
5152		}
5153		if (is_ssid_required) {
5154			ret += websWrite(wp, "<option value=\"%s\" %s>%s(%s)</option>\n", unit_str,
5155				(!strncmp(unit_str,str_to_compare,sizeof(unit_str))) ? "selected" : "",
5156				 translate_ssid(ssid), hwaddr);
5157		}
5158		else {
5159			ret += websWrite(wp, "<option value=\"%s\" %s>(%s)</option>\n", unit_str,
5160				(!strncmp(unit_str,str_to_compare,sizeof(unit_str))) ? "selected" : "",
5161				  hwaddr);
5162		}
5163	}
5164
5165	if (!ret)
5166		ret += websWrite(wp, "<option value=\"-1\" selected>None</option>");
5167
5168	return ret;
5169}
5170
5171/* Return a list of the supported bands on the currently selected wireless interface */
5172static int
5173ej_wl_phytypes(int eid, webs_t wp, int argc, char_t **argv)
5174{
5175	int  ret = 0;
5176	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5177	char *phytype=NULL, *name;
5178	char *phylist=NULL;
5179	int i=0;
5180	int bandtype, error;
5181	int list[WLC_BAND_ALL];
5182
5183	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL))
5184		return websWrite(wp, "None");
5185
5186	/* Get configured phy type */
5187	phytype = nvram_safe_get("wl_phytype");
5188
5189	if (phytype[i] == 'n' || phytype[i] == 'l' || phytype[i] == 's' || phytype[i] == 'c' || phytype[i] == 'h' || phytype[i] == 'v') {
5190		bandtype = atoi(nvram_safe_get(strcat_r(prefix, "nband", tmp)));
5191
5192		name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5193
5194		/* Get band list. Assume both the bands in case of error */
5195		if ((error = wl_ioctl(name, WLC_GET_BANDLIST, list, sizeof(list))) < 0) {
5196			for (i = 1; i < 3; i++)
5197				ret += websWrite(wp, "<option value=\"%d\" %s> %s GHz</option>\n",
5198				                 i,
5199				                 (bandtype == i)? "selected": "",
5200				                 (i == WLC_BAND_5G)? "5":"2.4");
5201			return ret;
5202		}
5203		if (list[0] > 2)
5204			list[0] = 2;
5205
5206		for (i = 1; i <= list[0]; i++) {
5207			if ((phytype[0] == 'n') || (phytype[0] == 's')|| (phytype[0] == 'c') || (phytype[0] == 'h') || phytype[0] == 'v')
5208				ret += websWrite(wp, "<option value=\"%d\" %s> %s GHz</option>",
5209					list[i], (bandtype == list[i])? "selected": "",
5210		                 	(list[i] == WLC_BAND_5G)? "5":"2.4");
5211			else /* if lpphy */ {
5212			    	if (list[i] == WLC_BAND_5G)
5213					sprintf(tmp, "802.11%c (%s GHz)",'a',"5");
5214				else
5215					sprintf(tmp, "802.11%c (%s GHz)",'g',"2.4");
5216				ret += websWrite(wp, "<option value=\"%c\" %s>%s</option>",
5217		                 	((list[i] == WLC_BAND_5G)? 'a':'g'),
5218					bandtype == list[i] ? "selected" : "", tmp);
5219			}
5220		}
5221		return ret;
5222	}
5223	/* Get available phy types of the currently selected wireless interface */
5224	phylist = nvram_safe_get(strcat_r(prefix, "phytypes", tmp));
5225
5226	for (i = 0; i < strlen(phylist); i++) {
5227		sprintf(tmp, "802.11%c (%s GHz)", phylist[i],
5228		        phylist[i] == 'a' ? "5" : "2.4");
5229		ret += websWrite(wp, "<option value=\"%c\" %s>%s</option>",
5230		                 phylist[i], phylist[i] == *phytype ? "selected" : "", tmp);
5231	}
5232
5233	return ret;
5234}
5235
5236static int
5237ej_wl_nmode_enabled(int eid, webs_t wp, int argc, char_t **argv)
5238{
5239	char *temp;
5240	int unit = -1;
5241	int sub_unit = -1;
5242	char nv_param[NVRAM_MAX_PARAM_LEN];
5243
5244	temp = nvram_get("wl_unit");
5245	if (strlen(temp) == 0) {
5246 		websError(wp, 400, "Error getting wl_unit\n");
5247		return EINVAL;
5248	}
5249
5250	if (get_ifname_unit(temp, &unit, &sub_unit) != 0) {
5251 		websError(wp, 400, "Error getting unit/subunit\n");
5252		return EINVAL;
5253	}
5254
5255	sprintf(nv_param, "wl%d_nmode", unit);
5256	temp = nvram_safe_get(nv_param);
5257	if (strncmp(temp, "0", 1) == 0)
5258		websWrite(wp, "\"0\"");
5259	else
5260		websWrite(wp, "\"1\"");
5261
5262	return 0;
5263}
5264
5265/* Return a list of the supported bands on the currently selected wireless interface */
5266static int
5267ej_wl_nphyrates(int eid, webs_t wp, int argc, char_t **argv)
5268{
5269	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5270	int phytype;
5271	int ret = 0, i;
5272	/* -2 is for Legacy rate
5273	 * -1 is placeholder for 'Auto'
5274	 */
5275	int mcsidxs[]= { -1, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 32};
5276	int selected_idx, selected_bw, nbw, rate;
5277
5278	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
5279		websError(wp, 400, "unit number variable doesn't exist\n");
5280		return -1;
5281	}
5282
5283	/* Get configured phy type */
5284	if ((ret = wl_phytype_get(wp, &phytype)) != 0)
5285		return ret;
5286
5287	if ((phytype != WLC_PHY_TYPE_N) && (phytype != WLC_PHY_TYPE_SSN) &&
5288	    (phytype != WLC_PHY_TYPE_LCN) && (phytype != WLC_PHY_TYPE_HT) &&
5289	    (phytype != WLC_PHY_TYPE_AC))
5290		return ret;
5291
5292	if (ejArgs(argc, argv, "%d", &nbw) < 1) {
5293		websError(wp, 400, "BW does not exist \n");
5294		return -1;
5295	}
5296	/* nbw: 0 - Good Neighbor, 20 - 20MHz, 40 - 40MHz */
5297
5298	selected_idx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
5299	selected_bw = atoi(nvram_safe_get(strcat_r(prefix, "nbw", tmp)));
5300	rate = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp)));
5301
5302	/* Zero out the length of options */
5303	ret += websWrite(wp, "\t\tdocument.forms[0].wl_nmcsidx.length = 0; \n");
5304
5305	ret += websWrite(wp, "\t\tdocument.forms[0].wl_nmcsidx[0] = "
5306	                 "new Option(\"Auto\", \"-1\");\n");
5307
5308	if (selected_idx == -1 || rate == 0)
5309		ret += websWrite(wp, "\t\tdocument.forms[0].wl_nmcsidx.selectedIndex = 0;\n");
5310
5311	for (i = 1; i < ARRAYSIZE(mcsidxs); i++) {
5312		/* Limit MCS rates based on number of user selected TxChains
5313		 * This block of code adds an "if" statement into the NPHY Rates List
5314		 * which surrounds the MCS indexes greater than 7
5315		 */
5316		if (mcsidxs[i] == 8) {
5317			ret += websWrite(wp, "\t\tif(document.forms[0].wl_txchain.selectedIndex > 0) {\n");
5318		}
5319
5320		/* MCS IDX 32 is valid only for 40 Mhz */
5321		if (mcsidxs[i] == 32 && (nbw == 20 || nbw == 0))
5322			continue;
5323		ret += websWrite(wp, "\t\tdocument.forms[0].wl_nmcsidx[%d] = new Option(\"", i);
5324		if (mcsidxs[i] == -2) {
5325			ret += websWrite(wp, "Use Legacy Rate\", \"-2\");\n");
5326			if (selected_idx == -2 && nbw == selected_bw)
5327				ret += websWrite(wp,
5328				                 "\t\tdocument.forms[0].wl_nmcsidx.selectedIndex ="
5329				                 "%d;\n", i);
5330		} else {
5331			uint mcs_rate = MCS_TABLE_RATE(mcsidxs[i], (nbw == 40));
5332			ret += websWrite(wp, "%2d: %d", mcsidxs[i], mcs_rate/1000);
5333			/* Handle floating point generation */
5334			if (mcs_rate % 1000)
5335				ret += websWrite(wp, ".%d", (mcs_rate % 1000)/100);
5336			ret += websWrite(wp, " Mbps");
5337			if (nbw == 0) {
5338				mcs_rate = MCS_TABLE_RATE(mcsidxs[i], TRUE);
5339				ret += websWrite(wp, " or %d", mcs_rate/1000);
5340				/* Handle floating point generation */
5341				if (mcs_rate % 1000)
5342					ret += websWrite(wp, ".%d", (mcs_rate % 1000)/100);
5343				ret += websWrite(wp, " Mbps");
5344			}
5345			ret += websWrite(wp, "\", \"%d\");\n", mcsidxs[i]);
5346
5347			if (selected_idx == mcsidxs[i] && selected_bw == nbw)
5348				ret += websWrite(wp,
5349				                 "\t\tdocument.forms[0].wl_nmcsidx.selectedIndex ="
5350				                 "%d;\n", i);
5351		}
5352	}
5353
5354	/* terminate the "if" condition for txchains */
5355	ret += websWrite(wp, "\t\t}\n");
5356
5357	return ret;
5358}
5359
5360/* Return a list of the available number of txchains */
5361static int
5362ej_wl_txchains_list(int eid, webs_t wp, int argc, char_t **argv)
5363{
5364	int ret = 0;
5365	int count;
5366	int txchain_cnt = 0; /* Default */
5367	int txchains = txchain_cnt;
5368	char *str;
5369	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5370
5371	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
5372		websError(wp, 400, "unit number variable doesn't exist\n");
5373		return -1;
5374	}
5375
5376	/* # of TX chains supported by device */
5377	str = nvram_get(strcat_r(prefix, "hw_txchain", tmp));
5378	if (str) {
5379		txchain_cnt = atoi(str);
5380		if (txchain_cnt == 2)
5381		  txchain_cnt = 1;
5382		else if (txchain_cnt == 3)
5383		  txchain_cnt = 2;
5384		else if (txchain_cnt == 7)
5385		  txchain_cnt = 3;
5386	}
5387
5388	/* User configured # of TX streams */
5389	str = nvram_get("wl_txchain");
5390	if (str) {
5391		txchains = atoi(str);
5392		if (txchains == 2)
5393		  txchains = 1;
5394		else if (txchains == 3)
5395		  txchains = 2;
5396		else if (txchains == 7)
5397		  txchains = 3;
5398	}
5399	for (count=1; count <= txchain_cnt; count++) {
5400		ret += websWrite(wp, "\t<option value=%d %s>%d</option>\n",
5401			(count == 1) ? 1 : (count == 2) ? 3 : 7,
5402			(count == txchains) ? "selected" : "", count);
5403	}
5404
5405	return ret;
5406}
5407
5408/* Return a list of the available number of rxchains */
5409static int
5410ej_wl_rxchains_list(int eid, webs_t wp, int argc, char_t **argv)
5411{
5412	int ret = 0;
5413	int count;
5414	int rxchain_cnt = 0; /* Default */
5415	int rxchains = rxchain_cnt;
5416	char *str;
5417	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5418
5419	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
5420		websError(wp, 400, "unit number variable doesn't exist\n");
5421		return -1;
5422	}
5423
5424	/* # of RX chains supported by device */
5425	str = nvram_get(strcat_r(prefix, "hw_rxchain", tmp));
5426	if (str) {
5427		rxchain_cnt = atoi(str);
5428		if (rxchain_cnt == 2)
5429		  rxchain_cnt = 1;
5430		else if (rxchain_cnt == 3)
5431		  rxchain_cnt = 2;
5432		else if (rxchain_cnt == 7)
5433		  rxchain_cnt = 3;
5434	}
5435
5436	/* User configured # of RX streams */
5437	str = nvram_get("wl_rxchain");
5438	if (str) {
5439		rxchains = atoi(str);
5440		if (rxchains == 2)
5441		  rxchains = 1;
5442		else if (rxchains == 3)
5443		  rxchains = 2;
5444		else if (rxchains == 7)
5445		  rxchains = 3;
5446	}
5447	for (count=1; count <= rxchain_cnt; count++) {
5448		ret += websWrite(wp, "\t<option value=%d %s>%d</option>\n",
5449			(count == 1) ? 1 : (count == 2) ? 3 : 7,
5450			(count == rxchains) ? "selected" : "", count);
5451	}
5452	return ret;
5453}
5454
5455/* Return a radio ID given a phy type */
5456static int
5457ej_wl_radioid(int eid, webs_t wp, int argc, char_t **argv)
5458{
5459	char *phytype=NULL, var[NVRAM_BUFSIZE], *next;
5460	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5461	int which;
5462
5463	if (ejArgs(argc, argv, "%s", &phytype) < 1) {
5464		websError(wp, 400, "Insufficient args\n");
5465		return -1;
5466	}
5467
5468	assert(phytype);
5469
5470	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL))
5471		return websWrite(wp, "None");
5472
5473	which = strcspn(nvram_safe_get(strcat_r(prefix, "phytypes", tmp)), phytype);
5474	foreach(var, nvram_safe_get(strcat_r(prefix, "radioids", tmp)), next) {
5475		if (which == 0)
5476			return websWrite(wp, var);
5477		which--;
5478	}
5479
5480	return websWrite(wp, "None");
5481}
5482
5483/* Return current core revision */
5484static int
5485ej_wl_corerev(int eid, webs_t wp, int argc, char_t **argv)
5486{
5487	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5488
5489	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL))
5490		return websWrite(wp, "None");
5491
5492	return websWrite(wp, nvram_safe_get(strcat_r(prefix, "corerev", tmp)));
5493}
5494
5495/* Return current wireless channel specification */
5496static int
5497ej_wl_cur_chanspec(int eid, webs_t wp, int argc, char_t **argv)
5498{
5499	char *name=NULL;
5500	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5501	channel_info_t ci;
5502	int phytype;
5503	uint32 chanspec;
5504	int channel;
5505	int chan_adj = 0;
5506	int status;
5507	uint32 chanim_enab = 0;
5508	uint32 interference = 0;
5509	const char CHANIM_S[] =  "***Interference Level: Severe";
5510	const char CHANIM_A[] =  "***Interference Level: Acceptable";
5511	static union {
5512		char bufdata[WLC_IOCTL_SMLEN];
5513		uint32 alignme;
5514	} bufstruct;
5515	char *retbuf = (char*) &bufstruct.bufdata;
5516	char chanbuf[CHANSPEC_STR_LEN];
5517#define CHANIMSTR(a, b, c, d) ((a) ? ((b) ? c : d) : "")
5518
5519	(void) chan_adj;
5520	(void) channel;
5521	(void) ci;
5522
5523	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5524		websError(wp, 400, "unit number variable doesn't exist\n");
5525		return -1;
5526	}
5527
5528	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5529
5530	/* Get configured phy type */
5531	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5532		return status;
5533
5534	if (wl_iovar_getint(name, "chanim_enab", (int*)(void*)&chanim_enab))
5535		chanim_enab = 0;
5536
5537	if (wl_iovar_getint(name, "chanspec", (int*)(void *)&chanspec))
5538		return -1;
5539
5540	if (chanim_enab) {
5541		if (wl_iovar_getbuf(name, "chanim_state", &chanspec, sizeof(chanspec),
5542			  retbuf, WLC_IOCTL_SMLEN))
5543			return -1;
5544
5545		interference = *(int*)retbuf;
5546	}
5547
5548	return websWrite(wp, "Current: %s %s",
5549	                 wf_chspec_ntoa(chanspec, chanbuf),
5550			 CHANIMSTR(chanim_enab, interference, CHANIM_S, CHANIM_A));
5551
5552#undef CHANIMSTR
5553}
5554
5555/* Return current wireless channel */
5556static int
5557ej_wl_cur_channel(int eid, webs_t wp, int argc, char_t **argv)
5558{
5559	char *name=NULL;
5560	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5561	channel_info_t ci;
5562	int phytype;
5563	uint32 chanspec;
5564	int channel;
5565	int chan_adj = 0;
5566	int status;
5567	uint32 chanim_enab = 0;
5568	uint32 interference = 0;
5569	const char CHANIM_S[] =  "***Interference Level: Severe";
5570	const char CHANIM_A[] =  "***Interference Level: Acceptable";
5571	char retbuf[WLC_IOCTL_SMLEN];
5572#define CHANIMSTR(a, b, c, d) ((a) ? ((b) ? c : d) : "")
5573
5574	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5575		websError(wp, 400, "unit number variable doesn't exist\n");
5576		return -1;
5577	}
5578
5579	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5580
5581	/* Get configured phy type */
5582	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5583		return status;
5584
5585	if (wl_iovar_getint(name, "chanim_enab", (int*)(void*)&chanim_enab))
5586		chanim_enab = 0;
5587
5588	if ((phytype != WLC_PHY_TYPE_N) && (phytype != WLC_PHY_TYPE_SSN) &&
5589		(phytype != WLC_PHY_TYPE_LCN) && (phytype != WLC_PHY_TYPE_HT)) {
5590		wl_ioctl(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
5591		channel = ci.target_channel;
5592		chanspec = CH20MHZ_CHSPEC(channel);
5593	} else {
5594		if (wl_iovar_getint(name, "chanspec", (int*)(void *)&chanspec))
5595			return -1;
5596		if ((chanspec & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) {
5597			int sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
5598			if (sb == WL_CHANSPEC_CTL_SB_LOWER)
5599				chan_adj = -2;
5600			else
5601				chan_adj = 2;
5602		}
5603
5604		channel = CHSPEC_CHANNEL(chanspec);
5605	}
5606
5607	if (chanim_enab) {
5608		if (wl_iovar_getbuf(name, "chanim_state", &chanspec, sizeof(chanspec),
5609			  retbuf, WLC_IOCTL_SMLEN))
5610			return -1;
5611
5612		interference = *(int*)retbuf;
5613	}
5614
5615	return websWrite(wp, "Current: %d %s",
5616			 (channel + chan_adj),
5617			 CHANIMSTR(chanim_enab, interference, CHANIM_S, CHANIM_A));
5618
5619#undef CHANIMSTR
5620}
5621
5622/* Return current 802.11n channel bandwidth */
5623static int
5624ej_wl_cur_bw(int eid, webs_t wp, int argc, char_t **argv)
5625{
5626	char *name=NULL;
5627	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5628	chanspec_t chanspec;
5629
5630	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5631		websError(wp, 400, "unit number variable doesn't exist\n");
5632		return -1;
5633	}
5634
5635	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5636
5637	if (wl_iovar_getint(name, "chanspec", (int*)(void *)&chanspec))
5638		return -1;
5639
5640	return websWrite(wp, "Current: %s",
5641	                 (CHSPEC_BW(chanspec) == WL_CHANSPEC_BW_80) ? "80MHz" :
5642	                 (CHSPEC_BW(chanspec) == WL_CHANSPEC_BW_40) ? "40MHz" : "20MHz");
5643}
5644
5645/* Return current 802.11n control sideband */
5646static int
5647ej_wl_cur_nctrlsb(int eid, webs_t wp, int argc, char_t **argv)
5648{
5649	char *name=NULL;
5650	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5651	chanspec_t chanspec;
5652
5653	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5654		websError(wp, 400, "unit number variable doesn't exist\n");
5655		return -1;
5656	}
5657
5658	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5659
5660	if (wl_iovar_getint(name, "chanspec", (int*)(void *)&chanspec))
5661		return -1;
5662
5663	return websWrite(wp, "Current: %s", (chanspec & WL_CHANSPEC_CTL_SB_MASK) ==
5664	                 WL_CHANSPEC_CTL_SB_LOWER ? "lower" :
5665	                 WL_CHANSPEC_CTL_SB_UPPER ? "upper" : "none");
5666}
5667
5668/* Return current country */
5669static int
5670ej_wl_cur_country(int eid, webs_t wp, int argc, char_t **argv)
5671{
5672	char *name=NULL;
5673	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5674	wl_country_t cspec = {{0}, 0, {0}};
5675
5676	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5677		websError(wp, 400, "unit number variable doesn't exist\n");
5678		return -1;
5679	}
5680
5681	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5682
5683	if (wl_iovar_get(name, "country", &cspec, sizeof(cspec)))
5684		return -1;
5685	return websWrite(wp, "%s", cspec.ccode);
5686}
5687
5688static int
5689ej_wl_cur_regrev(int eid, webs_t wp, int argc, char_t **argv)
5690{
5691	char *name=NULL;
5692	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5693	wl_country_t cspec = {{0}, 0, {0}};
5694
5695	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5696		websError(wp, 400, "unit number variable doesn't exist\n");
5697		return -1;
5698	}
5699
5700	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5701
5702	/* country_rev is not in the nvram get it from the driver */
5703	if (wl_iovar_get(name, "country", &cspec, sizeof(cspec)))
5704		return -1;
5705	return websWrite(wp, "%d", cspec.rev);
5706}
5707
5708/* Return current phytype */
5709static int
5710ej_wl_cur_phytype(int eid, webs_t wp, int argc, char_t **argv)
5711{
5712	char *name;
5713	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5714	int phytype;
5715
5716	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5717		websError(wp, 400, "unit number variable doesn't exist\n");
5718		return -1;
5719	}
5720
5721	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5722
5723	/* Get configured phy type */
5724	wl_ioctl(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
5725
5726	if ((phytype != WLC_PHY_TYPE_N) && (phytype != WLC_PHY_TYPE_SSN) &&
5727	    (phytype != WLC_PHY_TYPE_LCN) && (phytype != WLC_PHY_TYPE_HT) &&
5728	    (phytype != WLC_PHY_TYPE_AC))
5729		if (phytype == WLC_PHY_TYPE_LP) {
5730			wl_ioctl(name, WLC_GET_BAND, &phytype, sizeof(phytype));
5731			return websWrite(wp, "Current: %s", phytype == WLC_BAND_5G ? "5 GHz" :
5732		                 phytype == WLC_BAND_2G ? "2.4 GHz" : "Auto");
5733		} else
5734			return websWrite(wp, "Current: 802.11%s", phytype == WLC_PHY_TYPE_A ? "a" :
5735		                 phytype == WLC_PHY_TYPE_B ? "b" : "g");
5736	else {
5737		wl_ioctl(name, WLC_GET_BAND, &phytype, sizeof(phytype));
5738		return websWrite(wp, "Current: %s", phytype == WLC_BAND_5G ? "5 GHz" :
5739		                 phytype == WLC_BAND_2G ? "2.4 GHz" : "Auto");
5740	}
5741	return 0;
5742}
5743
5744/* Return whether the current phytype is NPHY */
5745static int
5746ej_wl_nphy_set(int eid, webs_t wp, int argc, char_t **argv)
5747{
5748	int phytype, status;
5749
5750	/* Get configured phy type */
5751	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5752		return status;
5753
5754	return websWrite(wp, "%d", ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5755	                            (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5756	                            (phytype == WLC_PHY_TYPE_AC)));
5757}
5758
5759/* Generate the whole protection rows */
5760static int
5761ej_wl_protection(int eid, webs_t wp, int argc, char_t **argv)
5762{
5763	int phytype, status;
5764	int ret =0;
5765	char *prot_str;
5766
5767	/* Get configured phy type */
5768	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5769		return status;
5770
5771	prot_str = ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5772			(phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5773			(phytype == WLC_PHY_TYPE_AC))?
5774		"wl_nmode_protection":"wl_gmode_protection";
5775
5776	ret += websWrite(wp, "<th width=\"310\"\n\tonMouseOver=\"return overlib('In <b>Auto</b>"
5777	                 "mode the AP will use RTS/CTS to improve");
5778	ret += websWrite(wp, " %s performance in mixed %s networks. Turn protection <b>Off</b> to "
5779	                 "maximize %s througput under most conditions.', LEFT);\"\n",
5780	                 ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5781			  (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5782			  (phytype == WLC_PHY_TYPE_AC))?
5783				"802.11n":"802.11g",
5784	                 ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5785			  (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5786			  (phytype == WLC_PHY_TYPE_AC))?
5787				"802.11n/a/b/g":"802.11g/b",
5788	                 ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5789			  (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5790			  (phytype == WLC_PHY_TYPE_AC))?
5791				"802.11n":"802.11g");
5792	ret += websWrite(wp, "\tonMouseOut=\"return nd();\">\n\t%s Protection:&nbsp;&nbsp;"
5793	                 "\n\t</th>\n\t<td>&nbsp;&nbsp;</td>\n\t<td>\n",
5794	                 ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5795			  (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5796			  (phytype == WLC_PHY_TYPE_AC))?
5797				"802.11n":"54g");
5798	ret += websWrite(wp, "\t\t<select name=\"%s\">\n",
5799	                 prot_str);
5800	ret += websWrite(wp, "\t\t\t<option value=\"auto\" %s>Auto</option>\n",
5801	                 nvram_match(prot_str, "auto")?"selected":"");
5802	ret += websWrite(wp, "\t\t\t<option value=\"off\" %s>Off</option>\n",
5803	                 nvram_match(prot_str, "off")?"selected":"");
5804	ret += websWrite(wp, "\t\t</select>\n\t</td>");
5805
5806	return ret;
5807}
5808
5809/* Generate the whole mimo preamble rows */
5810static int
5811ej_wl_mimo_preamble(int eid, webs_t wp, int argc, char_t **argv)
5812{
5813	int ret =0, mode = 0;
5814	char *prot_str;
5815	char prefix[] = "wlXXXXXXXXXX_";
5816	char *name = NULL;
5817	char wlif[64];
5818	wlc_rev_info_t rev;
5819
5820	if (!make_wl_prefix(prefix, sizeof(prefix), mode, NULL)) {
5821		websError(wp, 400, "unit number variable doesn't exist\n");
5822		return -1;
5823	}
5824
5825	name = nvram_safe_get(strcat_r(prefix, "ifname",wlif));
5826
5827	wl_ioctl(name, WLC_GET_REVINFO, &rev, sizeof(rev));
5828
5829	if (!((rev.chipnum == BCM4716_CHIP_ID) ||
5830		(rev.chipnum == BCM47162_CHIP_ID) ||
5831		(rev.chipnum == BCM4748_CHIP_ID) ||
5832		(rev.chipnum == BCM4331_CHIP_ID) ||
5833		(rev.chipnum == BCM43431_CHIP_ID)))
5834		return -1;
5835
5836
5837	prot_str =  "wl_mimo_preamble";
5838
5839	ret += websWrite(wp, "<th width=\"310\"\n\tonMouseOver=\"return overlib('Force to use Green-Field or Mixed-Mode preamble. in<b>Auto</b>"
5840				"mode the AP will use GF or MM based on required protection ', LEFT);\"\n");
5841	ret += websWrite(wp, "\tonMouseOut=\"return nd();\">\n\t%s Mimo PrEamble:&nbsp;&nbsp;"
5842				"\n\t</th>\n\t<td>&nbsp;&nbsp;</td>\n\t<td>\n","802.11n");
5843	ret += websWrite(wp, "\t\t<select name=\"%s\">\n", prot_str);
5844	ret += websWrite(wp, "\t\t\t<option value=\"gfbcm\" %s>GF-BRCM</option>\n",
5845				nvram_match(prot_str, "gfbcm")?"selected":"");
5846	ret += websWrite(wp, "\t\t\t<option value=\"auto\" %s>Auto</option>\n",
5847				nvram_match(prot_str, "auto")?"selected":"");
5848	ret += websWrite(wp, "\t\t\t<option value=\"gf\" %s>Green Field</option>\n",
5849				nvram_match(prot_str, "gf")?"selected":"");
5850	ret += websWrite(wp, "\t\t\t<option value=\"mm\" %s>Mixed Mode</option>\n",
5851				nvram_match(prot_str, "mm")?"selected":"");
5852	ret += websWrite(wp, "\t\t</select>\n\t</td>");
5853
5854	return ret;
5855}
5856
5857/* If current phytype is nphy, the print string 'legacy' for Rate drop down */
5858static int
5859ej_wl_legacy_string(int eid, webs_t wp, int argc, char_t **argv)
5860{
5861	int phytype, status;
5862
5863	/* Get configured phy type */
5864	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5865		return status;
5866
5867	return websWrite(wp, "%s", ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5868			(phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT))? "Legacy":"");
5869}
5870
5871/* If current phytype is NOT nphy, the print start of comment <!--
5872 * in the HTML for the concerned fields to prevent them from appearing on the page
5873 */
5874static int
5875ej_wl_nphy_comment_beg(int eid, webs_t wp, int argc, char_t **argv)
5876{
5877	int phytype, status;
5878
5879	/* Get configured phy type */
5880	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5881		return status;
5882	return websWrite(wp, "%s", ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5883	                            (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5884	                            (phytype == WLC_PHY_TYPE_AC))? "":"<!--");
5885}
5886
5887static int
5888ej_wl_nphy_comment_end(int eid, webs_t wp, int argc, char_t **argv)
5889{
5890	int phytype, status;
5891
5892	/* Get configured phy type */
5893	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5894		return status;
5895	return websWrite(wp, "%s", ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5896	                            (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5897	                            (phytype == WLC_PHY_TYPE_AC))? "":"-->");
5898}
5899
5900/* Return the variable for the Band field.
5901 * For 11n, its wl_nband, while for a/b/g, it's wl_phytype
5902 */
5903static int
5904ej_wl_phytype_name(int eid, webs_t wp, int argc, char_t **argv)
5905{
5906	int phytype, status;
5907
5908	/* Get configured phy type */
5909	if ((status = wl_phytype_get(wp, &phytype)) != 0)
5910		return status;
5911
5912	return websWrite(wp, "%s", ((phytype == WLC_PHY_TYPE_N) || (phytype == WLC_PHY_TYPE_SSN) ||
5913	                            (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_HT) ||
5914	                            (phytype == WLC_PHY_TYPE_AC))? "\"wl_nband\"":"\"wl_phytype\"");
5915}
5916
5917/* Return current band */
5918static int
5919ej_wl_cur_band(int eid, webs_t wp, int argc, char_t **argv)
5920{
5921	char *name;
5922	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
5923	int bandtype;
5924
5925	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
5926		websError(wp, 400, "unit number variable doesn't exist\n");
5927		return -1;
5928	}
5929
5930	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
5931
5932	/* Get configured phy type */
5933	wl_ioctl(name, WLC_GET_BAND, &bandtype, sizeof(bandtype));
5934
5935	return websWrite(wp, "Current: %s ", bandtype == WLC_BAND_5G ? "5 GHz" :
5936	                 bandtype == WLC_BAND_2G? "2.4 GHz" : "Auto");
5937}
5938
5939static int
5940ej_wl_crypto(int eid, webs_t wp, int argc, char_t **argv)
5941{
5942	char *temp;
5943	int unit = -1;
5944	int sub_unit = -1;
5945	char nv_param[NVRAM_MAX_PARAM_LEN];
5946
5947	temp = nvram_get("wl_unit");
5948	if (strlen(temp) == 0) {
5949 		websError(wp, 400, "Error getting wl_unit\n");
5950		return EINVAL;
5951	}
5952
5953	if (get_ifname_unit(temp, &unit, &sub_unit) != 0) {
5954 		websError(wp, 400, "Error getting unit/subunit\n");
5955		return EINVAL;
5956	}
5957
5958	sprintf(nv_param, "wl%d_crypto", unit);
5959
5960	websWrite(wp, nvram_safe_get(nv_param));
5961
5962	return 0;
5963}
5964
5965static int
5966ej_wl_wep(int eid, webs_t wp, int argc, char_t **argv)
5967{
5968	char *temp;
5969	int unit = -1;
5970	int sub_unit = -1;
5971	char nv_param[NVRAM_MAX_PARAM_LEN];
5972
5973	temp = nvram_get("wl_unit");
5974	if (strlen(temp) == 0) {
5975 		websError(wp, 400, "Error getting wl_unit\n");
5976		return EINVAL;
5977	}
5978
5979	if (get_ifname_unit(temp, &unit, &sub_unit) != 0) {
5980 		websError(wp, 400, "Error getting unit/subunit\n");
5981		return EINVAL;
5982	}
5983
5984	sprintf(nv_param, "wl%d_wep", unit);
5985
5986	websWrite(wp, nvram_safe_get(nv_param));
5987
5988	return 0;
5989}
5990
5991static unsigned int bits_count(unsigned int n)
5992{
5993	unsigned int count = 0;
5994
5995	while (n > 0) {
5996		if (n & 1)
5997			count++;
5998		n >>= 1;
5999	}
6000
6001	return count;
6002}
6003
6004/* Writes "1" if Tx beamforming is supported. Otherwise, "0" */
6005static int
6006ej_wl_txbf_capable(int eid, webs_t wp, int argc, char_t **argv)
6007{
6008	char *name = NULL;
6009	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
6010	int txbf_capable = 0;
6011	wlc_rev_info_t revinfo;
6012
6013	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)) {
6014		websError(wp, 400, "unit number variable doesn't exist\n");
6015		return -1;
6016	}
6017
6018	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
6019
6020	/* Get revision info */
6021	wl_ioctl(name, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
6022
6023	/*
6024	 * Beamforming is available on core revs >= 40. Currently, 1-2
6025	 * streams have beamforming.
6026	 */
6027	if (revinfo.corerev >= 40) {
6028		int txchain;
6029
6030		if (wl_iovar_getint(name, "txchain", &txchain))
6031			return -1;
6032
6033		if (bits_count((unsigned int)txchain) > 1) {
6034			txbf_capable = 1;
6035		}
6036	}
6037
6038	return websWrite(wp, "%d", txbf_capable);
6039}
6040
6041/*
6042*/
6043#ifdef __CONFIG_WFI__
6044#define WPSM_WFI_CMD_NVNAME			"wfi_cmd"
6045
6046/* Return WFI enabled STA list */
6047static int
6048ej_wl_invite_list(int eid, webs_t wp, int argc, char_t **argv)
6049{
6050	int i;
6051	char *sta_list, *wl_unit, *tmp1= NULL;
6052	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
6053	char *dest_ptr, *dest, *src_ptr;
6054	int count = 0, len = 0;
6055
6056	if(!nvram_match("wl_wfi_enable", "1" ))
6057		return 0;
6058
6059	nvram_set(WPSM_WFI_CMD_NVNAME, "list 0 1");
6060	for (i = 0; i < 3; i++) {
6061		SLEEP(1);
6062		if (nvram_match(WPSM_WFI_CMD_NVNAME , ""))
6063			break;
6064	}
6065
6066	wl_unit = nvram_safe_get("wl_unit");
6067	tmp1 = strchr(wl_unit, '.');
6068	if (tmp1) {
6069		strncpy( tmp, wl_unit, (strlen(wl_unit) - strlen(tmp1)) );
6070		tmp[strlen(wl_unit) - strlen(tmp1)]='\0';
6071		sprintf(prefix,"wl%s_", tmp);
6072	}
6073	else
6074		sprintf(prefix,"wl%s_", wl_unit);
6075
6076	strcat_r(prefix, "wfi_list", tmp);
6077	sta_list = nvram_safe_get(tmp);
6078
6079	/* change '"' to '\''"' */
6080	while(sta_list[len])
6081		if (sta_list[len++] == '"') ++count;
6082	src_ptr = sta_list;
6083	dest = (char *) malloc(sizeof(char) * (count + len + 1));
6084	if (dest == NULL) /* malloc failed */
6085		return 0;
6086	dest_ptr = dest;
6087
6088	while(tmp1 = strchr(src_ptr, '"')) {
6089		int chunk_len = tmp1 - src_ptr; /* length of current chunk without " in it */
6090		memcpy(dest_ptr, src_ptr, chunk_len);
6091		dest_ptr[chunk_len++] = '\\';
6092		dest_ptr[chunk_len++] = '"';
6093		dest_ptr += chunk_len;
6094		src_ptr = tmp1 +1; /* skip " too */
6095	}
6096	strcpy(dest_ptr,src_ptr); /* yes, strcpy, copy rest of the string there is no " in it */
6097
6098	len =  websWrite(wp, dest);
6099	free(dest);
6100	return len;
6101
6102}
6103
6104static int
6105ej_wl_wfi_mode(int eid, webs_t wp, int argc, char_t **argv)
6106{
6107	char tmp[32], *wl_unit, *wfi_mode;
6108
6109	wl_unit = nvram_safe_get("wl_unit");
6110	sprintf(tmp, "wl%s_wps_mode", wl_unit);
6111	wfi_mode = nvram_safe_get(tmp);
6112	if(nvram_match("wl_wfi_enable", "1" )){
6113		if (!strcmp("enabled", wfi_mode))
6114			return websWrite(wp, "WPS mode is enabled on this BSS.");
6115		else
6116			return websWrite(wp, "WPS mode is not enabled on this BSS.");
6117	}
6118	return 0;
6119}
6120#endif /* __CONFIG_WFI__ */
6121/*
6122*/
6123
6124#ifdef __CONFIG_NAT__
6125static char *
6126wan_name(int unit, char *prefix, char *name, int len)
6127{
6128	char tmp[NVRAM_BUFSIZE], *desc;
6129	desc = nvram_safe_get(strcat_r(prefix, "desc", tmp));
6130	snprintf(tmp, sizeof(tmp), "Connection %d", unit + 1);
6131	snprintf(name, len, "%s", !strcmp(desc, "") ? tmp : desc);
6132	return name;
6133}
6134
6135/* Return a list of wan connections (Connection <N>/<Connection Name>) */
6136static int
6137ej_wan_list(int eid, webs_t wp, int argc, char_t **argv)
6138{
6139	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
6140	int unit, ret = 0;
6141
6142	/* build wan connection name list */
6143	for (unit = 0; unit < MAX_NVPARSE; unit ++) {
6144		WAN_PREFIX(unit, prefix);
6145		if (!nvram_get(strcat_r(prefix, "unit", tmp)))
6146			continue;
6147		ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", unit,
6148				unit == atoi(nvram_safe_get("wan_unit")) ? "selected" : "",
6149				wan_name(unit, prefix, tmp, sizeof(tmp)));
6150	}
6151
6152	return ret;
6153}
6154#endif	/* __CONFIG_NAT__ */
6155
6156#ifdef __CONFIG_WPS__
6157static int
6158ej_wps_current_mode(int eid, webs_t wp, int argc, char_t **argv, int wps_sta)
6159{
6160	if (nvram_match( "wl_wps_mode", "enabled" ))
6161	{
6162		if (wps_sta)
6163			websWrite(wp, "Station");
6164		else if (wps_is_oob() && !nvram_match("wps_oob_configured", "1"))
6165			websWrite(wp, "Unconfiged AP");
6166		else if (wps_is_reg())
6167			websWrite(wp, "AP with Built-in Registrar");
6168		else
6169			websWrite(wp, "Proxing");
6170	}
6171	else {
6172		if (wps_sta)
6173		{
6174			websWrite(wp, "Station Disabled");
6175			return 0;
6176		}
6177		else {
6178			websWrite(wp, "AP Disabled");
6179			return 0;
6180		}
6181	}
6182
6183	return 0;
6184}
6185
6186static int
6187ej_wps_process(int eid, webs_t wp, int argc, char_t **argv)
6188{
6189
6190	char *status;
6191
6192	if (!nvram_match( "wl_wps_mode", "enabled" ))
6193		return 0;
6194
6195	status = nvram_safe_get("wps_proc_status");
6196
6197	switch (atoi(status)) {
6198	case WPS_UI_ASSOCIATED:
6199		websWrite(wp, "Processing WPS start...");
6200		break;
6201	case WPS_UI_OK:
6202	case WPS_UI_MSGDONE:
6203		websWrite(wp, "Success");
6204		break;
6205	case WPS_UI_MSG_ERR:
6206		websWrite(wp, "Fail due to WPS message exchange error!");
6207		break;
6208	case WPS_UI_TIMEOUT:
6209		websWrite(wp, "Fail due to WPS time out!");
6210		break;
6211	case WPS_UI_PBCOVERLAP:
6212		websWrite(wp, "Fail due to WPS session overlap!");
6213		break;
6214#ifdef __CONFIG_NFC__
6215	case WPS_UI_NFC_WR_CFG:
6216	case WPS_UI_NFC_WR_PW:
6217	case WPS_UI_NFC_RD_CFG:
6218	case WPS_UI_NFC_RD_PW:
6219		websWrite(wp, "Please place your NFC token now.");
6220		break;
6221	case WPS_UI_NFC_WR_CPLT:
6222		websWrite(wp, "NFC write token successful, please remove the tag.");
6223		break;
6224	case WPS_UI_NFC_RD_CPLT:
6225		websWrite(wp, "NFC read token successful, please remove the tag.");
6226		break;
6227	case WPS_UI_NFC_HO_S:
6228		websWrite(wp, "Handover as selector.");
6229		break;
6230	case WPS_UI_NFC_HO_R:
6231		websWrite(wp, "Handover as requester.");
6232		break;
6233	case WPS_UI_NFC_HO_NDEF:
6234		websWrite(wp, "Handover done, please remove the peer.");
6235		break;
6236	case WPS_UI_NFC_HO_CPLT:
6237		websWrite(wp, "Handover successful.");
6238		break;
6239	case WPS_UI_NFC_OP_ERROR:
6240		websWrite(wp, "NFC operation fail. Code %d", wps_nfc_err_code);
6241		break;
6242	case WPS_UI_NFC_OP_STOP:
6243		websWrite(wp, "NFC operation stop.");
6244		break;
6245	case WPS_UI_NFC_OP_TO:
6246		websWrite(wp, "NFC operation timeout.");
6247		break;
6248	case WPS_UI_NFC_FM:
6249		websWrite(wp, "Formating NFC, please place your NFC token now!.");
6250		break;
6251	case WPS_UI_NFC_FM_CPLT:
6252		websWrite(wp, "Format NFC successful, please remove the tag.");
6253		break;
6254#endif /* __CONFIG_NFC__ */
6255	default:
6256		websWrite(wp, "Init");
6257	}
6258
6259	if (strcmp(wps_unit, nvram_safe_get("wl_unit"))== 0) {
6260		if (wps_config_command == WPS_UI_CMD_START) {
6261			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"STOPWPS\">");
6262
6263			/* Add in PF #3, show "PBC Again" */
6264			if (wps_method == WPS_UI_METHOD_PBC) {
6265				websWrite(wp, "<input type=\"hidden\" name=\"wps_action\" value=\"AddEnrollee\">");
6266				websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"PBC Again\">");
6267			}
6268		}
6269#ifdef __CONFIG_NFC__
6270		else if (wps_config_command == WPS_UI_CMD_NFC_WR_CFG ||
6271			 wps_config_command == WPS_UI_CMD_NFC_WR_PW) {
6272			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Stop NFC Write\">");
6273		}
6274		else if (wps_config_command == WPS_UI_CMD_NFC_RD_CFG ||
6275			 wps_config_command == WPS_UI_CMD_NFC_RD_PW) {
6276			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Stop NFC Read\">");
6277		}
6278		else if (wps_config_command == WPS_UI_CMD_NFC_HO_S ||
6279			 wps_config_command == WPS_UI_CMD_NFC_HO_R) {
6280			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Stop NFC Hand Over\">");
6281		}
6282#endif /* __CONFIG_NFC__ */
6283	}
6284	return 0;
6285}
6286
6287extern void RAND_bytes(unsigned char *buf, int num);
6288
6289/* generate a printable key string */
6290static int
6291wps_gen_key(char *key, int key_len)
6292{
6293	unsigned short key_length;
6294	unsigned char random_key[64] = {0};
6295	int i = 0;
6296
6297	if (key == NULL || key_len == 0)
6298		return -1;
6299
6300	/* key_length < 16 */
6301	RAND_bytes((unsigned char *)&key_length, sizeof(key_length));
6302	key_length = (unsigned short)((((long)key_length + 56791)*13579)%8) + 8;
6303
6304	while (i < key_length) {
6305		RAND_bytes(&random_key[i], 1);
6306		if ((islower(random_key[i]) || isdigit(random_key[i])) &&
6307			(random_key[i] < 0x7f)) {
6308			i++;
6309		}
6310	}
6311	memcpy(key, random_key, key_len);
6312	return 0;
6313}
6314
6315static int
6316wps_gen_ssid(char *ssid, int ssid_len)
6317{
6318	int i;
6319	char mac[18] = {0};
6320	unsigned short ssid_length;
6321	unsigned char random_ssid[33] = {0};
6322	char prefix[] = "wlXXXXXXXXXX_";
6323	char vif[64];
6324	char *value;
6325
6326	if (ssid == NULL || ssid_len == 0)
6327		return -1;
6328
6329	if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
6330		return -1;
6331	}
6332	snprintf(vif, sizeof(vif), "%shwaddr", prefix);
6333	value  = nvram_get(vif);
6334	strncpy(mac, value, sizeof(mac) - 1);
6335
6336	RAND_bytes((unsigned char *)&ssid_length, sizeof(ssid_length));
6337	ssid_length = (unsigned short)((((long)ssid_length + 56791)*13579)%8) + 1;
6338
6339	RAND_bytes((unsigned char *)random_ssid, ssid_length);
6340
6341	for (i = 0; i < ssid_length; i++) {
6342		if ((random_ssid[i] < 48) || (random_ssid[i] > 57))
6343			random_ssid[i] = random_ssid[i]%9 + 48;
6344	}
6345
6346	random_ssid[ssid_length++] = tolower(mac[6]);
6347	random_ssid[ssid_length++] = tolower(mac[7]);
6348	random_ssid[ssid_length++] = tolower(mac[9]);
6349	random_ssid[ssid_length++] = tolower(mac[10]);
6350	random_ssid[ssid_length++] = tolower(mac[12]);
6351	random_ssid[ssid_length++] = tolower(mac[13]);
6352	random_ssid[ssid_length++] = tolower(mac[15]);
6353	random_ssid[ssid_length++] = tolower(mac[16]);
6354
6355	memset(ssid, 0, ssid_len);
6356	sprintf(ssid, "Broadcom_");
6357
6358	strncat(ssid, (char *)random_ssid, 33 - strlen(ssid) - 1);
6359
6360	return 0;
6361}
6362
6363static int
6364ej_wps_credentials(int eid, webs_t wp, int argc, char_t **argv, int wps_sta)
6365{
6366	int oob;
6367	char prefix[] = "wlXXXXXXXXXX_";
6368	char *value, *next;
6369	char tmp[64];
6370	int configable = FALSE;
6371	char ssid[33] = {0};
6372	char psk[65] = {0};
6373	int akm = 0, crypto = 0;
6374
6375	oob = wps_is_oob();
6376	if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
6377		websError(wp, 400, "unit number variable doesn't exist\n");
6378		return -1;
6379	}
6380
6381	if (wps_action == WPS_UI_ACT_ADDENROLLEE || wps_action == WPS_UI_ACT_STA_CONFIGAP)
6382		configable = TRUE;
6383
6384	/* Get current SSID */
6385	snprintf(tmp, sizeof(tmp), "%sssid", prefix);
6386	value  = nvram_safe_get(tmp);
6387	strncpy(ssid, value, sizeof(ssid)-1);
6388	ssid[sizeof(ssid) - 1] = '\0';
6389
6390	/* Get current AKM */
6391	snprintf(tmp, sizeof(tmp), "%sakm", prefix);
6392	value  = nvram_safe_get(tmp);
6393	foreach(tmp, value, next) {
6394		if (!strcmp(tmp, "psk"))
6395			akm |= 1;
6396		if (!strcmp(tmp, "psk2"))
6397			akm |= 2;
6398	}
6399
6400	/* Encryption type */
6401	snprintf(tmp, sizeof(tmp), "%scrypto", prefix);
6402	value  = nvram_safe_get(tmp);
6403	if (!strcmp(value, "aes"))
6404		crypto = 1;
6405	else if (!strcmp(value, "tkip+aes"))
6406		crypto = 2;
6407	/* psk */
6408	snprintf(tmp, sizeof(tmp), "%swpa_psk", prefix);
6409	value  = nvram_safe_get(tmp);
6410	strncpy(psk, value, sizeof(psk) - 1);
6411	psk[sizeof(psk) - 1] = '\0';
6412
6413	/* If the credentials can be configured, also display the current credentials. */
6414	if (configable) {
6415		/* SSID */
6416		websWrite(wp, "<tr>");
6417		websWrite(wp, "<th width=\"310\">Current SSID:&nbsp;&nbsp;</th><td>&nbsp;&nbsp;</td>\n");
6418		websWrite(wp, "<td>%s</td>\n", translate_ssid(ssid));
6419		/* AKM */
6420		websWrite(wp, "<tr>");
6421		websWrite(wp, "<th width=\"310\">Current Authentication Type:&nbsp;&nbsp;</th>\n");
6422		websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
6423		websWrite(wp, "<td>%s</td>\n", (akm == 0) ? "Open" : (akm == 2) ? "WPA2-PSK" : "WPA/WPA2-PSK");
6424		/* Crypto */
6425		websWrite(wp, "<tr>");
6426		websWrite(wp, "<th width=\"310\">Current Encryption Type:&nbsp;&nbsp;</th>\n");
6427		websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
6428		websWrite(wp, "<td>%s</td>\n", (akm == 0) ? "" : (crypto == 1) ? "AES" : "TKIP+AES");
6429		/* PSK */
6430		websWrite(wp, "<tr>");
6431		websWrite(wp, "<th width=\"310\">Current PSK:&nbsp;&nbsp;</th><td>&nbsp;&nbsp;</td>\n");
6432		websWrite(wp, "<td><A HREF=\"javascript:wps_current_psk_window();\">Click here to display</A></td>\n");
6433		websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td><td></td></tr>\n");
6434	}
6435
6436	/* Show SSID */
6437	if (oob && configable) {
6438		if ((value  = nvram_get("wps_randomssid"))) {
6439			strncpy(random_ssid, value, sizeof(random_ssid) - 1 );
6440			random_ssid[sizeof(random_ssid) - 1] = '\0';
6441		}
6442		else if (random_ssid[0] == 0)
6443			wps_gen_ssid(random_ssid, sizeof(random_ssid));
6444		strcpy(ssid, random_ssid);
6445		akm = 2; /* Default to WPA2 */
6446
6447		/* When I test with WSC 1.0 NXP NFC STA, APUT send crypto type in AES
6448		 * but APUT will save in tkip+aes because in wpsap_close_session() it said
6449		 * " Set AES+TKIP in OOB mode, otherwise in WPS test plan 4.2.4 the
6450		 * Broadcom legacy is not able to associate in TKIP".
6451		 * It results the NXP STA cannot authenticate with APUT.  So, I change
6452		 * the Default to TKIP+AES, but I'm not sure is it have other side effect.
6453		 */
6454		crypto = 2; /* Default to TKIP + AES */
6455
6456		if ((value  = nvram_get("wps_randomkey"))) {
6457			strncpy(random_psk, value, sizeof(random_psk) - 1);
6458			random_psk[sizeof(random_psk) - 1] = '\0';
6459		}
6460		else  if (random_psk[0] == 0)
6461			wps_gen_key(random_psk, sizeof(random_psk));
6462		strcpy(psk, random_psk);
6463	}
6464
6465	/* Config SSID */
6466	websWrite(wp, "<tr><th width=\"310\"");
6467	websWrite(wp, "onMouseOver=\"return overlib(\'Sets the Network Name (also known as SSID) of this network.\', LEFT);\"");
6468	websWrite(wp, "onMouseOut=\"return nd();\">SSID:&nbsp;&nbsp;</th>\n");
6469	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
6470	websWrite(wp, "<td><input name=\"wps_ssid\" value=\"%s\" size=\"32\" maxlength=\"32\"%s></td></tr>\n",
6471			translate_ssid(ssid), (configable ? "" : " disabled"));
6472
6473	/* Config AKM */
6474	websWrite(wp, "<tr><th onmouseover=\"return overlib(\'Select WPS Authentication Type\', LEFT);\" onmouseout=\"return nd();\" width=\"310\">");
6475	websWrite(wp, "Authentication Type:&nbsp;&nbsp;</th><td>&nbsp;&nbsp;</td>\n");
6476	websWrite(wp, "<td><select name=\"wps_akm\" onClick=\"wps_akm_change()\"%s>", configable ? "" : "disabled");
6477	websWrite(wp, "<option value=\"\"%s>Open</option>",
6478			akm == 0 ? " selected=\"selected\"" : "");
6479	websWrite(wp, "<option value=\"psk2\"%s>WPA2-PSK</option>",
6480			akm == 2 ? " selected=\"selected\"" : "");
6481	websWrite(wp, "<option value=\"psk psk2\"%s>WPA/WPA2-PSK</option></select>\n",
6482			akm == 3 ? " selected=\"selected\"" : "");
6483	websWrite(wp, "</td></tr>\n");
6484	/* Config Encryption */
6485	websWrite(wp, "<tr><th onmouseover=\"return overlib(\'Select WPS Encryption Type\', LEFT);\" onmouseout=\"return nd();\" width=\"310\">");
6486	websWrite(wp, "Encryption Type:&nbsp;&nbsp;</th><td>&nbsp;&nbsp;</td>\n");
6487	websWrite(wp, "<td><select name=\"wps_crypto\"%s>", configable ? "" : "disabled");
6488	websWrite(wp, "<option value=\"aes\"%s>AES</option>",
6489			crypto == 1 ? " selected=\"selected\"" : "");
6490	websWrite(wp, "<option value=\"tkip+aes\"%s>TKIP+AES</option></select>\n",
6491			crypto == 2 ? " selected=\"selected\"" : "");
6492	websWrite(wp, "</td></tr>\n");
6493
6494	/* Config PSK */
6495	websWrite(wp, "<tr><th width=\"310\"");
6496	websWrite(wp, " onMouseOver=\"return overlib(\'Sets the WPA passphrase.\', LEFT);\"onMouseOut=\"return nd();\">");
6497	websWrite(wp, "WPA passphrase:&nbsp;&nbsp;</th>\n");
6498	websWrite(wp, "<td>&nbsp;&nbsp;</td>\n");
6499	websWrite(wp, "<td><input name=\"wps_psk\" value=\"%s\" size=\"32\""
6500			" maxlength=\"32\" type=\"password\"%s><A HREF=\"javascript:wps_psk_window();\">Click here to display</A></td>\n",
6501			psk, (configable ? "" : "disabled"));
6502	websWrite(wp, "</tr>\n");
6503
6504	if (!wps_sta && wps_config_command == WPS_UI_CMD_NONE) {
6505		websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td>\n");
6506		websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"Save Credentials\""
6507				" onClick=\"return pre_submit();\">"
6508				"&nbsp;&nbsp<input type=\"submit\" name=\"action\" value=\"Reset To OOB\"></td></tr>\n");
6509	}
6510	return 0;
6511}
6512static int
6513ej_wps_start(int eid, webs_t wp, int argc, char_t **argv, int wps_sta)
6514{
6515	if (wps_config_command == WPS_UI_CMD_NONE) {
6516		if (!wps_sta) {
6517			websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td>");
6518			websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"Add Enrollee\">");
6519			websWrite(wp, "</td> </tr>\n");
6520		}
6521		else {
6522			websWrite(wp, "<tr><th width=\"310\"></th><td>&nbsp;&nbsp;</td>");
6523			websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"Start\"  onClick=\"return pre_submit();\"></td></tr>\n");
6524		}
6525	}
6526
6527	return 0;
6528}
6529
6530static int
6531wps_enr_display_aplist(wps_ap_list_info_t *ap)
6532{
6533	char eastr[ETHER_ADDR_STR_LEN];
6534	int i=0;
6535
6536	if(!ap)
6537		return 0;
6538
6539	printf("-------------------------------------\n");
6540	while(ap->used == TRUE ) {
6541		printf(" %d :  ", i);
6542		printf("SSID:%s  ", ap->ssid);
6543		printf("BSSID:%s  ", ether_etoa(ap->BSSID, eastr));
6544		printf("Channel:%d  ", ap->channel);
6545		printf("Configured:%s  ", ap->scstate?"True":"False");
6546		if(ap->wep)
6547			printf("WEP");
6548		printf("\n");
6549		ap++;
6550		i++;
6551	}
6552
6553	printf("-------------------------------------\n");
6554	return 0;
6555}
6556
6557static uint8*
6558wps_enr_parse_wsc_tlvs(uint8 *tlv_buf, int buflen, uint16 type)
6559{
6560	uint8 *cp;
6561	uint16 *tag;
6562	int totlen;
6563	uint16 len;
6564	uint8 buf[4];
6565
6566	cp = tlv_buf;
6567	totlen = buflen;
6568
6569	/* TLV: 2 bytes for T, 2 bytes for L */
6570	while (totlen >= 4) {
6571		memcpy(buf, cp, 4);
6572		tag = (uint16 *)buf;
6573
6574		if (ntohs(tag[0]) == type)
6575			return (cp + 4);
6576		len = ntohs(tag[1]);
6577		cp += (len + 4);
6578		totlen -= (len + 4);
6579	}
6580
6581	return NULL;
6582}
6583
6584static uint8 *
6585wps_enr_parse_ie_tlvs(uint8 *tlv_buf, int buflen, uint key)
6586{
6587	uint8 *cp;
6588	int totlen;
6589
6590	cp = tlv_buf;
6591	totlen = buflen;
6592
6593	/* find tagged parameter */
6594	while (totlen >= 2) {
6595		uint tag;
6596		int len;
6597
6598		tag = *cp;
6599		len = *(cp +1);
6600
6601		/* validate remaining totlen */
6602		if ((tag == key) && (totlen >= (len + 2)))
6603			return (cp);
6604
6605		cp += (len + 2);
6606		totlen -= (len + 2);
6607	}
6608
6609	return NULL;
6610}
6611
6612static bool
6613wps_enr_wl_is_wps_ie(uint8 **wpaie, uint8 **tlvs, uint *tlvs_len, char *configured)
6614{
6615	uint8 *ie = *wpaie;
6616	uint8 *data;
6617
6618	/* If the contents match the WPA_OUI and type=1 */
6619	if ((ie[1] >= 6) && !memcmp(&ie[2], WPA_OUI "\x04", 4)) {
6620		ie += 6;
6621		data = wps_enr_parse_wsc_tlvs(ie, *tlvs_len-6, 0x1044);
6622		if (data && *data == 0x01)
6623			*configured = FALSE;
6624		else
6625			*configured = TRUE;
6626		return TRUE;
6627	}
6628
6629	/* point to the next ie */
6630	ie += ie[1] + 2;
6631	/* calculate the length of the rest of the buffer */
6632	*tlvs_len -= (int)(ie - *tlvs);
6633	/* update the pointer to the start of the buffer */
6634	*tlvs = ie;
6635
6636	return FALSE;
6637}
6638
6639static bool
6640wps_enr_is_wps_ies(uint8* cp, uint len, char *configured)
6641{
6642	uint8 *parse = cp;
6643	uint parse_len = len;
6644	uint8 *wpaie;
6645
6646	while ((wpaie = wps_enr_parse_ie_tlvs(parse, parse_len, DOT11_MNG_WPA_ID)))
6647		if (wps_enr_wl_is_wps_ie(&wpaie, &parse, &parse_len, configured))
6648			break;
6649	if (wpaie)
6650		return TRUE;
6651	else
6652		return FALSE;
6653}
6654
6655static int
6656wps_enr_get_aplist(wps_ap_list_info_t *list_in, wps_ap_list_info_t *list_out )
6657{
6658	wps_ap_list_info_t *ap_in = &list_in[0];
6659	wps_ap_list_info_t *ap_out = &list_out[0];
6660	int i=0, wps_apcount = 0;
6661	char configured;
6662
6663	/* ignore hidden SSID AP */
6664	while(ap_in->used == TRUE && ap_in->ssidLen && i < WPS_ENR_MAX_AP_SCAN_LIST_LEN) {
6665		if(TRUE == wps_enr_is_wps_ies(ap_in->ie_buf, ap_in->ie_buflen, &configured)) {
6666			ap_in->scstate = configured;
6667			memcpy(ap_out, ap_in, sizeof(wps_ap_list_info_t));
6668			wps_apcount++;
6669			ap_out = &list_out[wps_apcount];
6670		}
6671		i++;
6672		ap_in = &list_in[i];
6673	}
6674	/* in case of on-the-spot filtering, make sure we stop the list  */
6675	if(wps_apcount < WPS_ENR_MAX_AP_SCAN_LIST_LEN)
6676		ap_out->used = 0;
6677
6678	return wps_apcount;
6679}
6680
6681/* WL_NUMCHANNELS is deemed a "bad word", define a local one  */
6682#define NUMCHANS 64
6683
6684static char *
6685wps_enr_get_scan_results(char *ifname)
6686{
6687	int ret, retry_times = 0;
6688	wl_scan_params_t *params;
6689	wl_scan_results_t *list = (wl_scan_results_t*)scan_result;
6690	int params_size = WL_SCAN_PARAMS_FIXED_SIZE + NUMCHANS * sizeof(uint16);
6691	int org_scan_time = 20, scan_time = 40;
6692
6693	params = (wl_scan_params_t*)malloc(params_size);
6694	if (params == NULL) {
6695		return NULL;
6696	}
6697
6698	memset(params, 0, params_size);
6699	params->bss_type = DOT11_BSSTYPE_ANY;
6700	memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
6701	params->scan_type = -1;
6702	params->nprobes = -1;
6703	params->active_time = -1;
6704	params->passive_time = -1;
6705	params->home_time = -1;
6706	params->channel_num = 0;
6707
6708	/* extend scan channel time to get more AP probe resp */
6709	wl_ioctl(ifname, WLC_GET_SCAN_CHANNEL_TIME, &org_scan_time, sizeof(org_scan_time));
6710	if (org_scan_time < scan_time)
6711		wl_ioctl(ifname, WLC_SET_SCAN_CHANNEL_TIME, &scan_time,	sizeof(scan_time));
6712
6713retry:
6714	ret = wl_ioctl(ifname, WLC_SCAN, params, params_size);
6715	if (ret < 0) {
6716		if (retry_times++ < WPS_ENR_SCAN_RETRY_TIMES) {
6717			printf("set scan command failed, retry %d\n", retry_times);
6718			SLEEP(1);
6719			goto retry;
6720		}
6721	}
6722
6723	SLEEP(2);
6724
6725	list->buflen = WPS_ENR_DUMP_BUF_LEN;
6726	ret = wl_ioctl(ifname, WLC_SCAN_RESULTS, scan_result, WPS_ENR_DUMP_BUF_LEN);
6727	if (ret < 0 && retry_times++ < WPS_ENR_SCAN_RETRY_TIMES) {
6728		printf("get scan result failed, retry %d\n", retry_times);
6729		SLEEP(1);
6730		goto retry;
6731	}
6732
6733	free(params);
6734
6735	/* restore original scan channel time */
6736	wl_ioctl(ifname, WLC_SET_SCAN_CHANNEL_TIME, &org_scan_time, sizeof(org_scan_time));
6737
6738	if (ret < 0)
6739		return NULL;
6740
6741	return scan_result;
6742}
6743
6744static wps_ap_list_info_t *
6745wps_enr_create_aplist()
6746{
6747	char *name = NULL;
6748	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
6749	wl_scan_results_t *list = (wl_scan_results_t*)scan_result;
6750	wl_bss_info_t *bi;
6751	wl_bss_info_107_t *old_bi;
6752	uint i, wps_ap_count = 0;
6753
6754	if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL))
6755		return NULL;
6756
6757	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
6758
6759	if (wps_enr_get_scan_results(name) == NULL)
6760		return NULL;
6761
6762	selected_ap = NULL;
6763
6764	memset(ap_list, 0, sizeof(ap_list));
6765	if (list->count == 0)
6766		return 0;
6767	else if (list->version != WL_BSS_INFO_VERSION &&
6768			list->version != LEGACY_WL_BSS_INFO_VERSION) {
6769		/* fprintf(stderr, "Sorry, your driver has bss_info_version %d "
6770		    "but this program supports only version %d.\n",
6771		    list->version, WL_BSS_INFO_VERSION); */
6772		return NULL;
6773	}
6774
6775	bi = list->bss_info;
6776	for (i = 0; i < list->count; i++) {
6777        /* Convert version 107 to 108 */
6778		if (bi->version == LEGACY_WL_BSS_INFO_VERSION) {
6779			old_bi = (wl_bss_info_107_t *)bi;
6780			bi->chanspec = CH20MHZ_CHSPEC(old_bi->channel);
6781			bi->ie_length = old_bi->ie_length;
6782			bi->ie_offset = sizeof(wl_bss_info_107_t);
6783		}
6784		if (bi->ie_length) {
6785			if(wps_ap_count < WPS_ENR_MAX_AP_SCAN_LIST_LEN){
6786				ap_list[wps_ap_count].used = TRUE;
6787				memcpy(ap_list[wps_ap_count].BSSID, (uint8 *)&bi->BSSID, 6);
6788				strncpy((char *)ap_list[wps_ap_count].ssid, (char *)bi->SSID, bi->SSID_len);
6789				ap_list[wps_ap_count].ssid[bi->SSID_len] = '\0';
6790				ap_list[wps_ap_count].ssidLen= bi->SSID_len;
6791				ap_list[wps_ap_count].ie_buf = (uint8 *)(((uint8 *)bi) + bi->ie_offset);
6792				ap_list[wps_ap_count].ie_buflen = bi->ie_length;
6793				ap_list[wps_ap_count].channel = (uint8)(bi->chanspec & WL_CHANSPEC_CHAN_MASK);
6794				ap_list[wps_ap_count].wep = bi->capability & DOT11_CAP_PRIVACY;
6795				wps_ap_count++;
6796			}
6797		}
6798		bi = (wl_bss_info_t*)((int8*)bi + bi->length);
6799	}
6800
6801	scanned = 1;
6802	return ap_list;
6803}
6804
6805static int
6806wl_wpsEnrScan()
6807{
6808	if (wps_config_command == WPS_UI_CMD_NONE)
6809		wps_enr_create_aplist();
6810
6811	return 0;
6812}
6813
6814static wps_ap_list_info_t *
6815wps_enr_get_selected_ap(int index)
6816{
6817	int i = 0;
6818	wps_ap_list_info_t *ap;
6819
6820	ap = ap_list;
6821	while(ap->used == TRUE ) {
6822		if (i == index)
6823			return ap;
6824		ap++;
6825		i++;
6826	}
6827	return NULL;
6828}
6829
6830static int
6831ej_wps_enr_scan_result(int eid, webs_t wp, int argc, char_t **argv)
6832{
6833	int i = 0, ret = 0;
6834	unsigned char macstr[18];
6835	wps_ap_list_info_t *wpsaplist, *ap;
6836
6837	if (!scanned && nvram_match( "wl_wps_mode", "disabled" )) {
6838		websWrite(wp, "<option value=\"-1\" selected>None</option>");
6839		wps_ap_num = 0;
6840		return 0;
6841	}
6842	else if (!scanned)
6843		wps_enr_create_aplist();
6844
6845	wpsaplist = ap_list;
6846	wps_enr_get_aplist(wpsaplist, wpsaplist);
6847	wps_enr_display_aplist(wpsaplist);
6848
6849	ap = wpsaplist;
6850	while(ap->used == TRUE ) {
6851		sprintf((char *)macstr, "%02X:%02X:%02X:%02X:%02X:%02X",
6852			ap->BSSID[0], ap->BSSID[1], ap->BSSID[2],
6853			ap->BSSID[3], ap->BSSID[4], ap->BSSID[5]);
6854		if (selected_ap == NULL) {
6855			ret += websWrite(wp, "<option value=\"%d\" %s>%s (%s)</option>\n", i,
6856					(i == 0) ? "selected" : "",
6857					translate_ssid((char *)ap->ssid),
6858					macstr);
6859		}
6860		else {
6861			ret += websWrite(wp, "<option value=\"%d\" %s>%s (%s)</option>\n", i,
6862					(selected_ap == ap) ? "selected" : "",
6863					translate_ssid((char *)ap->ssid),
6864					macstr);
6865		}
6866		ap++;
6867		i++;
6868	}
6869
6870	if (!ret)
6871		websWrite(wp, "<option value=\"-1\" selected>None</option>");
6872
6873	wps_ap_num = i;
6874	return 0;
6875}
6876
6877static int
6878ej_wps_enr_process(int eid, webs_t wp, int argc, char_t **argv)
6879{
6880
6881	char *status;
6882
6883	status = nvram_safe_get("wps_proc_status");
6884
6885	switch (atoi(status)) {
6886	case WPS_UI_ASSOCIATED:
6887		websWrite(wp, "Start enrolling...");
6888		break;
6889	case WPS_UI_OK:
6890		websWrite(wp, "Succeeded...");
6891		break;
6892	case WPS_UI_MSG_ERR:
6893		websWrite(wp, "Failed...");
6894		break;
6895	case WPS_UI_TIMEOUT:
6896		websWrite(wp, "Failed (timeout)...");
6897		break;
6898	case WPS_UI_PBCOVERLAP:
6899		websWrite(wp, "Failed (pbc overlap)...");
6900		break;
6901	case WPS_UI_FIND_PBC_AP:
6902		websWrite(wp, "Finding a pbc access point...");
6903		break;
6904	case WPS_UI_ASSOCIATING:
6905		websWrite(wp, "Assciating with access point...");
6906		break;
6907#ifdef __CONFIG_NFC__
6908	case WPS_UI_NFC_WR_CFG:
6909	case WPS_UI_NFC_WR_PW:
6910	case WPS_UI_NFC_RD_CFG:
6911	case WPS_UI_NFC_RD_PW:
6912		websWrite(wp, "Please place your NFC token now.");
6913		break;
6914	case WPS_UI_NFC_WR_CPLT:
6915		websWrite(wp, "NFC write token successful, please remove the tag.");
6916		break;
6917	case WPS_UI_NFC_RD_CPLT:
6918		websWrite(wp, "NFC read token successful, please remove the tag.");
6919		break;
6920	case WPS_UI_NFC_HO_S:
6921		websWrite(wp, "Handover as selector.");
6922		break;
6923	case WPS_UI_NFC_HO_R:
6924		websWrite(wp, "Handover as requester.");
6925		break;
6926	case WPS_UI_NFC_HO_NDEF:
6927		websWrite(wp, "Handover done, please remove the peer.");
6928		break;
6929	case WPS_UI_NFC_HO_CPLT:
6930		websWrite(wp, "Handover successful.");
6931		break;
6932	case WPS_UI_NFC_OP_ERROR:
6933		websWrite(wp, "NFC operation fail. Code %d", wps_nfc_err_code);
6934		break;
6935	case WPS_UI_NFC_OP_STOP:
6936		websWrite(wp, "NFC operation stop.");
6937		break;
6938	case WPS_UI_NFC_OP_TO:
6939		websWrite(wp, "NFC operation timeout.");
6940		break;
6941	case WPS_UI_NFC_FM:
6942		websWrite(wp, "Formating NFC, please place your NFC token now!");
6943		break;
6944	case WPS_UI_NFC_FM_CPLT:
6945		websWrite(wp, "Format NFC successful, please remove the tag.");
6946		break;
6947#endif /* __CONFIG_NFC__ */
6948	default:
6949		websWrite(wp, "Init");
6950		break;
6951	}
6952
6953	if (strcmp(wps_unit, nvram_safe_get("wl_unit"))== 0) {
6954		if (wps_config_command == WPS_UI_CMD_START) {
6955			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"STOPWPS\">");
6956
6957			/* WPS 2.0, test plan 5.1.7, show "STA PBC Again" */
6958			if (wps_method == WPS_UI_METHOD_PBC) {
6959				websWrite(wp, "<input type=\"hidden\" name=\"wps_action\" value=\"Enroll\">");
6960				websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"PBC Again\">");
6961			}
6962		}
6963#ifdef __CONFIG_NFC__
6964		else if (wps_config_command == WPS_UI_CMD_NFC_WR_CFG ||
6965			 wps_config_command == WPS_UI_CMD_NFC_WR_PW) {
6966			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Stop NFC Write\">");
6967		}
6968		else if (wps_config_command == WPS_UI_CMD_NFC_RD_CFG ||
6969			 wps_config_command == WPS_UI_CMD_NFC_RD_PW) {
6970			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Stop NFC Read\">");
6971		}
6972		else if (wps_config_command == WPS_UI_CMD_NFC_HO_S ||
6973			 wps_config_command == WPS_UI_CMD_NFC_HO_R) {
6974			websWrite(wp, "&nbsp;&nbsp;<input type=\"submit\" name=\"action\" value=\"Stop NFC Hand Over\">");
6975		}
6976#endif /* __CONFIG_NFC__ */
6977	}
6978
6979	return 0;
6980}
6981#endif /* __CONFIG_WPS__ */
6982
6983/* write "selected" to page if the argument matches the current
6984	 wl_ure setting */
6985static int
6986ej_ure_list(int eid, webs_t wp, int argc, char_t **argv)
6987{
6988	char *temp;
6989	int match_value;
6990	int nv_value;
6991
6992	if (ejArgs(argc, argv, "%d", &match_value) < 1) {
6993		websError(wp, 400, "Insufficient args\n");
6994		return EINVAL;
6995	}
6996
6997	temp = nvram_safe_get("wl_ure");
6998	if(strlen( temp ) == 0) {
6999		if( match_value == 0 )
7000		{
7001			/* treat empty string as "0" */
7002			websWrite(wp, "selected" );
7003		}
7004		return 0;
7005	}
7006
7007	nv_value = atoi( temp );
7008	if( nv_value == match_value) {
7009		websWrite(wp, "selected" );
7010	}
7011
7012	return 0;
7013}
7014
7015/* Return wlX_ure setting for the current wireless interface.  If
7016   the current wireless interface is a virtual interface, return
7017   the value of the parent interface
7018*/
7019static int
7020ej_ure_enabled(int eid, webs_t wp, int argc, char_t **argv)
7021{
7022	char *temp;
7023	int unit = -1;
7024	int sub_unit = -1;
7025	char nv_param[NVRAM_MAX_PARAM_LEN];
7026
7027	temp = nvram_get("wl_unit");
7028	if(strlen( temp ) == 0) {
7029 		websError(wp, 400, "Error getting wl_unit\n");
7030		return EINVAL;
7031	}
7032
7033	if( get_ifname_unit( temp, &unit, &sub_unit ) != 0 ) {
7034 		websError(wp, 400, "Error getting unit/subunit\n");
7035		return EINVAL;
7036	}
7037
7038	sprintf( nv_param, "wl%d_ure", unit );
7039	temp = nvram_safe_get( nv_param );
7040	if( strncmp( temp, "1", 1 ) == 0 ) {
7041		websWrite(wp, "\"1\"");
7042	}
7043	else {
7044		websWrite(wp, "\"0\"");
7045	}
7046
7047	return 0;
7048}
7049
7050/* Write "1" or "0" for URE enabled on any interface to the web page
7051	 1 - URE enabled for an interface
7052	 0 - URE not enabled for any interface
7053
7054	 This is currently used on the Basic web page for helping to decide
7055	 whether "router_disable" should be greyed-out or not.  We prevent
7056	 changing the router mode while in URE to minimize the complexity of
7057	 mode changes that require network interfaces to move from the LAN to the
7058	 WAN and vice-versa.
7059*/
7060static int
7061ej_ure_any_enabled(int eid, webs_t wp, int argc, char_t **argv)
7062{
7063	if( ure_any_enabled() )
7064		websWrite(wp, "\"1\"");
7065	else
7066		websWrite(wp, "\"0\"");
7067
7068	return 0;
7069}
7070
7071/* Write "1" for IBSS mode, "0" for Infrastructure based on wlX_infra NVRAM setting.
7072 * This will always write "0" for a virtual/secondary interface.  We don't currently support
7073 * IBSS mode for a non-primary BSS config.
7074 */
7075static int
7076ej_wl_ibss_mode(int eid, webs_t wp, int argc, char_t **argv)
7077{
7078	char *temp;
7079	int unit = -1;
7080	int sub_unit = -1;
7081	int sta_mode = FALSE;
7082	char nv_param[NVRAM_MAX_PARAM_LEN];
7083
7084	temp = nvram_get("wl_unit");
7085	if(strlen( temp ) == 0) {
7086		websError(wp, 400, "Error getting wl_unit\n");
7087		return EINVAL;
7088	}
7089
7090	if( get_ifname_unit( temp, &unit, &sub_unit ) != 0 ) {
7091		websError(wp, 400, "Error getting unit/subunit\n");
7092		return EINVAL;
7093	}
7094
7095	/* In order for wlX_infra setting to be meaningful, we must be in a valid STA mode.  */
7096	sprintf( nv_param, "wl%d_mode", unit );
7097	temp = nvram_safe_get( nv_param );
7098	if ((strncmp(temp, "wet", 3) == 0) || (strncmp(temp, "mac_spoof", 3) == 0) ||
7099	    (strncmp(temp, "sta", 3) == 0)) {
7100		sta_mode = TRUE;
7101	}
7102
7103	sprintf( nv_param, "wl%d_infra", unit );
7104	temp = nvram_safe_get( nv_param );
7105
7106	/* Write "0" if non-STA mode OR Infrastructure STA */
7107	if (!sta_mode || (strncmp(temp, "1", 1) == 0)) {
7108		websWrite(wp, "\"0\"");
7109	} else if (strncmp(temp, "0", 1) == 0) {
7110		websWrite(wp, "\"1\"");
7111	} else {
7112		websError(wp, 400, "Invalid wl%d_infra setting in NVRAM\n", unit);
7113		return EINVAL;
7114	}
7115
7116	return 0;
7117}
7118
7119/* Display DFS Reentry parameters */
7120static int
7121ej_dfs_reentry_display(int eid, webs_t wp, int argc, char_t **argv)
7122{
7123#define NWINS 3
7124	static struct {
7125		const char *keyword;
7126		const char *description;
7127	} wins[NWINS] = {
7128		{ "acs_dfsr_immediate", "Immediate Reentry" },
7129		{ "acs_dfsr_deferred", "Deferred Reentry" },
7130		{ "acs_dfsr_activity", "Channel Active" }
7131	};
7132	static char *table_start =
7133	"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n"
7134	"<tr>"
7135		"<th width=\"310\""
7136			" onMouseOver=\"return overlib('DFS Reentry Window parameters', LEFT);\""
7137			" onMouseOut=\"return nd();\">"
7138			"DFS Reentry Window Settings&nbsp;&nbsp;"
7139		"</th>"
7140		"<td>&nbsp;&nbsp;</td>"
7141		"<td class=\"label\">Seconds</td>"
7142		"<td class=\"label\">Threshold</td>"
7143	"</tr>\n";
7144	static char *table_entry =
7145	"<tr>"
7146		"<th width=\"310\""
7147			" onMouseOver=\"return overlib('DFS %s window parameters', LEFT);\""
7148			" onMouseOut=\"return nd();\">"
7149			"%s:&nbsp;&nbsp;"
7150		"</th>"
7151		"<input type=\"hidden\" name=\"wl_%s\" value=\"1\">" /* needed to call validateFn */
7152		"<td>&nbsp;&nbsp;</td>"
7153		"<td>"
7154			"<input name=\"wl_%s_sec\" "
7155			" onMouseOver=\"return overlib('Window size in seconds', LEFT);\""
7156			" onMouseOut=\"return nd();\""
7157			" value=\"%u\" size=\"8\" maxlength=\"8\">"
7158		"</td>"
7159		"<td>"
7160			"<input name=\"wl_%s_thr\" "
7161			" onMouseOver=\"return overlib('Window threshold value', LEFT);\""
7162			" onMouseOut=\"return nd();\""
7163			" value=\"%u\" size=\"8\" maxlength=\"8\">"
7164		"</td>"
7165	"</tr>\n";
7166	static char *table_end = "</table>\n";
7167	char tmp[NVRAM_BUFSIZE], prefix[16]; /* "wlXXXXXXXXXX_" */
7168	unsigned sec, thr;
7169	int i;
7170
7171	if (!make_wl_prefix(prefix, sizeof(prefix), 0, NULL)) {
7172		strcpy(prefix, "wl_");
7173	}
7174
7175	websWrite(wp, table_start);
7176
7177	for (i = 0; i < NWINS; ++i) {
7178		if (sscanf(nvram_safe_get(strcat_r(prefix, wins[i].keyword, tmp)), "%u %u",
7179			&sec, &thr) != 2) {
7180			sec = thr = 0;
7181		}
7182		websWrite(wp, table_entry, wins[i].description, wins[i].description,
7183			wins[i].keyword,
7184			wins[i].keyword, sec,
7185			wins[i].keyword, thr );
7186	}
7187	websWrite(wp, table_end);
7188	return 0;
7189}
7190
7191/* Fill HTML input form with traffic management filters data stored in NVRAM */
7192static int
7193ej_trf_mgmt_display(int eid, webs_t wp, int argc, char_t **argv)
7194{
7195	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
7196	char cap[WLC_IOCTL_SMLEN];
7197	char caps[WLC_IOCTL_MEDLEN];
7198	char *name = NULL;
7199	char *next = NULL;
7200	int trf_mgmt_cap = 0;
7201	int i, n = 9, ret = 0;
7202	netconf_trmgmt_t trm;
7203	bool valid;
7204	char port[] = "XXXXX";
7205	char eastr[ETHER_ADDR_STR_LEN];
7206	unsigned char *hwaddr;
7207
7208	if (!make_wl_prefix(prefix, sizeof(prefix), 0, NULL)) {
7209		websError(wp, 400, "unit number variable doesn't exist\n");
7210		return -1;
7211	}
7212
7213	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
7214#ifdef __CONFIG_DHDAP__
7215	/* Traffic Management Setting is not supported on DHD/PCIEFD driver */
7216	if (!dhd_probe(name)) {
7217		return -1;
7218	}
7219#endif
7220	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
7221		return -1;
7222
7223	foreach(cap, caps, next) {
7224		if (!strcmp(cap, "traffic-mgmt")) {
7225			trf_mgmt_cap = 1;
7226			break;
7227		}
7228	}
7229	if (trf_mgmt_cap == 0)
7230		return -1;
7231
7232	websWrite(wp, "<p>");
7233	websWrite(wp, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
7234	websWrite(wp, "<tr>");
7235	websWrite(wp, "<th width=\"310\" valign=\"top\" rowspan=\"11\"");
7236	websWrite(wp, "onMouseOver=\"return overlib('Adds up to 10 traffic management filters which specifies the TCP/UDP port, MAC and priority.', LEFT);\"");
7237	websWrite(wp, "onMouseOut=\"return nd();\">");
7238	websWrite(wp, "<input type=\"hidden\" name=\"trf_mgmt_port\" value=\"10\">");
7239	websWrite(wp, "Traffic Management Settings:&nbsp;&nbsp;");
7240	websWrite(wp, "</th>");
7241	websWrite(wp, "<td>&nbsp;&nbsp;</td>");
7242	websWrite(wp, "<td class=\"label\">Protocol</td>");
7243	websWrite(wp, "<td></td>");
7244	websWrite(wp, "<td class=\"label\">Src Port</td>");
7245	websWrite(wp, "<td></td>");
7246	websWrite(wp, "<td class=\"label\">Dst Port</td>");
7247	websWrite(wp, "<td></td>");
7248	websWrite(wp, "<td class=\"label\">Dst Mac Addr</td>");
7249	websWrite(wp, "<td></td>");
7250	websWrite(wp, "<td class=\"label\">Priority</td>");
7251	websWrite(wp, "<td></td>");
7252	websWrite(wp, "<td class=\"label\">Favored</td>");
7253	websWrite(wp, "<td></td>");
7254	websWrite(wp, "<td class=\"label\">Enabled</td>");
7255	websWrite(wp, "</tr>");
7256
7257	for (i = 0; i <= n; i++) {
7258		valid = get_trf_mgmt_port(prefix, i, &trm);
7259
7260		ret += websWrite(wp, "<tr>");
7261		ret += websWrite(wp, "<td></td>");
7262
7263		/* Print protocol */
7264		ret += websWrite(wp, "<td>");
7265		ret += websWrite(wp, "<select name=\"%strf_mgmt_port_proto%d\">", prefix, i);
7266		ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>",
7267				 valid && trm.match.ipproto == IPPROTO_TCP ? "selected" : "");
7268		ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>",
7269				 valid && trm.match.ipproto == IPPROTO_UDP ? "selected" : "");
7270		ret += websWrite(wp, "<option value=\"mac\" %s>MAC</option>",
7271				 valid && trm.match.ipproto == IPPROTO_IP ? "selected" : "");
7272		ret += websWrite(wp, "</select>");
7273		ret += websWrite(wp, "</td>");
7274		ret += websWrite(wp, "<td></td>");
7275
7276
7277		/* Print source port number,  map source port value  zero to  NULL */
7278		if ((valid) && (trm.match.ipproto != IPPROTO_IP) && trm.match.src.ports[0])
7279			snprintf(port, sizeof(port), "%d", ntohs(trm.match.src.ports[0]));
7280		else
7281			*port = '\0';
7282		ret += websWrite(wp, "<td><input name=\"%strf_mgmt_port_sport%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
7283				 prefix, i, port);
7284		ret += websWrite(wp, "<td></td>");
7285
7286		/* Print destination port number,  map dest port value  zero to  NULL */
7287		if ((valid) && (trm.match.ipproto != IPPROTO_IP) && trm.match.dst.ports[0])
7288			snprintf(port, sizeof(port), "%d", ntohs(trm.match.dst.ports[0]));
7289		else
7290			*port = '\0';
7291		ret += websWrite(wp, "<td><input name=\"%strf_mgmt_port_dport%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>",
7292				 prefix, i, port);
7293		ret += websWrite(wp, "<td></td>");
7294
7295		/* Print mac address */
7296		hwaddr = (unsigned char *)&trm.match.mac;
7297		/* Check for bad, multicast, broadcast, or null address */
7298		if ((hwaddr[0] & 1) ||
7299			(hwaddr[0] & hwaddr[1] & hwaddr[2] & hwaddr[3] & hwaddr[4] & hwaddr[5]) == 0xff ||
7300			(hwaddr[0] | hwaddr[1] | hwaddr[2] | hwaddr[3] | hwaddr[4] | hwaddr[5]) == 0x00) {
7301			ret += websWrite(wp, "<td><input name=\"%strf_mgmt_port_macaddr%d\" value=\"%s\" size=\"17\" maxlength=\"17\"></td>",
7302					 prefix, i, "");
7303		} else {
7304			ret += websWrite(wp, "<td><input name=\"%strf_mgmt_port_macaddr%d\" value=\"%s\" size=\"17\" maxlength=\"17\"></td>",
7305					 prefix, i, valid ? ether_etoa((const unsigned char *)&trm.match.mac, eastr) : "");
7306		}
7307		ret += websWrite(wp, "<td></td>");
7308
7309		/* Print priority */
7310		ret += websWrite(wp, "<td>");
7311		ret += websWrite(wp, "<select name=\"%strf_mgmt_port_prio%d\">", prefix, i);
7312		ret += websWrite(wp, "<option value=\"0\" %s>BK</option>",
7313				 valid && trm.prio == 0 ? "selected" : "");
7314		ret += websWrite(wp, "<option value=\"1\" %s>BE</option>",
7315				 valid && trm.prio == 1 ? "selected" : "");
7316		ret += websWrite(wp, "<option value=\"2\" %s>VI</option>",
7317				 valid && trm.prio == 2 ? "selected" : "");
7318		ret += websWrite(wp, "<option value=\"3\" %s>NOCHANGE</option>",
7319				 valid && trm.prio == 3 ? "selected" : "");
7320
7321		ret += websWrite(wp, "</select>");
7322		ret += websWrite(wp, "</td>");
7323		ret += websWrite(wp, "<td></td>");
7324
7325		/* Print Favored */
7326		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"%strf_mgmt_port_favored%d\" %s></td>",
7327				 prefix, i, valid && (trm.favored) ? "checked" : "");
7328
7329		/* Print enable */
7330		ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"%strf_mgmt_port_enable%d\" %s></td>",
7331				 prefix, i, valid && !(trm.match.flags & NETCONF_DISABLED) ? "checked" : "");
7332
7333		ret += websWrite(wp, "</tr>\n");
7334	}
7335
7336	websWrite(wp, "</table>");
7337
7338	return ret;
7339}
7340
7341char *webs_buf=NULL;
7342int webs_buf_offset=0;
7343
7344/* This routine extracts the index variable in the string
7345   format
7346   eg get_string_index("lan_","lan0_ifname",buf,sizeof(buf))
7347   returns the string "0" in buf.
7348
7349   In the case of where there is no index
7350   eg get_string_index("lan_","lan_ifname",buf,sizeof(buf))
7351   returns NULL in buf[0].
7352
7353   Inputs :
7354   - prefix: prefix to start of index string
7355   - varname: value to process
7356   - outbuf: output buffer
7357   - bufsize: output buffer size
7358
7359   Returns:
7360   -string null terminated string in output buffer
7361   -pointer to output buffer or NULL if error
7362*/
7363char *
7364get_index_string(char *prefix, char *varname, char *outbuf, int bufsize)
7365{
7366	int offset, len;
7367
7368	if (!prefix) return NULL;
7369	if (!varname) return NULL;
7370	if (!outbuf) return NULL;
7371	if (!bufsize) return NULL;
7372
7373	memset(outbuf,0,bufsize);
7374
7375	/* offset is the start of the index number eg
7376	 *  offset of dhcp0 is 4. prefix contains the "dhcp" as
7377	 *  the prefix
7378	 */
7379
7380	offset = strlen(prefix);
7381
7382	/* This calculates the string length of the index
7383	 * ie the index value represented as a string
7384	 * strchr(varname,'_') is the end of the index string.
7385	 * strchr(varname,'_') - varname is the length of the var including
7386	 * the index string but before the underscore "_"
7387	*/
7388	len = strchr(varname,'_') - varname - offset ;
7389
7390	if (len > bufsize) return NULL;
7391
7392	if (len) strncpy(outbuf,&varname[offset],len);
7393	outbuf[len]='\0';
7394
7395	return outbuf;
7396}
7397
7398/*
7399 * DFS Reentry Window parameters (seconds and threshold) are saved in a single nvram variable,
7400 * separated by a blank, ie, wlX_acs_dfsr_immediate="300 2". This unfortunately requires us to
7401 * do some specialised web page display and parsing.
7402 */
7403static int
7404validate_dfs_window(webs_t wp, char *value, struct variable *v, char *varname)
7405{
7406	char name[40]; /* wl_xxxxxxxxx_acs_dfsr_immediate_sec */
7407	unsigned sec,thr;
7408
7409	snprintf(name, sizeof(name), "%s_sec", v->name );
7410	value = websGetVar(wp, name, NULL);
7411	sec = (value && *value) ? atoi(value) : 0;
7412
7413	snprintf(name, sizeof(name), "%s_thr", v->name );
7414	value = websGetVar(wp, name, NULL);
7415	thr = (value && *value) ? atoi(value) : 0;
7416
7417	/* A zero threshold is valid, but a zero window size is not. */
7418	if (!sec) {
7419		/* Only complain if  a zero value is in there and the field is not disabled. */
7420		if (value) {
7421			websBufferWrite(wp, "Invalid <b>%s</b>: Seconds may be not zero<br>",
7422				v->longname );
7423		}
7424		return FALSE;
7425	}
7426
7427	sprintf(name, "%u %u", sec, thr);
7428	nvram_set((varname) ? varname : v->name, name);
7429
7430	return TRUE;
7431}
7432
7433static void
7434validate_list(webs_t wp, char *value, struct variable *v,
7435	      int (*valid)(webs_t, char *, struct variable *), char *varname )
7436{
7437	int n, i;
7438	char name[100];
7439	char buf[1000] = "", *cur = buf;
7440
7441	assert(v);
7442
7443	ret_code = EINVAL;
7444	n = atoi(value);
7445
7446	for (i = 0; i < n; i++) {
7447		snprintf(name, sizeof(name), "%s%d", v->name, i);
7448		if (!(value = websGetVar(wp, name, NULL)))
7449				return;
7450
7451		if (!*value && v->nullok)
7452			continue;
7453		if (!valid(wp, value, v ))
7454			continue;
7455		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s",
7456				cur == buf ? "" : " ", value);
7457	}
7458
7459	/* Use varname override if specified. Used to make the routine
7460	   multiinstance compatible */
7461	if (varname)
7462		nvram_set(varname, buf);
7463	else
7464		nvram_set(v->name, buf);
7465
7466	ret_code = 0;
7467}
7468
7469static int
7470valid_ipaddr(webs_t wp, char *value, struct variable *v)
7471{
7472	unsigned int buf[4];
7473	struct in_addr ipaddr, netaddr, broadaddr, netmask;
7474
7475	assert(v);
7476
7477	if (sscanf(value, "%d.%d.%d.%d", &buf[0], &buf[1], &buf[2], &buf[3]) != 4) {
7478		websBufferWrite(wp, "Invalid <b>%s</b> %s: not an IP address<br>",
7479			  v->longname, value);
7480		return FALSE;
7481	}
7482
7483	ipaddr.s_addr = htonl((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
7484
7485	if (v->argv) {
7486		(void) inet_aton(nvram_safe_get(v->argv[0]), &netaddr);
7487		(void) inet_aton(nvram_safe_get(v->argv[1]), &netmask);
7488		netaddr.s_addr &= netmask.s_addr;
7489		broadaddr.s_addr = netaddr.s_addr | ~netmask.s_addr;
7490		if (netaddr.s_addr != (ipaddr.s_addr & netmask.s_addr)) {
7491			websBufferWrite(wp, "Invalid <b>%s</b> %s: not in the %s/",
7492				  v->longname, value, inet_ntoa(netaddr));
7493			websBufferWrite(wp, "%s network<br>", inet_ntoa(netmask));
7494			return FALSE;
7495		}
7496		if (ipaddr.s_addr == netaddr.s_addr) {
7497			websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the network address<br>",
7498				  v->longname, value);
7499			return FALSE;
7500		}
7501		if (ipaddr.s_addr == broadaddr.s_addr) {
7502			websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the broadcast address<br>",
7503				  v->longname, value);
7504			return FALSE;
7505		}
7506	}
7507
7508	return TRUE;
7509}
7510
7511static void
7512validate_ipaddr(webs_t wp, char *value, struct variable *v , char *varname)
7513{
7514
7515	assert(v);
7516
7517	ret_code = EINVAL;
7518
7519	if (!valid_ipaddr(wp, value, v) ) return;
7520
7521	if (varname)
7522		nvram_set(varname,value) ;
7523	else
7524		nvram_set(v->name, value);
7525
7526	ret_code = 0;
7527
7528}
7529
7530static void
7531validate_ipaddrs(webs_t wp, char *value, struct variable *v, char *varname)
7532{
7533	ret_code = EINVAL;
7534	validate_list(wp, value, v, valid_ipaddr, varname);
7535}
7536
7537int
7538valid_choice(webs_t wp, char *value, struct variable *v)
7539{
7540	char **choice=NULL;
7541
7542	assert(v);
7543
7544	for (choice = v->argv; *choice; choice++) {
7545		if (!strcmp(value, *choice))
7546			return TRUE;
7547	}
7548
7549	websBufferWrite(wp, "Invalid <b>%s</b> %s: not one of ", v->longname, value);
7550	for (choice = v->argv; *choice; choice++)
7551		websBufferWrite(wp, "%s%s", choice == v->argv ? "" : "/", *choice);
7552	websBufferWrite(wp, "<br>");
7553
7554	return FALSE;
7555}
7556
7557static void
7558validate_choice(webs_t wp, char *value, struct variable *v, char *varname)
7559{
7560
7561	assert(v);
7562
7563	ret_code = EINVAL;
7564
7565	if (!valid_choice(wp, value, v)) return;
7566
7567	if (varname )
7568		nvram_set(varname, value);
7569	else
7570		nvram_set(v->name, value);
7571	ret_code = 0;
7572
7573}
7574
7575static void
7576validate_router_disable(webs_t wp, char *value, struct variable *v,
7577												char *varname)
7578{
7579	char *temp = NULL;
7580
7581	assert(v);
7582
7583	ret_code = EINVAL;
7584
7585	if (!valid_choice(wp, value, v)) return;
7586
7587	/* we need to find out if we're changing the router mode or not.  if
7588		 we're really changing the setting, we need to reboot */
7589	temp = nvram_safe_get( v->name );
7590
7591	if( strcmp( temp, value ) )
7592		action = REBOOT;
7593
7594	if (varname )
7595		nvram_set(varname,value) ;
7596	else
7597		nvram_set(v->name, value);
7598	ret_code = 0;
7599
7600}
7601
7602int
7603valid_range(webs_t wp, char *value, struct variable *v)
7604{
7605	int n, start, end;
7606
7607	assert(v);
7608
7609	n = atoi(value);
7610	start = atoi(v->argv[0]);
7611	end = atoi(v->argv[1]);
7612
7613	if (n < start || n > end) {
7614		websBufferWrite(wp, "Invalid <b>%s</b> %s: out of range %d-%d<br>",
7615			  v->longname, value, start, end);
7616		return FALSE;
7617	}
7618
7619	return TRUE;
7620}
7621
7622static void
7623validate_range(webs_t wp, char *value, struct variable *v , char *varname)
7624{
7625
7626	assert(v);
7627
7628	ret_code = EINVAL;
7629
7630	if (!valid_range(wp, value, v)) return ;
7631
7632	if (varname )
7633		nvram_set(varname,value) ;
7634	else
7635		nvram_set(v->name, value);
7636
7637	ret_code = 0;
7638}
7639
7640int
7641valid_octet(webs_t wp, char *value, struct variable *v)
7642{
7643	int n, start, end;
7644	assert(v);
7645
7646	n = atoi(value);
7647	start = atoi(v->argv[0]);
7648	end = atoi(v->argv[1]);
7649
7650	if (n == 255) {
7651		return TRUE;
7652	} else if (n < start || n > end) {
7653		websBufferWrite(wp, "Invalid <b>%s</b> %s: out of range %d-%d<br>",
7654			v->longname, value, start, end);
7655		return FALSE;
7656	}
7657
7658	return TRUE;
7659}
7660
7661
7662#ifdef BCMQOS
7663static void
7664valid_qos_var(webs_t wp, char *value, struct variable *v, char *varname )
7665{
7666	ret_code = EINVAL;
7667	printf("\nIN valid_qos_varvalid_name()");
7668	if (varname )
7669		nvram_set(varname,value) ;
7670	else
7671		nvram_set(v->name, value);
7672	ret_code = 0;
7673}
7674#endif /* BCMQOS */
7675int
7676valid_name(webs_t wp, char *value, struct variable *v)
7677{
7678	int n, min, max;
7679
7680	assert(v);
7681
7682	n = strlen(value);
7683	min = atoi(v->argv[0]);
7684	max = atoi(v->argv[1]);
7685
7686	if (n > max) {
7687		websBufferWrite(wp, "Invalid <b>%s</b> %s: longer than %d characters<br>",
7688			  v->longname, value, max);
7689		return FALSE;
7690	}
7691	else if (n < min) {
7692		websBufferWrite(wp, "Invalid <b>%s</b> %s: shorter than %d characters<br>",
7693			  v->longname, value, min);
7694		return FALSE;
7695	}
7696
7697	return TRUE;
7698}
7699
7700int
7701valid_hex(webs_t wp, char *value, struct variable *v)
7702{
7703	int n, min, max;
7704	char *c=NULL;
7705
7706	assert(v);
7707
7708	n = strlen(value);
7709	min = atoi(v->argv[0]);
7710	max = atoi(v->argv[1]);
7711
7712	if (n > max) {
7713		websBufferWrite(wp, "Invalid <b>%s</b> %s: longer than %d characters<br>",
7714			v->longname, value, max);
7715		return FALSE;
7716	}
7717	else if (n < min) {
7718		websBufferWrite(wp, "Invalid <b>%s</b> %s: shorter than %d characters<br>",
7719			v->longname, value, min);
7720		return FALSE;
7721	}
7722	else if(n%2)
7723	{
7724		websBufferWrite(wp, "Invalid <b>%s</b> %s: must be in even length<br>",
7725			v->longname, value);
7726		return FALSE;
7727	}
7728
7729	for (c = value; *c; c++) {
7730		if (!isxdigit((int) *c)) {
7731			websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>",
7732			v->longname, *c);
7733			return FALSE;
7734		}
7735	}
7736
7737	return TRUE;
7738}
7739
7740
7741static void
7742validate_guest_lan_ifname(webs_t wp, char *value, struct variable *v, char *varname )
7743{
7744	int index,unit;
7745	char ifname[IFNAMSIZ],os_name[IFNAMSIZ];
7746
7747	assert(v);
7748	assert(value);
7749
7750	ret_code = EINVAL;
7751
7752	if (!*value){
7753		websBufferWrite(wp, "Guest LAN interface must be specified.<br>");
7754		return;
7755	}
7756
7757	if (!v->argv[0]){
7758		websBufferWrite(wp, "Guest LAN interface index must be specified.<br>");
7759		return;
7760	}
7761
7762	index = atoi (v->argv[0]);
7763
7764	if ((index < 1 ) || (index > 4))
7765		if (!v->argv[0]){
7766		websBufferWrite(wp, "Guest LAN interface index must be between 1 and 4.<br>");
7767		return;
7768	}
7769
7770	if (nvifname_to_osifname( value, os_name, sizeof(os_name) ) < 0){
7771		websBufferWrite(wp, "Unable to translate Guest LAN interface name: %s.<br>",value);
7772			return;
7773	}
7774
7775	if (wl_probe(os_name) ||
7776		    wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit))){
7777			websBufferWrite(wp, "Guest LAN interface %s is not a Wireless Interface.<br>",value);
7778			return;
7779	}
7780
7781	/* Guest SSID are not part of a bridge, unset lanX_ifnames */
7782
7783	snprintf(ifname,sizeof(ifname),"lan%d_ifname",index);
7784	nvram_set(ifname,value);
7785
7786	snprintf(ifname,sizeof(ifname),"lan%d_ifnames",index);
7787	nvram_unset(ifname);
7788
7789	ret_code=0;
7790}
7791static void
7792validate_vif_ssid(webs_t wp, char *value, struct variable *v, char *varname )
7793{
7794/* Validation of the guest ssids does 3 things
7795 * 1)adds the wlX.Y_ssid field
7796 * 2)updates the wlX_vif list
7797 * 3)removes entry from wlX_vif if the interface is empty
7798*/
7799
7800	char *wl_unit=NULL;
7801	char wl_vif[]="wlXXXXXXXXX_vifs",*wl_vif_value=NULL;
7802	char wl_ssid[]="wlXXXXXXXXX_ssid";
7803	char wl_radio[]="wlXXXXXXXXX_radio";
7804	char wl_mode[]="wlXXXXXXXXX_mode";
7805	char buf[100];
7806	char prefix[]="wlXXXXX";
7807	int p=-1;
7808	char *subunit=NULL,unit[]="0000";
7809	char *argv[3];
7810
7811	assert(v);
7812	assert(value);
7813
7814	ret_code = EINVAL;
7815
7816
7817	if (varname)
7818		wl_unit=varname;
7819	else
7820		wl_unit=websGetVar(wp, "wl_unit", NULL);
7821
7822	if (!wl_unit || get_ifname_unit(wl_unit,&p,NULL) < 0) return ;
7823
7824	if (p < 0) return;
7825
7826
7827	snprintf(unit,sizeof(unit),"%d",p);
7828	subunit = v->argv[0];
7829
7830	/* If SSID is not null try to validate it for correct range */
7831	if (*value){
7832		struct variable local;
7833
7834		memcpy(&local,v,sizeof(local));
7835		argv[0]="1";
7836		argv[1]="32";
7837		argv[2]=NULL;
7838		local.argv=argv;
7839		if (!valid_name(wp, value, &local)) return;
7840	}
7841
7842	snprintf(wl_ssid,sizeof(wl_ssid),"wl_ssid");
7843	snprintf(wl_vif,sizeof(wl_vif),"wl%s_vifs",unit);
7844
7845	memset(buf,0,sizeof(buf));
7846
7847	/* This logic here decides if updates to virtual interface list on the
7848	   parent is required */
7849
7850	wl_vif_value = nvram_get(wl_vif);
7851
7852	if (wl_vif_value ){
7853	 		char vif[]="wlXXXXXXXXX";
7854			int  found = 0;
7855			char name[IFNAMSIZ], *next = NULL;
7856
7857			snprintf(vif,sizeof(vif),"wl%s.%s",unit,subunit);
7858
7859			/* virtual interface on the list already? */
7860			foreach(name,wl_vif_value,next) {
7861				if (!strcmp(name, vif)) {
7862					found = 1;
7863					break;
7864				}
7865			}
7866
7867			if (*value){
7868				/* New interface , non-NULL SSID add to wl_vifs */
7869				if (!found)
7870					snprintf(buf,sizeof(buf),"%s wl%s.%s",wl_vif_value,unit,subunit);
7871				else
7872				/* Interface present ,non-NULL SSID copy entire vifs string */
7873					snprintf(buf,sizeof(buf),"%s",wl_vif_value);
7874			}else{
7875			/* Purge interface from wl_vifs as the SSID is now NULL */
7876
7877			/* vif present , delete from wl_vifs */
7878				if ((found)){
7879
7880					memset(buf,0,sizeof(buf));
7881
7882					foreach(name,wl_vif_value,next)
7883						/* Copy all interfaces except the one to be removed*/
7884						if (strcmp(name,vif)){
7885							int len;
7886
7887							len = strlen(buf);
7888							if (*buf)
7889								strncat(buf," ",1);
7890							strncat(buf,name,strlen(name));
7891						}
7892				}else
7893					/* Interface absent from wl_vifs, just copy vifs string */
7894					snprintf(buf,sizeof(buf),"%s",wl_vif_value);
7895			}
7896	}else
7897		if (*value) snprintf(buf,sizeof(buf),"wl%s.%s",unit,subunit);
7898
7899	/* Regenerate virtual interface list */
7900	if (*buf)
7901		nvram_set(wl_vif,buf);
7902	else
7903		nvram_unset(wl_vif);
7904
7905
7906	/* Update/clean up wlX.Y_guest flag and wlX.Y_ssid */
7907
7908	snprintf(prefix,sizeof(prefix),"wl%s.%s",unit,subunit);
7909	snprintf(wl_radio,sizeof(wl_radio),"wl_radio");
7910	snprintf(wl_mode,sizeof(wl_mode),"wl_mode");
7911
7912	if (*value){
7913		nvram_set(wl_mode,"ap");
7914#ifdef __CONFIG_WPS__
7915		if (!nvram_match(wl_ssid, value))
7916			ssid_update = 1;
7917#endif
7918		nvram_set(wl_ssid,value);
7919		nvram_set(wl_radio,"1");
7920	}else{
7921		nvram_unset(wl_ssid);
7922		nvram_unset(wl_radio);
7923		nvram_unset(wl_mode);
7924		nvram_unset("wl_bss_enabled");
7925	}
7926
7927	ret_code = 0;
7928}
7929static void
7930validate_name(webs_t wp, char *value, struct variable *v, char *varname )
7931{
7932	ret_code = EINVAL;
7933
7934	assert(v);
7935
7936	if (!valid_name(wp, value, v)) return;
7937
7938	if (varname )
7939		nvram_set(varname,value) ;
7940	else
7941		nvram_set(v->name, value);
7942
7943	ret_code = 0;
7944}
7945
7946static void
7947validate_names(webs_t wp, char *value, struct variable *v, char *varname )
7948{
7949
7950	assert(v);
7951
7952	ret_code = EINVAL;
7953
7954	validate_list(wp, value, v, valid_name, varname);
7955}
7956
7957static void
7958validate_bridge(webs_t wp, char *value, struct variable *v, char *varname )
7959{
7960	char prefix[] = "wlXXXXXXXXXX_";
7961	char *wl_bssid = NULL;
7962	int mode = 0;
7963	char vif[sizeof(prefix)];
7964	char add_br[] = "xxxxxxxxxxxxx_" ;
7965	char del_br[] = "xxxxxxxxxxxxx_" ;
7966#ifdef __CONFIG_GMAC3__
7967	char fwd_wlandevs[NVRAM_MAX_VALUE_LEN];
7968#endif
7969	char name[IFNAMSIZ], *next = NULL;
7970	int need_to_add = 1;
7971	char buf[NVRAM_MAX_VALUE_LEN];
7972	unsigned int len;
7973
7974	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid)))
7975		mode=1;
7976
7977	if(!mode) {
7978		/* primary configuration, , so no choice for bridge ,always at br0 */
7979		ret_code = 0 ;
7980		return ;
7981	}
7982
7983	if (!make_wl_prefix(prefix, sizeof(prefix), mode, NULL)) {
7984		websError(wp, 400, "unit number variable doesn't exist\n");
7985		return ;
7986	}
7987
7988	/* interface name is prefix less the trailing '_' */
7989	strcpy(vif, prefix);
7990	len = strlen(vif);
7991	len--;
7992	vif[len] = 0;
7993
7994	/* add the interface to bridge br1, and delete it from br0 */
7995	if(atoi(value)){
7996		snprintf(add_br, sizeof(add_br), "lan1_ifnames") ;
7997		snprintf(del_br, sizeof(del_br), "lan_ifnames") ;
7998#ifdef __CONFIG_GMAC3__
7999		/* in theory we should have three Network Bridge type "LAN", "Guest" and
8000		 * "Forwarder" in GMAC3 platform, for now we assume all "LAN" wireless
8001		 * interfaces are belong to Forwarder too.  Customer can change the
8002		 * fwd_wlandevs NVRAM to configure a "LAN" virtual interface to bind to
8003		 * sw br0 in order to apply layer 2 filter in sw bridge.  For now our GUI we
8004		 * don't support this of configuration.
8005		 */
8006		/* remove vif from fwd_wlandevs if any */
8007		strncpy(fwd_wlandevs, nvram_safe_get("fwd_wlandevs"), sizeof(fwd_wlandevs)-1);
8008		if (remove_from_list(vif, fwd_wlandevs, sizeof(fwd_wlandevs)) == 0)
8009			nvram_set("fwd_wlandevs", fwd_wlandevs);
8010#endif
8011	}
8012	/* add the interface to bridge br0, and delete it from br1 */
8013	else {
8014		snprintf(add_br, sizeof(add_br), "lan_ifnames") ;
8015		snprintf(del_br, sizeof(del_br), "lan1_ifnames") ;
8016#ifdef __CONFIG_GMAC3__
8017		/* add vif to fwd_wlandevs. */
8018		strncpy(fwd_wlandevs, nvram_safe_get("fwd_wlandevs"), sizeof(fwd_wlandevs)-1);
8019		if (!find_in_list(fwd_wlandevs, vif) &&
8020		    add_to_list(vif, fwd_wlandevs, sizeof(fwd_wlandevs)-1) == 0)
8021			nvram_set("fwd_wlandevs", fwd_wlandevs);
8022#endif
8023	}
8024
8025	memset(buf,0,sizeof(buf));
8026	/* Copy all the interfaces except the the one we want to remove*/
8027	foreach(name, nvram_get(del_br),next) {
8028		if (strcmp(name,vif)){
8029			int len;
8030			len = strlen(buf);
8031			if (*buf)
8032				strncat(buf," ",1);
8033			strncat(buf,name,strlen(name));
8034		}
8035	}
8036	nvram_set(del_br, buf);
8037	memset(buf,0,sizeof(buf));
8038	strncpy(buf, nvram_get(add_br),sizeof(buf) - 1);
8039	foreach(name, buf, next) {
8040		if (!strcmp(name,vif)){
8041			need_to_add = 0;
8042			break;
8043		}
8044	}
8045
8046	if (need_to_add) {
8047		/* the first entry ? */
8048		if (*buf)
8049			strncat(buf," ",1);
8050		strncat(buf, vif, strlen(vif));
8051	}
8052
8053	nvram_set(add_br, buf);
8054
8055	ret_code = 0;
8056}
8057static void
8058validate_ssid(webs_t wp, char *value, struct variable *v, char *varname )
8059{
8060	char *wl_bssid = NULL;
8061
8062	ret_code = EINVAL ;
8063
8064	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid))){
8065		v->argv[0] = wl_bssid;
8066		validate_vif_ssid(wp, value, v,varname);
8067	}
8068	else {
8069#ifdef __CONFIG_WPS__
8070		char *name;
8071		if (!valid_name(wp, value, v))
8072			return;
8073		if (varname)
8074			name = varname;
8075		else
8076			name = v->name;
8077
8078		if (!nvram_match(name, value))
8079			ssid_update = 1;
8080#endif
8081		validate_name(wp, value, v, varname);
8082	}
8083#ifdef __CONFIG_WPS__
8084	if (ssid_update) {
8085		wps_disable_oob();
8086		ssid_update = 0;
8087	}
8088#endif
8089	ret_code = 0;
8090}
8091
8092static void
8093validate_wl_closed(webs_t wp, char *value, struct variable *v, char *varname )
8094{
8095	validate_choice(wp, value, v, varname);
8096
8097#ifdef __CONFIG_WPS__
8098	if (ret_code == 0 && strcmp(value, "1" /* Closed */) == 0) {
8099		char *wl_wps_mode = NULL;
8100
8101		/* Disabled WPS if it is enabled */
8102		wl_wps_mode = nvram_get("wl_wps_mode");
8103		if (strcmp(wl_wps_mode, "enabled") == 0)
8104			nvram_set("wl_wps_mode", "disabled");
8105	}
8106#endif /* __CONFIG_WPS__ */
8107}
8108
8109static void
8110validate_wl_macmode(webs_t wp, char *value, struct variable *v, char *varname )
8111{
8112	validate_choice(wp, value, v, varname);
8113
8114#ifdef __CONFIG_WPS__
8115	if (ret_code == 0 && strcmp(value, "allow") == 0) {
8116		int i;
8117		char *wl_wps_mode = NULL;
8118		char wl_maclist[] = "wl_maclistxxx";
8119		char *wl_mac;
8120		unsigned char hwaddr[6];
8121
8122		/* Disabled WPS if it is enabled */
8123		wl_wps_mode = nvram_get("wl_wps_mode");
8124		if (strcmp(wl_wps_mode, "enabled") == 0) {
8125			for (i = 0; i < MACLIST_MAX_NUM; i++) {
8126				sprintf(wl_maclist, "wl_maclist%d", i);
8127				wl_mac = websGetVar(wp, wl_maclist, "");
8128				/* a legal non-empty mac check */
8129				if (strlen(wl_mac) && ether_atoe(wl_mac, hwaddr) &&
8130				    !(hwaddr[0] & 1) &&
8131				    (hwaddr[0] & hwaddr[1] & hwaddr[2] & hwaddr[3] & hwaddr[4] & hwaddr[5]) != 0xff &&
8132				    (hwaddr[0] | hwaddr[1] | hwaddr[2] | hwaddr[3] | hwaddr[4] | hwaddr[5]) != 0x00)
8133					break;
8134			}
8135			/* All maclist are empty */
8136			if (i == MACLIST_MAX_NUM) {
8137				nvram_set("wl_wps_mode", "disabled");
8138				websBufferWrite(wp, "Selecting <b>allow</b> with <b>empty</b> "
8139					"MAC Address will disable the WPS.<br>");
8140			}
8141		}
8142	}
8143#endif /* __CONFIG_WPS__ */
8144}
8145
8146#ifdef __CONFIG_WPS__
8147#ifdef WFA_WPS_20_TESTBED
8148static void
8149validate_wps2_range(webs_t wp, char *value, struct variable *v , char *varname)
8150{
8151	int n;
8152
8153	assert(v);
8154
8155	ret_code = EINVAL;
8156
8157	/* 0 is mean unset it */
8158	n = atoi(value);
8159	if (n == 0) {
8160		if (varname )
8161			nvram_unset(varname) ;
8162		else
8163			nvram_unset(v->name);
8164
8165		ret_code = 0;
8166		return;
8167	}
8168
8169	if (!valid_range(wp, value, v)) return ;
8170
8171	if (varname )
8172		nvram_set(varname, value) ;
8173	else
8174		nvram_set(v->name, value);
8175
8176	ret_code = 0;
8177}
8178#endif /* WFA_WPS_20_TESTBED */
8179
8180static void
8181validate_wps_reg(webs_t wp, char *value, struct variable *v, char *varname)
8182{
8183	char *temp = NULL;
8184	char tmp[NVRAM_BUFSIZE];
8185	int lan_idx;
8186
8187	if((temp = websGetVar(wp, "wps_reg", NULL))) {
8188		if(*temp) {
8189			/* set lanx_wps_reg according to wl_unit */
8190			lan_idx = wps_get_lan_idx();
8191
8192			if (lan_idx == 0)
8193				snprintf(tmp, sizeof(tmp), "lan_wps_reg");
8194			else
8195				snprintf(tmp, sizeof(tmp), "lan%d_wps_reg", lan_idx);
8196
8197			if (!strcmp(value,"enabled"))
8198				nvram_set(tmp, "enabled"); /* Built-in Reg */
8199			else
8200				nvram_set(tmp, "disabled");
8201
8202			ret_code = 0;
8203			return;
8204		}
8205	}
8206
8207	websError(wp, 400, "Insufficient args\n");
8208	ret_code = EINVAL;
8209	return;
8210}
8211
8212static void
8213validate_wps_oob(webs_t wp, char *value, struct variable *v, char *varname)
8214{
8215	char tmp[NVRAM_BUFSIZE];
8216
8217	ret_code = 0;
8218	if(wps_get_oob_name(tmp, NVRAM_BUFSIZE) != 0)
8219		return;
8220
8221	if (!strcmp(value, "enabled")) {
8222		nvram_set(tmp, "enabled"); /* OOB (Unconfigued) */
8223	}
8224	else
8225		nvram_set(tmp, "disabled"); /* Configured */
8226	return;
8227}
8228
8229static void
8230validate_wps_mode(webs_t wp, char *value, struct variable *v, char *varname)
8231{
8232	char *auth = NULL, *crypto = NULL, *wep = NULL;
8233	char *wpa = NULL, *psk = NULL;
8234	char *wpa2 = NULL, *psk2 = NULL;
8235	char *vname = NULL;
8236	bool b_wps_version2 = FALSE;
8237
8238	int i;
8239	char *wl_mac, wl_maclist[] = "wl_maclistxxx";
8240	unsigned char hwaddr[6];
8241
8242
8243	assert(v);
8244
8245	ret_code = EINVAL;
8246
8247	if (varname)
8248		vname = varname;
8249	else
8250		vname = v->name;
8251
8252	/* WSC 2.0,  support WPS V2 or not */
8253	if (strcmp(nvram_safe_get("wps_version2"), "enabled") == 0)
8254		b_wps_version2 = TRUE;
8255
8256	/* Do not check AKM and Crypto in OOB */
8257
8258	/* Do AKM and Crypto checking when WPS enabled */
8259	if (!strcmp(value, "enabled")) {
8260		if (b_wps_version2) {
8261			/* Check Auth, deprecated "Shared" mode */
8262			if((auth = websGetVar(wp, "wl_auth", NULL)) && (strcmp(auth, "1") == 0)) {
8263				websBufferWrite(wp, "WPS does not support <b>Shared</b> "
8264					"authentication<br><b>Force to disable WPS</b><br>");
8265				goto invalid;
8266			}
8267
8268			/* Get WEP */
8269			wep = websGetVar(wp, "wl_wep", NULL);
8270
8271			/*
8272			 * WiFi WPA2 requires that WEP be disabled if WPA2 or WPA2-PSK is used,
8273			 * GUI has the WEP Enable/Disable field disabled when the user selects
8274			 * WPA2, so WEP setting doesn't come in the HTTP buffer, which means we
8275			 * must manually turn it off here to disable WEP.
8276			 *
8277			 * According above description and WSC 2.0 only allowed WPA2, WPA2-PSK
8278			 * and WPA-PSK+WPA2-PSK(mix mode). Here WEP is allowed only when
8279			 * wep_survival back door enabled and akm is empty.
8280			 */
8281		 	 /*
8282			 * WSC 2.0, Authentication type check.
8283			 * Allowed type : Open, WPA2, WPA2-PSK and WPA-PSK+WPA2-PSK(Mix mode)
8284			 * Deprecated type: Shared, WPA and WPS-PSK only
8285			 */
8286			/* Check AKM and Crypto */
8287			if ((wpa = websGetVar(wp, "wl_akm_wpa", NULL)) == NULL)
8288				wpa = "disabled";
8289			if ((psk = websGetVar(wp, "wl_akm_psk", NULL)) == NULL)
8290				psk = "disabled";
8291			if ((wpa2 = websGetVar(wp, "wl_akm_wpa2", NULL)) == NULL)
8292				wpa2 = "disabled";
8293			if ((psk2 = websGetVar(wp, "wl_akm_psk2", NULL)) == NULL)
8294				psk2 = "disabled";
8295
8296			if (!strcmp(wpa, "enabled") || !strcmp(psk, "enabled")
8297			    || !strcmp(wpa2, "enabled") || !strcmp(psk2, "enabled")
8298			    ) {
8299			    	/* AKM enabled */
8300				/*
8301				 * For now, Broadcom WPS does not support WPA and WPA2.
8302				 * We support WPA2-PSK and WPA2PSK+WPA-PSK
8303				 */
8304				/* Check AKM. BCMWPA2 MUST enabled */
8305				if (strcmp(psk2, "enabled") != 0) {
8306					websBufferWrite(wp, "WPS only support <b>WPA2-PSK or "
8307						"WPA2-PSK+WPA-PSK mixed mode</b> authentication "
8308						"key management<br>"
8309						"<b>Force to disable WPS</b><br>");
8310					goto invalid;
8311				}
8312
8313				/*
8314				 * WSC 2.0, Encryption type check.
8315				 * Allowed type : None, AES and TKIP+AES(Mix mode)
8316				 * Deprecated type: Wep and TKIP only
8317				 *
8318				 * Note: A back door to keep supporting WEP by seting
8319				 * NVRAM "wps_wep_survival"
8320				 */
8321			    	crypto = websGetVar(wp, "wl_crypto", NULL);
8322				if (!crypto || (
8323				    strcmp(crypto, "tkip") &&
8324				    strcmp(crypto, "aes") &&
8325				    strcmp(crypto, "tkip+aes"))) {
8326					websBufferWrite(wp, "<b>Crypto Algorithm</b> mode must be"
8327						" TKIP or AES or TKIP+AES<br>"
8328						"<b>Force to disable WPS</b><br>");
8329					goto invalid;
8330				} else if (strcmp(crypto, "tkip") == 0) {
8331					websBufferWrite(wp, "WPS does not support <b>TKIP</b> only "
8332						"crypto algorithm<br><b>Force to disable WPS</b>"
8333						"<br>");
8334					goto invalid;
8335				}
8336			}
8337			else {
8338				/* AKM Disabled */
8339				/* Check WEP */
8340				if (wep && strcmp(wep, "enabled") == 0) {
8341					websBufferWrite(wp, "WPS does not support <b>WEP</b> crypto "
8342						"algorithm<br><b>Force to disable WPS</b><br>");
8343					goto invalid;
8344				}
8345
8346			}
8347		}
8348
8349		/* Set wl_wps_mode */
8350		nvram_set(vname, "enabled");
8351
8352		/* WSC 2.0, Set SSID Network Type to Open */
8353		if (nvram_invmatch("wl_closed", "0")) {
8354			websBufferWrite(wp, "<br>Enable WPS will change the SSID "
8355				"<b>Network Type to Open</b><br>");
8356			nvram_set("wl_closed", "0");
8357		}
8358
8359		/* WSC 2.0, MAC filter check */
8360		if (nvram_match("wl_macmode", "allow")) {
8361			for (i = 0; i < MACLIST_MAX_NUM; i++) {
8362				sprintf(wl_maclist, "wl_maclist%d", i);
8363				wl_mac = nvram_get(wl_maclist);
8364				/* a legal non-empty mac check */
8365				if (wl_mac && strlen(wl_mac) && ether_atoe(wl_mac, hwaddr) &&
8366				    !(hwaddr[0] & 1) &&
8367				    (hwaddr[0] & hwaddr[1] & hwaddr[2] & hwaddr[3] & hwaddr[4] & hwaddr[5]) != 0xff &&
8368				    (hwaddr[0] | hwaddr[1] | hwaddr[2] | hwaddr[3] | hwaddr[4] | hwaddr[5]) != 0x00)
8369					break;
8370			}
8371			/* All maclist are empty */
8372			if (i == MACLIST_MAX_NUM) {
8373				websBufferWrite(wp, "Enable WPS will <b>Disabled MAC Restrict Mode</b><br>");
8374				nvram_set("wl_macmode", "disabled");
8375			}
8376		}
8377	}
8378	else if (!strcmp(value, "enr_enabled")) {
8379		nvram_set(vname, "enr_enabled");
8380	}
8381	else {
8382		nvram_set(vname, "disabled");
8383	}
8384
8385	ret_code = 0;
8386	return;
8387
8388invalid:
8389	/* Force disable WPS */
8390	nvram_set(vname, "disabled");
8391
8392	return;
8393}
8394#endif /* __CONFIG_WPS__ */
8395
8396static char *get_ifname (webs_t wp)
8397{
8398	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
8399	if (!make_wl_prefix(prefix,sizeof(prefix),0,NULL)){
8400		websError(wp, 400, "unit number variable doesn't exist<br>");
8401		return NULL;
8402	}
8403	return (nvram_safe_get(strcat_r(prefix, "ifname", tmp)));
8404}
8405
8406static void
8407validate_wl_chanspec(webs_t wp, char *value, struct variable *v, char *varname)
8408{
8409	/* chanspec "N/A" are set to 0 (Auto) */
8410	nvram_set(v->name, !strcmp("N/A", value) ? "0" : value);
8411	ret_code = 0;
8412}
8413
8414static void
8415validate_wl_country_code(webs_t wp, char *value, struct variable *v, char *varname)
8416{
8417	wl_country_t country_spec = {{0}, 0, {0}};
8418	ret_code = EINVAL;
8419	char *name=NULL;
8420	char *rev=NULL;
8421
8422	assert(v);
8423
8424	name = get_ifname(wp);
8425
8426	rev = websGetVar(wp, "wl_country_rev", NULL);
8427	country_spec.rev = atoi(rev);
8428	sprintf( country_spec.ccode, "%s", value );
8429	sprintf( country_spec.country_abbrev, "%s", value );
8430	if (wl_iovar_set(name, "country", &country_spec, sizeof(country_spec))){
8431		websError(wp, 400, "<br><b>ERROR:</b>Country");
8432		return;
8433	}
8434	nvram_set( v->name, value);
8435	ret_code = 0;
8436}
8437
8438static void
8439validate_wl_country_rev(webs_t wp, char *value, struct variable *v, char *varname)
8440{
8441	wl_country_t country_spec = {{0}, 0, {0}};
8442	ret_code = EINVAL;
8443	char *name=NULL;
8444	char *country=NULL;
8445
8446	assert(v);
8447
8448	name = get_ifname(wp);
8449	country = websGetVar(wp, "wl_country_code", NULL);
8450	country_spec.rev = atoi(value);
8451	sprintf( country_spec.ccode, "%s", country );
8452	sprintf( country_spec.country_abbrev, "%s", country );
8453	if (wl_iovar_set(name, "country", &country_spec, sizeof(country_spec))){
8454		websError(wp, 400, "/Regulatory revision doesn't exist<br>");
8455		return;
8456	}
8457	nvram_set( v->name, value);
8458	ret_code = 0;
8459}
8460
8461static void
8462validate_ure(webs_t wp, char *value, struct variable *v, char *varname)
8463{
8464	char *temp=NULL;
8465	int wl_unit = -1;
8466	int wl_subunit = -1;
8467	int wl_ure = -1;
8468	int ii = 0;
8469	char nv_param[NVRAM_MAX_PARAM_LEN];
8470	char nv_interface[NVRAM_MAX_PARAM_LEN];
8471	char os_interface[NVRAM_MAX_PARAM_LEN];
8472	char interface_list[NVRAM_MAX_VALUE_LEN];
8473	int interface_list_size = sizeof(interface_list);
8474	char *wan0_ifname = "wan0_ifname";
8475	char *lan_ifnames = "lan_ifnames";
8476	char *wan_ifnames = "wan_ifnames";
8477	int travel_router = 0;
8478	char cap[WLC_IOCTL_SMLEN];
8479	char caps[WLC_IOCTL_MEDLEN];
8480	char *name = NULL;
8481	char *next = NULL;
8482	int max_no_vifs = 0;
8483	int i = 0;
8484	char tmp[20];
8485
8486	if ((temp = websGetVar(wp, "wl_unit", NULL)))
8487	{
8488		if( *temp ) {
8489			if (get_ifname_unit( temp, &wl_unit, &wl_subunit ) != 0) {
8490				websError(wp, 400, "URE error getting wl_unit\n");
8491				ret_code = EINVAL;
8492				return;
8493			}
8494		}
8495
8496		if( wl_subunit != -1 )
8497		{
8498			websError(wp, 400, "URE can't be enabled for a virtual I/F\n");
8499			ret_code = EINVAL;
8500			return;
8501		}
8502	}
8503
8504	if((temp = websGetVar(wp, "wl_ure", NULL)))
8505	{
8506		if( *temp )
8507			wl_ure = atoi( temp );
8508	}
8509
8510	if( wl_ure < 0 || wl_unit < 0 )
8511	{
8512		websError(wp, 400, "Insufficient args\n");
8513		ret_code = EINVAL;
8514		return;
8515	}
8516
8517	if ( nvram_match( "router_disable", "1" ) && wl_ure == 1 )
8518		travel_router = 0;
8519	else
8520		travel_router = 1;
8521
8522	/* Get the No of VIFS */
8523	sprintf( nv_interface, "wl%d_ifname", wl_unit );
8524	name = nvram_safe_get(nv_interface);
8525	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
8526		return;
8527	foreach(cap, caps, next) {
8528		if (!strcmp(cap, "mbss16"))
8529			max_no_vifs = 16;
8530		else if (!strcmp(cap, "mbss8"))
8531			max_no_vifs = 8;
8532		else if (!strcmp(cap, "mbss4"))
8533			max_no_vifs = 4;
8534	}
8535
8536	if( wl_ure == 1 )
8537	{
8538		/* turning on URE*/
8539
8540		/* If TR, we can only allow a single TR interface */
8541		for( ii = 0; ii < DEV_NUMIFS; ii++ ) {
8542			if( ii == wl_unit )
8543				continue;
8544
8545			sprintf( nv_param, "wl%d_ure", ii );
8546			temp = nvram_safe_get( nv_param );
8547			if( temp && strlen( temp ) > 0 )
8548			{
8549				if( atoi( temp ) == 1 ) {
8550					websError(wp, 400, "Can not have more than one URE interface\n");
8551					ret_code = EINVAL;
8552					return;
8553				}
8554			}
8555		}
8556
8557		sprintf( nv_param, "wl_ure" );
8558		temp = nvram_safe_get( nv_param );
8559		if( strncmp( temp, "0", 1 ) == 0 || strlen( temp ) == 0 )
8560		{
8561			action = REBOOT;
8562		}
8563		else {
8564			/* nothing to do, bail out now */
8565			return;
8566		}
8567 		/* turn URE on for this primary interface */
8568		nvram_set( nv_param, "1" );
8569
8570		nvram_set( "ure_disable", "0" );
8571
8572		/* Set the wl modes for the primary wireless adapter and it's
8573			 virtual interface */
8574		sprintf( nv_param, "wl%d_mode", wl_unit );
8575		if( travel_router == 1 ) {
8576		nvram_set( nv_param, "sta" );
8577		nvram_set( "wl_mode", "sta" );
8578		}
8579		else {
8580			nvram_set( nv_param, "wet" );
8581			nvram_set( "wl_mode", "wet" );
8582		}
8583
8584		sprintf( nv_param, "wl%d.1_mode", wl_unit );
8585		nvram_set( nv_param, "ap" );
8586
8587		if( travel_router == 1 ) {
8588			/* For URE with routing(Travel Router)we're using the STA part of our
8589				 URE enabled radio as our WAN connection.  So, we need to remove this
8590				 interface from the list of bridged lan interfaces and set it up as
8591				 the WAN device.
8592			*/
8593			temp = nvram_safe_get(lan_ifnames);
8594			if( interface_list_size <= strlen( temp ) )
8595			{
8596				websError(wp, 400, "string too long\n");
8597				ret_code = 1;
8598				return;
8599			}
8600			strncpy( interface_list, temp, interface_list_size );
8601			/* this may be confusing, right now the interface name that is stored
8602				 in the nvram lists is OS specific.  For linux it's an "ethX" for
8603				 wireless interfaces and for VxWorks "wlX" is stored as "wlX" so
8604				 this is trying to make OS independant code */
8605			sprintf( nv_interface, "wl%d", wl_unit );
8606			nvifname_to_osifname( nv_interface, os_interface, sizeof(os_interface) );
8607			remove_from_list( os_interface, interface_list, interface_list_size );
8608			nvram_set( lan_ifnames, interface_list );
8609
8610			/* Now remove the existing WAN interface from "wan_ifnames" */
8611			temp = nvram_safe_get( wan_ifnames );
8612			if( interface_list_size <= (strlen( temp ) + strlen( interface_list )) )
8613			{
8614				websError(wp, 400, "string too long\n");
8615				ret_code = 1;
8616				return;
8617			}
8618			strncpy( interface_list, temp, interface_list_size );
8619			temp = nvram_safe_get( wan0_ifname );
8620			if( strlen( temp ) != 0 )
8621			{
8622				/* stash this interface name in an nvram variable so
8623					 we can restore this interface as the WAN interface when URE
8624					 is disabled. */
8625				nvram_set( "old_wan0_ifname", temp );
8626				remove_from_list( temp, interface_list, interface_list_size );
8627			}
8628
8629			/* set the new WAN interface as the pimary WAN interface and add to
8630				 the list wan_ifnames */
8631			nvram_set( wan0_ifname, os_interface );
8632			add_to_list( os_interface, interface_list, interface_list_size );
8633			nvram_set( wan_ifnames, interface_list );
8634
8635			/* now add the AP to the list of bridged lan interfaces */
8636			temp = nvram_safe_get(lan_ifnames);
8637			if( interface_list_size <= strlen( temp ) )
8638			{
8639				websError(wp, 400, "string too long\n");
8640				ret_code = 1;
8641				return;
8642			}
8643			strncpy( interface_list, temp, interface_list_size );
8644			sprintf( nv_interface, "wl%d.1", wl_unit );
8645			/* virtual interfaces that appear in NVRAM lists are ALWAYS stored
8646				 as the NVRAM_FORM so we can add to list without translating */
8647			if( add_to_list( nv_interface, interface_list, interface_list_size ) !=
8648					0 )
8649		{
8650			websError(wp, 400, "Failed to add AP interface to lan_ifnames\n");
8651			ret_code = 1;
8652			return;
8653		}
8654		nvram_set( lan_ifnames, interface_list );
8655
8656		}
8657		else {
8658			/* For URE without routing(Range Extender) we're using the STA
8659				 as a WET device to connect to the "upstream" AP.  We need to
8660				 add our virtual interface(AP) to the bridged lan */
8661			temp = nvram_safe_get(lan_ifnames);
8662			if( interface_list_size <= strlen( temp ) )
8663			{
8664				websError(wp, 400, "string too long\n");
8665				ret_code = 1;
8666				return;
8667			}
8668			strncpy( interface_list, temp, interface_list_size );
8669
8670			sprintf( nv_interface, "wl%d.1", wl_unit );
8671			add_to_list( nv_interface, interface_list, interface_list_size );
8672			nvram_set( lan_ifnames, interface_list );
8673
8674		}
8675
8676		/* Security - We don't support any RADIUS-based authentication, so
8677			 we must force these options to OFF */
8678		/* turn off wlX_auth_mode and wlX.1_auth_mode */
8679		sprintf( nv_param, "wl%d_auth_mode", wl_unit );
8680		nvram_set( nv_param, "none" );
8681		sprintf( nv_param, "wl%d.1_auth_mode", wl_unit );
8682		nvram_set( nv_param, "none" );
8683		/* remove wpa and wpa2 from wlX_akm and wlX.1_akm */
8684		/* wl_akm should be used here rather than wlX_akm, it's an
8685			 indexed param, so wl_akm represents wlX_akm */
8686		sprintf( nv_param, "wl_akm" );
8687		temp = nvram_get( nv_param );
8688		if( temp && *temp )
8689		{
8690			memset( interface_list, 0, interface_list_size );
8691			/* NOTE: using "interface_list" to hold security nvram values */
8692			strncpy( interface_list, temp, interface_list_size - 1 );
8693			remove_from_list("wpa", interface_list, interface_list_size );
8694			remove_from_list("wpa2", interface_list, interface_list_size );
8695			nvram_set( nv_param, interface_list );
8696		}
8697		sprintf( nv_param, "wl%d.1_akm", wl_unit );
8698		temp = nvram_get( nv_param );
8699		if( temp && *temp )
8700		{
8701			memset( interface_list, 0, interface_list_size );
8702			/* NOTE: using "interface_list" to hold security nvram values */
8703			strncpy( interface_list, temp, interface_list_size - 1 );
8704			remove_from_list("wpa", interface_list, interface_list_size );
8705			remove_from_list("wpa2", interface_list, interface_list_size );
8706			nvram_set( nv_param, interface_list );
8707		}
8708
8709		/* Make lan1_ifname lan1_ifnames empty sothat br1 is not created in URE mode. */
8710		/* Disable all VIFS wlX.2 onwards */
8711	        nvram_set("lan1_ifname", "" );
8712	        nvram_set("lan1_ifnames", "" );
8713		if(wl_unit)
8714			nvram_set("wl0.1_bss_enabled", "0");
8715		else
8716			nvram_set("wl1.1_bss_enabled", "0");
8717		for (i=2; i<max_no_vifs; i++) {
8718			sprintf( nv_interface, "wl0.%d_bss_enabled", i );
8719			nvram_set(nv_interface, "0");
8720			sprintf( nv_interface, "wl1.%d_bss_enabled", i );
8721			nvram_set(nv_interface, "0");
8722		}
8723
8724	}
8725	else
8726	{
8727		sprintf( nv_param, "wl_ure");
8728		temp = nvram_get( nv_param );
8729		if( strncmp( temp, "1", 1 ) != 0 ) {
8730			/* nothing to do, bail out now */
8731			return;
8732		}
8733		nvram_set( nv_param, "0" );
8734
8735		nvram_set( "ure_disable", "1" );
8736
8737		/* Restore default WAN interface */
8738
8739		/* Now remove the existing WAN interface from "wan_ifnames" */
8740		temp = nvram_safe_get( wan_ifnames );
8741		if( interface_list_size <= (strlen( temp ) + strlen( interface_list )) )
8742		{
8743			websError(wp, 400, "string too long\n");
8744			ret_code = 1;
8745			return;
8746		}
8747		strncpy( interface_list, temp, interface_list_size );
8748		temp = nvram_safe_get( wan0_ifname );
8749		if( strlen( temp ) != 0 )
8750		{
8751			remove_from_list( temp, interface_list, interface_list_size );
8752		}
8753
8754		/* set the default WAN interface as the pimary WAN interface and add to
8755		   the list wan_ifnames */
8756		temp = nvram_get( "old_wan0_ifname" );
8757
8758		if( temp && *temp )
8759			strcpy( os_interface, temp );
8760		else /* best guess */
8761		strcpy( os_interface, "eth1" );
8762		nvram_set( wan0_ifname, os_interface );
8763		add_to_list( os_interface, interface_list, interface_list_size );
8764		nvram_set( wan_ifnames, interface_list );
8765
8766		/* Now we need to remove the virtual I/F from the bridged lan interfaces */
8767		temp = nvram_safe_get(lan_ifnames);
8768		if( interface_list_size <= strlen( temp ) )
8769		{
8770			websError(wp, 400, "string too long\n");
8771			ret_code = 1;
8772			return;
8773		}
8774		strncpy( interface_list, temp, interface_list_size );
8775		sprintf( nv_interface, "wl%d.1", wl_unit );
8776		/* virtual interfaces that appear in NVRAM lists are ALWAYS stored
8777			 as the NVRAM_FORM so we can add to list without translating */
8778		remove_from_list( nv_interface, interface_list, interface_list_size );
8779		/* Add our primary interface to lan_ifnames - default behavior */
8780		sprintf( nv_interface, "wl%d", wl_unit );
8781		nvifname_to_osifname( nv_interface, os_interface, sizeof(os_interface) );
8782		add_to_list( os_interface, interface_list, interface_list_size );
8783		nvram_set( lan_ifnames, interface_list );
8784
8785		/* Make lan1_ifname, lan1_ifnames to default values */
8786	        nvram_set("lan1_ifname", "br1" );
8787		memset( interface_list, 0, interface_list_size );
8788		for (i=1; i<max_no_vifs; i++) {
8789			sprintf( nv_interface, "wl0.%d", i );
8790			add_to_list(nv_interface, interface_list, interface_list_size );
8791			nvram_set(strcat_r(nv_interface, "_hwaddr",tmp),"");
8792			sprintf( nv_interface, "wl1.%d", i );
8793			add_to_list(nv_interface, interface_list, interface_list_size );
8794			nvram_set(strcat_r(nv_interface, "_hwaddr",tmp),"");
8795		}
8796	       	nvram_set("lan1_ifnames", interface_list );
8797
8798	}
8799	action = REBOOT;
8800
8801	/* We're unsetting the WAN hardware address so that we get the correct
8802		 address for the new WAN interface the next time we boot. */
8803	nvram_unset( "wan0_hwaddr" );
8804
8805	ret_code = 0;
8806	return;
8807}
8808
8809static int
8810valid_hwaddr(webs_t wp, char *value, struct variable *v)
8811{
8812	unsigned char hwaddr[6];
8813
8814	assert(v);
8815
8816	/* Make exception for "NOT IMPLELEMENTED" string */
8817	if (!strcmp(value,"NOT_IMPLEMENTED"))
8818		return(TRUE);
8819
8820	/* Check for bad, multicast, broadcast, or null address */
8821	if (!ether_atoe(value, hwaddr) ||
8822	    (hwaddr[0] & 1) ||
8823	    (hwaddr[0] & hwaddr[1] & hwaddr[2] & hwaddr[3] & hwaddr[4] & hwaddr[5]) == 0xff ||
8824	    (hwaddr[0] | hwaddr[1] | hwaddr[2] | hwaddr[3] | hwaddr[4] | hwaddr[5]) == 0x00) {
8825		websBufferWrite(wp, "Invalid <b>%s</b> %s: not a MAC address<br>",
8826			  v->longname, value);
8827		return FALSE;
8828	}
8829
8830	return TRUE;
8831}
8832
8833static void
8834validate_hwaddr(webs_t wp, char *value, struct variable *v, char *varname )
8835{
8836
8837	ret_code = EINVAL;
8838
8839	if (!valid_hwaddr(wp, value, v)) return;
8840
8841	if(varname )
8842		nvram_set(varname,value);
8843	else
8844		nvram_set(v->name, value);
8845
8846	ret_code = 0;
8847
8848
8849}
8850
8851static void
8852validate_hwaddrs(webs_t wp, char *value, struct variable *v, char *varname )
8853{
8854
8855	assert(v);
8856
8857	ret_code = EINVAL;
8858	validate_list(wp, value, v, valid_hwaddr, varname);
8859}
8860
8861static void
8862validate_dhcp(webs_t wp, char *value, struct variable *v, char *varname)
8863{
8864	struct variable dhcp_variables[] = {
8865		{ longname: "DHCP Server Starting LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
8866		{ longname: "DHCP Server Ending LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
8867	};
8868	char *start=NULL, *end=NULL;
8869	char dhcp_start[20]="dhcp_start";
8870	char dhcp_end[20]="dhcp_start";
8871	char lan_proto[20]="lan_proto";
8872	char lan_ipaddr[20]="lan_ipaddr";
8873	char lan_netmask[20]= "lan_netmask";
8874	char *dhcp0_argv[3],*dhcp1_argv[3];
8875	char index[5];
8876
8877	assert(v);
8878
8879	ret_code = EINVAL;
8880
8881	memset(index,0,sizeof(index));
8882	/* fixup the nvram varnames if varname override is provided */
8883	if (varname){
8884		if (!get_index_string(v->prefix,
8885			varname,index,sizeof(index)))
8886				return;
8887
8888		snprintf(dhcp_start,sizeof(dhcp_start),"dhcp%s_start",index);
8889		snprintf(dhcp_end,sizeof(dhcp_end),"dhcp%s_end",index);
8890		snprintf(lan_proto,sizeof(lan_proto),"lan%s_proto",index);
8891		snprintf(lan_ipaddr,sizeof(lan_ipaddr),"lan%s_ipaddr",index);
8892		snprintf(lan_netmask,sizeof(lan_netmask),"lan%s_netmask",index);
8893		dhcp0_argv[0]=lan_ipaddr;
8894		dhcp0_argv[1]=lan_netmask;
8895		dhcp0_argv[2]=NULL;
8896		dhcp1_argv[0]=lan_ipaddr;
8897		dhcp1_argv[1]=lan_netmask;
8898		dhcp1_argv[2]=NULL;
8899		dhcp_variables[0].argv = dhcp0_argv;
8900		dhcp_variables[1].argv = dhcp1_argv;
8901	}
8902
8903	if (!(start = websGetVar(wp, dhcp_start, NULL)) ||
8904	    !(end = websGetVar(wp, dhcp_end, NULL)))
8905		return;
8906	if (!*start) start = end;
8907	if (!*end) end = start;
8908	if (!*start && !*end && !strcmp(nvram_safe_get(lan_proto), "dhcp")) {
8909		websBufferWrite(wp, "Invalid <b>%s</b>: must specify a range<br>", v->longname);
8910		return;
8911	}
8912	if (!valid_ipaddr(wp, start, &dhcp_variables[0]) ||
8913	    !valid_ipaddr(wp, end, &dhcp_variables[1]))
8914		return;
8915	if (ntohl(inet_addr(start)) > ntohl(inet_addr(end))) {
8916		websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
8917			  dhcp_variables[0].longname, start, dhcp_variables[1].longname, end);
8918		return;
8919	}
8920
8921	nvram_set(dhcp_start, start);
8922	nvram_set(dhcp_end, end);
8923
8924	ret_code = 0;
8925}
8926
8927static void
8928validate_lan_ipaddr(webs_t wp, char *value, struct variable *v, char *varname)
8929{
8930	struct variable fields[] = {
8931		{ name: "lan_ipaddr", longname: "LAN IP Address" },
8932		{ name: "lan_netmask", longname: "LAN Subnet Mask" },
8933	};
8934	char *lan_ipaddr=NULL, *lan_netmask=NULL;
8935	char tmp_ipaddr[20], tmp_netmask[20];
8936	struct in_addr ipaddr, netmask, netaddr, broadaddr;
8937	char lan_ipaddrs[][20] = { "dhcp_start", "dhcp_end", "dmz_ipaddr" };
8938#ifdef __CONFIG_NAT__
8939	netconf_filter_t start, end;
8940#ifdef __CONFIG_URLFILTER__
8941	netconf_urlfilter_t url_start, url_end;
8942#endif /* __CONFIG_URLFILTER__ */
8943	netconf_nat_t nat;
8944	bool valid;
8945#endif	/* __CONFIG_NAT__ */
8946	int i;
8947
8948	assert(v);
8949
8950	ret_code = EINVAL;
8951
8952	/* Insert name overrides */
8953	if (varname)
8954	{
8955		char index[5];
8956
8957		if (!get_index_string(v->prefix,
8958			varname,index,sizeof(index)))
8959				return ;
8960
8961		snprintf(tmp_ipaddr,sizeof(tmp_ipaddr),"lan%s_ipaddr",index);
8962		snprintf(tmp_netmask,sizeof(tmp_netmask),"lan%s_netmask",index);
8963		fields[0].name = tmp_ipaddr;
8964		fields[1].name = tmp_netmask;
8965		snprintf(lan_ipaddrs[0],sizeof(lan_ipaddrs[0]),"dhcp%s_start",index);
8966		snprintf(lan_ipaddrs[1],sizeof(lan_ipaddrs[1]),"dhcp%s_end",index);
8967	}
8968	/* Basic validation */
8969	if (!(lan_ipaddr = websGetVar(wp, fields[0].name, NULL)) ||
8970	    !(lan_netmask = websGetVar(wp, fields[1].name, NULL)) ||
8971	    !valid_ipaddr(wp, lan_ipaddr, &fields[0]) ||
8972	    !valid_ipaddr(wp, lan_netmask, &fields[1]))
8973		return;
8974
8975	/* Check for broadcast or network address */
8976	(void) inet_aton(lan_ipaddr, &ipaddr);
8977	(void) inet_aton(lan_netmask, &netmask);
8978	netaddr.s_addr = ipaddr.s_addr & netmask.s_addr;
8979	broadaddr.s_addr = netaddr.s_addr | ~netmask.s_addr;
8980	if (ipaddr.s_addr == netaddr.s_addr) {
8981		websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the network address<br>",
8982			  fields[0].longname, lan_ipaddr);
8983		return;
8984	}
8985	if (ipaddr.s_addr == broadaddr.s_addr) {
8986		websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the broadcast address<br>",
8987			  fields[0].longname, lan_ipaddr);
8988		return;
8989	}
8990
8991
8992	nvram_set(fields[0].name, lan_ipaddr);
8993	nvram_set(fields[1].name, lan_netmask);
8994
8995
8996	/* Fix up LAN IP addresses */
8997	for (i = 0; i < ARRAYSIZE(lan_ipaddrs); i++) {
8998
8999		value = nvram_get(lan_ipaddrs[i]);
9000		if (value && *value) {
9001			(void) inet_aton(value, &ipaddr);
9002			ipaddr.s_addr &= ~netmask.s_addr;
9003			ipaddr.s_addr |= netaddr.s_addr;
9004
9005			nvram_set(lan_ipaddrs[i], inet_ntoa(ipaddr));
9006		}
9007	}
9008
9009#ifdef __CONFIG_NAT__
9010	/* Fix up client filters and port forwards */
9011	for (i = 0; i < MAX_NVPARSE; i++) {
9012		if (get_filter_client(i, &start, &end)) {
9013			start.match.src.ipaddr.s_addr &= ~netmask.s_addr;
9014			start.match.src.ipaddr.s_addr |= netaddr.s_addr;
9015			end.match.src.ipaddr.s_addr &= ~netmask.s_addr;
9016			end.match.src.ipaddr.s_addr |= netaddr.s_addr;
9017
9018			valid = set_filter_client(i, &start, &end);
9019			a_assert(valid);
9020		}
9021#ifdef __CONFIG_URLFILTER__
9022		if (get_filter_url(i, &url_start, &url_end)) {
9023			url_start.match.src.ipaddr.s_addr &= ~netmask.s_addr;
9024			url_start.match.src.ipaddr.s_addr |= netaddr.s_addr;
9025			url_end.match.src.ipaddr.s_addr &= ~netmask.s_addr;
9026			url_end.match.src.ipaddr.s_addr |= netaddr.s_addr;
9027
9028			valid = set_filter_url(i, &url_start, &url_end);
9029			a_assert(valid);
9030		}
9031#endif /* __CONFIG_URLFILTER__ */
9032		if (get_forward_port(i, &nat)) {
9033			nat.ipaddr.s_addr &= ~netmask.s_addr;
9034			nat.ipaddr.s_addr |= netaddr.s_addr;
9035			valid = set_forward_port(i, &nat);
9036			a_assert(valid);
9037		}
9038	}
9039#endif	/* __CONFIG_NAT__ */
9040
9041	ret_code = 0;
9042}
9043
9044#ifdef __CONFIG_NAT__
9045static void
9046validate_filter_client(webs_t wp, char *value, struct variable *v, char *varname)
9047{
9048	int n, i, j;
9049	bool valid;
9050	struct variable fields[] = {
9051		{ name: "filter_client_from_start%d", longname: "LAN Client Filter Starting IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
9052		{ name: "filter_client_from_end%d", longname: "LAN Client Filter Ending IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
9053		{ name: "filter_client_proto%d", longname: "LAN Client Filter Protocol", argv: ARGV("tcp", "udp") },
9054		{ name: "filter_client_to_start%d", longname: "LAN Client Filter Starting Destination Port", argv: ARGV("0", "65535") },
9055		{ name: "filter_client_to_end%d", longname: "LAN Client Filter Ending Destination Port", argv: ARGV("0", "65535") },
9056		{ name: "filter_client_from_day%d", longname: "LAN Client Filter Starting Day", argv: ARGV("0", "6") },
9057		{ name: "filter_client_to_day%d", longname: "LAN Client Filter Ending Day", argv: ARGV("0", "6") },
9058		{ name: "filter_client_from_sec%d", longname: "LAN Client Filter Starting Second", argv: ARGV("0", "86400") },
9059		{ name: "filter_client_to_sec%d", longname: "LAN Client Filter Ending Second", argv: ARGV("0", "86400") },
9060	};
9061	char *from_start=NULL, *from_end=NULL, *proto=NULL, *to_start=NULL;
9062	char *to_end=NULL, *from_day=NULL, *to_day=NULL, *from_sec=NULL, *to_sec=NULL, *enable=NULL;
9063	char **locals[] = { &from_start, &from_end, &proto, &to_start, &to_end, &from_day, &to_day, &from_sec, &to_sec };
9064	char name[1000];
9065	netconf_filter_t start, end;
9066
9067	assert(v);
9068
9069	ret_code = EINVAL;
9070
9071	/* filter_client indicates how many to expect */
9072	if (!valid_range(wp, value, v)){
9073		websBufferWrite(wp, "Invalid filter client string <b>%s</b><br>",value);
9074		return;
9075	}
9076	n = atoi(value);
9077
9078	for (i = 0; i <= n; i++) {
9079		/* Set up field names */
9080		for (j = 0; j < ARRAYSIZE(fields); j++) {
9081			snprintf(name, sizeof(name), fields[j].name, i);
9082			if (!(*locals[j] = websGetVar(wp, name, NULL)))
9083				break;
9084		}
9085		/* Incomplete web page */
9086		if (j < ARRAYSIZE(fields))
9087			continue;
9088		/* Enable is a checkbox */
9089		snprintf(name, sizeof(name), "filter_client_enable%d", i);
9090		if (websGetVar(wp, name, NULL))
9091			enable = "on";
9092		else
9093			enable = "off";
9094		/* Delete entry if all fields are blank */
9095		if (!*from_start && !*from_end && !*to_start && !*to_end) {
9096			del_filter_client(i);
9097			continue;
9098		}
9099		/* Fill in empty fields with default values */
9100		if (!*from_start) from_start = from_end;
9101		if (!*from_end) from_end = from_start;
9102		if (!*to_start) to_start = to_end;
9103		if (!*to_end) to_end = to_start;
9104		if (!*from_start || !*from_end) {
9105			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname);
9106			continue;
9107		}
9108		if (!*to_start || !*to_end) {
9109			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Destination Port Range<br>", v->longname);
9110			continue;
9111		}
9112		/* Check individual fields */
9113		if (!valid_ipaddr(wp, from_start, &fields[0]) ||
9114		    !valid_ipaddr(wp, from_end, &fields[1]) ||
9115		    !valid_choice(wp, proto, &fields[2]) ||
9116		    !valid_range(wp, to_start, &fields[3]) ||
9117		    !valid_range(wp, to_end, &fields[4]) ||
9118		    !valid_range(wp, from_day, &fields[5]) ||
9119		    !valid_range(wp, to_day, &fields[6]) ||
9120		    !valid_range(wp, from_sec, &fields[7]) ||
9121		    !valid_range(wp, to_sec, &fields[8]))
9122			continue;
9123		/* Check dependencies between fields */
9124		if (ntohl(inet_addr(from_start)) > ntohl(inet_addr(from_end))) {
9125			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9126				  fields[0].longname, from_start, fields[1].longname, from_end);
9127			continue;
9128		}
9129		if (atoi(to_start) > atoi(to_end)) {
9130			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9131				  fields[3].longname, to_start, fields[4].longname, to_end);
9132			continue;
9133		}
9134
9135		/* Set up parameters */
9136		memset(&start, 0, sizeof(netconf_filter_t));
9137		if (!strcmp(proto, "tcp"))
9138			start.match.ipproto = IPPROTO_TCP;
9139		else if (!strcmp(proto, "udp"))
9140			start.match.ipproto = IPPROTO_UDP;
9141		(void) inet_aton(from_start, &start.match.src.ipaddr);
9142		start.match.src.netmask.s_addr = htonl(0xffffffff);
9143		start.match.dst.ports[0] = htons(atoi(to_start));
9144		start.match.dst.ports[1] = htons(atoi(to_end));
9145		start.match.days[0] = atoi(from_day);
9146		start.match.days[1] = atoi(to_day);
9147		start.match.secs[0] = atoi(from_sec);
9148		start.match.secs[1] = atoi(to_sec);
9149		if (!strcmp(enable, "off"))
9150			start.match.flags |= NETCONF_DISABLED;
9151		memcpy(&end, &start, sizeof(netconf_filter_t));
9152		(void) inet_aton(from_end, &end.match.src.ipaddr);
9153
9154		/* Do it */
9155		valid = set_filter_client(i, &start, &end);
9156		a_assert(valid);
9157	}
9158
9159		ret_code = 0;
9160}
9161
9162#ifdef __CONFIG_URLFILTER__
9163static void
9164validate_filter_url(webs_t wp, char *value, struct variable *v, char *varname)
9165{
9166	int n, i, j;
9167	bool valid;
9168	struct variable fields[] = {
9169		{ name: "filter_url_from_start%d", longname: "URL Filter Starting IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
9170		{ name: "filter_url_from_end%d", longname: "URL Filter Ending IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
9171	};
9172	char *from_start=NULL, *from_end=NULL;
9173	char *url_addr=NULL, *enable=NULL;
9174	char **locals[] = { &from_start, &from_end };
9175	char name[1000];
9176	netconf_urlfilter_t start, end;
9177
9178	assert(v);
9179
9180	ret_code = EINVAL;
9181
9182	/* filter_url indicates how many to expect */
9183	if (!valid_range(wp, value, v)){
9184		websBufferWrite(wp, "Invalid url filter string <b>%s</b><br>",value);
9185		return;
9186	}
9187	n = atoi(value);
9188
9189	for (i = 0; i <= n; i++) {
9190		/* Set up field names */
9191		for (j = 0; j < ARRAYSIZE(fields); j++) {
9192			snprintf(name, sizeof(name), fields[j].name, i);
9193			if (!(*locals[j] = websGetVar(wp, name, NULL)))
9194				break;
9195		}
9196		/* Incomplete web page */
9197		if (j < ARRAYSIZE(fields))
9198			continue;
9199		/* URL */
9200		snprintf(name, sizeof(name), "filter_url_addr%d", i);
9201		if (!(url_addr = websGetVar(wp, name, NULL))) {
9202			del_filter_url(i);
9203			continue;
9204		}
9205		/* Enable is a checkbox */
9206		snprintf(name, sizeof(name), "filter_url_enable%d", i);
9207		if (websGetVar(wp, name, NULL))
9208			enable = "on";
9209		else
9210			enable = "off";
9211		/* Delete entry if all fields are blank */
9212		if (!*from_start && !*from_end) {
9213			del_filter_url(i);
9214			continue;
9215		}
9216		/* Fill in empty fields with default values */
9217		if (!*from_start) from_start = from_end;
9218		if (!*from_end) from_end = from_start;
9219		if (!*from_start || !*from_end) {
9220			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname);
9221			continue;
9222		}
9223		/* Check individual fields */
9224		if (!valid_ipaddr(wp, from_start, &fields[0]) ||
9225		    !valid_ipaddr(wp, from_end, &fields[1]))
9226			continue;
9227		/* Check dependencies between fields */
9228		if (ntohl(inet_addr(from_start)) > ntohl(inet_addr(from_end))) {
9229			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9230				  fields[0].longname, from_start, fields[1].longname, from_end);
9231			continue;
9232		}
9233
9234		/* Set up parameters */
9235		memset(&start, 0, sizeof(netconf_urlfilter_t));
9236		(void) inet_aton(from_start, &start.match.src.ipaddr);
9237		start.match.src.netmask.s_addr = htonl(0xffffffff);
9238		strcpy(start.url, url_addr);
9239		if (!strcmp(enable, "off"))
9240			start.match.flags |= NETCONF_DISABLED;
9241		memcpy(&end, &start, sizeof(netconf_urlfilter_t));
9242		(void) inet_aton(from_end, &end.match.src.ipaddr);
9243
9244		/* Do it */
9245		valid = set_filter_url(i, &start, &end);
9246		a_assert(valid);
9247	}
9248
9249		ret_code = 0;
9250}
9251#endif /* __CONFIG_URLFILTER__ */
9252
9253static void
9254validate_forward_port(webs_t wp, char *value, struct variable *v, char *varname)
9255{
9256	int n, i, j;
9257	bool valid;
9258	struct variable fields[] = {
9259		{ name: "forward_port_proto%d", longname: "Port Forward Protocol", argv: ARGV("tcp", "udp") },
9260		{ name: "forward_port_from_start%d", longname: "Port Forward Starting WAN Port", argv: ARGV("0", "65535") },
9261		{ name: "forward_port_from_end%d", longname: "Port Forward Ending WAN Port", argv: ARGV("0", "65535") },
9262		{ name: "forward_port_to_ip%d", longname: "Port Forward LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") },
9263		{ name: "forward_port_to_start%d", longname: "Port Forward Starting LAN Port", argv: ARGV("0", "65535") },
9264		{ name: "forward_port_to_end%d", longname: "Port Forward Ending LAN Port", argv: ARGV("0", "65535") },
9265	};
9266	char *proto=NULL, *from_start=NULL, *from_end=NULL;
9267	char *to_ip=NULL, *to_start=NULL, *to_end=NULL, *enable=NULL;
9268	char **locals[] = { &proto, &from_start, &from_end, &to_ip, &to_start, &to_end };
9269	char name[1000];
9270	netconf_nat_t nat;
9271
9272	assert(v);
9273
9274	ret_code = EINVAL;
9275
9276	/* forward_port indicates how many to expect */
9277	if (!valid_range(wp, value, v)){
9278		websBufferWrite(wp, "Invalid forward port string <b>%s</b><br>",value);
9279		return;
9280	}
9281	n = atoi(value);
9282
9283	for (i = 0; i <= n; i++) {
9284		/* Set up field names */
9285		for (j = 0; j < ARRAYSIZE(fields); j++) {
9286			snprintf(name, sizeof(name), fields[j].name, i);
9287			if (!(*locals[j] = websGetVar(wp, name, NULL)))
9288				break;
9289		}
9290		/* Incomplete web page */
9291		if (j < ARRAYSIZE(fields))
9292			continue;
9293		/* Enable is a checkbox */
9294		snprintf(name, sizeof(name), "forward_port_enable%d", i);
9295		if (websGetVar(wp, name, NULL))
9296			enable = "on";
9297		else
9298			enable = "off";
9299		/* Delete entry if all fields are blank */
9300		if (!*from_start && !*from_end && !*to_ip && !*to_start && !*to_end) {
9301			del_forward_port(i);
9302			continue;
9303		}
9304		/* Fill in empty fields with default values */
9305		if (!*from_start) from_start = from_end;
9306		if (!*from_end) from_end = from_start;
9307		if (!*to_start && !*to_end)
9308			to_start = from_start;
9309		if (!*to_start) to_start = to_end;
9310		if (!*to_end) to_end = to_start;
9311		if (!*from_start || !*from_end) {
9312			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname);
9313			continue;
9314		}
9315		if (!*to_ip) {
9316			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address<br>", v->longname);
9317			continue;
9318		}
9319		if (!*to_start || !*to_end) {
9320			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Destination Port Range<br>", v->longname);
9321			continue;
9322		}
9323		/* Check individual fields */
9324		if (!valid_choice(wp, proto, &fields[0]) ||
9325		    !valid_range(wp, from_start, &fields[1]) ||
9326		    !valid_range(wp, from_end, &fields[2]) ||
9327		    !valid_ipaddr(wp, to_ip, &fields[3]) ||
9328		    !valid_range(wp, to_start, &fields[4]) ||
9329		    !valid_range(wp, to_end, &fields[5]))
9330			continue;
9331		if (atoi(from_start) > atoi(from_end)) {
9332			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9333				  fields[1].longname, from_start, fields[2].longname, from_end);
9334			continue;
9335		}
9336		if (atoi(to_start) > atoi(to_end)) {
9337			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9338				  fields[4].longname, to_start, fields[5].longname, to_end);
9339			continue;
9340		}
9341		if ((atoi(from_end) - atoi(from_start)) != (atoi(to_end) - atoi(to_start))) {
9342			websBufferWrite(wp, "Invalid <b>%s</b>: WAN Port Range and LAN Port Range must be the same size<br>", v->longname);
9343			continue;
9344		}
9345
9346		/* Set up parameters */
9347		memset(&nat, 0, sizeof(netconf_nat_t));
9348		if (!strcmp(proto, "tcp"))
9349			nat.match.ipproto = IPPROTO_TCP;
9350		else if (!strcmp(proto, "udp"))
9351			nat.match.ipproto = IPPROTO_UDP;
9352		nat.match.dst.ports[0] = htons(atoi(from_start));
9353		nat.match.dst.ports[1] = htons(atoi(from_end));
9354		(void) inet_aton(to_ip, &nat.ipaddr);
9355		nat.ports[0] = htons(atoi(to_start));
9356		nat.ports[1] = htons(atoi(to_end));
9357		if (!strcmp(enable, "off"))
9358			nat.match.flags |= NETCONF_DISABLED;
9359
9360		/* Do it */
9361		valid = set_forward_port(i, &nat);
9362		a_assert(valid);
9363	}
9364	ret_code =0;
9365}
9366
9367#if !defined(AUTOFW_PORT_DEPRECATED)
9368static void
9369validate_autofw_port(webs_t wp, char *value, struct variable *v, char *varname)
9370{
9371	int n, i, j;
9372	bool valid;
9373	struct variable fields[] = {
9374		{ name: "autofw_port_out_proto%d", longname: "Outbound Protocol", argv: ARGV("tcp", "udp") },
9375		{ name: "autofw_port_out_start%d", longname: "Outbound Port Start", argv: ARGV("0", "65535") },
9376		{ name: "autofw_port_out_end%d", longname: "Outbound Port End", argv: ARGV("0", "65535") },
9377		{ name: "autofw_port_in_proto%d", longname: "Inbound Protocol", argv: ARGV("tcp", "udp") },
9378		{ name: "autofw_port_in_start%d", longname: "Inbound Port Start", argv: ARGV("0", "65535") },
9379		{ name: "autofw_port_in_end%d", longname: "Inbound Port End", argv: ARGV("0", "65535") },
9380 		{ name: "autofw_port_to_start%d", longname: "To Port Start", argv: ARGV("0", "65535") },
9381 		{ name: "autofw_port_to_end%d", longname: "To Port End", argv: ARGV("0", "65535") },
9382	};
9383	char *out_proto=NULL, *out_start=NULL, *out_end=NULL, *in_proto=NULL;
9384	char *in_start=NULL, *in_end=NULL, *to_start=NULL, *to_end=NULL, *enable=NULL;
9385	char **locals[] = { &out_proto, &out_start, &out_end, &in_proto, &in_start, &in_end, &to_start, &to_end };
9386	char name[1000];
9387	netconf_app_t app;
9388
9389	assert(v);
9390
9391	ret_code = EINVAL;
9392
9393	/* autofw_port indicates how many to expect */
9394	if (!valid_range(wp, value, v)){
9395		websBufferWrite(wp, "Invalid auto forward port string <b>%s</b><br>",value);
9396		return;
9397	}
9398	n = atoi(value);
9399
9400	for (i = 0; i <= n; i++) {
9401		/* Set up field names */
9402		for (j = 0; j < ARRAYSIZE(fields); j++) {
9403			snprintf(name, sizeof(name), fields[j].name, i);
9404			if (!(*locals[j] = websGetVar(wp, name, NULL)))
9405				break;
9406		}
9407		/* Incomplete web page */
9408		if (j < ARRAYSIZE(fields))
9409			continue;
9410		/* Enable is a checkbox */
9411		snprintf(name, sizeof(name), "autofw_port_enable%d", i);
9412		if (websGetVar(wp, name, NULL))
9413			enable = "on";
9414		else
9415			enable = "off";
9416		/* Delete entry if all fields are blank */
9417		if (!*out_start && !*out_end && !*in_start && !*in_end && !*to_start && !*to_end) {
9418			del_autofw_port(i);
9419			continue;
9420		}
9421		/* Fill in empty fields with default values */
9422		if (!*out_start) out_start = out_end;
9423		if (!*out_end) out_end = out_start;
9424		if (!*in_start) in_start = in_end;
9425		if (!*in_end) in_end = in_start;
9426		if (!*to_start && !*to_end)
9427			to_start = in_start;
9428		if (!*to_start) to_start = to_end;
9429		if (!*to_end) to_end = to_start;
9430		if (!*out_start || !*out_end) {
9431			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an Outbound Port Range<br>", v->longname);
9432			continue;
9433		}
9434		if (!*in_start || !*in_end) {
9435			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an Inbound Port Range<br>", v->longname);
9436			continue;
9437		}
9438		if (!*to_start || !*to_end) {
9439			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a To Port Range<br>", v->longname);
9440			continue;
9441		}
9442		/* Check individual fields */
9443		if (!valid_choice(wp, out_proto, &fields[0]) ||
9444		    !valid_range(wp, out_start, &fields[1]) ||
9445		    !valid_range(wp, out_end, &fields[2]) ||
9446		    !valid_choice(wp, in_proto, &fields[3]) ||
9447		    !valid_range(wp, in_start, &fields[4]) ||
9448		    !valid_range(wp, in_end, &fields[5]) ||
9449		    !valid_range(wp, to_start, &fields[6]) ||
9450		    !valid_range(wp, to_end, &fields[7]))
9451			continue;
9452		/* Check dependencies between fields */
9453		if (atoi(out_start) > atoi(out_end)) {
9454			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9455				  fields[1].longname, out_start, fields[2].longname, out_end);
9456			continue;
9457		}
9458		if (atoi(in_start) > atoi(in_end)) {
9459			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9460				  fields[4].longname, in_start, fields[5].longname, in_end);
9461			continue;
9462		}
9463		if (atoi(to_start) > atoi(to_end)) {
9464			websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>",
9465				  fields[6].longname, in_start, fields[7].longname, in_end);
9466			continue;
9467		}
9468		if ((atoi(in_end) - atoi(in_start)) != (atoi(to_end) - atoi(to_start))) {
9469			websBufferWrite(wp, "Invalid <b>%s</b>: Inbound Port Range and To Port Range must be the same size<br>", v->longname);
9470			continue;
9471		}
9472#ifdef NEW_PORT_TRIG
9473		if ((atoi(in_end) - atoi(in_start)) > 100) {
9474			websBufferWrite(wp, "Invalid <b>%s</b>: Inbound Port Range must be less than 100<br>", v->longname);
9475			continue;
9476		}
9477#endif
9478
9479		/* Set up parameters */
9480		memset(&app, 0, sizeof(netconf_app_t));
9481		if (!strcmp(out_proto, "tcp"))
9482			app.match.ipproto = IPPROTO_TCP;
9483		else if (!strcmp(out_proto, "udp"))
9484			app.match.ipproto = IPPROTO_UDP;
9485		app.match.dst.ports[0] = htons(atoi(out_start));
9486		app.match.dst.ports[1] = htons(atoi(out_end));
9487		if (!strcmp(in_proto, "tcp"))
9488			app.proto = IPPROTO_TCP;
9489		else if (!strcmp(in_proto, "udp"))
9490			app.proto = IPPROTO_UDP;
9491		app.dport[0] = htons(atoi(in_start));
9492		app.dport[1] = htons(atoi(in_end));
9493		app.to[0] = htons(atoi(to_start));
9494		app.to[1] = htons(atoi(to_end));
9495		if (!strcmp(enable, "off"))
9496			app.match.flags |= NETCONF_DISABLED;
9497
9498		/* Do it */
9499		valid = set_autofw_port(i, &app);
9500		a_assert(valid);
9501	}
9502	ret_code = 0;
9503}
9504#endif /* !AUTOFW_PORT_DEPRECATED */
9505#endif	/* __CONFIG_NAT__ */
9506
9507/* Validate HTML input data modified by Web user and stored in NVRAM */
9508static void
9509validate_trf_mgmt_port(webs_t wp, char *value, struct variable *v, char *varname)
9510{
9511	int n, i, j, enable;
9512	bool valid;
9513	struct variable fields[] = {
9514		{ name: "%strf_mgmt_port_proto%d", longname: "Traffic Management Protocol", argv: ARGV("tcp", "udp", "mac") },
9515		{ name: "%strf_mgmt_port_sport%d", longname: "Traffic Management Source Port", argv: ARGV("0", "65535") },
9516		{ name: "%strf_mgmt_port_dport%d", longname: "Traffic Management Dest Port", argv: ARGV("0", "65535") },
9517		{ name: "%strf_mgmt_port_macaddr%d", longname: "Traffic Management Mac Addr", argv: NULL },
9518		{ name: "%strf_mgmt_port_prio%d", longname: "Traffic Management Priority", argv: ARGV("0", "1", "2", "3") },
9519	};
9520	char *proto=NULL, *prio=NULL, *flags=NULL;
9521	char *sport=NULL, *dport=NULL, *dmacaddr=NULL;
9522	char **locals[] = { &proto, &sport, &dport, &dmacaddr, &prio, &flags };
9523	char name[1000];
9524	netconf_trmgmt_t trm;
9525	char prefix[32];
9526	char *wlunit = nvram_get("wl_unit");
9527
9528	snprintf(prefix, sizeof(prefix), "wl%s_", wlunit);
9529
9530	assert(v);
9531
9532	ret_code = EINVAL;
9533
9534	/* forward_port indicates how many to expect */
9535	if (!valid_range(wp, value, v)){
9536		websBufferWrite(wp, "Invalid traffic management port string <b>%s</b><br>",value);
9537		return;
9538	}
9539	n = atoi(value);
9540
9541	for (i = 0; i <= n; i++) {
9542		/* Set up field names */
9543		for (j = 0; j < ARRAYSIZE(fields); j++) {
9544			snprintf(name, sizeof(name), fields[j].name, prefix, i);
9545			if (!(*locals[j] = websGetVar(wp, name, NULL)))
9546				break;
9547		}
9548		/* Incomplete web page */
9549		if (j < ARRAYSIZE(fields))
9550			continue;
9551
9552		/* Set up parameters */
9553		memset(&trm, 0, sizeof(netconf_trmgmt_t));
9554
9555		/* Enable is a checkbox */
9556		snprintf(name, sizeof(name), "%strf_mgmt_port_enable%d", prefix, i);
9557		if (websGetVar(wp, name, NULL))
9558			enable = 1;
9559		else
9560			enable = 0;
9561
9562		/* Check favored checkbox */
9563		snprintf(name, sizeof(name), "%strf_mgmt_port_favored%d", prefix, i);
9564		if (websGetVar(wp, name, NULL))
9565			trm.favored = 1;
9566		else
9567			trm.favored = 0;
9568
9569		/* Check protocol field, remove if not valid */
9570		if (!valid_choice(wp, proto, &fields[0])) {
9571			del_trf_mgmt_port(prefix, i);
9572			continue;
9573		}
9574
9575		if (!strcmp(proto, "tcp"))
9576			trm.match.ipproto = IPPROTO_TCP;
9577		else if (!strcmp(proto, "udp"))
9578			trm.match.ipproto = IPPROTO_UDP;
9579		else if (!strcmp(proto, "mac"))
9580			trm.match.ipproto = IPPROTO_IP;
9581
9582
9583		if (trm.match.ipproto == IPPROTO_IP) {
9584			/* Delete entry if mac address not specified for proto type "all" */
9585			if (!*dmacaddr || !*prio) {
9586				if (enable)
9587					websBufferWrite(wp, "Invalid <b>settings at index %d</b> MAC address<br>",i);
9588				del_trf_mgmt_port(prefix, i);
9589				continue;
9590			}
9591
9592			/* Check individual fields */
9593			if (!valid_hwaddr(wp, dmacaddr, &fields[3]) ||
9594			    !valid_choice(wp, prio, &fields[4])) {
9595				continue;
9596			}
9597
9598			/* Set up parameters */
9599			trm.prio = atoi(prio);
9600			(void) ether_atoe((const char *)dmacaddr, (unsigned char *)&trm.match.mac);
9601		} else {
9602			/* Delete entry if priority field is blank */
9603			if (!*prio ) {
9604				if (enable)
9605					websBufferWrite(wp, "Invalid <b>settings at index %d </b><br>",i);
9606				del_trf_mgmt_port(prefix, i);
9607				continue;
9608			}
9609			trm.prio = atoi(prio);
9610
9611			/* Validate source port number, "no value" treatred as zero value */
9612			if (*sport) {
9613				if (!valid_range(wp, sport, &fields[1])) {
9614					if (enable)
9615						websBufferWrite(wp, "Invalid <b>settings at index %d </b><br>",i);
9616					del_trf_mgmt_port(prefix, i);
9617					continue;
9618				}
9619				trm.match.src.ports[0] = htons(atoi(sport));
9620			}
9621
9622			/* Validate destination port number, "no value" treatred as zero value */
9623			if (*dport) {
9624				if (!valid_range(wp, dport, &fields[2])) {
9625					if (enable)
9626						websBufferWrite(wp, "Invalid <b>settings at index %d </b><br>",i);
9627					del_trf_mgmt_port(prefix, i);
9628					continue;
9629				}
9630				trm.match.dst.ports[0] = htons(atoi(dport));
9631			}
9632		}
9633
9634		if (enable == 0)
9635			trm.match.flags |= NETCONF_DISABLED;
9636
9637		/* Do it */
9638		valid = set_trf_mgmt_port(prefix, i, &trm);
9639		a_assert(valid);
9640	}
9641	ret_code =0;
9642}
9643
9644static void
9645validate_lan_route(webs_t wp, char *value, struct variable *v, char *varname)
9646{
9647	int n, i;
9648	char buf[1000] = "", *cur = buf;
9649	char lan_ipaddr[20] ="lan_ipaddr";
9650	char lan_netmask[20]="lan_netmask";
9651	char *lan_argv[3];
9652
9653	struct variable lan_route_variables[] = {
9654		{ longname: "Route IP Address", argv: NULL },
9655		{ longname: "Route Subnet Mask", argv: NULL },
9656		{ longname: "Route Gateway", argv: NULL },
9657		{ longname: "Route Metric", argv: ARGV("0", "15") },
9658	};
9659
9660	assert(v);
9661
9662	ret_code = EINVAL;
9663
9664	/* Insert name overrides */
9665	if (varname)
9666	{
9667		char index[5];
9668
9669		if (!get_index_string(v->prefix,varname,
9670			index,sizeof(index)))
9671				return;
9672
9673		snprintf(lan_ipaddr,sizeof(lan_ipaddr),"lan%s_ipaddr",index);
9674		snprintf(lan_netmask,sizeof(lan_netmask),"lan%s_netmask",index);
9675	}
9676
9677	n = atoi(value);
9678
9679	for (i = 0; i < n; i++) {
9680		char lan_route_ipaddr[] = "lan_route_ipaddrXXX";
9681		char lan_route_netmask[] = "lan_route_netmaskXXX";
9682		char lan_route_gateway[] = "lan_route_gatewayXXX";
9683		char lan_route_metric[] = "lan_route_metricXXX";
9684		char *ipaddr, *netmask, *gateway, *metric;
9685
9686 		snprintf(lan_route_ipaddr, sizeof(lan_route_ipaddr), "%s_ipaddr%d", v->name, i);
9687		snprintf(lan_route_netmask, sizeof(lan_route_netmask), "%s_netmask%d", v->name, i);
9688 		snprintf(lan_route_gateway, sizeof(lan_route_gateway), "%s_gateway%d", v->name, i);
9689 		snprintf(lan_route_metric, sizeof(lan_route_metric), "%s_metric%d", v->name, i);
9690		if (!(ipaddr = websGetVar(wp, lan_route_ipaddr, NULL)) ||
9691		    !(netmask = websGetVar(wp, lan_route_netmask, NULL)) ||
9692		    !(gateway = websGetVar(wp, lan_route_gateway, NULL)) ||
9693		    !(metric = websGetVar(wp, lan_route_metric, NULL)))
9694			return;
9695		if (!*ipaddr && !*netmask && !*gateway && !*metric)
9696			continue;
9697		if (!*ipaddr && !*netmask && *gateway) {
9698			ipaddr = "0.0.0.0";
9699			netmask = "0.0.0.0";
9700		}
9701		if (!*gateway)
9702			gateway = "0.0.0.0";
9703		if (!*metric)
9704			metric = "0";
9705		if (!*ipaddr) {
9706			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an IP Address<br>", v->longname);
9707			continue;
9708		}
9709		if (!*netmask) {
9710			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Subnet Mask<br>", v->longname);
9711			continue;
9712		}
9713
9714		lan_argv[0]=lan_ipaddr;
9715		lan_argv[1]=lan_netmask;
9716		lan_argv[2]=NULL;
9717
9718		lan_route_variables[2].argv = lan_argv;
9719		if (!valid_ipaddr(wp, ipaddr, &lan_route_variables[0]) ||
9720		    !valid_ipaddr(wp, netmask, &lan_route_variables[1]) ||
9721		    !valid_ipaddr(wp, gateway, &lan_route_variables[2]) ||
9722		    !valid_range(wp, metric, &lan_route_variables[3]))
9723			continue;
9724		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s:%s:%s",
9725				cur == buf ? "" : " ", ipaddr, netmask, gateway, metric);
9726	}
9727
9728	if (varname)
9729		nvram_set(varname,buf);
9730	else
9731		nvram_set(v->name, buf);
9732	ret_code = 0;
9733}
9734
9735#ifdef __CONFIG_EMF__
9736static void
9737validate_emf_entry(webs_t wp, char *value, struct variable *v, char *varname)
9738{
9739	int n, i;
9740	char buf[1000] = "", temp[128], *cur = buf;
9741
9742	assert(v);
9743
9744	bzero(buf, sizeof(buf));
9745	ret_code = EINVAL;
9746
9747	n = atoi(value);
9748
9749	for (i = 0; i < n; i++) {
9750		char emf_entry_mgrp[] = "emf_entry_mgrpXXX";
9751		char emf_entry_if[] = "emf_entry_ifXXX";
9752		char *mgrp, *ifname;
9753		struct in_addr mgrp_addr;
9754
9755 		snprintf(emf_entry_mgrp, sizeof(emf_entry_mgrp), "%s_mgrp%d", v->name, i);
9756
9757		snprintf(emf_entry_if, sizeof(emf_entry_if), "%s_if%d", v->name, i);
9758
9759		if (!(mgrp = websGetVar(wp, emf_entry_mgrp, NULL)) ||
9760		    !(ifname = websGetVar(wp, emf_entry_if, NULL)))
9761			return;
9762
9763		if (!*mgrp && !*ifname)
9764			continue;
9765
9766#define IP_ISMULTI(addr) (((addr) & 0xf0000000) == 0xe0000000)
9767		if ((inet_aton(mgrp, &mgrp_addr) == 0) ||
9768		    (!IP_ISMULTI(ntohl(mgrp_addr.s_addr)))) {
9769			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a valid multicast IP Address<br>",
9770			                v->longname);
9771			return;
9772		}
9773
9774		if ((*ifname) == 0) {
9775			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN interface name<br>",
9776			                v->longname);
9777			return;
9778		}
9779
9780		if ((strstr(nvram_safe_get("br0_ifnames"), ifname) == NULL) &&
9781		    (strstr(nvram_safe_get("new_lan_ifnames"), ifname) == NULL) &&
9782		    (strncmp(ifname, "wds", 3) != 0)) {
9783			websBufferWrite(wp, "Invalid <b>%s</b>: must specify one of the bridge interfaces<br>",
9784			                v->longname);
9785			return;
9786		}
9787
9788		/* Check for duplicate MFDB entry */
9789		snprintf(temp, 128, "%s:%s", mgrp, ifname);
9790		if (strstr(buf, temp) != NULL)
9791			continue;
9792
9793		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s",
9794		                cur == buf ? "" : " ", mgrp, ifname);
9795	}
9796
9797	if (varname)
9798		nvram_set(varname, buf);
9799	else
9800		nvram_set(v->name, buf);
9801
9802	ret_code = 0;
9803
9804	return;
9805}
9806
9807static void
9808validate_emf_uffp_entry(webs_t wp, char *value, struct variable *v, char *varname)
9809{
9810	int n, i;
9811	char buf[1000] = "", *cur = buf;
9812
9813	assert(v);
9814
9815	bzero(buf, sizeof(buf));
9816	ret_code = EINVAL;
9817
9818	n = atoi(value);
9819
9820	for (i = 0; i < n; i++) {
9821		char emf_uffp_entry_if[] = "emf_uffp_entry_ifXXX";
9822		char *ifname;
9823
9824		snprintf(emf_uffp_entry_if, sizeof(emf_uffp_entry_if), "%s_if%d", v->name, i);
9825
9826		if (!(ifname = websGetVar(wp, emf_uffp_entry_if, NULL)))
9827			return;
9828
9829		if (!*ifname)
9830			continue;
9831
9832		if ((*ifname) == 0) {
9833			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN interface name<br>",
9834			                v->longname);
9835			return;
9836		}
9837
9838		if ((strstr(nvram_safe_get("br0_ifnames"), ifname) == NULL) &&
9839		    (strstr(nvram_safe_get("new_lan_ifnames"), ifname) == NULL) &&
9840		    (strncmp(ifname, "wds", 3) != 0)) {
9841			websBufferWrite(wp, "Invalid <b>%s</b>: must specify one of the bridge interfaces<br>",
9842			                v->longname);
9843			return;
9844		}
9845
9846		/* Duplicate UFFP interface entry */
9847		if (strstr(buf, ifname) != NULL)
9848			continue;
9849
9850		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s",
9851		                cur == buf ? "" : " ", ifname);
9852	}
9853
9854	if (varname)
9855		nvram_set(varname, buf);
9856	else
9857		nvram_set(v->name, buf);
9858
9859	ret_code = 0;
9860
9861	return;
9862}
9863
9864static void
9865validate_emf_rtport_entry(webs_t wp, char *value, struct variable *v, char *varname)
9866{
9867	int n, i;
9868	char buf[1000] = "", *cur = buf;
9869
9870	assert(v);
9871
9872	bzero(buf, sizeof(buf));
9873	ret_code = EINVAL;
9874
9875	n = atoi(value);
9876
9877	for (i = 0; i < n; i++) {
9878		char emf_rtport_entry_if[] = "emf_rtport_entry_ifXXX";
9879		char *ifname;
9880
9881		snprintf(emf_rtport_entry_if, sizeof(emf_rtport_entry_if), "%s_if%d", v->name, i);
9882
9883		if (!(ifname = websGetVar(wp, emf_rtport_entry_if, NULL)))
9884			return;
9885
9886		if (!*ifname)
9887			continue;
9888
9889		if ((*ifname) == 0) {
9890			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN interface name<br>",
9891			                v->longname);
9892			return;
9893		}
9894
9895		if ((strstr(nvram_safe_get("br0_ifnames"), ifname) == NULL) &&
9896		    (strstr(nvram_safe_get("new_lan_ifnames"), ifname) == NULL) &&
9897		    (strncmp(ifname, "wds", 3) != 0)) {
9898			websBufferWrite(wp, "Invalid <b>%s</b>: must specify one of the bridge interfaces<br>",
9899			                v->longname);
9900			return;
9901		}
9902
9903		/* Duplicate rtport interface entry */
9904		if (strstr(buf, ifname) != NULL)
9905			continue;
9906
9907		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s",
9908		                cur == buf ? "" : " ", ifname);
9909	}
9910
9911	if (varname)
9912		nvram_set(varname, buf);
9913	else
9914		nvram_set(v->name, buf);
9915
9916	ret_code = 0;
9917
9918	return;
9919}
9920#endif /* __CONFIG_EMF__ */
9921
9922#ifdef __CONFIG_NAT__
9923static void
9924validate_wan_route(webs_t wp, char *value, struct variable *v, char *varname)
9925{
9926	int n, i;
9927	char buf[1000] = "", *cur = buf;
9928	struct variable wan_route_variables[] = {
9929		{ longname: "Route IP Address", argv: NULL },
9930		{ longname: "Route Subnet Mask", argv: NULL },
9931		{ longname: "Route Gateway", argv: NULL },
9932		{ longname: "Route Metric", argv: ARGV("0", "15") },
9933	};
9934
9935	assert(v);
9936
9937	ret_code = EINVAL;
9938
9939	n = atoi(value);
9940
9941	for (i = 0; i < n; i++) {
9942		char wan_route_ipaddr[] = "wan_route_ipaddrXXX";
9943		char wan_route_netmask[] = "wan_route_netmaskXXX";
9944		char wan_route_gateway[] = "wan_route_gatewayXXX";
9945		char wan_route_metric[] = "wan_route_metricXXX";
9946		char *ipaddr, *netmask, *gateway, *metric;
9947
9948 		snprintf(wan_route_ipaddr, sizeof(wan_route_ipaddr), "%s_ipaddr%d", v->name, i);
9949		snprintf(wan_route_netmask, sizeof(wan_route_netmask), "%s_netmask%d", v->name, i);
9950 		snprintf(wan_route_gateway, sizeof(wan_route_gateway), "%s_gateway%d", v->name, i);
9951 		snprintf(wan_route_metric, sizeof(wan_route_metric), "%s_metric%d", v->name, i);
9952		if (!(ipaddr = websGetVar(wp, wan_route_ipaddr, NULL)) ||
9953		    !(netmask = websGetVar(wp, wan_route_netmask, NULL)) ||
9954		    !(gateway = websGetVar(wp, wan_route_gateway, NULL)) ||
9955		    !(metric = websGetVar(wp, wan_route_metric, NULL)))
9956			continue;
9957		if (!*ipaddr && !*netmask && !*gateway && !*metric)
9958			continue;
9959		if (!*ipaddr && !*netmask && *gateway) {
9960			ipaddr = "0.0.0.0";
9961			netmask = "0.0.0.0";
9962		}
9963		if (!*gateway)
9964			gateway = "0.0.0.0";
9965		if (!*metric)
9966			metric = "0";
9967		if (!*ipaddr) {
9968			websBufferWrite(wp, "Invalid <b>%s</b>: must specify an IP Address<br>", v->longname);
9969			continue;
9970		}
9971		if (!*netmask) {
9972			websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Subnet Mask<br>", v->longname);
9973			continue;
9974		}
9975		if (!valid_ipaddr(wp, ipaddr, &wan_route_variables[0]) ||
9976		    !valid_ipaddr(wp, netmask, &wan_route_variables[1]) ||
9977		    !valid_ipaddr(wp, gateway, &wan_route_variables[2]) ||
9978		    !valid_range(wp, metric, &wan_route_variables[3]))
9979			continue;
9980		cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s:%s:%s",
9981				cur == buf ? "" : " ", ipaddr, netmask, gateway, metric);
9982	}
9983
9984
9985	nvram_set(v->name, buf);
9986
9987	ret_code = 0;
9988}
9989#endif	/* __CONFIG_NAT__ */
9990
9991/*
9992*/
9993#ifdef __CONFIG_IPV6__
9994static void
9995validate_ipv6mode(webs_t wp, char *value, struct variable *v , char *varname)
9996{
9997	char *pvarname;
9998
9999	assert(v);
10000
10001	if (!valid_range(wp, value, v)) {
10002		websBufferWrite(wp, "<p>Invalid <b>%s</b> %s: Unsupported IPv6 mode.<br>",
10003			v->longname, value);
10004		ret_code = EINVAL;
10005		return;
10006	}
10007
10008	if (varname)
10009		pvarname = varname;
10010	else
10011		pvarname = v->name;
10012
10013	nvram_set(pvarname, value);
10014
10015	ret_code = 0;
10016}
10017
10018static void
10019validate_ipv6prefix(webs_t wp, char *value, struct variable *v , char *varname)
10020{
10021	char prefix[48];
10022	struct in6_addr addr;
10023	int bits = -1;
10024	int i;
10025
10026	assert(v);
10027
10028	i = sscanf(value, "%[^/]/%d", prefix, &bits);
10029	if (i != 2) {
10030		websBufferWrite(wp, "<p>Invalid <b>%s</b> %s: IPv6 network prefix contains an IPv6 address followed by a slash(/) and then by the number of netmask bits.<br>",
10031			v->longname, value);
10032		ret_code = EINVAL;
10033		return;
10034	}
10035	if (bits >= 128 || bits <= 0) {
10036		websBufferWrite(wp, "<p>Invalid <b>%s</b> %s: the number of netmask bits after shash(/) is between 1~127.<br>",
10037			v->longname, value);
10038		ret_code = EINVAL;
10039		return;
10040	}
10041	if (inet_pton(AF_INET6, prefix, &addr) <= 0) {
10042		websBufferWrite(wp, "<p>Invalid <b>%s</b> %s: Not a proper IPv6 address before slash(/).<br>",
10043			v->longname, value);
10044		ret_code = EINVAL;
10045		return;
10046	}
10047
10048	if (varname)
10049		nvram_set(varname, value);
10050	else
10051		nvram_set(v->name, value);
10052
10053	ret_code = 0;
10054}
10055
10056static void
10057validate_ipv6addr(webs_t wp, char *value, struct variable *v , char *varname)
10058{
10059	struct in6_addr addr;
10060
10061	assert(v);
10062
10063	if ((inet_pton(AF_INET6, value, &addr) <= 0)) {
10064		websBufferWrite(wp, "<p>Invalid <b>%s</b> %s: Incorrect IPv6 address format.<br>",
10065			v->longname, value);
10066		ret_code = EINVAL;
10067		return;
10068	}
10069
10070	if (varname)
10071		nvram_set(varname, value);
10072	else
10073		nvram_set(v->name, value);
10074
10075	ret_code = 0;
10076}
10077
10078#endif	/* __CONFIG_IPV6__ */
10079/*
10080*/
10081
10082static void
10083validate_wl_auth(webs_t wp, char *value, struct variable *v, char *varname)
10084{
10085
10086	assert(v);
10087
10088	ret_code = EINVAL;
10089
10090	if (!valid_choice(wp, value, v)){
10091		websBufferWrite(wp, "Invalid auth value string <b>%s</b><br>",value);
10092		return;
10093	}
10094
10095	if (!strcmp(value, "1")) {
10096		char *wep = websGetVar(wp, "wl_wep", "");
10097		if (!wep || strcmp(wep, "enabled")) {
10098			websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>802.11 Authentication</b> is <b>%s</b><br>", value);
10099			return;
10100		}
10101		else {
10102			/* Clear nvrams that conflict with this setting */
10103			nvram_set("wl_akm", "");
10104		}
10105	}
10106
10107	if (varname)
10108		nvram_set(varname, value);
10109	else
10110		nvram_set(v->name, value);
10111	ret_code = 0;
10112}
10113
10114static void
10115validate_wl_preauth(webs_t wp, char *value, struct variable *v, char *varname)
10116{
10117	char *ptr=NULL;
10118
10119	assert(v);
10120
10121	ptr =( (varname) ? varname : v->name );
10122
10123	if (!strcmp(value, "disabled"))
10124			nvram_set(ptr, "0");
10125	else
10126			nvram_set(ptr, "1");
10127
10128	ret_code =0;
10129
10130	return;
10131}
10132
10133static void
10134validate_wl_auth_mode(webs_t wp, char *value, struct variable *v, char *varname)
10135{
10136
10137	assert(v);
10138
10139	ret_code = EINVAL;
10140
10141	if (!valid_choice(wp, value, v)){
10142		websBufferWrite(wp, "Invalid auto mode string <b>%s</b>",value);
10143		return;
10144	}
10145
10146	if (!strcmp(value, "radius")) {
10147		char *wep = websGetVar(wp, "wl_wep", "");
10148		char *ipaddr = websGetVar(wp, "wl_radius_ipaddr", "");
10149		if (!wep || strcmp(wep, "enabled")) {
10150			websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>Network Authentication</b> is <b>%s</b><br>", value);
10151			return;
10152		}
10153		if (!ipaddr || !strcmp(ipaddr, "")) {
10154			websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>RADIUS Server</b><br>", v->longname);
10155			return;
10156		}
10157	}
10158
10159	if (varname)
10160		nvram_set(varname, value);
10161	else
10162		nvram_set(v->name, value);
10163
10164	ret_code = 0;
10165
10166}
10167
10168static void
10169validate_wl_akm(webs_t wp, char *value, struct variable *v, char *varname)
10170{
10171	char akms[WLC_IOCTL_SMLEN] = "";
10172	char *wpa=NULL, *psk=NULL;
10173	char *wpa2=NULL, *psk2=NULL, *brcm_psk=NULL;
10174	char *name;
10175
10176	assert(v);
10177
10178	ret_code = EINVAL;
10179
10180	wpa = websGetVar(wp, "wl_akm_wpa", NULL);
10181	if( !wpa )
10182		wpa = "disabled";
10183	psk = websGetVar(wp, "wl_akm_psk", NULL);
10184	if( !psk )
10185		psk = "disabled";
10186	wpa2 = websGetVar(wp, "wl_akm_wpa2", NULL);
10187	if( !wpa2 )
10188		wpa2 = "disabled";
10189	psk2 = websGetVar(wp, "wl_akm_psk2", NULL);
10190	if( !psk2 )
10191		psk2 = "disabled";
10192	brcm_psk = websGetVar(wp, "wl_akm_brcm_psk", NULL);
10193	if( !brcm_psk )
10194		brcm_psk = "disabled";
10195
10196	if (!strcmp(wpa, "enabled")
10197	    || !strcmp(wpa2, "enabled")
10198	    ) {
10199		char *ipaddr = websGetVar(wp, "wl_radius_ipaddr", "");
10200		if (!ipaddr || !strcmp(ipaddr, "")) {
10201			websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>RADIUS Server</b><br>", v->longname);
10202			return;
10203		}
10204	}
10205
10206	if (!strcmp(psk, "enabled")
10207	    || !strcmp(psk2, "enabled")
10208	    ) {
10209		char *key = websGetVar(wp, "wl_wpa_psk", "");
10210		if (!key || !strcmp(key, "")) {
10211			websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>WPA Pre-Shared Key</b><br>", v->longname);
10212			return;
10213		}
10214	}
10215
10216	if (!strcmp(wpa, "enabled") || !strcmp(psk, "enabled")
10217	    || !strcmp(wpa2, "enabled") || !strcmp(psk2, "enabled") || !strcmp(brcm_psk, "enabled")
10218	    ) {
10219		char *crypto = websGetVar(wp, "wl_crypto", NULL);
10220		if (!crypto || (
10221			strcmp(crypto, "tkip") &&
10222			strcmp(crypto, "aes") &&
10223			strcmp(crypto, "tkip+aes")
10224			)) {
10225			bool wapi_sel = FALSE;
10226
10227			if (wapi_sel == FALSE) {
10228				websBufferWrite(wp, "Invalid <b>%s</b>: <b>Crypto Algorithm</b> mode must be TKIP or AES or TKIP+AES<br>", v->longname);
10229				return;
10230			}
10231		}
10232	}
10233
10234	if (!strcmp(wpa, "enabled"))
10235		strcat(akms, "wpa ");
10236	if (!strcmp(psk, "enabled"))
10237		strcat(akms, "psk ");
10238	if (!strcmp(wpa2, "enabled"))
10239		strcat(akms, "wpa2 ");
10240	if (!strcmp(psk2, "enabled"))
10241		strcat(akms, "psk2 ");
10242	if (!strcmp(brcm_psk, "enabled"))
10243		strcat(akms, "brcm_psk ");
10244
10245	/* WiFi WPA2 requires that WEP be disabled if WPA2 or WPA2-PSK is used,
10246	 * GUI has the WEP Enable/Disable field disabled when the user selects
10247	 * WPA2, so WEP setting doesn't come in the HTTP buffer, which means we
10248	 * must manually turn it off here to disable WEP.
10249	 */
10250	if ((!strcmp(wpa2, "enabled")) || (!strcmp(psk2, "enabled"))
10251	    || (!strcmp(brcm_psk, "enabled")))
10252		nvram_set("wl_wep", "disabled");
10253
10254	if (varname)
10255		name = varname;
10256	else
10257		name = "wl_akm";
10258
10259	if (nvram_match(name, akms) != TRUE) {
10260		nvram_set(name, akms);
10261#ifdef __CONFIG_WPS__
10262	wps_disable_oob();
10263#endif
10264	}
10265	ret_code = 0;
10266}
10267
10268static void
10269validate_wl_wpa_psk(webs_t wp, char *value, struct variable *v, char *varname)
10270{
10271	int len = strlen(value);
10272	char *c=NULL;
10273	char *name;
10274
10275	assert(v);
10276
10277	ret_code = EINVAL;
10278
10279	if (len == 64) {
10280		for (c = value; *c; c++) {
10281			if (!isxdigit((int) *c)) {
10282				websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>", v->longname, *c);
10283				return;
10284			}
10285		}
10286	} else if (len < 8 || len > 63) {
10287		websBufferWrite(wp, "Invalid <b>%s</b>: must be between 8 and 63 ASCII characters or 64 hexadecimal digits<br>", v->longname);
10288		return;
10289	}
10290
10291	if (varname)
10292		name = varname;
10293	else
10294		name = v->name;
10295
10296	if (nvram_match(name, value) != TRUE) {
10297		nvram_set(name, value);
10298#ifdef __CONFIG_WPS__
10299		wps_disable_oob();
10300#endif
10301	}
10302	ret_code = 0;
10303}
10304
10305static void
10306validate_wl_key(webs_t wp, char *value, struct variable *v, char *varname)
10307{
10308	char *c=NULL;
10309
10310	assert(v);
10311
10312	ret_code = EINVAL;
10313
10314	switch (strlen(value)) {
10315	case 5:
10316	case 13:
10317		break;
10318	case 10:
10319	case 26:
10320		for (c = value; *c; c++) {
10321			if (!isxdigit((int) *c)) {
10322				websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>", v->longname, *c);
10323				return;
10324			}
10325		}
10326		break;
10327	default:
10328		websBufferWrite(wp, "Invalid <b>%s</b>: must be 5 or 13 ASCII characters or 10 or 26 hexadecimal digits<br>", v->longname);
10329		return;
10330	}
10331
10332	if (varname)
10333		nvram_set(varname, value);
10334	else
10335		nvram_set(v->name, value);
10336
10337	ret_code = 0;
10338}
10339
10340static void
10341validate_wl_wep(webs_t wp, char *value, struct variable *v, char *varname)
10342{
10343	char *auth_mode=NULL,*name=NULL, *auth=NULL;
10344
10345	assert(v);
10346
10347	ret_code = EINVAL;
10348
10349	if (!valid_choice(wp, value, v)){
10350		websBufferWrite(wp, "Invalid wep string <b>%s</b>",value);
10351		return;
10352	}
10353	if (varname)
10354		name = varname;
10355	else
10356		name = v->name;
10357
10358
10359	/* WSC 2.0, auth may grayed by WPS enabled */
10360	auth = websGetVar(wp, "wl_auth", "");
10361
10362	auth_mode = websGetVar(wp, "wl_auth_mode", NULL);
10363	if (!strcmp(value, "enabled")) {
10364		if (!auth_mode || strcmp(auth_mode, "radius")) {
10365			char wl_key[] = "wl_keyXXX";
10366			char wl_key_index[] = "wl_keyXXX";
10367
10368			if (varname){
10369				char index[5];
10370				if (!get_index_string(v->prefix,varname,index,sizeof(index)))
10371						return;
10372				snprintf(wl_key_index, sizeof(wl_key_index),"wl%s_key",index);
10373			}else
10374				snprintf(wl_key_index, sizeof(wl_key_index),"wl_key");
10375
10376			snprintf(wl_key, sizeof(wl_key), "%s%s",wl_key_index, nvram_safe_get(wl_key_index));
10377			if (!strlen(nvram_safe_get(wl_key))) {
10378				websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>Network Key %s</b><br>",
10379						v->longname, nvram_safe_get(wl_key_index));
10380				if (nvram_match(name, "enabled")) {
10381					websBufferWrite(wp, "<b>%s</b> is <b>Disabled</b><br>", v->longname);
10382					nvram_set(name, "disabled");
10383				}
10384				return;
10385			}
10386		}
10387		/* WSC 2.0, when wep is enabled, wps must disabled */
10388		if (strcmp(websGetVar(wp, "wl_wps_mode", ""), "enabled") == 0) {
10389			char prefix[] = "wlXXXXXXXXXX_";
10390			char wps_mode[64];
10391			if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
10392				websError(wp, 400, "unit number variable doesn't exist\n");
10393				return;
10394			}
10395			snprintf(wps_mode, sizeof(wps_mode), "%swps_mode", prefix);
10396			nvram_set(wps_mode, "disabled");
10397		}
10398	}
10399	else {
10400		if (!auth || !strcmp(auth, "shared") ||
10401		    ( auth_mode && !strcmp(auth_mode, "radius"))) {
10402			websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>Network Authentication</b> is <b>%s</b><br>", auth_mode);
10403			return;
10404		}
10405	}
10406
10407	nvram_set(name, value);
10408
10409	ret_code = 0;
10410}
10411
10412static void
10413validate_wl_crypto(webs_t wp, char *value, struct variable *v, char *varname)
10414{
10415	char *name;
10416
10417	assert(v);
10418
10419	ret_code = EINVAL;
10420
10421	if (!valid_choice(wp, value, v)){
10422		websBufferWrite(wp, "Invalid crypto config string <b>%s</b>",value);
10423		return;
10424	}
10425
10426	if (varname)
10427		name = varname;
10428	else
10429		name = v->name;
10430
10431	if (nvram_match(name, value) != TRUE) {
10432		nvram_set(name, value);
10433#ifdef __CONFIG_WPS__
10434		wps_disable_oob();
10435#endif
10436	}
10437	ret_code = 0;
10438}
10439
10440#ifdef MFP
10441static void
10442validate_wl_mfp(webs_t wp, char *value, struct variable *v, char *varname)
10443{
10444	char *ptr=NULL;
10445
10446	assert(v);
10447
10448	ptr =( (varname) ? varname : v->name );
10449
10450	if ('0' <= value[0] && value[0] <= '2' && value[1] == '\0')
10451		nvram_set(ptr, value);
10452	else
10453		nvram_set(ptr, "0");
10454
10455	ret_code =0;
10456}
10457#endif
10458
10459#ifdef __CONFIG_NAT__
10460static void
10461validate_wan_ifname(webs_t wp, char *value, struct variable *v, char *varname)
10462{
10463	char ifname[64], *next=NULL;
10464
10465	assert(v);
10466
10467	ret_code = EINVAL;
10468	foreach (ifname, nvram_safe_get("wan_ifnames"), next)
10469		if (!strcmp(ifname, value)) {
10470			nvram_set(v->name, value);
10471			ret_code = 0;
10472			return;
10473		}
10474	websBufferWrite(wp, "Invalid <b>%s</b>: must be one of <b>%s</b><br>", v->longname, nvram_safe_get("wan_ifnames"));
10475}
10476#endif	/* __CONFIG_NAT__ */
10477
10478static void
10479validate_wl_lazywds(webs_t wp, char *value, struct variable *v, char *varname)
10480{
10481	assert(v);
10482
10483	ret_code = EINVAL;
10484	validate_choice(wp, value, v, varname);
10485}
10486
10487static void
10488validate_wl_wds_hwaddrs(webs_t wp, char *value, struct variable *v, char *varname)
10489{
10490	assert(v);
10491
10492	ret_code = EINVAL;
10493	validate_list(wp, value, v, valid_hwaddr, varname);
10494}
10495
10496typedef enum {
10497	CALLFROM_DWDS,
10498	CALLFROM_PSTA
10499} callfrom_e;
10500
10501static void
10502validate_dpsta(webs_t wp, callfrom_e callfrom)
10503{
10504	char *temp = NULL;
10505	int wl_unit = -1;
10506	int wl_subunit = -1;
10507	char *wl_dwds;
10508	char nv_param[NVRAM_MAX_PARAM_LEN];
10509	char nv_interface[NVRAM_MAX_PARAM_LEN];
10510	char os_interface[NVRAM_MAX_PARAM_LEN];
10511	char *mode[2];
10512	int dwds[2];
10513	int psta[2];
10514	int dpsta;
10515
10516	if ((temp = websGetVar(wp, "wl_unit", NULL))) {
10517		if (*temp)
10518			get_ifname_unit(temp, &wl_unit, &wl_subunit);
10519
10520		if (wl_subunit != -1) {
10521			websError(wp, 400, "psta can't be enabled for a virtual i/f\n");
10522			ret_code = EINVAL;
10523		}
10524	}
10525
10526	if (wl_unit == -1) {
10527		websError(wp, 400, "Insufficient args\n");
10528		ret_code = EINVAL;
10529	}
10530
10531	/* While enabling proxy sta,repeater or dwds modes on second wl interface
10532	 * (dual band repeater) set nvram variable dpsta_ifnames to upstream
10533	 * interfaces.
10534	 */
10535
10536	if (callfrom == CALLFROM_DWDS) {
10537		/* Called after setting DWDS from SSID page */
10538		wl_dwds = websGetVar(wp, "wl_dwds", NULL);
10539		if (wl_dwds == NULL) {
10540			ret_code = EINVAL;
10541		}
10542		dwds[wl_unit] = atoi(wl_dwds);
10543
10544		sprintf(nv_param, "wl%d_dwds", 1 - wl_unit);
10545		dwds[1 - wl_unit] = atoi(nvram_safe_get(nv_param));
10546
10547		mode[0] = nvram_safe_get("wl0_mode");
10548		mode[1] = nvram_safe_get("wl1_mode");
10549	} else {
10550		/* Called after setting PSTA/mode from radio page */
10551		mode[wl_unit]= websGetVar(wp, "wl_mode", NULL);
10552		if (mode[wl_unit] == NULL) {
10553			ret_code = EINVAL;
10554		}
10555
10556		sprintf(nv_param, "wl%d_mode", 1 - wl_unit);
10557		mode[1-wl_unit] = nvram_safe_get(nv_param);
10558
10559		dwds[0] = atoi(nvram_safe_get("wl0_dwds"));
10560		dwds[1] = atoi(nvram_safe_get("wl1_dwds"));
10561	}
10562
10563	psta[0] = !strcmp(mode[0], "psta") || !strcmp(mode[0], "psr");
10564	psta[1] = !strcmp(mode[1], "psta") || !strcmp(mode[1], "psr");
10565
10566	dwds[0] = (dwds[0] && strcmp(mode[0], "ap"));
10567	dwds[1] = (dwds[1] && strcmp(mode[1], "ap"));
10568
10569	dpsta = ((dwds[0] || psta[0]) && (dwds[1] || psta[1]));
10570
10571	strcpy(nv_param, "dpsta_ifnames");
10572	if (dpsta) {
10573		char if_list[NVRAM_MAX_VALUE_LEN];
10574		int if_list_size = sizeof(if_list);
10575
10576		sprintf(nv_interface, "wl0");
10577		nvifname_to_osifname(nv_interface, os_interface, sizeof(os_interface));
10578		add_to_list(os_interface, if_list, if_list_size);
10579
10580		sprintf(nv_interface, "wl1");
10581		nvifname_to_osifname(nv_interface, os_interface, sizeof(os_interface));
10582		add_to_list(os_interface, if_list, if_list_size);
10583
10584		nvram_set(nv_param, if_list);
10585	} else {
10586		nvram_set(nv_param, "");
10587	}
10588}
10589
10590static bool
10591validate_psta(webs_t wp, char *value, struct variable *v, char *varname)
10592{
10593	char *temp = NULL;
10594	int wl_unit = -1;
10595	int wl_subunit = -1;
10596	char *wl_mode;
10597	char nv_param[NVRAM_MAX_PARAM_LEN];
10598	char nv_interface[NVRAM_MAX_PARAM_LEN];
10599	char os_interface[NVRAM_MAX_PARAM_LEN];
10600	char interface_list[NVRAM_MAX_VALUE_LEN];
10601	int interface_list_size = sizeof(interface_list);
10602	char lan_ifnames[NVRAM_MAX_PARAM_LEN] = "lan_ifnames";
10603	char cap[WLC_IOCTL_SMLEN];
10604	char caps[WLC_IOCTL_MEDLEN];
10605	char *name = NULL;
10606	char *next = NULL;
10607	int max_no_vifs = 0;
10608	int i = 0;
10609	char tmp[20];
10610	bool psta, psr, db_rpt;
10611
10612	if ((temp = websGetVar(wp, "wl_unit", NULL))) {
10613		if (*temp) {
10614			if (get_ifname_unit(temp, &wl_unit, &wl_subunit) != 0) {
10615				websError(wp, 400, "psta error getting wl_unit\n");
10616				ret_code = EINVAL;
10617				return FALSE;
10618			}
10619		}
10620
10621		if (wl_subunit != -1) {
10622			websError(wp, 400, "psta can't be enabled for a virtual i/f\n");
10623			ret_code = EINVAL;
10624			return FALSE;
10625		}
10626	}
10627
10628	if (wl_unit == -1) {
10629		websError(wp, 400, "Insufficient args\n");
10630		ret_code = EINVAL;
10631		return FALSE;
10632	}
10633
10634	wl_mode = websGetVar(wp, "wl_mode", NULL);
10635	if (wl_mode == NULL) {
10636		ret_code = EINVAL;
10637		return FALSE;
10638	}
10639
10640	psta = !strcmp(wl_mode, "psta");
10641	psr = !strcmp(wl_mode, "psr");
10642
10643	sprintf(nv_param, "wl_mode");
10644	temp = nvram_safe_get(nv_param);
10645	/* No change in mode */
10646	if ((strcmp(temp, wl_mode) == 0) || (strlen(temp) == 0)) {
10647		ret_code = 0;
10648		return TRUE;
10649	}
10650
10651	/* Get the number of VIFS */
10652	sprintf(nv_interface, "wl%d_ifname", wl_unit);
10653	name = nvram_safe_get(nv_interface);
10654	if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps))) {
10655		ret_code = EINVAL;
10656		return FALSE;
10657	}
10658	foreach(cap, caps, next) {
10659		if (!strcmp(cap, "mbss16"))
10660			max_no_vifs = 16;
10661		else if (!strcmp(cap, "mbss4"))
10662			max_no_vifs = 4;
10663	}
10664
10665	/* See if other interface also has psta or psr enabled */
10666	sprintf(nv_param, "wl%d_mode", 1 - wl_unit);
10667	db_rpt = ((!strcmp(nvram_safe_get(nv_param), "psta") ||
10668		   !strcmp(nvram_safe_get(nv_param), "psr")) && (psta || psr));
10669
10670	if (psta || psr) {
10671		temp = nvram_safe_get(lan_ifnames);
10672		if (interface_list_size <= strlen(temp)) {
10673			websError(wp, 400, "string too long\n");
10674			ret_code = EINVAL;
10675			return FALSE;
10676		}
10677		strncpy(interface_list, temp, interface_list_size);
10678
10679		sprintf(nv_interface, "wl%d.1", wl_unit);
10680
10681		/* Set the wl mode for the virtual interface */
10682		sprintf(nv_param, "wl%d.1_mode", wl_unit);
10683		if (psta) {
10684			/* For Proxy we need to remove our ap interface */
10685			remove_from_list(nv_interface, interface_list, interface_list_size);
10686			nvram_set(lan_ifnames, interface_list);
10687
10688			/* Clear the ap mode */
10689			nvram_set(nv_param, "");
10690		} else {
10691			/* For Repeater we need to add our ap interface to the bridged lan */
10692			add_to_list(nv_interface, interface_list, interface_list_size);
10693			nvram_set(lan_ifnames, interface_list);
10694
10695			/* Set the ap mode */
10696			nvram_set(nv_param, "ap");
10697		}
10698
10699		/* Turn off wlX_ure when proxy repeater modes are enabled */
10700		nvram_set("wl_ure", "0");
10701
10702		/* Security - We don't support any RADIUS-based authentication,
10703		 * so we must force these options to OFF.
10704		 */
10705		/* turn off wlX_auth_mode and wlX.1_auth_mode */
10706		sprintf(nv_param, "wl%d_auth_mode", wl_unit);
10707		nvram_set(nv_param, "none");
10708		sprintf(nv_param, "wl%d.1_auth_mode", wl_unit);
10709		nvram_set(nv_param, "none");
10710		/* Remove wpa and wpa2 from wlX_akm and wlX.1_akm */
10711		/* wl_akm should be used here rather than wlX_akm, it's an
10712		 * indexed param, so wl_akm represents wlX_akm
10713		 */
10714		sprintf(nv_param, "wl_akm");
10715		temp = nvram_get(nv_param);
10716		if (temp && *temp) {
10717			memset(interface_list, 0, interface_list_size);
10718			/* NOTE: using "interface_list" to hold security nvram values */
10719			strncpy(interface_list, temp, interface_list_size - 1);
10720			remove_from_list("wpa", interface_list, interface_list_size);
10721			remove_from_list("wpa2", interface_list, interface_list_size);
10722			nvram_set(nv_param, interface_list);
10723		}
10724		sprintf(nv_param, "wl%d.1_akm", wl_unit);
10725		temp = nvram_get(nv_param);
10726		if(temp && *temp) {
10727			memset(interface_list, 0, interface_list_size);
10728			/* NOTE: using "interface_list" to hold security nvram values */
10729			strncpy(interface_list, temp, interface_list_size - 1);
10730			remove_from_list("wpa", interface_list, interface_list_size);
10731			remove_from_list("wpa2", interface_list, interface_list_size);
10732			nvram_set(nv_param, interface_list);
10733		}
10734
10735		sprintf(nv_param, "wl%d.1_bss_enabled", wl_unit);
10736
10737		if (psta) {
10738			nvram_set(nv_param, "0");
10739		} else {
10740			nvram_set(nv_param, "1");
10741		}
10742
10743		/* Make lan1_ifname lan1_ifnames empty so that br1 is not created
10744		 * in psta/psr modes.
10745		 */
10746	        nvram_set("lan1_ifname", "");
10747	        nvram_set("lan1_ifnames", "");
10748
10749		/* Disable all VIFS wlX.2 onwards */
10750		for (i = 2; i < max_no_vifs; i++) {
10751			sprintf(nv_param, "wl%d.%d_bss_enabled", wl_unit, i);
10752			nvram_set(nv_param, "0");
10753		}
10754	} else {
10755		/* Now we need to remove the virtual i/f from the bridged lan interfaces */
10756		temp = nvram_safe_get(lan_ifnames);
10757		if(interface_list_size <= strlen(temp)) {
10758			websError(wp, 400, "string too long\n");
10759			ret_code = EINVAL;
10760			return FALSE;
10761		}
10762		strncpy(interface_list, temp, interface_list_size);
10763		sprintf(nv_interface, "wl%d.1", wl_unit);
10764		/* Virtual interfaces that appear in NVRAM lists are ALWAYS stored
10765		 * as the NVRAM_FORM so we can add to list without translating.
10766		 */
10767		remove_from_list(nv_interface, interface_list, interface_list_size);
10768		/* Add our primary interface to lan_ifnames - default behavior */
10769		sprintf(nv_interface, "wl%d", wl_unit);
10770		nvifname_to_osifname(nv_interface, os_interface, sizeof(os_interface));
10771		add_to_list(os_interface, interface_list, interface_list_size);
10772		nvram_set(lan_ifnames, interface_list);
10773
10774		/* Make lan1_ifname, lan1_ifnames to default values */
10775	        nvram_set("lan1_ifname", "br1");
10776		memset(interface_list, 0, interface_list_size);
10777		for (i = 1; i < max_no_vifs; i++) {
10778			sprintf(nv_interface, "wl%d.%d", wl_unit, i);
10779			add_to_list(nv_interface, interface_list, interface_list_size);
10780			nvram_set(strcat_r(nv_interface, "_hwaddr", tmp), "");
10781		}
10782	       	nvram_set("lan1_ifnames", interface_list);
10783	}
10784
10785	return TRUE;
10786}
10787
10788
10789static void
10790validate_wl_mode(webs_t wp, char *value, struct variable *v, char *varname)
10791{
10792	assert(v);
10793
10794	ret_code = EINVAL;
10795
10796	if (!valid_choice(wp, value, v))
10797		return;
10798
10799	/* Configure the nvram for Proxy STA or Repeater modes */
10800	if (!validate_psta(wp, value, v, varname))
10801		return;
10802
10803	if (varname)
10804		nvram_set(varname, value);
10805	else
10806		nvram_set(v->name, value);
10807
10808	/* Based on DWDS/PSTA/PSR, turn on/off dpsta */
10809	validate_dpsta(wp, CALLFROM_PSTA);
10810
10811	ret_code = 0;
10812}
10813
10814static void
10815validate_wl_dwds(webs_t wp, char *value, struct variable *v, char *varname)
10816{
10817	assert(v);
10818
10819	ret_code = EINVAL;
10820
10821	if (!valid_choice(wp, value, v))
10822		return;
10823
10824	if (varname)
10825		nvram_set(varname, value);
10826	else
10827		nvram_set(v->name, value);
10828
10829	/* Based on DWDS/PSTA/PSR, turn on/off dpsta */
10830	validate_dpsta(wp, CALLFROM_DWDS);
10831
10832	ret_code = 0;
10833}
10834
10835static void
10836validate_wme_bool(webs_t wp, char *value, struct variable *v,char *varname)
10837{
10838	char *wme=NULL;
10839
10840	assert(v);
10841
10842	ret_code = EINVAL;
10843
10844	/* return if wme is not enabled */
10845	if (!(wme = websGetVar(wp, "wl_wme", NULL))){
10846		ret_code = 0;
10847		return;
10848	} else if (!strcmp(wme, "off")){
10849		ret_code = 0;
10850		return;
10851	}
10852
10853	validate_choice(wp, value, v, varname);
10854}
10855
10856#define CW_VALID(v)	((v) >= 0 && (v) <= 32767 && ((v) & ((v) + 1)) == 0)
10857#define AIFSN_VALID(a)	((a) >= 1 && (a) <= 15)
10858#define TXOP_VALID(t)	((t) >= 0 && (t) <= 65504 && ((t) % 32) == 0)
10859
10860static void
10861validate_wl_wme_params(webs_t wp, char *value, struct variable *v, char *varname)
10862{
10863	int cwmin = 0, cwmax = 0, aifsn = 1, txop_b = 0, txop_ag = 0;
10864	char acm_str[100] = "off", dof_str[100] = "off";
10865	char *s, *errmsg;
10866	char tmp[256];
10867
10868	assert(v);
10869
10870	ret_code = EINVAL;
10871
10872	/* return if wme is not enabled */
10873	if (!(s = websGetVar(wp, "wl_wme", NULL))) {
10874		ret_code = 0;
10875		return;
10876	} else if (!strcmp(s, "off")) {
10877		ret_code = 0;
10878		return;
10879	}
10880
10881	if (!value || atoi(value) != 5) {		/* Number of INPUTs */
10882		ret_code = 0;
10883		return;
10884	}
10885
10886	s = nvram_get(v->name);
10887
10888	if (s != NULL)
10889		sscanf(s, "%d %d %d %d %d %s %s",
10890		       &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, acm_str, dof_str);
10891
10892	if ((value = websGetVar(wp, strcat_r(v->name, "0", tmp), NULL)) != NULL)
10893		cwmin = atoi(value);
10894
10895	if ((value = websGetVar(wp, strcat_r(v->name, "1", tmp), NULL)) != NULL)
10896		cwmax = atoi(value);
10897
10898	if (!CW_VALID(cwmin) || !CW_VALID(cwmax)) {
10899		errmsg = "CWmin and CWmax must be one less than a power of 2, up to 32767.";
10900		goto error;
10901	}
10902
10903	if (cwmax < cwmin) {
10904		errmsg = "CWmax must be greater than CWmin.";
10905		goto error;
10906	}
10907
10908	if ((value = websGetVar(wp, strcat_r(v->name, "2", tmp), NULL)) != NULL)
10909		aifsn = atoi(value);
10910
10911	if (!AIFSN_VALID(aifsn)) {
10912		errmsg = "AIFSN must be in the range 1 to 15.";
10913		goto error;
10914	}
10915
10916	if ((value = websGetVar(wp, strcat_r(v->name, "3", tmp), NULL)) != NULL)
10917		txop_b = atoi(value);
10918
10919	if ((value = websGetVar(wp, strcat_r(v->name, "4", tmp), NULL)) != NULL)
10920		txop_ag = atoi(value);
10921
10922	if (!TXOP_VALID(txop_b) || !TXOP_VALID(txop_ag)) {
10923		errmsg = "TXOP(b) and TXOP(a/g) must be multiples of 32 in the range 0 to 65504.";
10924		goto error;
10925	}
10926
10927	if ((value = websGetVar(wp, strcat_r(v->name, "5", tmp), NULL)) != NULL)
10928		if (!strcmp(value, "off") || !strcmp(value, "on")) {
10929			strncpy(acm_str, value, sizeof(acm_str)-1);
10930			acm_str[sizeof(acm_str)-1] = '\0';
10931		}
10932
10933	if ((value = websGetVar(wp, strcat_r(v->name, "6", tmp), NULL)) != NULL)
10934		if (!strcmp(value, "off") || !strcmp(value, "on")) {
10935			strncpy(dof_str, value, sizeof(dof_str)-1);
10936			dof_str[sizeof(dof_str)-1] = '\0';
10937		}
10938
10939	sprintf(tmp, "%d %d %d %d %d %s %s",
10940	        cwmin, cwmax, aifsn, txop_b, txop_ag, acm_str, dof_str);
10941
10942	nvram_set(v->name, tmp);
10943
10944	ret_code = 0;
10945
10946	return;
10947
10948error:
10949        websBufferWrite(wp, "Error setting WME AC value: <b>");
10950        websBufferWrite(wp, errmsg);
10951	websBufferWrite(wp, "<b><br>");
10952}
10953
10954uint8 prio2ac[NUMPRIO] = {
10955	AC_BE,	/* 0	BE	Best Effort */
10956	AC_BK,	/* 1	BK	Background */
10957	AC_BK,	/* 2	--	Background */
10958	AC_BE,	/* 3	EE	Best Effort */
10959	AC_VI,	/* 4	CL	Video */
10960	AC_VI,	/* 5	VI	Video */
10961	AC_VO,	/* 6	VO	Voice */
10962	AC_VO	/* 7	NC	Voice */
10963};
10964
10965static void
10966wl_set_ampdu_rerty_limit(char *acname, int srl, int sfbl)
10967{
10968	int ac_type = -1;
10969	int retry[NUMPRIO], rr_retry[NUMPRIO], tid, len;
10970	char tmp[256], *s, nvram[256], prefix[] = "wlXXXXXXXXXX_";
10971
10972	if (acname == NULL ||
10973	     (len = strlen(acname)) < 2)
10974		return;
10975
10976	if (acname[len-2] == 'b') {
10977		if (acname[len-1] == 'e')
10978			ac_type = AC_BE;
10979		else if (acname[len-1] == 'k')
10980			ac_type = AC_BK;
10981	}
10982	else if (acname[len-2] == 'v') {
10983		if (acname[len-1] == 'i')
10984			ac_type = AC_VI;
10985		else if (acname[len-1] == 'o')
10986			ac_type = AC_VO;
10987	}
10988
10989	if (ac_type == -1)
10990		return;
10991
10992	/*
10993	 * convert ac_type to tid index, set srl to ampdu_rtylimit_tid,
10994	 * set sfbl to ampdu_rr_rtylimit_tid.
10995	*/
10996	sprintf(prefix,"wl%s_", nvram_get("wl_unit"));
10997	s = nvram_get(strcat_r(prefix, "ampdu_rtylimit_tid", nvram));
10998	if (!s) {
10999		s = nvram_default_get(strcat_r(prefix, "ampdu_rtylimit_tid", nvram));
11000	}
11001	if (s != NULL)
11002		sscanf(s, "%d %d %d %d %d %d %d %d",
11003		       &retry[0], &retry[1], &retry[2], &retry[3],
11004		       &retry[4], &retry[5], &retry[6], &retry[7]);
11005
11006	s = nvram_get(strcat_r(prefix, "ampdu_rr_rtylimit_tid", nvram));
11007	if (!s) {
11008		s = nvram_default_get(strcat_r(prefix, "ampdu_rtylimit_tid", nvram));
11009	}
11010	if (s != NULL)
11011		sscanf(s, "%d %d %d %d %d %d %d %d",
11012		       &rr_retry[0], &rr_retry[1], &rr_retry[2], &rr_retry[3],
11013		       &rr_retry[4], &rr_retry[5], &rr_retry[6], &rr_retry[7]);
11014
11015	for (tid = 0; tid < NUMPRIO; tid++) {
11016		if (ac_type == prio2ac[tid]) {
11017			/* over-write retry[tid] and rr_retry[tid] value */
11018			retry[tid] = srl;
11019			rr_retry[tid] = sfbl;
11020		}
11021	}
11022
11023	sprintf(tmp, "%d %d %d %d %d %d %d %d",
11024	        retry[0], retry[1], retry[2], retry[3], retry[4],
11025	        retry[5], retry[6], retry[7]);
11026
11027	nvram_set(strcat_r(prefix, "ampdu_rtylimit_tid", nvram), tmp);
11028
11029	sprintf(tmp, "%d %d %d %d %d %d %d %d",
11030	        rr_retry[0], rr_retry[1], rr_retry[2], rr_retry[3],
11031	        rr_retry[4], rr_retry[5], rr_retry[6], rr_retry[7]);
11032	nvram_set(strcat_r(prefix, "ampdu_rr_rtylimit_tid", nvram), tmp);
11033
11034	return;
11035}
11036
11037#define SRL_VALID(v)        (((v) > 0) && ((v) <= 15))
11038#define SFBL_VALID(v)       (((v) > 0) && ((v) <= 15))
11039#define LRL_VALID(v)        (((v) > 0) && ((v) <= 15))
11040#define LFBL_VALID(v)       (((v) > 0) && ((v) <= 15))
11041
11042static void
11043validate_wl_wme_tx_params(webs_t wp, char *value, struct variable *v, char *varname)
11044{
11045	int srl = 0, sfbl = 0, lrl = 0, lfbl = 0, max_rate = 0, nmode = 0;
11046	char *s, *errmsg;
11047	char tmp[256];
11048
11049	assert(v);
11050
11051	ret_code = EINVAL;
11052
11053	/* return if wme is not enabled */
11054	if (!(s = websGetVar(wp, "wl_wme", NULL))) {
11055		ret_code = 0;
11056		return;
11057	} else if (!strcmp(s, "off")) {
11058		ret_code = 0;
11059		return;
11060	}
11061
11062	if (!value || atoi(value) != 5) {		/* Number of INPUTs */
11063		ret_code = 0;
11064		return;
11065	}
11066
11067	s = nvram_get(v->name);
11068
11069	if (s != NULL)
11070		sscanf(s, "%d %d %d %d %d", &srl, &sfbl, &lrl, &lfbl, &max_rate);
11071
11072	if ((value = websGetVar(wp, strcat_r(v->name, "0", tmp), NULL)) != NULL)
11073		srl = atoi(value);
11074
11075	if (!SRL_VALID(srl)) {
11076		errmsg = "Short Retry Limit must be in the range 1 to 15";
11077		goto error;
11078	}
11079
11080	if ((value = websGetVar(wp, strcat_r(v->name, "1", tmp), NULL)) != NULL)
11081		sfbl = atoi(value);
11082
11083	if (!SFBL_VALID(sfbl)) {
11084		errmsg = "Short Fallback Limit must be in the range 1 to 15";
11085		goto error;
11086	}
11087
11088	if ((value = websGetVar(wp, strcat_r(v->name, "2", tmp), NULL)) != NULL)
11089		lrl = atoi(value);
11090
11091	if (!LRL_VALID(lrl)) {
11092		errmsg = "Long Retry Limit must be in the range 1 to 15";
11093		goto error;
11094	}
11095
11096	if ((value = websGetVar(wp, strcat_r(v->name, "3", tmp), NULL)) != NULL)
11097		lfbl = atoi(value);
11098
11099	if (!LFBL_VALID(lfbl)) {
11100		errmsg = "Long Fallback Limit must be in the range 1 to 15";
11101		goto error;
11102	}
11103
11104	if ((value = websGetVar(wp, strcat_r(v->name, "4", tmp), NULL)) != NULL)
11105		max_rate = atoi(value);
11106
11107	s = nvram_get("wl_nmode");
11108	if (s != NULL)
11109		nmode = atoi(s);
11110
11111	sprintf(tmp, "%d %d %d %d %d",
11112	        srl, sfbl, lrl, lfbl, max_rate);
11113
11114	nvram_set(v->name, tmp);
11115
11116	wl_set_ampdu_rerty_limit(v->name, srl, sfbl);
11117
11118	ret_code = 0;
11119
11120	return;
11121
11122error:
11123	websBufferWrite(wp, "Error setting WME TX parameters value: <b>");
11124	websBufferWrite(wp, errmsg);
11125	websBufferWrite(wp, "<b><br>");
11126}
11127
11128static void
11129validate_dfs_prefchan(webs_t wp, char *value, struct variable *v, char *varname)
11130{
11131	char tmp[256];
11132	char pref0[32], pref1[32], pref2[32], pref3[32], pref4[32], pref5[32];
11133
11134	if ((value = websGetVar(wp, strcat_r(v->name, "0", tmp), NULL)) != NULL)
11135		sprintf(pref0, "%s", !strcmp("N/A", value) ? "0" : value);
11136	else
11137		sprintf(pref0, "%s", "0");
11138	if ((value = websGetVar(wp, strcat_r(v->name, "1", tmp), NULL)) != NULL)
11139		sprintf(pref1, "%s", !strcmp("N/A", value) ? "0" : value);
11140	else
11141		sprintf(pref1, "%s", "0");
11142	if ((value = websGetVar(wp, strcat_r(v->name, "2", tmp), NULL)) != NULL)
11143		sprintf(pref2, "%s", !strcmp("N/A", value) ? "0" : value);
11144	else
11145		sprintf(pref2, "%s", "0");
11146	if ((value = websGetVar(wp, strcat_r(v->name, "3", tmp), NULL)) != NULL)
11147		sprintf(pref3, "%s", !strcmp("N/A", value) ? "0" : value);
11148	else
11149		sprintf(pref3, "%s", "0");
11150	if ((value = websGetVar(wp, strcat_r(v->name, "4", tmp), NULL)) != NULL)
11151		sprintf(pref4, "%s", !strcmp("N/A", value) ? "0" : value);
11152	else
11153		sprintf(pref4, "%s", "0");
11154	if ((value = websGetVar(wp, strcat_r(v->name, "5", tmp), NULL)) != NULL)
11155		sprintf(pref5, "%s", !strcmp("N/A", value) ? "0" : value);
11156	else
11157		sprintf(pref5, "%s", "0");
11158
11159	sprintf(tmp, "%s %s %s %s %s %s", pref0, pref1, pref2, pref3, pref4, pref5);
11160
11161	nvram_set(v->name, tmp);
11162	ret_code = 0;
11163	return;
11164}
11165
11166/* Hook to write wl_* default set through to wl%d_* variable set */
11167static void
11168wl_unit(webs_t wp, char *value, struct variable *v, char *varname)
11169{
11170	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
11171	char *wl_bssid = NULL;
11172	char vif[64];
11173
11174	assert(v);
11175
11176	ret_code = 0;
11177
11178	if (!value) return;
11179
11180
11181	if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid))){
11182		snprintf(vif,sizeof(vif),"%s.%s",value,wl_bssid);
11183		value = vif;
11184	}
11185
11186
11187
11188	/* The unit numbers are built dynamically so what is
11189	   present is assumed to be running */
11190
11191	snprintf(prefix,sizeof(prefix),"wl%s_",value);
11192
11193	/* Write through to selected variable set
11194	 * If the VIF_IGNORE flag is set, we still need to write if the interface is the
11195	 * physical device.
11196	 */
11197
11198	for (; v >= variables && !strncmp(v->name, "wl_", 3); v--){
11199		if (( v->ezc_flags & WEB_IGNORE) || ((v->ezc_flags & VIF_IGNORE) && (prefix[3] == '.')))
11200			continue;
11201		nvram_set(strcat_r(prefix, &v->name[3], tmp), nvram_safe_get(v->name));
11202	}
11203}
11204
11205#ifdef __CONFIG_NAT__
11206static void
11207wan_primary(webs_t wp)
11208{
11209	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
11210	int i;
11211
11212	for (i = 0; i < MAX_NVPARSE; i ++) {
11213		/* skip non-exist and disabled connection */
11214		WAN_PREFIX(i, prefix);
11215		if (!nvram_get(strcat_r(prefix, "unit", tmp))||
11216		    nvram_match(strcat_r(prefix, "proto", tmp), "disabled"))
11217			continue;
11218		/* make connection <i> primary */
11219		nvram_set(strcat_r(prefix, "primary", tmp), "1");
11220		/* notify the user */
11221		websBufferWrite(wp, "<br><b>%s</b> is set to primary.",
11222			wan_name(i, prefix, tmp, sizeof(tmp)));
11223		break;
11224	}
11225}
11226
11227/* Hook to write wan_* default set through to wan%d_* variable set */
11228static void
11229wan_unit(webs_t wp, char *value, struct variable *v, char *varname)
11230{
11231	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
11232	char pppx[] = "pppXXXXXXXXXXX";
11233	int unit, i;
11234	char *wan_ifname=NULL;
11235	int wan_disabled = 0;
11236	int wan_prim = 0;
11237	int wan_wildcard = 0;
11238	char *wan_pppoe_service=NULL;
11239	char *wan_pppoe_ac=NULL;
11240	char wan_tmp[NVRAM_BUFSIZE];
11241	int wildcard;
11242	char *pppoe_service=NULL;
11243	char *pppoe_ac=NULL;
11244	unsigned char ea[ETHER_ADDR_LEN], wan_ea[ETHER_ADDR_LEN];
11245
11246	assert(v);
11247	ret_code = 0;
11248
11249	/* Do not write through if no connections are present */
11250	if ((unit = atoi(value)) < 0)
11251		return;
11252
11253	/* override wan_pppoe_ifname */
11254	if (nvram_match("wan_proto", "pppoe")) {
11255		snprintf(pppx, sizeof(pppx), "ppp%d", unit);
11256		nvram_set("wan_pppoe_ifname", pppx);
11257	}
11258	/*
11259	* Need to make sure this connection can co-exist with others.
11260	* Disable others if it can't (assuming this is the wanted one).
11261	* Disabled connection is for sure no problem to co-exist with
11262	* other connections.
11263	*/
11264	if (nvram_match("wan_proto", "disabled")) {
11265		/* Non primary always go with disabled connection. */
11266		nvram_set("wan_primary", "0");
11267		wan_disabled = 1;
11268	}
11269	/*
11270	* PPPoE connection is for sure no problem to co-exist with
11271	* other PPPoE connections even when they share the same
11272	* ethernet interface, but we need to make sure certain
11273	* PPPoE parameters are reasonablely different from eatch other
11274	* if they share the same ethernet interface.
11275	*/
11276	else if (nvram_match("wan_proto", "pppoe")) {
11277		/* must disable others if this connection is wildcard (any service any ac) */
11278		wan_pppoe_service = nvram_get("wan_pppoe_service");
11279		wan_pppoe_ac = nvram_get("wan_pppoe_ac");
11280		wan_wildcard = (wan_pppoe_service == NULL || *wan_pppoe_service == 0) &&
11281			(wan_pppoe_ac == NULL || *wan_pppoe_ac == 0);
11282		wan_ifname = nvram_safe_get("wan_ifname");
11283		wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp));
11284		/* check all PPPoE connections that share the same interface */
11285		for (i = 0; i < MAX_NVPARSE; i ++) {
11286			/* skip the current connection */
11287			if (i == unit)
11288				continue;
11289			/* skip non-exist and connection that does not share the same i/f */
11290			WAN_PREFIX(i, prefix);
11291			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
11292			    nvram_match(strcat_r(prefix, "proto", tmp), "disabled") ||
11293			    nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname))
11294				continue;
11295			/* PPPoE can share the same i/f, but none can be wildcard */
11296			if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) {
11297				if (wan_wildcard) {
11298					/* disable connection <i> */
11299					nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
11300					nvram_set(strcat_r(prefix, "primary", tmp), "0");
11301					/* notify the user */
11302					websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because both "
11303						"<b>PPPoE Service Name</b> and <b>PPPoE Access Concentrator</b> "
11304						"in <b>%s</b> are empty.",
11305						wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp);
11306				}
11307				else {
11308					pppoe_service = nvram_get(strcat_r(prefix, "pppoe_service", tmp));
11309					pppoe_ac = nvram_get(strcat_r(prefix, "pppoe_ac", tmp));
11310					wildcard = (pppoe_service == NULL || *pppoe_service == 0) &&
11311						(pppoe_ac == NULL || *pppoe_ac == 0);
11312					/* allow connection <i> if certain pppoe parameters are not all same */
11313					if (!wildcard &&
11314					    (nvram_invmatch(strcat_r(prefix, "pppoe_service", tmp), nvram_safe_get("wan_pppoe_service")) ||
11315					         nvram_invmatch(strcat_r(prefix, "pppoe_ac", tmp), nvram_safe_get("wan_pppoe_ac"))))
11316						continue;
11317					/* disable connection <i> */
11318					nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
11319					nvram_set(strcat_r(prefix, "primary", tmp), "0");
11320					/* notify the user */
11321					websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because both its "
11322						"<b>PPPoE Service Name</b> and <b>PPPoE Access Concentrator</b> "
11323						"are empty.",
11324						wan_name(i, prefix, tmp, sizeof(tmp)));
11325				}
11326			}
11327			/* other types can't (?) share the same i/f with PPPoE */
11328			else {
11329				/* disable connection <i> */
11330				nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
11331				nvram_set(strcat_r(prefix, "primary", tmp), "0");
11332				/* notify the user */
11333				websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because it can't  "
11334					"share the same interface with <b>%s</b>.",
11335					wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp);
11336			}
11337		}
11338	}
11339	/*
11340	* All other types (now DHCP, Static) can't co-exist with
11341	* other connections if they use the same ethernet i/f.
11342	*/
11343	else {
11344		wan_ifname = nvram_safe_get("wan_ifname");
11345		wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp));
11346		/* check all connections that share the same interface */
11347		for (i = 0; i < MAX_NVPARSE; i ++) {
11348			/* skip the current connection */
11349			if (i == unit)
11350				continue;
11351			/* check if connection <i> exists and share the same i/f*/
11352			WAN_PREFIX(i, prefix);
11353			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
11354			    nvram_match(strcat_r(prefix, "proto", tmp), "disabled") ||
11355			    nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname))
11356				continue;
11357			/* disable connection <i> */
11358			nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
11359			nvram_set(strcat_r(prefix, "primary", tmp), "0");
11360			/* notify the user */
11361			websBufferWrite(wp, "<br><b>%s</b> is disabled because it can't share "
11362				"the ethernet interface with <b>%s</b>.",
11363				wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp);
11364		}
11365	}
11366
11367	/*
11368	* Check if MAC address has been changed. Need to sync it to all connections
11369	* that share the same i/f if it is changed.
11370	*/
11371	WAN_PREFIX(unit, prefix);
11372	ether_atoe(nvram_safe_get("wan_hwaddr"), wan_ea);
11373	ether_atoe(nvram_safe_get(strcat_r(prefix, "hwaddr", tmp)), ea);
11374	if (memcmp(ea, wan_ea, ETHER_ADDR_LEN)) {
11375		wan_ifname = nvram_safe_get("wan_ifname");
11376		wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp));
11377		/* sync all connections that share the same interface */
11378		for (i = 0; i < MAX_NVPARSE; i ++) {
11379			/* skip the current connection */
11380			if (i == unit)
11381				continue;
11382			/* check if connection <i> exists and share the same i/f*/
11383			WAN_PREFIX(i, prefix);
11384			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
11385			    nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname))
11386				continue;
11387			/* check if connection <i>'s hardware address is different */
11388			if (ether_atoe(nvram_safe_get(strcat_r(prefix, "hwaddr", tmp)), ea) &&
11389			    !memcmp(ea, wan_ea, ETHER_ADDR_LEN))
11390			    continue;
11391			/* change connection <i>'s hardware address */
11392			nvram_set(strcat_r(prefix, "hwaddr", tmp), nvram_safe_get("wan_hwaddr"));
11393			/* notify the user */
11394			websBufferWrite(wp, "<br><b>MAC Address</b> in <b>%s</b> is changed to "
11395				"<b>%s</b> because it shares the ethernet interface with <b>%s</b>.",
11396				wan_name(i, prefix, tmp, sizeof(tmp)), nvram_safe_get("wan_hwaddr"),
11397				wan_tmp);
11398		}
11399	}
11400
11401	/* Set prefix */
11402	WAN_PREFIX(unit, prefix);
11403
11404	/* Write through to selected variable set */
11405	for (; v >= variables && !strncmp(v->name, "wan_", 4); v--){
11406		if (v->ezc_flags & WEB_IGNORE)
11407			continue;
11408		nvram_set(strcat_r(prefix, &v->name[4], tmp), nvram_safe_get(v->name));
11409	}
11410
11411	/*
11412	* There must be one and only one primary connection among all
11413	* enabled connections so that traffic can be routed by default
11414	* through the primary connection unless they are targetted to
11415	* a specific connection by means of static routes. (Primary ~=
11416	* Default Gateway).
11417	*/
11418	/* the current connection is primary, set others to non-primary */
11419	if (!wan_disabled && nvram_match(strcat_r(prefix, "primary", tmp), "1")) {
11420		/* set other connections to non-primary */
11421		for (i = 0; i < MAX_NVPARSE; i ++) {
11422			/* skip the current connection */
11423			if (i == unit)
11424				continue;
11425			/* skip non-exist and disabled connection */
11426			WAN_PREFIX(i, prefix);
11427			if (!nvram_get(strcat_r(prefix, "unit", tmp)) ||
11428			    nvram_match(strcat_r(prefix, "proto", tmp), "disabled"))
11429				continue;
11430			/* skip non-primary connection */
11431			if (nvram_invmatch(strcat_r(prefix, "primary", tmp), "1"))
11432				continue;
11433			/* force primary to non-primary */
11434			nvram_set(strcat_r(prefix, "primary", tmp), "0");
11435			/* notify the user */
11436			websBufferWrite(wp, "<br><b>%s</b> is set to non-primary.",
11437				wan_name(i, prefix, tmp, sizeof(tmp)));
11438		}
11439		wan_prim = 1;
11440	}
11441	/* the current connection is not parimary, check if there is any primary */
11442	else {
11443		/* check other connections to see if there is any primary */
11444		for (i = 0; i < MAX_NVPARSE; i ++) {
11445			/* skip the current connection */
11446			if (i == unit)
11447				continue;
11448			/* primary connection exists, honor it */
11449			WAN_PREFIX(i, prefix);
11450			if (nvram_match(strcat_r(prefix, "primary", tmp), "1")) {
11451				wan_prim = 1;
11452				break;
11453			}
11454		}
11455	}
11456	/* no one is primary, pick the first enabled one as primary */
11457	if (!wan_prim)
11458		wan_primary(wp);
11459}
11460#endif	/* __CONFIG_NAT__ */
11461
11462/* This is the monster V-block
11463 *
11464 * It controls the following functions
11465 *
11466 * Configuration variables are validated and saved in NVRAM
11467 * Variables saved by NVRAM save/restore routine
11468 * Method in which the variables are to be validates
11469 * SES handling
11470 *
11471 * The control flags:
11472 * EZC_FLAGS_READ,EZC_FLAGS_WRITE :Ses read/write flags
11473 * NVRAM_ENCRYPT: Encrypt variable prior to downloading NVRAM variable to file
11474 * NVRAM_MI: Multi instance NVRAM variable eg wlXX,wanXX
11475 * NVRAM_VLAN_MULTI: Special flag to handle oddball vlanXXname and its cousins
11476 * NVRAM_MP: Variable can be single & multi instance eg lan_ifname, lanX_ifname
11477 * NVRAM_IGNORE: Dont save/restore this var.
11478 * WEB_IGNORE: Don't validate or process this var during web validation.
11479 * VIF_IGNORE: Don't create from wlx.y interface. Shared within one phy. devive.
11480 *
11481 *
11482 * Below is the definition of the structure
11483 *struct variable {
11484 *	char *name; <- name of variable
11485 * 	char *longname; <- display name
11486 * 	char *prefix; <- prefix for processing the multi-instance versions
11487 *	void (*validate)(); <- Validation routine
11488 * 	char **argv; <- Optional argument vector for validation routine
11489 *	int nullok; <- value can be NULL
11490 *	int ezc_flags; <- control flags
11491 * };
11492 *
11493 * IMPORTANT:
11494 * =========
11495 *
11496 * The variables in tne table below determine if they will be saved/restored
11497 * by the UI NVRAM save/restore feature
11498 *
11499 * If an NVRAM variable is not present in this list it will
11500 * not be processed and thus will not be saved or restored.
11501 *
11502*/
11503
11504/*
11505 * Variables are set in order (put dependent variables later). Set
11506 * nullok to TRUE to ignore zero-length values of the variable itself.
11507 * For more complicated validation that cannot be done in one pass or
11508 * depends on additional form components or can throw an error in a
11509 * unique painful way, write your own validation routine and assign it
11510 * to a hidden variable (e.g. filter_ip).
11511 *
11512 * EZC_FLAGS_READ : implies the variable will be returned for ezconfig read request
11513 * EZC_FLAGS_WRITE : allows the variable to be modified by the ezconfig tool
11514 *
11515 * The variables marked with EZConfig have to maintain backward compatibility.
11516 * If they cannot then the ezc_version has to be bumped up
11517 */
11518static char wl_prefix[]="wl";
11519#ifdef __CONFIG_NAT__
11520static char wan_prefix[]="wan";
11521#endif
11522static char lan_prefix[]="lan";
11523static char dhcp_prefix[]="dhcp";
11524static char vlan_prefix[]="vlan";
11525
11526static struct hsearch_data vtab;
11527
11528static char *wan_proto_argv[] = {
11529	"dhcp",
11530	"static",
11531	"pppoe",
11532"disabled"
11533};
11534
11535struct variable variables[] = {
11536#ifdef __CONFIG_WAPI_IAS__
11537	/* AS setting */
11538	{ "as_mode", "Authentication Server mode",NULL, NULL, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11539#endif
11540	/* basic settings */
11541	{ "http_username", "Router Username",NULL, validate_name, ARGV("0", "63"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11542	{ "http_passwd", "Router Password",NULL, validate_name, ARGV("0", "63"), TRUE, NVRAM_ENCRYPT | EZC_FLAGS_WRITE },
11543	{ "http_wanport", "Router WAN Port",NULL, validate_range, ARGV("0", "65535"), TRUE, 0 },
11544	{ "http_lanport", "HTTP daemon lanport",NULL, NULL, NULL, TRUE, 0 },
11545	{ "router_disable", "Router Mode",NULL, validate_router_disable, ARGV("0", "1"), FALSE, 0 },
11546	{ "fw_disable", "Firewall",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11547	{ "time_zone", "Time Zone",NULL, validate_choice, ARGV("PST8PDT", "MST7MDT", "CST6CDT", "EST5EDT"), FALSE },
11548	{ "upnp_enable", "UPnP",NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11549	{ "ezc_enable", "EZConfig",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE},
11550	{ "ntp_server", "NTP Servers",NULL, validate_ipaddrs, NULL, TRUE, 0 },
11551	{ "log_level", "Connection Logging",NULL, validate_range, ARGV("0", "3"), FALSE, 0 },
11552	{ "log_ipaddr", "Log LAN IP Address",NULL, validate_ipaddr, ARGV("lan_ipaddr", "lan_netmask"), TRUE, 0 },
11553	{ "log_ram_enable", "Syslog in RAM",NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11554#ifdef BCMQOS
11555	{ "qos_enable", "Qos enable",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11556	{ "qos_ack", "Prioritize ACK",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11557	{ "qos_icmp", "Prioritize ICMP",NULL, validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11558  	{ "qos_default", "Default Outbound Class", NULL, validate_choice, ARGV("0", "1", "2", "3", "4"), FALSE, 0},
11559	{ "qos_obw", "Outbound BW", NULL, validate_range, ARGV("0", "999999"), TRUE, 0 },
11560	{ "qos_ibw", "Inbound BW", NULL, validate_range, ARGV("0", "999999"), TRUE, 0 },
11561	{ "qos_orates", "Outbound BW", NULL, valid_qos_var, NULL, TRUE, 0 },
11562	{ "qos_irates", "Inbound BW", NULL, valid_qos_var, NULL, TRUE, 0 },
11563	{ "qos_orules", "Qos rules", NULL, valid_qos_var, NULL, TRUE, 0 },
11564#endif /* BCMQOS */
11565	{ "igmp_enable" , "Enable IGMP proxy", NULL, validate_choice, ARGV("1", "0"), FALSE, 0},
11566	{ "bsd_role" , "BandSteer Daemon State", NULL, validate_choice, ARGV("3", "2", "1", "0"), FALSE, 0},
11567	{ "bsd_helper", "BandSteer Helper IP Address", lan_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
11568	{ "bsd_hport", "BandSteer Helper Port", wl_prefix, validate_range, ARGV("0", "65535"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11569	{ "bsd_primary", "BandSteer Primary IP Address", lan_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
11570	{ "bsd_pport", "BandSteer Primary Port", wl_prefix, validate_range, ARGV("0", "65535"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11571	{ "trf_mgmt_port", "Traffic Port", NULL, validate_trf_mgmt_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11572	/* LAN settings */
11573	{ "lan_ifname" "LAN Interface Name", lan_prefix, NULL, NULL, FALSE, NVRAM_MI|NVRAM_IGNORE },
11574	{ "lan_hwaddr", "LAN MAC Address", lan_prefix, validate_hwaddr, NULL, TRUE, NVRAM_MI|NVRAM_IGNORE },
11575	{ "lan_dhcp", "DHCP Client", lan_prefix, validate_choice, ARGV("1", "0"), FALSE, NVRAM_MI | NVRAM_MP },
11576	{ "lan_ipaddr", "IP Address", lan_prefix, validate_lan_ipaddr, NULL, FALSE, NVRAM_MI| NVRAM_MP | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11577	{ "lan_netmask", "Subnet Mask", lan_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
11578	{ "lan_gateway", "Gateway Address", lan_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
11579	{ "lan_proto", "DHCP Server", lan_prefix, validate_choice, ARGV("dhcp", "static"), FALSE, NVRAM_MI| NVRAM_MP | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11580	{ "dhcp_start", "DHCP Server LAN IP Address Range", dhcp_prefix, validate_dhcp, NULL, FALSE, NVRAM_MI| NVRAM_MP | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11581	{ "dhcp_end", "DHCP Server LAN IP End Address", dhcp_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI| NVRAM_MP },
11582	{ "dhcp_wins", "DHCP WINS domain", dhcp_prefix, NULL, NULL, TRUE, NVRAM_MI | NVRAM_MP},
11583	{ "dhcp_domain", "DHCP domain", dhcp_prefix, NULL, NULL, TRUE, NVRAM_MI | NVRAM_MP },
11584	{ "lan_lease", "DHCP Server Lease Time", lan_prefix, validate_range, ARGV("1", "604800"), FALSE,  NVRAM_MI | NVRAM_MP  |EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11585	{ "lan_stp", "Spanning Tree Protocol", lan_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | NVRAM_MP| EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11586	{ "lan_route", "Static Routes", lan_prefix, validate_lan_route, NULL, FALSE,  NVRAM_MI | NVRAM_MP },
11587#ifdef __CONFIG_EMF__
11588	{ "emf_enable", "Efficient Multicast Forwarding", NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11589	{ "emf_entry", "Static Multicast Forwarding entries", NULL, validate_emf_entry, NULL, FALSE,  NVRAM_MI | NVRAM_MP },
11590	{ "emf_uffp_entry", "Unregistered Frames Forwarding Ports", NULL, validate_emf_uffp_entry, NULL, FALSE,  NVRAM_MI | NVRAM_MP },
11591	{ "emf_rtport_entry", "Multicast Router / IGMP Forwarding Ports", NULL, validate_emf_rtport_entry, NULL, FALSE,  NVRAM_MI | NVRAM_MP },
11592#endif /* __CONFIG_EMF__ */
11593	{ "lan_wins", "Lan WINS", lan_prefix, NULL, NULL, TRUE, NVRAM_MI| NVRAM_MP},
11594	{ "lan_domain", "Lan Domain", lan_prefix,NULL, NULL, TRUE,  NVRAM_MI| NVRAM_MP },
11595	{ "lan_route","LAN route", lan_prefix, NULL, NULL, TRUE,  NVRAM_MI| NVRAM_MP },
11596	{ "lan_guest_ifname","Guest LAN 1", lan_prefix, validate_guest_lan_ifname, ARGV("1"), FALSE,  NVRAM_MI| NVRAM_IGNORE},
11597	/*VLAN config vars. These are multi-instance Used by NVRAM save/restore for the moment */
11598	{ "vlanhwname", "VLAN HW name", vlan_prefix, NULL, NULL, TRUE, NVRAM_VLAN_MULTI},
11599	{ "vlanports", "VLAN Ports", vlan_prefix, NULL, NULL, TRUE, NVRAM_VLAN_MULTI},
11600/*
11601*/
11602#ifdef __CONFIG_IPV6__
11603	{ "lan_ipv6_prefix", "IPv6 LAN Network Prefix", lan_prefix, validate_ipv6prefix, NULL, TRUE, NVRAM_MI | NVRAM_MP },
11604	{ "lan_ipv6_dns", "IPv6 Domain Name Server IP", lan_prefix, validate_ipv6addr, NULL, TRUE, NVRAM_MI | NVRAM_MP },
11605	{ "lan_ipv6_mode", "IPv6 Mode", lan_prefix, validate_ipv6mode, ARGV("0", "3"), TRUE, NVRAM_MI | NVRAM_MP },
11606	{ "lan_ipv6_6to4id", "IPv6 6to4 Subnet ID", lan_prefix, validate_range, ARGV("0", "65535"), TRUE, NVRAM_MI | NVRAM_MP },
11607	/* Note the wan_ipv6_prefix is per WAN interface configuration */
11608	{ "wan_ipv6_prefix", "IPv6 WAN Network Prefix", wan_prefix, validate_ipv6prefix, NULL, TRUE, NVRAM_MI },
11609#endif /* __CONFIG_IPV6__ */
11610/*
11611*/
11612#ifdef __CONFIG_NAT__
11613	/* ALL wan_XXXX variables below till wan_unit variable are per-interface */
11614	{ "wan_desc", "Description", wan_prefix, validate_name, ARGV("0", "255"), TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11615	{ "wan_proto", "Protocol", wan_prefix, validate_choice, wan_proto_argv , FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11616	{ "wan_hostname", "Host Name", wan_prefix, validate_name, ARGV("0", "255"), TRUE, NVRAM_MI |EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11617	{ "wan_domain", "Domain Name", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11618	{ "wan_ifname", "Interface Name", wan_prefix, validate_wan_ifname, NULL, TRUE, NVRAM_MI  },
11619	{ "wan_hwaddr", "MAC Address", wan_prefix, validate_hwaddr, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11620	{ "wan_ipaddr", "IP Address", wan_prefix, validate_ipaddr, NULL, FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11621	{ "wan_netmask", "Subnet Mask", wan_prefix, validate_ipaddr, NULL, FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11622	{ "wan_gateway", "Default Gateway", wan_prefix, validate_ipaddr, NULL, TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11623	{ "wan_dns", "DNS Servers", wan_prefix, validate_ipaddrs, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11624	{ "wan_wins", "WINS Servers", wan_prefix, validate_ipaddrs, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11625	{ "wan_pppoe_ifname", "PPPoE Interface Name", wan_prefix, NULL, NULL, TRUE, NVRAM_MI  },
11626	{ "wan_pppoe_username", "PPPoE Username", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11627	{ "wan_pppoe_passwd", "PPPoE Password", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_WRITE },
11628	{ "wan_pppoe_service", "PPPoE Service Name", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11629	{ "wan_pppoe_ac", "PPPoE Access Concentrator", wan_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11630	{ "wan_pppoe_keepalive", "PPPoE Keep Alive", wan_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11631	{ "wan_pppoe_demand", "PPPoE Connect on Demand", wan_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11632	{ "wan_pppoe_idletime", "PPPoE Max Idle Time", wan_prefix, validate_range, ARGV("1", "3600"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11633	{ "wan_pppoe_mru", "PPPoE MRU", wan_prefix, validate_range, ARGV("128", "16384"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11634	{ "wan_pppoe_mtu", "PPPoE MTU", wan_prefix, validate_range, ARGV("128", "16384"), FALSE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11635	{ "wan_primary", "Primary Interface", wan_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI },
11636	{ "wan_route", "Static Routes", wan_prefix, validate_wan_route, NULL, FALSE, NVRAM_MI  },
11637	/* MUST leave this entry here after all wl_XXXX per-interface variables */
11638	{ "wan_unit", "WAN Instance", wan_prefix, wan_unit, NULL, TRUE, NVRAM_MI|NVRAM_MP },
11639	/* filter settings */
11640	{ "filter_macmode", "MAC Filter Mode", NULL, validate_choice, ARGV("disabled", "allow", "deny"), FALSE, 0 },
11641	{ "filter_maclist", "MAC Filter", NULL, validate_hwaddrs, NULL, TRUE, 0 },
11642	{ "filter_client", "LAN Client Filter", NULL, validate_filter_client, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11643#ifdef __CONFIG_URLFILTER__
11644	{ "filter_url", "URL Filter", NULL, validate_filter_url, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11645#endif /* __CONFIG_URLFILTER__ */
11646	/* routing settings */
11647	{ "forward_port", "Port Forward", NULL, validate_forward_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11648#if !defined(AUTOFW_PORT_DEPRECATED)
11649	{ "autofw_port", "Application Specific Port Forward", NULL, validate_autofw_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11650#endif
11651	{ "nat_type", "NAT Type Support", NULL, validate_choice, ARGV("cone", "sym"), TRUE, 0 },
11652	{ "dmz_ipaddr", "DMZ LAN IP Address", NULL, validate_ipaddr, ARGV("lan_ipaddr", "lan_netmask"), TRUE, 0 },
11653#endif	/* __CONFIG_NAT__ */
11654	{ "ure_disable", "URE Mode", NULL, NULL, ARGV("0"), FALSE, WEB_IGNORE },
11655
11656	/* ALL wl_XXXX variables are per-interface  */
11657	/* This group is per ssid */
11658	{ "wl_bss_enabled", "BSS Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11659
11660#ifdef __CONFIG_HSPOT__
11661	{ "wl_hsflag", "Passpoint Flags", wl_prefix, validate_wl_hsflag, ARGV("0", "65535"), FALSE, NVRAM_MI },
11662	{ "wl_hs2cap", "Passpoint Capability", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11663	{ "wl_opercls", "Operating Class", wl_prefix, validate_choice, ARGV("1", "2", "3"), FALSE, NVRAM_MI },
11664	{ "wl_anonai", "Anonymous NAI", wl_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11665	{ "wl_wanmetrics", "WAN Metrics", wl_prefix, validate_wl_wanmetrics, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11666	{ "wl_oplist", "Operator Friendly Name List", wl_prefix, validate_wl_oplist, ARGV("0", "1080"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11667	{ "wl_homeqlist", "NAI Home Realm Query List", wl_prefix, validate_wl_homeqlist, ARGV("0", "1080"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11668	{ "wl_osu_ssid",  "OSU provider SSID", wl_prefix, validate_name, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11669	{ "wl_osu_frndname", "OSU Friendly name", wl_prefix, validate_wl_osuplist, ARGV("0", "2048"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11670	{ "wl_osu_uri", "OSU URI", wl_prefix, validate_wl_osuplist, ARGV("0", "1024"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11671	{ "wl_osu_nai", "OSU NAI", wl_prefix, validate_wl_osuplist, ARGV("0", "1024"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11672	{ "wl_osu_method", "OSU Icon", wl_prefix, validate_wl_osuplist, ARGV("0", "20"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11673	{ "wl_osu_icons", "OSU Icon", wl_prefix, validate_wl_osuplist, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11674	{ "wl_osu_servdesc", "OSU Service Description", wl_prefix, validate_wl_osuplist, ARGV("0", "2048"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11675	{ "wl_concaplist", "Connection Capability List", wl_prefix, validate_wl_concaplist, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11676	{ "wl_qosmapie", "QoS Map IE", wl_prefix, validate_wl_qosmapie, ARGV("0", "255"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11677	{ "wl_gascbdel", "GAS CB Delay", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11678
11679	/* ---- 802.11u -----------------------------------  */
11680	{ "wl_iwnettype", "Acees Network Type", wl_prefix, validate_choice, ARGV("0", "1", "2", "3", "4", "5", "14", "15"), FALSE, NVRAM_MI },
11681	{ "wl_hessid", "Interworking HESSID", wl_prefix, validate_hwaddr, NULL, TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11682	{ "wl_ipv4addr", "IPV4 Address Type Availability", wl_prefix, validate_choice, ARGV("0", "1", "2", "3", "4", "5", "6", "7"), FALSE, NVRAM_MI },
11683	{ "wl_ipv6addr", "IPV6 Address Type Availability", wl_prefix, validate_choice, ARGV("0", "1", "2"), FALSE, NVRAM_MI },
11684	{ "wl_netauthlist", "Network Authentication Type List", wl_prefix, validate_wl_netauthlist, ARGV("0", "600"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11685	{ "wl_venuegrp", "Venue Group", wl_prefix, validate_choice, ARGV("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"), FALSE, NVRAM_MI },
11686	{ "wl_venuetype", "BSS Venue Type", wl_prefix, validate_choice, ARGV("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17"), FALSE, NVRAM_MI },
11687	{ "wl_venuelist", "Venue Name List", wl_prefix, validate_wl_venuelist, ARGV("0", "1080"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11688	{ "wl_ouilist", "Roaming Consortium List", wl_prefix, validate_wl_ouilist, ARGV("0", "128"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11689	{ "wl_3gpplist", "3GPP Cellular Network Information Name List", wl_prefix, validate_wl_3gpplist, ARGV("0", "128"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11690	{ "wl_domainlist", "Domain Name List", wl_prefix, validate_names, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11691	{ "wl_realmlist", "NAI Realm List", wl_prefix, validate_wl_realmlist, ARGV("0", "4096"), TRUE,NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11692
11693#endif /* __CONFIG_HSPOT__ */
11694
11695	{ "wl_ssid", "Network Name (ESSID)", wl_prefix, validate_ssid, ARGV("1", "32"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11696	{ "wl_bridge", "Bridge Details", wl_prefix, validate_bridge, ARGV("0", "1"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11697	{ "wl_closed", "Network Type", wl_prefix, validate_wl_closed, ARGV("0", "1"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11698	{ "wl_ap_isolate", "AP Isolate", wl_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI },
11699	{ "wl_wmf_bss_enable", "WMF Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11700	{ "wl_mcast_regen_bss_enable", "Multicast Regen Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11701	{ "wl_macmode", "MAC Restrict Mode", wl_prefix, validate_wl_macmode, ARGV("disabled", "allow", "deny"), FALSE,NVRAM_MI },
11702	{ "wl_maclist", "Allowed MAC Address", wl_prefix, validate_hwaddrs, NULL, TRUE, NVRAM_MI },
11703	{ "wl_mode", "Mode", wl_prefix, validate_wl_mode, ARGV("ap", "wds", "sta", "wet", "apsta", "mac_spoof", "psta", "psr"), FALSE,NVRAM_MI },
11704	{ "wl_infra", "Network", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11705	{ "wl_dwds", "DWDS", wl_prefix, validate_wl_dwds, ARGV("0", "1"), FALSE, NVRAM_MI },
11706#ifdef __CONFIG_ROUTER_MINI__
11707	/* Mini router has lower maxassoc (MAXSCB) limit */
11708	{ "wl_bss_maxassoc", "Per BSS Max Association Limit", wl_prefix, validate_range, ARGV("1", "64"), FALSE,NVRAM_MI },
11709#else
11710	{ "wl_bss_maxassoc", "Per BSS Max Association Limit", wl_prefix, validate_range, ARGV("1", "128"), FALSE,NVRAM_MI },
11711#endif /* __CONFIG_ROUTER_MINI__ */
11712	{ "wl_wme_bss_disable", "Per-BSS WME Disable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11713	{ "wl_bss_opmode_cap_reqd", "Per-BSS operational capabilities required", wl_prefix, validate_choice, ARGV("0", "1", "2", "3"), FALSE, NVRAM_MI },
11714/*
11715*/
11716#ifdef 	__CONFIG_WFI__
11717	{ "wl_wfi_enable", "Wifi Invite feature", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11718	{ "wl_wfi_pinmode", "WFI PIN mode", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11719#endif /* __CONFIG_WFI__ */
11720/*
11721*/
11722	{ "wl_wet_tunnel" , "Enable WET Tunnel", wl_prefix, validate_choice, ARGV("1", "0"), FALSE, NVRAM_MI},
11723#ifdef TRAFFIC_MGMT_RSSI_POLICY
11724	{ "wl_trf_mgmt_rssi_policy", "TRF MGMT RSSI Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11725#endif /* TRAFFIC_MGMT_RSSI_POLICY */
11726	{ "wl_atf", "Airtime Fairness", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11727#ifdef __CONFIG_EMF__
11728	{ "wl_wmf_ucigmp_query", "Unicast IGMP Query Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11729	{ "wl_wmf_mdata_sendup", "Sendup Multicast Data Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11730	{ "wl_wmf_psta_disable", "Sendup Multicast to PSTA disable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11731#endif /* __CONFIG_EMF__ */
11732	{ "wl_pspretend_threshold", "Stalled Link Detection Threshold", wl_prefix, validate_range, ARGV("0", "32"), FALSE, NVRAM_MI | VIF_IGNORE },
11733	{ "wl_pspretend_retry_limit", "PsPretend retry limit", wl_prefix, validate_range, ARGV("0", "32"), FALSE, NVRAM_MI | VIF_IGNORE },
11734#ifdef __CONFIG_EXTACS__
11735	{ "wl_acs_fcs_mode", "ACS Fast Channel Switch Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11736	{ "wl_acs_dfs", "ACS DFS Channel Selection", wl_prefix, validate_range, ARGV("0", "2"), FALSE, NVRAM_MI | VIF_IGNORE },
11737	{ "wl_acs_dfsr_immediate", "ACS DFS Immediate Reentry Window", wl_prefix, validate_dfs_window, NULL, NVRAM_MI | VIF_IGNORE },
11738	{ "wl_acs_dfsr_deferred", "ACS DFS Deferred Reentry Window", wl_prefix, validate_dfs_window, NULL, NVRAM_MI | VIF_IGNORE },
11739	{ "wl_acs_dfsr_activity", "ACS DFS Channel Active Window", wl_prefix, validate_dfs_window, NULL, NVRAM_MI | VIF_IGNORE },
11740	{ "wl_acs_cs_scan_timer", "ACS CS Scan Interval", wl_prefix, validate_range, ARGV("60", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11741	{ "wl_acs_ci_scan_timer", "ACS CI Scan Interval", wl_prefix, validate_range, ARGV("1", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11742	{ "wl_acs_ci_scan_timeout", "ACS CI Scan Timeout", wl_prefix, validate_range, ARGV("1", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11743	{ "wl_acs_scan_entry_expire", "Scan Result Timeout", wl_prefix, validate_range, ARGV("1", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11744	{ "wl_acs_tx_idle_cnt", "TX Idle Frame Count", wl_prefix, validate_range, ARGV("0", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11745	{ "wl_acs_chan_dwell_time", "ACS Scan Dwell Time", wl_prefix, validate_range, ARGV("1", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11746	{ "wl_acs_chan_flop_period", "ACS Chan Flop Period", wl_prefix, validate_range, ARGV("1", "4294967295"), FALSE, NVRAM_MI | VIF_IGNORE },
11747
11748	{ "wl_intfer_period", "Sample Period", wl_prefix, validate_range, ARGV("0", "65535"), FALSE, NVRAM_MI | VIF_IGNORE },
11749	{ "wl_intfer_cnt", "Sample Count", wl_prefix, validate_range, ARGV("1", "4"), FALSE, NVRAM_MI | VIF_IGNORE },
11750	{ "wl_intfer_txfail", "non-TCP TxFail threshold", wl_prefix, validate_range, ARGV("0", "65535"), FALSE, NVRAM_MI | VIF_IGNORE },
11751	{ "wl_intfer_tcptxfail", "TCP TxFail threshold", wl_prefix, validate_range, ARGV("0", "65535"), FALSE, NVRAM_MI | VIF_IGNORE },
11752#endif /* __CONFIG_EXTACS__ */
11753	{ "wl_probresp_mf", "MAC filter based Probe Response", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11754	/* This group is per radio */
11755	{ "wl_ure", "URE Mode",NULL, validate_ure, ARGV("0"), FALSE, NVRAM_MI | VIF_IGNORE },
11756	{ "wl_vifs", "WL Virtual Interfaces", NULL, NULL, ARGV("0"), FALSE, NVRAM_MI | WEB_IGNORE },
11757	{ "wl_country_code", "Country Code", wl_prefix, validate_wl_country_code, NULL, FALSE, NVRAM_MI | VIF_IGNORE },
11758	{ "wl_country_rev", "Country Revision", wl_prefix, validate_wl_country_rev, NULL, FALSE, NVRAM_MI | VIF_IGNORE },
11759	{ "wl_lazywds", "Bridge Restrict", wl_prefix, validate_wl_lazywds, ARGV("0", "1"), FALSE,NVRAM_MI | VIF_IGNORE },
11760	{ "wl_wds", "Bridges", wl_prefix, validate_wl_wds_hwaddrs, NULL, TRUE, NVRAM_MI | VIF_IGNORE },
11761	{ "wl_wds_timeout", "Link Timeout Interval", wl_prefix, NULL, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11762	{ "wl_radio", "Radio Enable", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI },
11763	{ "wl_phytype", "Radio Band", wl_prefix, validate_choice, ARGV("a", "b", "g", "n", "l", "s", "h"), TRUE, NVRAM_MI | VIF_IGNORE },
11764	{ "wl_antdiv", "Antenna Diversity", wl_prefix, validate_choice, ARGV("-1", "0", "1", "3"), FALSE, NVRAM_MI | VIF_IGNORE },
11765	{ "wl_chanspec", "Channel Specification", wl_prefix, validate_wl_chanspec, NULL, FALSE, NVRAM_MI | VIF_IGNORE | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11766	{ "wl_reg_mode", "Regulatory Mode", wl_prefix, validate_choice, ARGV("off", "h", "strict_h", "d"), FALSE, NVRAM_MI | VIF_IGNORE},
11767	{ "wl_tpc_db", "TPC Mitigation (db)",  wl_prefix, validate_range, ARGV("0", "99"), FALSE,NVRAM_MI | VIF_IGNORE},
11768	{ "wl_rate", "Rate", wl_prefix, validate_range, ARGV("0", "54000000"), FALSE,NVRAM_MI | VIF_IGNORE },
11769	{ "wl_rateset", "Supported Rates", wl_prefix, validate_choice, ARGV("all", "default", "12"), FALSE,NVRAM_MI | VIF_IGNORE},
11770	{ "wl_mrate", "Multicast Rate", wl_prefix, validate_range, ARGV("0", "54000000"), FALSE,NVRAM_MI | VIF_IGNORE },
11771	{ "wl_frag", "Fragmentation Threshold", wl_prefix, validate_range, ARGV("256", "2346"), FALSE,NVRAM_MI | VIF_IGNORE },
11772	{ "wl_rts", "RTS Threshold", wl_prefix, validate_range, ARGV("0", "2347"), FALSE, NVRAM_MI | VIF_IGNORE },
11773	{ "wl_dtim", "DTIM Period", wl_prefix, validate_range, ARGV("1", "255"), FALSE, NVRAM_MI | VIF_IGNORE },
11774	{ "wl_bcn", "Beacon Interval", wl_prefix, validate_range, ARGV("1", "65535"), FALSE, NVRAM_MI | VIF_IGNORE},
11775	{ "wl_bcn_rotate", "Beacon Rotation", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11776	{ "wl_plcphdr", "Preamble Type", wl_prefix, validate_choice, ARGV("long", "short"), FALSE, NVRAM_MI | VIF_IGNORE },
11777	{ "wl_maxassoc", "Max Association Limit", wl_prefix, validate_range, ARGV("1", "128"), FALSE,NVRAM_MI | VIF_IGNORE },
11778	{ "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 | VIF_IGNORE },
11779	{ "wl_gmode_protection", "54g Protection", wl_prefix, validate_choice, ARGV("off", "auto"), FALSE,NVRAM_MI | VIF_IGNORE },
11780	{ "wl_frameburst", "XPress Technology", wl_prefix, validate_choice, ARGV("off", "on"), FALSE,NVRAM_MI | VIF_IGNORE |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11781	{ "wl_txbf_bfr_cap", "TX Beamformer", wl_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI | VIF_IGNORE |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11782	{ "wl_txbf_bfe_cap", "TX Beamformee", wl_prefix, validate_choice, ARGV("0", "1"), FALSE,NVRAM_MI | VIF_IGNORE |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11783	{ "wl_nband", "Radio Band for EWC", wl_prefix, validate_choice, ARGV("1", "2"), TRUE, NVRAM_MI | VIF_IGNORE },
11784	{ "wl_bw_cap", "Channel Bandwidth", wl_prefix, validate_choice, ARGV("1", "3", "7"), TRUE, NVRAM_MI | VIF_IGNORE},
11785	{ "wl_nmcsidx", "MCS Index", wl_prefix, validate_range, ARGV("-2", "32"), TRUE, NVRAM_MI | VIF_IGNORE},
11786	{ "wl_nmode", "802.11 N mode", wl_prefix, validate_choice, ARGV("-1", "0"), TRUE, NVRAM_MI | VIF_IGNORE},
11787	{ "wl_txchain", "Number of TxChains", wl_prefix, validate_range, ARGV("1", "7"), TRUE, NVRAM_MI | VIF_IGNORE },
11788	{ "wl_rxchain", "Number of RxChains", wl_prefix, validate_range, ARGV("1", "7"), TRUE, NVRAM_MI | VIF_IGNORE },
11789	{ "wl_vlan_prio_mode", "VLAN Priority Support", wl_prefix, validate_choice, ARGV("off", "on"), TRUE, NVRAM_MI | VIF_IGNORE},
11790	{ "wl_nmode_protection", "802.11n Protection", wl_prefix, validate_choice, ARGV("off", "auto"), FALSE,NVRAM_MI | VIF_IGNORE },
11791	{ "wl_mimo_preamble", "802.11n Preamble", wl_prefix, validate_choice, ARGV("mm", "gf", "auto", "gfbcm"), FALSE,NVRAM_MI | VIF_IGNORE },
11792	{ "wl_rifs", "Enable/Disable RIFS Transmissions", wl_prefix, validate_choice, ARGV("auto", "off", "on"), FALSE, NVRAM_MI | VIF_IGNORE},
11793	{ "wl_rifs_advert", "RIFS Mode Advertisement", wl_prefix, validate_choice, ARGV("auto", "off"), FALSE, NVRAM_MI | VIF_IGNORE},
11794	{ "wl_stbc_tx", "Enable/Disable STBC Transmissions", wl_prefix, validate_choice, ARGV("auto", "off", "on"), FALSE, NVRAM_MI | VIF_IGNORE},
11795	{ "wl_amsdu", "MSDU aggregation Technology", wl_prefix, validate_choice, ARGV("auto", "off", "on"), FALSE, NVRAM_MI | VIF_IGNORE },
11796	{ "wl_ampdu", "MPDU aggregation Technology", wl_prefix, validate_choice, ARGV("auto", "off", "on"), FALSE, NVRAM_MI | VIF_IGNORE },
11797	{ "wl_wme", "WME Support", wl_prefix, validate_choice, ARGV("auto", "off", "on"), FALSE, NVRAM_MI | VIF_IGNORE | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11798	{ "wl_wme_no_ack", "No-Acknowledgement", wl_prefix, validate_wme_bool, ARGV("off", "on"), FALSE,NVRAM_MI | VIF_IGNORE |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11799	{ "wl_wme_apsd", "U-APSD Support", wl_prefix, validate_wme_bool, ARGV("off", "on"), FALSE, NVRAM_MI | VIF_IGNORE | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11800	{ "wl_wme_ap_be", "WME AP BE", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11801	{ "wl_wme_ap_bk", "WME AP BK", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11802	{ "wl_wme_ap_vi", "WME AP VI", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11803	{ "wl_wme_ap_vo", "WME AP VO", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11804	{ "wl_wme_sta_be", "WME STA BE", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11805	{ "wl_wme_sta_bk", "WME STA BK", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11806	{ "wl_wme_sta_vi", "WME STA VI", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11807	{ "wl_wme_sta_vo", "WME STA VO", wl_prefix, validate_wl_wme_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11808	{ "wl_wme_txp_be", "WME TXP BE", wl_prefix, validate_wl_wme_tx_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11809	{ "wl_wme_txp_bk", "WME TXP BK", wl_prefix, validate_wl_wme_tx_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11810	{ "wl_wme_txp_vi", "WME TXP VI", wl_prefix, validate_wl_wme_tx_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11811	{ "wl_wme_txp_vo", "WME TXP VO", wl_prefix, validate_wl_wme_tx_params, NULL, TRUE, NVRAM_MI | VIF_IGNORE},
11812	{ "wl_obss_coex", "Overlapping BSS Coexistence", wl_prefix, validate_choice, ARGV("0", "1"), TRUE, NVRAM_MI | VIF_IGNORE },
11813	{ "wl_probresp_sw", "SW Probe Response", wl_prefix, validate_choice, ARGV("0", "1"), FALSE, NVRAM_MI | VIF_IGNORE },
11814	{ "wl_vht_features", "VHT features", wl_prefix, validate_range, ARGV("0", "255"), FALSE, NVRAM_MI | VIF_IGNORE },
11815	/* security parameters */
11816	{ "wl_key", "Network Key Index", wl_prefix, validate_range, ARGV("1", "4"), FALSE,NVRAM_MI | EZC_FLAGS_WRITE },
11817	{ "wl_key1", "Network Key 1", wl_prefix, validate_wl_key, NULL, TRUE, NVRAM_MI | NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
11818	{ "wl_key2", "Network Key 2", wl_prefix, validate_wl_key, NULL, TRUE, NVRAM_MI | NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
11819	{ "wl_key3", "Network Key 3", wl_prefix, validate_wl_key, NULL, TRUE,NVRAM_MI |  NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
11820	{ "wl_key4", "Network Key 4", wl_prefix, validate_wl_key, NULL, TRUE,NVRAM_MI | NVRAM_ENCRYPT |  EZC_FLAGS_WRITE},
11821	{ "wl_auth", "802.11 Authentication", wl_prefix, validate_wl_auth, ARGV("0", "1", "2"), FALSE, NVRAM_MI | 0},
11822	{ "wl_auth_mode", "Network Authentication", wl_prefix, validate_wl_auth_mode, ARGV("radius", "none"), FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11823	{ "wl_akm", "Authenticated Key Management", wl_prefix, validate_wl_akm, NULL, FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11824	{ "wl_wep", "WEP Encryption", wl_prefix, validate_wl_wep, ARGV("disabled", "enabled"), FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11825	{ "wl_crypto", "WPA Encryption", wl_prefix, validate_wl_crypto, ARGV("tkip", "aes", "tkip+aes"), FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11826	{ "wl_net_reauth", "Network Re-auth Interval", wl_prefix, NULL, NULL, TRUE, NVRAM_MI  },
11827	{ "wl_preauth", "Network Preauthentication Support", wl_prefix, validate_wl_preauth, ARGV("disabled", "enabled"), FALSE,NVRAM_MI |  0 },
11828	{ "wl_radius_ipaddr", "RADIUS Server", wl_prefix, validate_ipaddr, NULL, TRUE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11829	{ "wl_radius_port", "RADIUS Port", wl_prefix, validate_range, ARGV("0", "65535"), FALSE,NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11830	{ "wl_radius_key", "RADIUS Shared Secret", wl_prefix, validate_name, ARGV("0", "255"), TRUE, NVRAM_MI |  NVRAM_ENCRYPT | EZC_FLAGS_WRITE},
11831	{ "wl_wpa_psk", "WPA Pre-Shared Key", wl_prefix, validate_wl_wpa_psk, ARGV("64"), TRUE, NVRAM_ENCRYPT | NVRAM_MI |  EZC_FLAGS_WRITE},
11832	{ "wl_wpa_gtk_rekey", "Network Key Rotation Interval", wl_prefix, NULL, NULL, TRUE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11833#ifdef MFP
11834	{ "wl_mfp", "Management Frame Protection", wl_prefix, validate_wl_mfp, NULL, FALSE, NVRAM_MI | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11835#endif
11836	/* Multi SSID Guest interface flag */
11837	{ "wl_guest", "Guest SSID Interface", wl_prefix, NULL, NULL, TRUE, WEB_IGNORE|NVRAM_MI  },
11838	{ "wl_sta_retry_time", "STA Retry Time", wl_prefix, validate_range, ARGV("0", "3600"), FALSE, NVRAM_MI },
11839#ifdef __CONFIG_WPS__
11840	/*
11841	 * WPS Setting, put wl_wps_mode latter than other wl_xxx variables except wl_unit.
11842	 * We have to do other validations check before validate_wps_mode
11843	 */
11844	{ "wl_wps_mode", "WPS Mode", wl_prefix, validate_wps_mode, NULL, FALSE, NVRAM_MI |  EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11845#endif /* __CONFIG_WPS__ */
11846	/* MUST leave this entry here after all wl_XXXX variables */
11847	{ "wl_unit", "802.11 Instance", wl_prefix, wl_unit, NULL, TRUE, NVRAM_IGNORE|NVRAM_MI|NVRAM_MP },
11848#ifdef __CONFIG_WPS__
11849	/* MUST leave wps_reg and wps_oob here after wl_unit */
11850	{ "wps_reg", "WPS Registrar Mode", NULL, validate_wps_reg, NULL, FALSE, 0 },
11851	{ "wps_oob", "WPS OOB state", NULL, validate_wps_oob, NULL, FALSE, 0 },
11852	{ "wps_device_name", "WPS device name", NULL, validate_name, ARGV("1", "32"), FALSE, 0 },
11853	{ "wps_wer_mode", "Wireless ER Restrict Mode", NULL, validate_choice, ARGV("allow", "deny"), FALSE,0 },
11854#ifdef WFA_WPS_20_TESTBED
11855	{ "wps_version2", "WPS version supported", NULL, validate_choice, ARGV("enabled", "disabled"), FALSE, 0 },
11856	{ "wps_version2_num", "WPS version2 number", NULL, validate_wps2_range, ARGV("20", "99"), FALSE, 0 },
11857	{ "wps_ie_frag", "WPS IE fragment threshold", NULL, validate_wps2_range, ARGV("72", "228"), FALSE, 0 },
11858	{ "wps_eap_frag", "WPS EAP fragment threshold", NULL, validate_wps2_range, ARGV("100", "1398"), FALSE, 0 },
11859	{ "wps_nattr", "New attribute", NULL, validate_name, ARGV("0", "127"), FALSE, 0 },
11860	{ "wps_zpadding", "Do Zero Padding", NULL, validate_range, ARGV("0", "1"), FALSE, 0 },
11861	{ "wps_mca", "Multiple Credential Attribute", NULL, validate_range, ARGV("0", "1"), FALSE, 0 },
11862#endif /* WFA_WPS_20_TESTBED */
11863#endif /* __CONFIG_WPS__ */
11864	/* Internal variables */
11865	{ "os_server", "OS Server", NULL, NULL, NULL, TRUE, 0 },
11866	{ "stats_server", "Stats Server", NULL, NULL, NULL, TRUE, 0 },
11867	{ "timer_interval", "Timer Interval", NULL, NULL, NULL, TRUE, 0 },
11868	{ "lan_ifname", "LAN Interface Name", lan_prefix, NULL, NULL, TRUE, NVRAM_MI | NVRAM_MP },
11869	{ "lan_ifnames", "LAN Interface Names", NULL, NULL, NULL, TRUE, 0 },
11870	{ "lan1_ifnames", "Guest Interface Names", NULL, NULL, NULL, TRUE, 0 },
11871	{ "wan_ifnames", "WAN Interface Names", NULL, NULL, NULL, TRUE, 0 },
11872#if defined(__CONFIG_DLNA_DMR__)
11873	{ "dlna_dmr_enable", "DLNA Renderer",NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11874#endif
11875#if defined(__CONFIG_DLNA_DMS__)
11876	{ "dlna_dms_enable", "DLNA Server",NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11877#endif
11878#if defined(__CONFIG_SAMBA__)
11879	{ "samba_mode", "Samba Mode",NULL, validate_range, ARGV("0", "2"), FALSE, 0 },
11880	{ "samba_passwd", "Samba Password",NULL, validate_name, ARGV("0", "63"), FALSE, NVRAM_ENCRYPT | EZC_FLAGS_WRITE },
11881#endif
11882#ifdef	__CONFIG_NORTON__
11883	{ "nga_lickey", "NGA License Key",NULL, validate_name, ARGV("0", "63"), TRUE, NVRAM_ENCRYPT },
11884	{ "nga_user", "NGA Username", NULL, validate_name, ARGV("0", "254"), TRUE, NVRAM_ENCRYPT },
11885	{ "nga_pass", "NGA Password", NULL, validate_name, ARGV("0", "63"), TRUE, NVRAM_IGNORE },
11886	{ "nga_devname", "NGA Device Name", NULL, validate_name, ARGV("0", "63"), TRUE, 0 },
11887	{ "nga_ncw", "NGA Community Watch", NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11888	{ "nga_enable", "NGA Enabled", NULL, validate_choice, ARGV("0", "1"), FALSE, 0 },
11889	{ "nga_gact", "NGA Generic Action", NULL, validate_name, ARGV("0", "2048"), TRUE, NVRAM_IGNORE },
11890	{ "ngap_0", "NGA Bind ID", NULL, NULL, NULL, TRUE, NVRAM_ENCRYPT | WEB_IGNORE },
11891	{ "ngap_1", "NGA Bind Validation", NULL, NULL, NULL, TRUE, NVRAM_ENCRYPT | WEB_IGNORE },
11892	{ "NGA_MID", "NGA MID", NULL, NULL, NULL, TRUE, WEB_IGNORE },
11893#endif /* __CONFIG_NORTON__ */
11894	{ "coma_sleep", "Coma Mode Sleep Time", NULL, NULL, NULL, TRUE, 0 },
11895	{ "trf_mgmt_dwm", "Traffic Management DWM", NULL, validate_trf_mgmt_dwm, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, NVRAM_GENERIC_MULTI },
11896	{ "wl_dfs_pref", "DFS Preferred chan", wl_prefix, validate_dfs_prefchan, NULL, FALSE, NVRAM_MI | VIF_IGNORE | EZC_FLAGS_READ | EZC_FLAGS_WRITE },
11897};
11898
11899/* build hashtable of the monster v-block
11900
11901   Inputs:
11902   -tab: 	hash table  structure
11903   -vblock:	the monster V-block
11904   -num_items:	estimated size of hash table
11905
11906   Returns: 0 on success -1 on error
11907*/
11908
11909int
11910hash_vtab(struct hsearch_data *tab,struct variable *vblock,int num_items)
11911{
11912	ENTRY e, *ep=NULL;
11913	int count;
11914
11915	assert(tab);
11916	assert(vblock);
11917
11918	if (!num_items) return -1;
11919
11920	if (!hcreate_r(num_items,tab))
11921	{
11922			return -1;
11923	}
11924
11925
11926	for (count=0; count < num_items; count++)
11927	{
11928		e.key = vblock[count].name;
11929		e.data = &vblock[count];
11930		if (!hsearch_r(e, ENTER, &ep, tab))
11931			return -1;
11932	}
11933
11934	return 0;
11935
11936}
11937/* The routine gets the pointer into the giant "V" block above give the cgi var name..
11938   Inputs:
11939   -varname: Pointer to cgi var name
11940
11941   Returns: entry within "V" block or NULL if not found.
11942
11943   It will try the following forms
11944   varXX_type
11945   var_typeXX
11946   vlanXXtype
11947
11948   where XX is the instance number
11949
11950*/
11951
11952static struct variable*
11953get_var_handle(char *varname)
11954{
11955	ENTRY e, *ep=NULL;
11956	struct variable *variable=NULL;
11957	char *ptr=NULL,*ptr2=NULL;
11958	int offset;
11959	char prefix[8],tmp[64];
11960
11961	if (!varname ) return NULL;
11962	if (!*varname) return NULL;
11963
11964	ep=NULL;
11965	e.key = varname;
11966	hsearch_r(e, FIND, &ep, &vtab);
11967
11968
11969	/* found something */
11970	if (ep)
11971	{
11972		variable = (struct variable *)ep->data;
11973		if ( variable->ezc_flags & NVRAM_MP) return variable;
11974
11975		/* Drop the variable is multi instance but not
11976		   Multi personality
11977		*/
11978
11979		if ( variable->ezc_flags & NVRAM_MI) return NULL;
11980		if ( variable->ezc_flags & NVRAM_VLAN_MULTI) return NULL;
11981		if ( variable->ezc_flags & NVRAM_GENERIC_MULTI) return NULL;
11982
11983		return variable;
11984
11985	}
11986
11987	/* variable not found could be the form of vlanXXtype, varXX_type or var_typeXX*/
11988
11989	ptr=strchr(varname,'_');
11990
11991	/* Is it  vlanXXtype ? */
11992	if (!ptr)
11993	{
11994		if (!strstr(varname,"vlan")) return NULL;
11995		strcpy(tmp,"vlan");
11996		offset=4;
11997		ptr=&varname[offset];
11998		while (*ptr){
11999				if (!isdigit((int)*ptr)) tmp[offset++] = *ptr;
12000				ptr++;
12001		}
12002
12003		tmp[offset] = '\0';
12004		ep = NULL;
12005		e.key = tmp;
12006		hsearch_r(e, FIND, &ep, &vtab);
12007
12008		/* check to see if this has the
12009		   NVRAM_VLAN MULTI flag set in the v-block
12010		*/
12011		if (ep){
12012			variable = (struct variable *)ep->data;
12013			if (variable->ezc_flags & NVRAM_VLAN_MULTI)
12014					return variable;
12015		}
12016
12017		return  NULL;
12018	}
12019
12020	/* Is it varXX_type ? */
12021	ptr2=varname;
12022	offset=0;
12023	memset(prefix,0,sizeof(prefix));
12024	while (ptr2 < ptr){
12025		if (isdigit((int)*ptr2)) break;
12026		prefix[offset++] =*ptr2;
12027		ptr2++;
12028	}
12029	snprintf(tmp,sizeof(tmp),"%s%s",prefix,ptr);
12030
12031	ep = NULL;
12032	e.key = tmp;
12033	hsearch_r(e, FIND, &ep, &vtab);
12034
12035	if (ep){
12036		variable = (struct variable *)ep->data;
12037		if (variable->ezc_flags & NVRAM_MI)
12038	 			return  variable;
12039	}
12040
12041	/* Is is a var_typeXX */
12042	strncpy(tmp,varname,sizeof(tmp) - 1);
12043	tmp[sizeof(tmp) - 1] = '\0';
12044
12045	offset = strlen(tmp) - 1 ;
12046	while(isdigit((int)tmp[offset]))
12047			tmp[offset--] = '\0';
12048	ep = NULL;
12049	e.key = tmp;
12050	hsearch_r(e, FIND, &ep, &vtab);
12051
12052	if (ep){
12053		variable = (struct variable *)ep->data;
12054		if (variable->ezc_flags & NVRAM_GENERIC_MULTI)
12055	 			return  variable;
12056	}
12057
12058	return  NULL;
12059}
12060int
12061variables_arraysize(void)
12062{
12063	return ARRAYSIZE(variables);
12064}
12065
12066/* Need to do special handling for the lan cgi stuff as the DHCP ranges need
12067 overlap checking . In addition multi index variables are also present
12068  on the same page. This breaks the conventional validation flow as implemented
12069*/
12070static void
12071validate_lan_cgi(webs_t wp)
12072{
12073	char cgi_vars[][32]= {
12074		       "lan_dhcp",
12075		       "lan_ipaddr",
12076		       "lan_netmask",
12077		       "lan_gateway",
12078		       "lan_proto",
12079		       "dhcp_start",
12080		       "dhcp_end",
12081		       "lan_lease",
12082		       "lan_stp",
12083		       "lan_route",
12084#ifdef __CONFIG_EMF__
12085		       "emf_enable",
12086		       "emf_entry",
12087		       "emf_uffp_entry",
12088		       "emf_rtport_entry",
12089#endif /* __CONFIG_EMF__ */
12090
12091/*
12092*/
12093#ifdef __CONFIG_IPV6__
12094		       "lan_ipv6_prefix",
12095		       "lan_ipv6_dns",
12096		       "lan_ipv6_mode",
12097		       "lan_ipv6_6to4id",
12098#endif /* __CONFIG_IPV6__ */
12099/*
12100*/
12101		       };
12102
12103	int count,num_ifaces;
12104	char *varname=NULL,*value=NULL;
12105	struct variable *v=NULL;
12106	int num_items = sizeof(cgi_vars)/sizeof(cgi_vars[0]);
12107	struct in_addr i_addr,g_addr,i_mask,g_mask;
12108	char err_msg[255] ;
12109	char vector[16];
12110	int router_enable=0;
12111
12112	ret_code = EINVAL;
12113
12114	memset(err_msg,0,sizeof(err_msg));
12115	memset(vector,0,sizeof(vector));
12116
12117	websBufferInit(wp);
12118	if (!webs_buf) {
12119		snprintf(err_msg,sizeof(err_msg),"out of memory<br>");
12120		goto validate_lan_cgi_error;
12121	}
12122
12123	value =  websGetVar(wp, "num_lan_ifaces" , NULL);
12124	if (!value){
12125		snprintf(err_msg,sizeof(err_msg),
12126			"unable to get number of lan interfaces<br>");
12127		goto validate_lan_cgi_error;
12128	}
12129
12130	num_ifaces=atoi(value);
12131
12132	router_enable = nvram_match("router_disable","0");
12133
12134	/* Build a LAN block valid enabled vector, skip processing if the
12135	 *  vector is not set.
12136	 */
12137	for (count=0; count < num_ifaces ; count++){
12138		char buf[64];
12139
12140		if (count)
12141			snprintf(buf, sizeof(buf), "lan%d_ifname", count);
12142		else
12143			snprintf(buf, sizeof(buf), "lan_ifname");
12144
12145		/* Skip LAN blocks that aren't enabled */
12146		value = websGetVar(wp, buf , NULL);
12147		if (!value || !*value)
12148			continue;
12149
12150		vector[count] = 1;
12151	}
12152
12153	/* check to see if the ip addresses overlap */
12154	for (count=0; count < num_ifaces ; count++){
12155		int entry;
12156		char *valueA,*valueB;
12157		char lanA_ipaddr[32],lanA_netmask[32];
12158		char lanB_ipaddr[32],lanB_netmask[32];
12159		char dhcpA_start[32],dhcpB_start[32];
12160		char dhcpA_end[32],dhcpB_end[32];
12161		char lanA_ifname[32],lanB_ifname[32];
12162		char lanA_proto[32],lanB_proto[32];
12163
12164		/* Skip LAN blocks that aren't enabled */
12165		if (!vector[count])
12166			continue;
12167
12168		if (count){
12169			snprintf(lanA_ifname,sizeof(lanA_ifname),"lan%d_ifname",count);
12170			snprintf(lanA_ipaddr,sizeof(lanA_ipaddr),"lan%d_ipaddr",count);
12171			snprintf(lanA_netmask,sizeof(lanA_netmask),"lan%d_netmask",count);
12172			snprintf(lanA_proto,sizeof(lanA_proto),"lan%d_proto",count);
12173			snprintf(dhcpA_start,sizeof(dhcpA_start),"dhcp%d_start",count);
12174			snprintf(dhcpA_end,sizeof(dhcpA_end),"dhcp%d_end",count);
12175		}else{
12176			snprintf(lanA_ifname,sizeof(lanA_ifname),"lan_ifname");
12177			snprintf(lanA_ipaddr,sizeof(lanA_ipaddr),"lan_ipaddr");
12178			snprintf(lanA_netmask,sizeof(lanA_netmask),"lan_netmask");
12179			snprintf(lanA_proto,sizeof(lanA_proto),"lan_proto");
12180			snprintf(dhcpA_start,sizeof(dhcpA_start),"dhcp_start");
12181			snprintf(dhcpA_end,sizeof(dhcpA_end),"dhcp_end");
12182		}
12183
12184		for (entry=0; entry < num_ifaces; entry++){
12185
12186			if (count == entry)
12187				continue;
12188
12189			/* Skip LAN blocks that aren't enabled */
12190			if (!vector[entry])
12191				continue;
12192
12193			if (entry){
12194				snprintf(lanB_ifname,sizeof(lanB_ifname),"lan%d_ifname",entry);
12195				snprintf(lanB_ipaddr,sizeof(lanB_ipaddr),"lan%d_ipaddr",entry);
12196				snprintf(lanB_netmask,sizeof(lanB_netmask),"lan%d_netmask",entry);
12197				snprintf(lanB_proto,sizeof(lanB_proto),"lan%d_proto",count);
12198				snprintf(dhcpB_start,sizeof(dhcpB_start),"dhcp%d_start",entry);
12199				snprintf(dhcpB_end,sizeof(dhcpB_end),"dhcp%d_end",entry);
12200			}else{
12201				snprintf(lanB_ifname,sizeof(lanB_ifname),"lan_ifname");
12202				snprintf(lanB_ipaddr,sizeof(lanB_ipaddr),"lan_ipaddr");
12203				snprintf(lanB_netmask,sizeof(lanB_netmask),"lan_netmask");
12204				snprintf(lanB_proto,sizeof(lanB_proto),"lan_proto");
12205				snprintf(dhcpB_start,sizeof(dhcpB_start),"dhcp_start");
12206				snprintf(dhcpB_end,sizeof(dhcpB_end),"dhcp_end");
12207			}
12208
12209			value =  websGetVar(wp, lanA_ipaddr , NULL);
12210			if (! value ) goto validate_lan_cgi_error;
12211			(void)inet_aton(value,&i_addr);
12212
12213			value = websGetVar(wp, lanB_ipaddr , NULL);
12214			if (! value ) goto validate_lan_cgi_error;
12215			(void)inet_aton(value,&g_addr);
12216
12217			value =  websGetVar(wp, lanA_netmask , NULL);
12218			if (! value ) goto validate_lan_cgi_error;
12219			(void)inet_aton(value,&i_mask);
12220
12221			value = websGetVar(wp, lanB_netmask , NULL);
12222			if (! value ) goto validate_lan_cgi_error;
12223			(void)inet_aton(value,&g_mask);
12224
12225			if ((i_addr.s_addr & i_mask.s_addr)==(g_addr.s_addr & g_mask.s_addr) ){
12226				snprintf(err_msg,sizeof(err_msg),
12227					"<br>Overlapping IP address ranges:<br>(RangeA=%s/%s) (RangeB=%s/%s)<br>",
12228						lanA_ipaddr,lanA_netmask,lanB_ipaddr,lanB_netmask);
12229	      			goto validate_lan_cgi_error;
12230			}
12231
12232			valueA = websGetVar(wp , lanA_proto , NULL);
12233			valueB = websGetVar(wp , lanB_proto , NULL);
12234
12235			/* If any of the proto vars are null skip the check */
12236			if ((!valueA) ||(!valueB))
12237						continue;
12238
12239			/* Overlapping DHCP range check only if DHCP is the lan proto on both*/
12240			if (!strcmp(valueA,"dhcp") && !strcmp(valueB,"dhcp"))
12241			{
12242				value =  websGetVar(wp, dhcpA_start , NULL);
12243				if (! value ) goto validate_lan_cgi_error;
12244				(void) inet_aton(value,&i_addr);
12245
12246				value = websGetVar(wp, dhcpB_start , NULL);
12247				if (! value ) goto validate_lan_cgi_error;
12248				(void) inet_aton(value,&g_addr);
12249
12250				/* Are they in the same subnetwork ? */
12251
12252				if ((i_addr.s_addr & i_mask.s_addr)==(g_addr.s_addr & g_mask.s_addr) ){
12253					snprintf(err_msg,sizeof(err_msg),
12254						"<br>Overlapping DHCP start ranges<br>(RangeA=%s/%s) (RangeB=%s/%s)<br>",
12255							dhcpA_start,lanA_netmask,dhcpB_start,lanB_netmask);
12256	      					goto validate_lan_cgi_error;
12257				}
12258
12259				value =  websGetVar(wp, dhcpA_end , NULL);
12260				if (! value ) goto validate_lan_cgi_error;
12261				(void) inet_aton(value,&i_addr);
12262
12263				value = websGetVar(wp, dhcpB_end , NULL);
12264				if (! value ) goto validate_lan_cgi_error;
12265				(void) inet_aton(value,&g_addr);
12266
12267				/* Are they in the same subnetwork ? */
12268
12269				if ((i_addr.s_addr & i_mask.s_addr)==(g_addr.s_addr & g_mask.s_addr) ){
12270					snprintf(err_msg,sizeof(err_msg),
12271						 "<br>Overlapping DHCP end ranges<br>(RangeA=%s/%s) (RangeB=%s/%s)<br>",
12272							dhcpA_end,lanA_netmask,dhcpB_end,lanB_netmask);
12273	      					goto validate_lan_cgi_error;
12274				}
12275			}
12276		}
12277	}
12278
12279	ret_code = 0;
12280
12281	/* The individual validation functions will set ret_code to EINVAL
12282	   if an error is encountered. On success zero is returned.
12283	   Validation stops on the first error encountered
12284	*/
12285	for  ( count = 0; ( count < num_items && !(ret_code) ); count++){
12286
12287		char var[64];
12288		int entry;
12289
12290		/* Lookup template */
12291		varname = cgi_vars[count];
12292		v = get_var_handle(varname);
12293
12294		/* Enumerate thru list of interfaces */
12295		if (v)
12296			for (entry=0; entry < num_ifaces; entry++){
12297
12298				/* Skip LAN blocks that aren't enabled */
12299				if (!vector[entry])
12300					continue;
12301
12302				if (v->ezc_flags & WEB_IGNORE)
12303					continue;
12304
12305				if (entry && v->prefix )
12306					snprintf(var,sizeof(var),"%s%d_%s",
12307						v->prefix,entry,&varname[strlen(v->prefix) + 1]);
12308				else
12309					snprintf(var,sizeof(var),"%s",varname);
12310
12311				value = websGetVar(wp, var, NULL);
12312
12313				if (value){
12314					if ((!*value && v->nullok) || !v->validate)
12315						nvram_set(var, value);
12316					else
12317						v->validate(wp, value, v, var);
12318				}
12319			}
12320	}
12321
12322
12323	/* Set lanX_dhcp to static for all interfaces in router mode */
12324	if (router_enable)
12325		for (count = 0; count < num_ifaces; count++){
12326			char lan_dhcp[]="lanXXXXX_dhcp";
12327
12328			/* Skip entry if the SSID is not turned on */
12329			if (!vector[count])
12330				continue;
12331
12332			if (count)
12333				snprintf(lan_dhcp,sizeof(lan_dhcp),"lan%d_dhcp",count);
12334			else
12335				snprintf(lan_dhcp,sizeof(lan_dhcp),"lan_dhcp");
12336			nvram_set(lan_dhcp,"0");
12337
12338		}
12339
12340	/* Handlers already print error messages. No need for further explanation */
12341	if (ret_code)
12342		snprintf(err_msg,sizeof(err_msg),"Error during variable validation.<br>");
12343
12344validate_lan_cgi_error:
12345	if (*err_msg)
12346		websWrite(wp, err_msg);
12347
12348	websBufferFlush(wp);
12349}
12350
12351static void
12352validate_cgi(webs_t wp)
12353{
12354	struct variable *v=NULL;
12355	char *value=NULL;
12356
12357	websBufferInit(wp);
12358	if (!webs_buf) {
12359		websWrite(wp, "out of memory<br>");
12360		websDone(wp, 0);
12361		return;
12362	}
12363
12364
12365	/* Validate and set variables in table order */
12366	for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) {
12367		if (!(value = websGetVar(wp, v->name, NULL)))
12368			continue;
12369
12370		if (v->ezc_flags & WEB_IGNORE)
12371			continue;
12372
12373		if ((!*value && v->nullok) || !v->validate)
12374			nvram_set(v->name, value);
12375		else
12376			v->validate(wp, value, v, NULL);
12377	}
12378
12379	websBufferFlush(wp);
12380}
12381
12382#ifdef __CONFIG_WPS__
12383static int
12384is_wps_enabled()
12385{
12386	int i, unit;
12387	char *ifnames, *next;
12388	char prefix[] = "wlXXXXXXXXXX_";
12389	char name[IFNAMSIZ], os_name[IFNAMSIZ], wl_name[IFNAMSIZ];
12390	char lan_name[IFNAMSIZ];
12391	char tmp[100];
12392	char *wps_mode;
12393	char *wl_radio, *wl_bss_enabled;
12394
12395	/* (LAN) */
12396	for (i = 0; i < 256; i ++) {
12397		/* Taking care of LAN interface names */
12398		if (i == 0) {
12399			strcpy(name, "lan_ifnames");
12400			strcpy(lan_name, "lan");
12401		}
12402		else {
12403			sprintf(name, "lan%d_ifnames", i);
12404			sprintf(lan_name, "lan%d", i);
12405		}
12406
12407		ifnames = nvram_get(name);
12408		if (!ifnames)
12409			continue;
12410
12411		/* Search for wl_name in ess */
12412		foreach(name, ifnames, next) {
12413			if (nvifname_to_osifname(name, os_name, sizeof(os_name)) < 0)
12414				continue;
12415			if (wl_probe(os_name) ||
12416				wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
12417				continue;
12418
12419			/* Convert eth name to wl name */
12420			if (osifname_to_nvifname(name, wl_name, sizeof(wl_name)) != 0)
12421				continue;
12422
12423			/* Get configured wireless address */
12424			snprintf(prefix, sizeof(prefix), "%s_", wl_name);
12425
12426			/* Ignore radio or bss is disabled */
12427			snprintf(tmp, sizeof(tmp), "wl%d_radio", unit);
12428			wl_radio = nvram_safe_get(tmp);
12429			wl_bss_enabled = nvram_safe_get(strcat_r(prefix, "bss_enabled", tmp));
12430			if (strcmp(wl_radio, "1") != 0 || strcmp(wl_bss_enabled, "1") != 0)
12431				continue;
12432			if (nvram_get(strcat_r(prefix, "hwaddr", tmp)) == NULL)
12433				continue;
12434
12435			/* Enabled/ Disabled */
12436			wps_mode = nvram_get(strcat_r(prefix, "wps_mode", tmp));
12437			if (!wps_mode ||
12438				(strcmp(wps_mode, "enabled") != 0 &&
12439				strcmp(wps_mode, "enr_enabled") != 0)) {
12440				continue;
12441			}
12442
12443			/* got it enabled, wps is running */
12444			return 1;
12445		}
12446	}
12447
12448	/* (WAN) */
12449	for (i = 0; i < 256; i ++) {
12450		/* Taking care of WAN interface names */
12451		if (i == 0)
12452			strcpy(name, "wan_ifnames");
12453		else
12454			sprintf(name, "wan%d_ifnames", i);
12455
12456		ifnames = nvram_get(name);
12457		if (!ifnames)
12458			continue;
12459
12460		/* Search for wl_name in it */
12461		foreach(name, ifnames, next) {
12462			if (nvifname_to_osifname(name, os_name, sizeof(os_name)) < 0)
12463				continue;
12464			if (wl_probe(os_name) ||
12465				wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
12466				continue;
12467
12468			/* Convert eth name to wl name */
12469			if (osifname_to_nvifname(name, wl_name, sizeof(wl_name)) != 0)
12470				continue;
12471
12472			/* Get configured wireless address */
12473			snprintf(prefix, sizeof(prefix), "%s_", wl_name);
12474
12475			/* Ignore radio or bss is disabled */
12476			snprintf(tmp, sizeof(tmp), "wl%d_radio", unit);
12477			wl_radio = nvram_safe_get(tmp);
12478			wl_bss_enabled = nvram_safe_get(strcat_r(prefix, "bss_enabled", tmp));
12479			if (strcmp(wl_radio, "1") != 0 || strcmp(wl_bss_enabled, "1") != 0)
12480				continue;
12481			if (nvram_get(strcat_r(prefix, "hwaddr", tmp)) == NULL)
12482				continue;
12483
12484			/* Enabled/ Disabled */
12485			wps_mode = nvram_get(strcat_r(prefix, "wps_mode", tmp));
12486			if (!wps_mode || strcmp(wps_mode, "enr_enabled") != 0)
12487				continue;
12488
12489			/* got it enabled, wps is running */
12490			return 1;
12491		}
12492	}
12493
12494	return 0;
12495}
12496
12497static int
12498write_to_wps(int fd, char *cmd)
12499{
12500	int n;
12501	int len;
12502	struct sockaddr_in to;
12503
12504	len = strlen(cmd)+1;
12505
12506	/* open loopback socket to communicate with wps */
12507	memset(&to, 0, sizeof(to));
12508	to.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
12509	to.sin_family = AF_INET;
12510	to.sin_port = htons(WPS_UI_PORT);
12511
12512	if ((n = sendto(fd, cmd, len, 0, (struct sockaddr *)&to,
12513		sizeof(struct sockaddr_in))) <0) {
12514		perror("write_to_wps: sendto failed");
12515	}
12516	else {
12517		/* Sleep 100 ms to make sure WPS have received socket */
12518		USLEEP(100*1000);
12519	}
12520	return n;
12521}
12522
12523static int
12524read_from_wps(int fd, char *databuf, int datalen)
12525{
12526	int n, max_fd = -1;
12527	fd_set fdvar;
12528	struct timeval timeout;
12529	int recvBytes;
12530	struct sockaddr_in addr;
12531	socklen_t size = sizeof(struct sockaddr);
12532
12533	timeout.tv_sec = 2;
12534	timeout.tv_usec = 0;
12535
12536	FD_ZERO(&fdvar);
12537
12538	/* get ui fd */
12539	if (fd >= 0) {
12540		FD_SET(fd, &fdvar);
12541		max_fd = fd;
12542	}
12543
12544	if (max_fd == -1) {
12545		fprintf(stderr, "wps ui utility: no fd set!\n");
12546		return -1;
12547	}
12548
12549	n = select(max_fd + 1, &fdvar, NULL, NULL, &timeout);
12550
12551	if (n < 0) {
12552		return -1;
12553	}
12554
12555	if (n > 0) {
12556		if (fd >= 0) {
12557			if (FD_ISSET(fd, &fdvar)) {
12558				recvBytes = recvfrom(fd, databuf, datalen,
12559					0, (struct sockaddr *)&addr, &size);
12560
12561				if (recvBytes == -1) {
12562					fprintf(stderr,
12563					"wps ui utility:recv failed, recvBytes = %d\n", recvBytes);
12564					return -1;
12565				}
12566
12567				return recvBytes;
12568			}
12569
12570			return 0;
12571		}
12572	}
12573
12574	return -1;
12575}
12576
12577#define MAX_WPS_ENV_ARGS 32
12578
12579int
12580parse_wps_env(char *buf)
12581{
12582	char *argv[MAX_WPS_ENV_ARGS] = {0};
12583	char *value, *p, *name;
12584	int i;
12585	int unit, subunit;
12586	char nvifname[IFNAMSIZ];
12587
12588	/* Seperate buf into argv[], we have to make sure at least one is empty */
12589	for (i = 0, p = buf; i < MAX_WPS_ENV_ARGS-1; i++) {
12590		/* Eat white space */
12591		while (*p == ' ')
12592			p++;
12593		if (*p == 0)
12594			goto all_found;
12595
12596		/* Save this item */
12597		argv[i] = p;
12598
12599		 /* Search until space */
12600		while (*p != ' ' && *p) {
12601			/* Take care of doube quot */
12602			if (*p == '\"') {
12603				char *qs, *qe;
12604
12605				qs = p;
12606				qe = strchr(p+1, '\"');
12607				if (qe == NULL) {
12608					printf("%s:%d, unbalanced quote string!", __func__, __LINE__);
12609					argv[i] = 0;
12610					goto all_found;
12611				}
12612
12613
12614				/* Null eneded quot string and do shift */
12615				*qe = '\0';
12616				memmove(qs, qs+1, (int)(qe-qs));
12617
12618				p = qe+1;
12619				break;
12620			}
12621
12622			p++;
12623		}
12624
12625		if (*p)
12626			*p++ = '\0';
12627	}
12628
12629all_found:
12630	/* Parse message */
12631	wps_config_command = WPS_UI_CMD_NONE;
12632	wps_method = 0; /* Add in PF #3 */
12633	memset(wps_autho_sta_mac, 0, sizeof(wps_autho_sta_mac)); /* Add in PF #3 */
12634
12635	for (i = 0; argv[i]; i++) {
12636		value = argv[i];
12637		name = strsep(&value, "=");
12638		if (name) {
12639			if (!strcmp(name, "wps_config_command"))
12640				wps_config_command = atoi(value);
12641			else if (!strcmp(name, "wps_uuid")) {
12642				strncpy(wps_uuid , value, sizeof(wps_uuid) - 1);
12643				wps_uuid[sizeof(wps_uuid) - 1] = '\0';
12644			}
12645			else if (!strcmp(name, "wps_method")) /* Add in PF #3 */
12646				wps_method = atoi(value);
12647			else if (!strcmp(name, "wps_autho_sta_mac")) /* Add in PF #3 */
12648				memcpy(wps_autho_sta_mac, value, sizeof(wps_autho_sta_mac));
12649			else if (!strcmp(name, "wps_ifname")) {
12650				if (strlen(value) <=0)
12651					continue;
12652				if (osifname_to_nvifname(value, nvifname, sizeof(nvifname)) != 0)
12653					continue;
12654
12655				if (get_ifname_unit(nvifname, &unit, &subunit) == -1)
12656					continue;
12657				if (unit < 0)
12658					unit = 0;
12659				if (subunit < 0)
12660					subunit = 0;
12661
12662				if (subunit)
12663					sprintf(wps_unit, "%d.%d", unit, subunit);
12664				else
12665					sprintf(wps_unit, "%d", unit);
12666			}
12667#ifdef __CONFIG_NFC__
12668			else if (!strcmp(name, "wps_nfc_dm_status"))
12669				wps_nfc_dm_status = atoi(value);
12670			else if (!strcmp(name, "wps_nfc_err_code"))
12671				wps_nfc_err_code = atoi(value);
12672#endif /* __CONFIG_NFC__ */
12673
12674		}
12675	}
12676
12677	return 0;
12678}
12679
12680static int
12681get_wps_env()
12682{
12683	int fd = -1;
12684	char databuf[257];
12685	int datalen = sizeof(databuf);
12686	databuf[--datalen] = 0;
12687
12688	if (is_wps_enabled() == 0)
12689		return -1;
12690
12691	if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
12692		fprintf(stderr, "wps ui utility: failed to open loopback socket\n");
12693		return -1;
12694	}
12695
12696	/* Receive response */
12697	if (write_to_wps(fd, "GET") >= 0 && read_from_wps(fd, databuf, datalen) > 0) {
12698		parse_wps_env(databuf);
12699	}
12700	else {
12701		/* Show error message ? */
12702	}
12703
12704	close(fd);
12705	return 0;
12706}
12707
12708
12709static int
12710set_wps_env(char *uibuf)
12711{
12712	int wps_fd = -1;
12713	struct sockaddr_in to;
12714	int sentBytes = 0;
12715	uint32 uilen = strlen(uibuf);
12716
12717	if (is_wps_enabled() == 0)
12718		return -1;
12719
12720	if ((wps_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
12721		goto exit;
12722	}
12723
12724	/* send to WPS */
12725	to.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
12726	to.sin_family = AF_INET;
12727	to.sin_port = htons(WPS_UI_PORT);
12728
12729	sentBytes = sendto(wps_fd, uibuf, uilen, 0, (struct sockaddr *) &to,
12730		sizeof(struct sockaddr_in));
12731
12732	if (sentBytes != uilen) {
12733		goto exit;
12734	}
12735
12736	/* Sleep 100 ms to make sure
12737	   WPS have received socket */
12738	USLEEP(100*1000);
12739	close(wps_fd);
12740	return 0;
12741
12742exit:
12743	if (wps_fd >= 0)
12744		close(wps_fd);
12745
12746	/* Show error message ?  */
12747	return -1;
12748}
12749
12750/* Check lan index according to wl_unit */
12751static int
12752wps_get_lan_idx()
12753{
12754	int i;
12755	char prefix[] = "wlXXXXXXXXXX_";
12756	char *wl_ifname, *lan_ifnames;
12757	char tmp[NVRAM_BUFSIZE];
12758
12759	if (!make_wl_prefix(prefix,sizeof(prefix), 1, NULL))
12760		return -1; /* Error */
12761
12762	wl_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
12763
12764	/* find wlx_ifname in lan_ifnames */
12765	for (i = 0; i< MAX_NVPARSE; i++) {
12766		if (i == 0)
12767			snprintf(tmp, sizeof(tmp), "lan_ifnames");
12768		else
12769			snprintf(tmp, sizeof(tmp), "lan%d_ifnames", i);
12770
12771		lan_ifnames = nvram_get(tmp);
12772		if (lan_ifnames && find_in_list(lan_ifnames, wl_ifname))
12773			break;
12774	}
12775
12776	if (i == MAX_NVPARSE)
12777		return -1;
12778
12779	return i;
12780}
12781
12782static int
12783wps_get_oob_name(char *name, int len)
12784{
12785	int i;
12786	char prefix[] = "wlXXXXXXXXXX_";
12787	char wl_mode[]="wlXXXXXXXXXX_mode";
12788	char *mode;
12789	char *wl_ifname, *lan_ifnames;
12790	char tmp[NVRAM_BUFSIZE];
12791
12792	if (!make_wl_prefix(prefix,sizeof(prefix), 1, NULL)) {
12793		return -1;
12794	}
12795
12796	snprintf(wl_mode,sizeof(wl_mode),"%smode",prefix);
12797	mode = nvram_safe_get(wl_mode);
12798	if (strcmp(mode, "ap") == 0) {
12799		/* For AP */
12800		wl_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
12801
12802		/* find wlx_ifname in lan_ifnames */
12803		for (i = 0; i< MAX_NVPARSE; i++) {
12804			if (i == 0)
12805				snprintf(tmp, sizeof(tmp), "lan_ifnames");
12806			else
12807				snprintf(tmp, sizeof(tmp), "lan%d_ifnames", i);
12808
12809			lan_ifnames = nvram_get(tmp);
12810			if (lan_ifnames && find_in_list(lan_ifnames, wl_ifname))
12811				break;
12812		}
12813
12814		if (i == MAX_NVPARSE)
12815			return -1;
12816
12817		if (i == 0)
12818			snprintf(name, len, "lan_wps_oob");
12819		else
12820			snprintf(name, len, "lan%d_wps_oob", i);
12821	}
12822	else {
12823		/* For STA */
12824		snprintf(name, len, "%swps_oob", prefix);
12825	}
12826	return 0;
12827}
12828
12829static void
12830wps_disable_oob()
12831{
12832	char name[NVRAM_BUFSIZE];
12833
12834	if (wps_get_oob_name(name, NVRAM_BUFSIZE) == -1)
12835		return;
12836	nvram_set(name, "disabled");
12837}
12838
12839static void
12840wps_enable_oob()
12841{
12842	char name[NVRAM_BUFSIZE];
12843#ifdef __CONFIG_NFC__
12844#define WPS_CONFMET_EXT_NFC_TOK     0x0010
12845	char *value, tmp[16];
12846	unsigned short config_method;
12847#endif
12848
12849	if (wps_get_oob_name(name, NVRAM_BUFSIZE) == -1)
12850		return;
12851	nvram_set(name, "enabled");
12852
12853#ifdef __CONFIG_NFC__
12854	/* Remove the external NFC Token bit. */
12855	value = nvram_get("wps_config_method");
12856	if (value) {
12857		config_method = strtoul(value, NULL, 16);
12858		if (config_method & WPS_CONFMET_EXT_NFC_TOK) {
12859			config_method &= ~WPS_CONFMET_EXT_NFC_TOK;
12860			sprintf(tmp, "0x%x", config_method);
12861			nvram_set("wps_config_method", tmp);
12862		}
12863	}
12864#endif /* __CONFIG_NFC__ */
12865}
12866
12867/* Check current wl_unit interfave wps_reg statuc */
12868static int
12869wps_is_reg()
12870{
12871	int lan_idx;
12872	char tmp[NVRAM_BUFSIZE];
12873
12874	lan_idx = wps_get_lan_idx();
12875	if (lan_idx == -1)
12876		return 0;
12877
12878	/* found, get lanx_wps_reg */
12879	if (lan_idx == 0)
12880		snprintf(tmp, sizeof(tmp), "lan_wps_reg");
12881	else
12882		snprintf(tmp, sizeof(tmp), "lan%d_wps_reg", lan_idx);
12883
12884	if (nvram_match(tmp, "enabled"))
12885		return 1;
12886
12887	return 0;
12888}
12889
12890/* Check current wl_unit interfave wps_oob status */
12891static int
12892wps_is_oob()
12893{
12894	char tmp[NVRAM_BUFSIZE];
12895
12896	/* WPS is disabled */
12897	if (wps_get_oob_name(tmp, NVRAM_BUFSIZE) == -1)
12898		return 0;
12899	/*
12900	 * OOB: enabled
12901	 * Configured: disabled
12902	 */
12903	if (nvram_match(tmp, "disabled"))
12904		return 0;
12905
12906	return 1;
12907}
12908static int wps_check_pin(char *pin, char *value)
12909{
12910
12911	/* add in PF#3, session 7.4.3 "1234-5670" */
12912	if (strlen(value) == 9 &&
12913	    (value[4] < '0' || value[4] > '9')) {
12914		/* remove '-' */
12915		memcpy(pin, value, 4);
12916		memcpy(pin+4, value+5, 4);
12917	}
12918	else {
12919		strncpy(pin, value, 8);
12920	}
12921
12922	/* pin validation */
12923	if (wl_wpsPincheck(pin))
12924		return -1;
12925	return 0;
12926}
12927
12928static int wps_get_credentials(webs_t wp, char *uibuf, int uilen)
12929{
12930	char *value;
12931	int wps_akm = 0;
12932
12933	/* credential setting */
12934	if ((value = websGetVar(wp, "wps_ssid", NULL)))
12935	{
12936		uilen += sprintf(uibuf + uilen, "wps_ssid=\"%s\" ", value);
12937	}
12938	else {
12939		websWrite(wp, "Unable to get SSID.");
12940		return -1;
12941	}
12942
12943	/* Authentication Type */
12944	if ((value = websGetVar(wp, "wps_akm", NULL)))
12945	{
12946		if (!strlen(value))
12947			uilen += sprintf(uibuf + uilen, "wps_akm=\"\" ");
12948		else {
12949			uilen += sprintf(uibuf + uilen, "wps_akm=\"%s\" ", value);
12950			wps_akm = 1;
12951		}
12952	}
12953	else {
12954		websWrite(wp, "Unable to get Authentication Type.");
12955		return -1;
12956	}
12957
12958	/* Encryption Type */
12959	if ((value = websGetVar(wp, "wps_crypto", NULL)))
12960	{
12961		uilen += sprintf(uibuf + uilen, "wps_crypto=\"%s\" ", value);
12962	}
12963	else {
12964		if (wps_akm) {
12965			websWrite(wp, "Unable to get Encryption Type.");
12966			return -1;
12967		}
12968	}
12969
12970	/* WPA passphrase */
12971	if ((value = websGetVar(wp, "wps_psk", NULL)))
12972	{
12973		uilen += sprintf(uibuf + uilen, "wps_psk=\"%s\" ", value);
12974	}
12975	else {
12976		if (wps_akm) {
12977			websWrite(wp, "Unable to get Passphrase Key.");
12978			return -1;
12979		}
12980	}
12981
12982	return uilen;
12983}
12984static int wps_cgi(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
12985	  char_t *url, char_t *path, char_t *query)
12986{
12987	char *value = NULL, *action_mode = NULL;
12988	char *wps_ssid = NULL, *wps_akm = NULL, *wps_crypto = NULL, *wps_psk = NULL;
12989	char tmp[256];
12990	char nvifname[IFNAMSIZ], osifname[IFNAMSIZ];
12991	char pin[9] = {0};
12992	char uibuf[1024] = "SET ";
12993	int uilen = 4;
12994	bool b_wps_version2 = FALSE;
12995	char prefix[] = "wlXXXXXXXXXX_";
12996	int len;
12997	int akm = 1;
12998
12999	action_mode = websGetVar(wp, "action", NULL);
13000
13001	if (action_mode == NULL) {
13002		websError(wp, 400, "action mode is not specified\n");
13003		return -1;
13004	}
13005
13006	if (!make_wl_prefix(prefix, sizeof(prefix), 1, NULL)) {
13007		websError(wp, 400, "unit number variable doesn't exist\n");
13008		return -1;
13009	}
13010
13011	if (!strcmp(action_mode, "Reset To OOB")) {
13012		websWrite(wp, "Reset to OOB ...");
13013		wps_enable_oob();
13014
13015		snprintf(tmp, sizeof(tmp), "%sssid", prefix);
13016		nvram_set(tmp, nvram_default_get("wl_ssid"));
13017
13018		snprintf(tmp, sizeof(tmp), "%sakm", prefix);
13019		nvram_set(tmp, nvram_default_get("wl_akm"));
13020
13021		snprintf(tmp, sizeof(tmp), "%scrypto", prefix);
13022		nvram_set(tmp, nvram_default_get("wl_crypto"));
13023
13024		snprintf(tmp, sizeof(tmp), "%swpa_psk", prefix);
13025		nvram_set(tmp, nvram_default_get("wl_wpa_psk"));
13026		nvram_commit();
13027		action = RESTART;
13028	}
13029	else if (!strcmp(action_mode, "Save Credentials")) {
13030		websWrite(wp, "Validating values...");
13031
13032		if (!(wps_ssid = websGetVar(wp, "wps_ssid", NULL))) {
13033			websWrite(wp, "Unable to get WPS SSID.\n");
13034			return -1;
13035		}
13036
13037		if ((wps_akm = websGetVar(wp, "wps_akm", NULL))) {
13038			if (!strlen(wps_akm))
13039				akm = 0;
13040		}
13041		else {
13042			websWrite(wp, "Unable to get Authentication Type.\n");
13043			return -1;
13044		}
13045
13046		if (akm) {
13047			if (!(wps_crypto = websGetVar(wp, "wps_crypto", NULL))) {
13048				websWrite(wp, "Unable to get Encryption Type.\n");
13049				return -1;
13050			}
13051
13052			if (!(wps_psk = websGetVar(wp, "wps_psk", NULL))) {
13053				websWrite(wp, "Unable to get WPA passphrase.\n");
13054				return -1;
13055			}
13056
13057			len = strlen(wps_psk);
13058			if (len == 64) {
13059				char *c;
13060				for (c = wps_psk; *c; c++) {
13061					if (!isxdigit((int) *c)) {
13062						websWrite(wp, "Invalid <b>WPA passphase</b>: character %c is not a hexadecimal digit<br>", *c);
13063						return -1;
13064					}
13065				}
13066			} else if (len < 8 || len > 63) {
13067				websWrite(wp, "Invalid <b>WPA passphase</b>: must be between 8 and 63 ASCII characters or 64 hexadecimal digits<br>");
13068				return -1;
13069			}
13070		}
13071
13072		action = RESTART;
13073		/* now we can apply new ssid/akm/crypto and psk */
13074		snprintf(tmp, sizeof(tmp), "%sssid", prefix);
13075		nvram_set(tmp, wps_ssid);
13076		nvram_set("wl_ssid", wps_ssid);
13077		snprintf(tmp, sizeof(tmp), "%sakm", prefix);
13078		nvram_set(tmp, wps_akm);
13079		nvram_set("wl_akm", wps_akm);
13080		if (akm) {
13081			snprintf(tmp, sizeof(tmp), "%scrypto", prefix);
13082			nvram_set(tmp, wps_crypto);
13083			nvram_set("wl_crypto", wps_crypto);
13084			snprintf(tmp, sizeof(tmp), "%swpa_psk", prefix);
13085			nvram_set(tmp, wps_psk);
13086			nvram_set("wl_wpa_psk", wps_psk);
13087		}
13088
13089		wps_disable_oob();
13090		websWrite(wp, "done<br>");
13091		websWrite(wp, "Committing values...");
13092		nvram_set("is_modified", "1");
13093		nvram_set("is_default", "0");
13094		nvram_commit();
13095		websWrite(wp, "done<br>");
13096	}
13097	/* WPS AP want to Add Enrollee */
13098	else if (!strcmp(action_mode, "Add Enrollee")) {
13099
13100		websWrite(wp, "validate variable...\n");
13101		wps_action = WPS_UI_ACT_ADDENROLLEE;
13102		websWrite(wp, "WPS is preparing to Add Enrollee...\n");
13103		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", wps_action);
13104
13105		uilen = wps_get_credentials(wp, uibuf, uilen);
13106		if (uilen == -1)
13107			return -1;
13108
13109		/* get sta pin, if pin value is empty the user want to use PBC method. */
13110		if ((value = websGetVar(wp, "wps_sta_pin", NULL))) {
13111			if (value[0] == 0) {
13112				wps_method = WPS_UI_METHOD_PBC;
13113				strncpy(pin, "00000000", 8);
13114				uilen += sprintf(uibuf + uilen, "wps_pbc_method=\"%d\" ", WPS_UI_PBC_SW);
13115			}
13116			else {
13117				wps_method = WPS_UI_METHOD_PIN;
13118
13119				/* check sta pin */
13120				if (wps_check_pin(pin, value)){
13121					websWrite(wp, "Warning: PIN checksum is invalid.\n");
13122					return -1;
13123				}
13124
13125				/* WSC 2.0, get authorized mac */
13126				value = websGetVar(wp, "wps_autho_sta_mac", NULL);
13127				if (value && *value) {
13128					unsigned char hwaddr[6];
13129
13130					/* Check for bad, multicast, broadcast, or null address */
13131					if (!ether_atoe(value, hwaddr) ||
13132					    (hwaddr[0] & 1) ||
13133					    (hwaddr[0] & hwaddr[1] & hwaddr[2] &
13134					     hwaddr[3] & hwaddr[4] & hwaddr[5]) == 0xff ||
13135					    (hwaddr[0] | hwaddr[1] | hwaddr[2] |
13136					     hwaddr[3] | hwaddr[4] | hwaddr[5]) == 0x00) {
13137						websWrite(wp, "Invalid <b>Authorized Station MAC</b> "
13138							"%s: not a MAC address\n", value);
13139						action = NOTHING;
13140						return -1;
13141					}
13142					else
13143						uilen += sprintf(uibuf + uilen, "wps_autho_sta_mac=\"%s\" ", value);
13144				}
13145
13146			}
13147			uilen += sprintf(uibuf + uilen, "wps_sta_pin=\"%s\" ", pin);
13148			uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", wps_method);
13149		}
13150		websWrite(wp, "OK");
13151
13152		nvram_set("wps_proc_status", "0");
13153		strncpy(wps_unit, nvram_safe_get("wl_unit"), sizeof(wps_unit));
13154		wps_unit[sizeof(wps_unit)-1] = '\0';
13155
13156		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_START);
13157
13158		sprintf(nvifname, "wl%s", wps_unit);
13159		(void)nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13160
13161		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13162		set_wps_env(uibuf);
13163	}
13164	else if (!strcmp(action_mode, "Start"))
13165	{
13166		int wps_config_command = WPS_UI_CMD_START;
13167
13168		websWrite(wp, "validate variable...\n");
13169
13170		if (!(value = websGetVar(wp, "wps_action", NULL))) {
13171			websWrite(wp, "Unable to get wps action.\n");
13172			return -1;
13173		}
13174		else {
13175			if (!strcmp(value, "Enroll"))
13176				wps_action = WPS_UI_ACT_ENROLL;
13177			else if (!strcmp(value, "ConfigAP"))
13178				wps_action = WPS_UI_ACT_STA_CONFIGAP;
13179			else if (!strcmp(value, "GetAPConfig"))
13180				wps_action = WPS_UI_ACT_STA_GETAPCONFIG;
13181
13182			sprintf(tmp, "%d", wps_action);
13183			nvram_set("wps_action", tmp);
13184			websWrite(wp, "WPS is preparing to %s...\n", value);
13185			uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", wps_action);
13186		}
13187
13188		if (wps_action == WPS_UI_ACT_ENROLL)
13189		{
13190			value = websGetVar(wp, "wps_method", NULL);
13191
13192			if (!strcmp(value, "PIN"))
13193				wps_method = WPS_UI_METHOD_PIN;
13194			else if (!strcmp(value, "PBC"))
13195			{
13196				wps_method = WPS_UI_METHOD_PBC;
13197				strncpy(pin, "00000000", 8);
13198				uilen += sprintf(uibuf + uilen, "wps_pbc_method=\"%d\" ", WPS_UI_PBC_SW);
13199			}
13200#ifdef __CONFIG_NFC__
13201			else if (!strcmp(value, "NFC")) {
13202				wps_method = WPS_UI_METHOD_NFC_PW;
13203				wps_config_command = WPS_UI_CMD_NFC_WR_PW;
13204				websWrite(wp, "<br><br>Please place your NFC token now!<br>\n");
13205				/* Station PIN comes from NFC Password */
13206				uilen += sprintf(uibuf + uilen, "wps_sta_pin=\"NFC_PW\" ");
13207			}
13208#endif
13209			uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", wps_method);
13210
13211		} /*  WPS_UI_ACT_ENROLL */
13212
13213		if (wps_action == WPS_UI_ACT_STA_CONFIGAP) {
13214			uilen = wps_get_credentials(wp, uibuf, uilen);
13215			if (uilen < 0)
13216				return -1;
13217		}
13218
13219		if (wps_action == WPS_UI_ACT_STA_CONFIGAP ||
13220		    wps_action == WPS_UI_ACT_STA_GETAPCONFIG) {
13221			wps_method = WPS_UI_METHOD_PIN;
13222#ifdef __CONFIG_NFC__
13223			value = websGetVar(wp, "wps_method", NULL);
13224
13225			if (!strcmp(value, "PIN"))
13226				wps_method = WPS_UI_METHOD_PIN;
13227			else if (!strcmp(value, "NFC")) {
13228				wps_method = WPS_UI_METHOD_NFC_PW;
13229				wps_config_command = WPS_UI_CMD_NFC_RD_PW;
13230				websWrite(wp, "<br><br>Please place your NFC password token now!<br>\n");
13231				/* AP PIN comes from NFC Password */
13232				uilen += sprintf(uibuf + uilen, "wps_stareg_ap_pin=\"NFC_PW\" ");
13233			}
13234#endif
13235			uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", wps_method);
13236
13237			/* get AP pin */
13238			if (!strcmp(value, "PIN")) {
13239				if ((value = websGetVar(wp, "wps_ap_pin", NULL)))
13240					if (wps_check_pin(pin, value)) {
13241						websWrite(wp, "Input AP PIN is invalidated.");
13242						return -1;
13243				}
13244				uilen += sprintf(uibuf + uilen, "wps_stareg_ap_pin=\"%s\" ", pin);
13245			}
13246		}
13247
13248		if ((wps_action == WPS_UI_ACT_ENROLL &&
13249			(wps_method == WPS_UI_METHOD_PIN ||
13250#ifdef __CONFIG_NFC__
13251			wps_method == WPS_UI_METHOD_NFC_PW ||
13252#endif
13253			FALSE)) ||
13254			wps_action == WPS_UI_ACT_STA_CONFIGAP ||
13255			wps_action == WPS_UI_ACT_STA_GETAPCONFIG) {
13256			wps_ap_list_info_t *ap;
13257			int wps_ap_index;
13258			char eastr[ETHER_ADDR_STR_LEN];
13259
13260
13261			if ((value = websGetVar(wp, "wps_ap_list", NULL)) == NULL ||
13262				(wps_ap_index = atoi(value)) == -1 ||
13263				(ap = wps_enr_get_selected_ap(wps_ap_index)) == NULL)
13264			{
13265				websWrite(wp, "Unable to get selected WPS AP.");
13266				return -1;
13267			}
13268
13269			selected_ap = ap;
13270			if (wps_action == WPS_UI_ACT_STA_CONFIGAP ||
13271				wps_action == WPS_UI_ACT_STA_GETAPCONFIG)
13272				uilen += sprintf(uibuf + uilen, "wps_scstate=\"%s\" ", ap->scstate ? "configured" : "unconfigured");
13273
13274			uilen += sprintf(uibuf + uilen, "wps_enr_ssid=\"%s\" ", ap->ssid);
13275			uilen += sprintf(uibuf + uilen, "wps_enr_bssid=\"%s\" ", ether_etoa(ap->BSSID, eastr));
13276			uilen += sprintf(uibuf + uilen, "wps_enr_wsec=\"%d\" ", ap->wep);
13277		}
13278		websWrite(wp, "OK");
13279
13280		nvram_set("wps_proc_status", "0");
13281		strncpy(wps_unit, nvram_safe_get("wl_unit"), sizeof(wps_unit));
13282		wps_unit[sizeof(wps_unit)-1] = '\0';
13283
13284		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", wps_config_command);
13285
13286		sprintf(nvifname, "wl%s", wps_unit);
13287		(void)nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13288
13289		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13290		set_wps_env(uibuf);
13291		nvram_commit();
13292	} /* start */
13293	else if (!strcmp(action_mode, "Rescan")) {
13294		websWrite(wp, "Re-Scanning WPS supported AP(s)...");
13295		wl_wpsEnrScan();
13296		websWrite(wp, "OK");
13297	}
13298	/* WPS PBC push again, Add in PF #3 */
13299	else if (!strcmp(action_mode, "PBC Again")) {
13300
13301		websWrite(wp, "validate variable...\n");
13302
13303	 	/* WSC 2.0,  support WPS V2 or not */
13304		if (strcmp(nvram_safe_get("wps_version2"), "enabled") == 0)
13305			b_wps_version2 = TRUE;
13306		if ((value = websGetVar(wp, "wps_action", NULL)) == NULL) {
13307			websError(wp, 400, "wps_action does not exist\n");
13308			return -1;
13309		}
13310		if (strcmp(value, "AddEnrollee") == 0)	{
13311
13312			/* Must in AddEnrollee in PBC method */
13313			uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", WPS_UI_METHOD_PBC);
13314
13315			/* WSC 2.0, get authorized mac, get by wps process itself */
13316			if (b_wps_version2 && strlen(wps_autho_sta_mac))
13317				uilen += sprintf(uibuf + uilen, "wps_autho_sta_mac=\"%s\" ", wps_autho_sta_mac);
13318			uilen += sprintf(uibuf + uilen, "wps_sta_pin=\"00000000\" "); /* PBC */
13319			uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", WPS_UI_ACT_ADDENROLLEE);
13320
13321			websWrite(wp, "OK");
13322			nvram_set("wps_proc_status", "0");
13323			strncpy(wps_unit, nvram_safe_get("wl_unit"), sizeof(wps_unit));
13324			wps_unit[sizeof(wps_unit)-1] = '\0';
13325
13326			uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_START);
13327
13328			sprintf(nvifname, "wl%s", wps_unit);
13329			(void)nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13330
13331			uilen += sprintf(uibuf + uilen, "wps_pbc_method=\"%d\" ", WPS_UI_PBC_SW);
13332			uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13333		}
13334		else if (strcmp(value, "Enroll") == 0){
13335			uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", WPS_UI_METHOD_PBC);
13336
13337			websWrite(wp, "OK");
13338			nvram_set("wps_proc_status", "0");
13339			strncpy(wps_unit, nvram_safe_get("wl_unit"), sizeof(wps_unit));
13340			wps_unit[sizeof(wps_unit)-1] = '\0';
13341
13342			uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", WPS_UI_ACT_ENROLL);
13343			uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_START);
13344
13345			sprintf(nvifname, "wl%s", wps_unit);
13346			(void)nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13347
13348			uilen += sprintf(uibuf + uilen, "wps_pbc_method=\"%d\" ", WPS_UI_PBC_SW);
13349			uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13350
13351
13352			uilen += sprintf(uibuf + uilen, "wps_enr_ssid=\"%s\" ", nvram_safe_get("wps_enr_ssid"));
13353			uilen += sprintf(uibuf + uilen, "wps_enr_bssid=\"%s\" ", nvram_safe_get("wps_enr_bssid"));
13354			uilen += sprintf(uibuf + uilen, "wps_enr_wsec=\"%s\" ", nvram_safe_get("wps_enr_wsec"));
13355			printf("\n*****\n%s\n", uibuf);
13356		}
13357		set_wps_env(uibuf);
13358	}
13359	/* WPS key generate */
13360	else if (!strcmp(action_mode, "Generate")) {
13361		char devPwd[12];
13362
13363		websWrite(wp, "Generating WPS PIN number...");
13364		wl_wpsPinGen(devPwd);
13365		nvram_set("wps_device_pin", devPwd);
13366		nvram_commit();
13367		websWrite(wp, "OK");
13368		/* Restart for WPS process take the new PIN */
13369		action = RESTART;
13370	}
13371	/* WPS stop */
13372	else if (!strcmp(action_mode, "STOPWPS")) {
13373		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_STOP);
13374		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", WPS_UI_ACT_NONE);
13375		set_wps_env(uibuf);
13376		websWrite(wp, "WPS process stopped");
13377	}
13378#ifdef __CONFIG_NFC__
13379	/* NFC write configuration */
13380	else if (!strcmp(action_mode, "NFC Write Configuration")) {
13381		websWrite(wp, "Please place your NFC token now!");
13382
13383		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13384		sprintf(nvifname, "wl%s", wps_unit);
13385		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13386
13387		/* Use UI credential */
13388		uilen = wps_get_credentials(wp, uibuf, uilen);
13389			if (uilen < 0)
13390				return -1;
13391
13392		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13393
13394		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_WR_CFG);
13395
13396		set_wps_env(uibuf);
13397	}
13398	/* NFC read configuration */
13399	else if (!strcmp(action_mode, "NFC Read Configuration")) {
13400		websWrite(wp, "Please place your configured NFC token now!");
13401
13402		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13403		sprintf(nvifname, "wl%s", wps_unit);
13404		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13405		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13406
13407		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_RD_CFG);
13408
13409		set_wps_env(uibuf);
13410	}
13411	else if (!strcmp(action_mode, "Stop NFC Write")){
13412		websWrite(wp, "Stopping NFC writing....");
13413
13414		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13415		sprintf(nvifname, "wl%s", wps_unit);
13416		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13417		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13418
13419		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_STOP);
13420		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", WPS_UI_ACT_NONE);
13421
13422		set_wps_env(uibuf);
13423	}
13424	else if (!strcmp(action_mode, "Stop NFC Read")){
13425		websWrite(wp, "Stopping NFC reading....");
13426
13427		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13428		sprintf(nvifname, "wl%s", wps_unit);
13429		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13430		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13431
13432		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_STOP);
13433		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", WPS_UI_ACT_NONE);
13434
13435		set_wps_env(uibuf);
13436	}
13437	else if (!strcmp(action_mode, "NFC Add Enrollee")) {
13438		websWrite(wp, "Please place your NFC password token now!");
13439
13440		/* Station PIN comes from NFC Password */
13441		uilen += sprintf(uibuf + uilen, "wps_sta_pin=\"NFC_PW\" ");
13442
13443		wps_action = WPS_UI_ACT_ADDENROLLEE;
13444		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", wps_action);
13445
13446		wps_method = WPS_UI_METHOD_NFC_PW;
13447		uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", wps_method);
13448
13449		uilen = wps_get_credentials(wp, uibuf, uilen);
13450		if (uilen == -1)
13451			return -1;
13452
13453		nvram_set("wps_proc_status", "0");
13454
13455		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13456		sprintf(nvifname, "wl%s", wps_unit);
13457		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13458		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13459
13460		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_RD_PW);
13461
13462		set_wps_env(uibuf);
13463	}
13464	else if (!strcmp(action_mode, "NFC Config AP")) {
13465		websWrite(wp, "Please place your NFC token now!");
13466
13467		/* API PIN comes from NFC Password, leverage wps_stareg_ap_pin */
13468		uilen += sprintf(uibuf + uilen, "wps_stareg_ap_pin=\"NFC_PW\" ");
13469
13470		wps_action = WPS_UI_ACT_CONFIGAP;
13471		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", wps_action);
13472
13473		wps_method = WPS_UI_METHOD_NFC_PW;
13474		uilen += sprintf(uibuf + uilen, "wps_method=\"%d\" ", wps_method);
13475
13476		uilen = wps_get_credentials(wp, uibuf, uilen);
13477		if (uilen == -1)
13478			return -1;
13479
13480		nvram_set("wps_proc_status", "0");
13481
13482		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13483		sprintf(nvifname, "wl%s", wps_unit);
13484		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13485		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13486
13487		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_WR_PW);
13488
13489		set_wps_env(uibuf);
13490	}
13491	/* NFC hand over selector */
13492	else if (!strcmp(action_mode, "NFC Hand Over As Selecotr")) {
13493		websWrite(wp, "Please place your NFC portable device now!");
13494
13495		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13496		sprintf(nvifname, "wl%s", wps_unit);
13497		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13498
13499		/* Use UI credential */
13500		uilen = wps_get_credentials(wp, uibuf, uilen);
13501			if (uilen < 0)
13502				return -1;
13503
13504		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13505
13506		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_HO_S);
13507
13508		set_wps_env(uibuf);
13509	}
13510	/* NFC hand over requester */
13511	else if (!strcmp(action_mode, "NFC Hand Over As Requester")) {
13512		websWrite(wp, "Please place your NFC device to AP now!");
13513
13514		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13515		sprintf(nvifname, "wl%s", wps_unit);
13516		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13517		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13518
13519		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_HO_R);
13520
13521		set_wps_env(uibuf);
13522	}
13523	else if (!strcmp(action_mode, "Stop NFC Hand Over")){
13524		websWrite(wp, "Stopping NFC Hand Over....");
13525
13526		strcpy(wps_unit, nvram_safe_get("wl_unit"));
13527		sprintf(nvifname, "wl%s", wps_unit);
13528		nvifname_to_osifname(nvifname, osifname, sizeof(osifname));
13529		uilen += sprintf(uibuf + uilen, "wps_ifname=\"%s\" ", osifname);
13530
13531		uilen += sprintf(uibuf + uilen, "wps_config_command=\"%d\" ", WPS_UI_CMD_NFC_STOP);
13532		uilen += sprintf(uibuf + uilen, "wps_action=\"%d\" ", WPS_UI_ACT_NONE);
13533
13534		set_wps_env(uibuf);
13535	}
13536#endif /* __CONFIG_NFC__ */
13537/*
13538*/
13539#ifdef __CONFIG_WFI__
13540	else if (!strcmp(action_mode, "Invite"))
13541	{
13542		char *invite_name=NULL, *invite_mac=NULL, *invite_unit=NULL;
13543
13544		action = NOTHING;
13545		websWrite(wp, "Validating values...");
13546
13547		invite_name = websGetVar(wp, "invite_name", "");
13548		invite_mac = websGetVar(wp, "invite_mac", "");
13549		invite_unit = nvram_safe_get("wl_unit");
13550		printf (" Inviting %s(%s) to %s ...\n", invite_mac, invite_name, invite_unit);
13551
13552		websWrite(wp, "done<br>");
13553
13554		websWrite(wp, "Committing values...");
13555		websWrite(wp, "done<br>");
13556
13557		websWrite(wp, "Inviting the STA...<p>");
13558
13559		/* Issue WFI Invite command */
13560		{
13561			int i;
13562			char acComamnd[64];
13563
13564			for (i = 0; i < 3; i++)  {
13565				if (nvram_match(WPSM_WFI_CMD_NVNAME, ""))
13566					break;
13567				SLEEP (1);
13568			}
13569			sprintf(acComamnd, "invite %s %s%s", invite_unit, invite_mac, invite_name);
13570			nvram_set(WPSM_WFI_CMD_NVNAME, acComamnd);
13571		}
13572
13573		nvram_set("wfi_count", "120");
13574
13575		if (nvram_match("wfi_pinmode", "1")){ /* wfi_pinmode manual */
13576			nvram_unset("wps_sta_pin");
13577			nvram_set("wfi_manual_pin", "0");
13578		}
13579
13580		/*
13581		 * redirect the page to "cancelinvite.aps",
13582		 * to allow user cancel WFI or Enter PIN manually
13583		 */
13584		websWrite(wp, "<script type=\"text/javascript\">\n");
13585		websWrite(wp, "<!--\n");
13586		websWrite(wp, "window.location = \"%s\"\n", "cancelinvite.asp");
13587		websWrite(wp, "//-->\n");
13588		websWrite(wp, "</script>\n");
13589
13590		websFooter(wp);
13591		websDone(wp, 200);
13592		return 1;
13593	}
13594	else if (!strcmp(action_mode, "Cancel"))
13595	{
13596		printf ("Cancel invitation!\n");
13597		/* Issue WFI command */
13598		{
13599			int i;
13600
13601			for (i = 0; i < 3; i++) {
13602				if (nvram_match(WPSM_WFI_CMD_NVNAME, ""))
13603					break;
13604				SLEEP (1);
13605			}
13606			nvram_set(WPSM_WFI_CMD_NVNAME, "cancel");
13607			for (i = 0; i < 3; i++) {
13608				SLEEP(1);
13609				if (nvram_match(WPSM_WFI_CMD_NVNAME, ""))
13610					break;
13611			}
13612		}
13613
13614		action = NOTHING;
13615
13616		websWrite(wp, "<p>Action is canceled <p>\n");
13617		websWrite(wp, "<script type=\"text/javascript\">\n");
13618		websWrite(wp, "<!--\n");
13619		websWrite(wp, "window.location = \"%s\"\n", "invite.asp");
13620		websWrite(wp, "//-->\n");
13621		websWrite(wp, "</script>\n");
13622
13623		websFooter(wp);
13624		websDone(wp, 200);
13625		return 1;
13626	}
13627	else if (!strcmp(action_mode, "Check"))
13628	{
13629		char *wfi_count=NULL, *wfi_error=NULL;
13630		int count, error_code=0, flag= -1;
13631
13632		wfi_count = websGetVar(wp, "count", "");
13633		if (wfi_count) {
13634			count = atoi(wfi_count);
13635			if (count >= 0)
13636			{
13637				/* Check wps_config_command value to see if the action is finished */
13638				if (nvram_match("wfi_status", "0")){ /* Invite Done */
13639					wfi_error = nvram_get("wfi_error");
13640					if (wfi_error && *wfi_error){
13641						error_code = atoi(wfi_error);
13642						printf(" get error_code = %d\n", error_code);
13643						switch (error_code){
13644						case 0 :
13645							flag = 0; /* No error */
13646							break;
13647						case 1 :
13648							flag = 1; /* Time out */
13649							break;
13650						case 2 :
13651							flag = 2; /* STA rejected the invite */
13652							break;
13653						case 3 :
13654							flag = 3; /* Cancelled */
13655							break;
13656						default:
13657							flag = 4; /* WPS Error */
13658							break;
13659						}
13660					}
13661				}
13662				else{   /* 1 : Inviting, 2: WPS in progress */
13663					nvram_set("wfi_count", wfi_count);
13664				}
13665			}
13666			else
13667				flag=1;
13668		}
13669		else
13670			flag=1;
13671
13672		if (flag >= 0) {
13673			/* Invite Done, redirect the page to "invite.asp */
13674			if (flag == 0) {
13675				/* Successful */
13676				printf("Invite successful.\n");
13677				websWrite(wp, " Invite successful.\n");
13678			}
13679			else if (flag == 1){
13680				/* Time out */
13681				printf("Time out...\n");
13682				websWrite(wp, " The station did not respond.\n");
13683			}
13684			else if (flag == 2){
13685				/* STA rejected the invite */
13686				websWrite(wp, " The station rejected the invitation.\n");
13687			}
13688			else if (flag == 3){
13689				websWrite(wp, " Cancelled.\n");
13690			}
13691			else
13692				websWrite(wp, " WPS Failed.\n");
13693			websWrite(wp, (char_t *) apply_footer, "invite.asp");
13694			websFooter(wp);
13695			websDone(wp, 200);
13696
13697			return 1;
13698		}
13699		else {
13700			/* Still in progress, redirect the page to "cancelinvite.aps", to allow user cancel WFI */
13701			/* redirect the page to "cancelinvite.aps" or "invite.asp, to allow user cancel WFI */
13702			websWrite(wp, "<script type=\"text/javascript\">\n");
13703			websWrite(wp, "<!--\n");
13704			websWrite(wp, "window.location = \"%s\"\n", "cancelinvite.asp");
13705			websWrite(wp, "//-->\n");
13706			websWrite(wp, "</script>\n");
13707
13708			websFooter(wp);
13709			websDone(wp, 200);
13710			return 1;
13711		}
13712	}
13713	else if (!strcmp(action_mode, "Enter")) {
13714		char *wps_sta_pin=NULL;
13715
13716		wps_sta_pin = websGetVar(wp, "wps_sta_pin", "");
13717
13718		nvram_set("wps_sta_pin", wps_sta_pin);
13719		nvram_set("wfi_manual_pin", "1");
13720
13721		//todo : Set PIN for WFI
13722		//
13723
13724		action = NOTHING;
13725	}
13726#endif /* __CONFIG_WFI__ */
13727/*
13728*/
13729	return 1;
13730
13731}
13732#endif /* __CONFIG_WPS__ */
13733
13734static int
13735apply_cgi(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
13736	  char_t *url, char_t *path, char_t *query)
13737{
13738	char *value=NULL;
13739	char *page=NULL;
13740
13741	action = NOTHING;
13742
13743	websHeader(wp);
13744	websWrite(wp, (char_t *) apply_header);
13745
13746	page = websGetVar(wp, "page", "");
13747
13748	value = websGetVar(wp, "action", "");
13749
13750	/* Apply values */
13751	if (!strcmp(value, "Apply")) {
13752		action = RESTART;
13753		websWrite(wp, "Validating values...");
13754
13755		if (strcmp("lan.asp",page))
13756			validate_cgi(wp);
13757		else
13758			validate_lan_cgi(wp);
13759		if(ret_code)
13760		{
13761			websWrite(wp, "<br>");
13762			action = NOTHING;
13763		}else{
13764			websWrite(wp, "done<br>");
13765			websWrite(wp, "Committing values...");
13766			nvram_set("is_modified", "1");
13767			nvram_set("is_default", "0");
13768			nvram_commit();
13769			websWrite(wp, "done<br>");
13770		}
13771	}
13772
13773	/* Restore defaults */
13774	else if (!strncmp(value, "Restore", 7)) {
13775		websWrite(wp, "Restoring defaults...");
13776		nvram_set("restore_defaults", "1");
13777		/* Unset FA overridden */
13778		if (FA_ON(atoi(nvram_safe_get("ctf_fa_mode"))))
13779			nvram_unset("ctf_fa_mode");
13780
13781		nvram_commit();
13782		websWrite(wp, "done<br>");
13783		action = REBOOT;
13784	}
13785
13786	/* Release lease */
13787	else if (!strcmp(value, "Release")) {
13788		websWrite(wp, "Releasing lease...");
13789		if (sys_release())
13790			websWrite(wp, "error<br>");
13791		else
13792			websWrite(wp, "done<br>");
13793		action = NOTHING;
13794	}
13795
13796	/* Renew lease */
13797	else if (!strcmp(value, "Renew")) {
13798		websWrite(wp, "Renewing lease...");
13799		if (sys_renew())
13800			websWrite(wp, "error<br>");
13801		else
13802			websWrite(wp, "done<br>");
13803		action = NOTHING;
13804	}
13805
13806	/* Reboot router */
13807	else if (!strcmp(value, "Reboot")) {
13808		websWrite(wp, "Rebooting...");
13809		action = REBOOT;
13810	}
13811
13812	/* Upgrade image */
13813	else if (!strcmp(value, "Upgrade")) {
13814		char *os_name = nvram_safe_get("os_name");
13815		char *os_server = websGetVar(wp, "os_server", nvram_safe_get("os_server"));
13816		char *os_version = websGetVar(wp, "os_version", "current");
13817		char upgrade_url[PATH_MAX];
13818		if (!*os_version)
13819			os_version = "current";
13820		snprintf(upgrade_url, sizeof(upgrade_url), "%s/%s/%s/%s.trx",
13821			 os_server, os_name, os_version, os_name);
13822		websWrite(wp, "Retrieving %s...", upgrade_url);
13823		if (sys_upgrade(upgrade_url, NULL, NULL)) {
13824			websWrite(wp, "error<br>");
13825			goto footer;
13826		} else {
13827			websWrite(wp, "done<br>");
13828			action = REBOOT;
13829		}
13830	}
13831
13832	/* Report stats */
13833	else if (!strcmp(value, "Stats")) {
13834		char *server = websGetVar(wp, "stats_server", nvram_safe_get("stats_server"));
13835		websWrite(wp, "Contacting %s...", server);
13836		if (sys_stats(server)) {
13837			websWrite(wp, "error<br>");
13838			goto footer;
13839		} else {
13840			websWrite(wp, "done<br>");
13841			nvram_set("stats_server", server);
13842		}
13843	}
13844	/* Radio On Off  */
13845	else if (!strcmp(value, "RadioOff")) {
13846		websWrite(wp, "Turing Off Radio...");
13847		wl_radio_onoff(wp, 1);
13848		action = NOTHING;
13849	}
13850	else if (!strcmp(value, "RadioOn")) {
13851		websWrite(wp, "Radio on...");
13852		wl_radio_onoff(wp, 0);
13853		action = NOTHING;
13854	}
13855#ifdef __CONFIG_NAT__
13856	/* Delete connection */
13857	else if (!strcmp(value, "Delete")) {
13858		int unit;
13859		if (!(value = websGetVar(wp, "wan_unit", NULL)) ||
13860		    (unit = atoi(value)) < 0 || unit >= MAX_NVPARSE) {
13861			websWrite(wp, "Unable to delete connection, index error.");
13862			action = NOTHING;
13863		}
13864		else {
13865			struct nvram_tuple *t;
13866			char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
13867			int unit2, units = 0;
13868			/*
13869			* We can't delete the last connection since we can't differentiate
13870			* the cases where user does not want any connection (user deletes
13871			* the last one) vs. the router is booted the first time when there
13872			* is no connection at all (where a default one is created anyway).
13873			*/
13874			for (unit2 = 0; unit2 < MAX_NVPARSE; unit2 ++) {
13875				WAN_PREFIX(unit2, prefix);
13876				if (nvram_get(strcat_r(prefix, "unit", tmp)) && units++ > 0)
13877					break;
13878			}
13879			if (units < 2) {
13880				websWrite(wp, "Can not delete the last connection.");
13881				action = NOTHING;
13882			}
13883			else {
13884				/* set prefix */
13885				WAN_PREFIX(unit, prefix);
13886				/* remove selected wan%d_ set */
13887				websWrite(wp, "Deleting connection...");
13888				for (t = router_defaults; t->name; t ++) {
13889					if (!strncmp(t->name, "wan_", 4))
13890						nvram_unset(strcat_r(prefix, &t->name[4], tmp));
13891				}
13892				/* fix unit number */
13893				unit2 = unit;
13894				for (; unit < MAX_NVPARSE; unit ++) {
13895					WAN_PREFIX(unit, prefix);
13896					if (nvram_get(strcat_r(prefix, "unit", tmp)))
13897						break;
13898				}
13899				if (unit >= MAX_NVPARSE) {
13900					unit = unit2 - 1;
13901					for (; unit >= 0; unit --) {
13902						WAN_PREFIX(unit, prefix);
13903						if (nvram_get(strcat_r(prefix, "unit", tmp)))
13904							break;
13905					}
13906				}
13907				snprintf(tmp, sizeof(tmp), "%d", unit);
13908				nvram_set("wan_unit", tmp);
13909				/* check if there is any primary connection - see comment in wan_unit() */
13910				for (unit = 0; unit < MAX_NVPARSE; unit ++) {
13911					WAN_PREFIX(unit, prefix);
13912					if (!nvram_get(strcat_r(prefix, "unit", tmp)))
13913						continue;
13914					if (nvram_invmatch(strcat_r(prefix, "proto", tmp), "disabled") &&
13915					    nvram_match(strcat_r(prefix, "primary", tmp), "1"))
13916						break;
13917				}
13918				/* no one is primary, pick the first enabled one as primary */
13919				if (unit >= MAX_NVPARSE)
13920					wan_primary(wp);
13921				/* save the change */
13922				nvram_set("is_modified", "1");
13923				nvram_set("is_default", "0");
13924				nvram_commit();
13925				websWrite(wp, "done<br>");
13926				action = RESTART;
13927			}
13928		}
13929	}
13930#endif	/* __CONFIG_NAT__ */
13931#ifdef __CONFIG_WAPI_IAS__
13932	else if (!strcmp(value, "Revoke")) {
13933		value = websGetVar(wp, "sn", NULL);
13934		if (value == NULL) {
13935			websWrite(wp, "Invalid Revoke action<br>");
13936		}
13937		else {
13938			cert_revoke(wp, value);
13939		}
13940		action = NOTHING;
13941	}
13942#endif /* __CONFIG_WAPI_IAS__ */
13943#ifdef __CONFIG_WPS__
13944	else if (!strcmp("wps.asp", page)) {
13945		wps_cgi(wp, urlPrefix, webDir, arg, url, path, query);
13946	}
13947#endif /* __CONFIG_WPS__ */
13948
13949	/* Invalid action */
13950	else
13951		websWrite(wp, "Invalid action %s<br>", value);
13952
13953 footer:
13954	websWrite(wp, (char_t *) apply_footer, websGetVar(wp, "page", ""));
13955	websFooter(wp);
13956	websDone(wp, 200);
13957	if (action == RESTART)
13958		sys_restart();
13959	else if (action == REBOOT)
13960		sys_reboot();
13961
13962	return 1;
13963}
13964
13965/* Copy all wl%d_XXXXX to wl_XXXXX */
13966int
13967copy_wl_index_to_unindex(webs_t wp, char_t *urlPrefix, char_t *webDir,
13968	int arg, char_t *url, char_t *path, char_t *query)
13969{
13970	struct variable *v=NULL;
13971	char *value=NULL;
13972	char name[IFNAMSIZ], os_name[IFNAMSIZ], *next=NULL;
13973	int unit = 0;
13974	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
13975	char unit_str[]={'\0','\0','\0','\0','\0'};
13976	int applying = 0;
13977	char *wl_bssid = NULL;
13978	char  vif[64] ;
13979
13980	/* Can enter this function through GET or POST */
13981	if ((value = websGetVar(wp, "action", NULL))) {
13982		if (strcmp(value, "Select"))
13983		{
13984			/* we need to make sure wl_unit on the web page matches the
13985				 wl_unit in NVRAM.  If they match, bail out now, otherwise
13986				 proceed with the rest of the function */
13987
13988			if ((value = websGetVar(wp, "wl_unit", NULL))) {
13989				if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid))){
13990					snprintf(vif,sizeof(vif),"%s.%s",value,wl_bssid);
13991					value = vif;
13992				}
13993				if (!strcmp( nvram_safe_get("wl_unit" ), value))
13994					return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
13995			}
13996			applying = 1;
13997		}
13998	}
13999
14000	/* copy wl%d_XXXXXXXX to wl_XXXXXXXX */
14001	if ((value = websGetVar(wp, "wl_unit", NULL))) {
14002		if ((wl_bssid = websGetVar(wp, "wl_bssid", NULL)) && (atoi(wl_bssid))){
14003			snprintf(vif,sizeof(vif),"%s.%s",value,wl_bssid);
14004			value = vif;
14005		}
14006		strncpy(unit_str,value,sizeof(unit_str) - 1);
14007	}
14008#ifdef __CONFIG_WPS__
14009	else if (!strcmp(path, "wps.asp")) {
14010		get_wps_env();
14011		return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query);
14012	}
14013#endif /* __CONFIG_WPS__ */
14014	else {
14015		char ifnames[256];
14016		snprintf(ifnames, sizeof(ifnames), "%s %s %s %s",
14017			nvram_safe_get("lan_ifnames"),
14018			nvram_safe_get("lan1_ifnames"),
14019			nvram_safe_get("wan_ifnames"),
14020			nvram_safe_get("unbridged_ifnames"));
14021
14022		if (!remove_dups(ifnames,sizeof(ifnames))){
14023			websError(wp, 400, "Unable to remove duplicate interfaces from ifname list<br>");
14024			return -1;
14025		}
14026
14027		/* Probe for first wl interface */
14028		foreach(name, ifnames, next) {
14029			if (nvifname_to_osifname( name, os_name, sizeof(os_name) ) < 0)
14030				continue;
14031			if (wl_probe(os_name) == 0 &&
14032			    wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)) == 0){
14033			    	snprintf(unit_str,sizeof(unit_str),"%d",unit);
14034				break;
14035			}
14036		}
14037
14038	}
14039	if (*unit_str) {
14040		snprintf(prefix, sizeof(prefix), "wl%s_", unit_str);
14041		for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) {
14042			char *val = NULL;
14043
14044			if ((v->ezc_flags & WEB_IGNORE) || ((prefix[3] == '.') && (v->ezc_flags & VIF_IGNORE))) {
14045				continue;
14046			}
14047			if (!strncmp(v->name, "wl_", 3)) {
14048				(void)strcat_r(prefix, &v->name[3], tmp);
14049				/*
14050				 * tmp holds fully qualified name (wl0.1_....)
14051				 * First try nvram; if NULL, try default; ? : is gcc-specific
14052				 */
14053				val = nvram_get(tmp) ? : nvram_default_get(tmp);
14054				if (val == NULL) {
14055					val = "";
14056				}
14057				nvram_set(v->name, val);
14058			}
14059			if (!strncmp(v->name, "wl_unit", 7)) {
14060				break;
14061			}
14062		}
14063	}
14064
14065	/* Set currently selected unit */
14066	nvram_set("wl_unit", unit_str);
14067
14068	if( applying )
14069		return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
14070
14071	/* Display the page */
14072	return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query);
14073}
14074
14075#ifdef __CONFIG_NAT__
14076static int
14077wan_asp(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
14078	     char_t *url, char_t *path, char_t *query)
14079{
14080	struct variable *v=NULL;
14081	char *value=NULL;
14082	int unit = 0;
14083	char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_";
14084	char ustr[16];
14085	struct nvram_tuple *t=NULL;
14086
14087	/* Can enter this function through GET or POST */
14088	if ((value = websGetVar(wp, "action", NULL))) {
14089		if (!strcmp(value, "New")) {
14090			/* pick one that 'does not' exist */
14091			for (unit = 0; unit < MAX_NVPARSE; unit ++) {
14092				WAN_PREFIX(unit, prefix);
14093				if (!nvram_get(strcat_r(prefix, "unit", tmp)))
14094					break;
14095			}
14096			if (unit >= MAX_NVPARSE) {
14097				websHeader(wp);
14098				websWrite(wp, (char_t *) apply_header);
14099				websWrite(wp, "Unable to create new connection. Maximum %d.", MAX_NVPARSE);
14100				websWrite(wp, (char_t *) apply_footer, websGetVar(wp, "page", ""));
14101				websFooter(wp);
14102				websDone(wp, 200);
14103				return 1;
14104			}
14105			/* copy default to newly created wan%d_ set */
14106			for (t = router_defaults; t->name; t ++) {
14107				if (!strncmp(t->name, "wan_", 4))
14108					nvram_set(strcat_r(prefix, &t->name[4], tmp), t->value);
14109			}
14110			/* the following variables must be overwritten */
14111			snprintf(ustr, sizeof(ustr), "%d", unit);
14112			nvram_set(strcat_r(prefix, "unit", tmp), ustr);
14113			nvram_set(strcat_r(prefix, "proto", tmp), "disabled");
14114			nvram_set(strcat_r(prefix, "ifname", tmp), nvram_safe_get("wan_ifname"));
14115			nvram_set(strcat_r(prefix, "hwaddr", tmp), nvram_safe_get("wan_hwaddr"));
14116			nvram_set(strcat_r(prefix, "ifnames", tmp), nvram_safe_get("wan_ifnames"));
14117			/* commit change */
14118			nvram_set("is_modified", "1");
14119			nvram_set("is_default", "0");
14120			nvram_commit();
14121		}
14122		else if (!strcmp(value, "Select")) {
14123			if ((value = websGetVar(wp, "wan_unit", NULL)))
14124				unit = atoi(value);
14125			else
14126				unit = -1;
14127		}
14128		else
14129			return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
14130	}
14131	else if ((value = websGetVar(wp, "wan_unit", NULL)))
14132		unit = atoi(value);
14133	else
14134		unit = atoi(nvram_safe_get("wan_unit"));
14135	if (unit < 0 || unit >= MAX_NVPARSE)
14136		unit = 0;
14137
14138	/* Set prefix */
14139	WAN_PREFIX(unit, prefix);
14140
14141	/* copy wan%d_ set to wan_ set */
14142	for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) {
14143		if (v->ezc_flags & WEB_IGNORE)
14144			continue;
14145		if (strncmp(v->name, "wan_", 4))
14146			continue;
14147		value = nvram_get(strcat_r(prefix, &v->name[4], tmp));
14148		if (value)
14149			nvram_set(v->name, value);
14150		if (!strncmp(v->name, "wan_unit", 8))
14151			break;
14152	}
14153
14154	/* Set currently selected unit */
14155	snprintf(tmp, sizeof(tmp), "%d", unit);
14156	nvram_set("wan_unit", tmp);
14157
14158	/* Display the page */
14159	return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query);
14160}
14161#endif	/* __CONFIG_NAT__ */
14162
14163#ifdef WEBS
14164
14165void
14166initHandlers(void)
14167{
14168	websAspDefine("nvram_get", ej_nvram_get);
14169	websAspDefine("nvram_match", ej_nvram_match);
14170	websAspDefine("nvram_match_bitflag", ej_nvram_match_bitflag);
14171	websAspDefine("nvram_get_bitflag", ej_nvram_get_bitflag);
14172	websAspDefine("nvram_invmatch", ej_nvram_invmatch);
14173	websAspDefine("nvram_list", ej_nvram_list);
14174	websAspDefine("nvram_indexmatch", ej_nvram_indexmatch);
14175	websAspDefine("filter_client", ej_filter_client);
14176	websAspDefine("filter_url", ej_filter_url);
14177	websAspDefine("forward_port", ej_forward_port);
14178#ifdef __CONFIG_HSPOT__
14179	websAspDefine("print_wl_wanmetrics",ej_print_wl_wanmetrics);
14180	websAspDefine("print_wl_oplist", ej_print_wl_oplist);
14181	websAspDefine("print_wl_homeqlist", ej_print_wl_homeqlist);
14182	websAspDefine("print_wl_osuplist", ej_print_wl_osuplist);
14183	websAspDefine("print_wl_concaplist", ej_print_wl_concaplist);
14184	websAspDefine("print_iconlist", ej_print_iconlist);
14185	websAspDefine("print_wl_qosmapie", ej_print_wl_qosmapie);
14186	/* ---- 802.11u -----------------------------------  */
14187	websAspDefine("print_wl_netauthlist", ej_print_wl_netauthlist);
14188	websAspDefine("print_wl_realmlist", ej_print_wl_realmlist);
14189	websAspDefine("print_wl_venuelist", ej_print_wl_venuelist);
14190	websAspDefine("print_wl_ouilist", ej_print_wl_ouilist);
14191	websAspDefine("print_wl_3gpplist", ej_print_wl_3gpplist);
14192#endif /* __CONFIG_HSPOT__ */
14193	websAspDefine("static_route", ej_static_route);
14194	websAspDefine("localtime", ej_localtime);
14195	websAspDefine("dumplog", ej_dumplog);
14196	websAspDefine("syslog", ej_syslog);
14197	websAspDefine("dumpleases", ej_dumpleases);
14198	websAspDefine("link", ej_link);
14199
14200	websUrlHandlerDefine("/apply.cgi", NULL, 0, apply_cgi, 0);
14201	websUrlHandlerDefine("/wireless.asp", NULL, 0, copy_wl_index_to_unindex, 0);
14202
14203	websSetPassword(nvram_safe_get("http_passwd"));
14204
14205	websSetRealm("Broadcom Home Gateway Reference Design");
14206
14207	/* Initialize hash table */
14208	hash_vtab(&vtab,v,variables_arraysize());
14209}
14210
14211#else /* !WEBS */
14212
14213int internal_init(void)
14214{
14215	/* Initialize hash table */
14216	if (hash_vtab(&vtab,variables,variables_arraysize()))
14217		return -1;
14218	return 0;
14219}
14220static void
14221do_auth(char *userid, char *passwd, char *realm)
14222{
14223	assert(userid);
14224	assert(passwd);
14225	assert(realm);
14226
14227	strncpy(userid, nvram_safe_get("http_username"), AUTH_MAX);
14228	strncpy(passwd, nvram_safe_get("http_passwd"), AUTH_MAX);
14229	strncpy(realm, "Broadcom Home Gateway Reference Design", AUTH_MAX);
14230}
14231
14232char post_buf[POST_BUF_SIZE];
14233char ezc_version[128];
14234char no_cache[] =
14235"Cache-Control: no-cache\r\n"
14236"Pragma: no-cache\r\n"
14237"Expires: 0"
14238;
14239
14240char download_hdr[] =
14241"Cache-Control: no-cache\r\n"
14242"Pragma: no-cache\r\n"
14243"Expires: 0\r\n"
14244"Content-Type: application/download\r\n"
14245"Content-Disposition: attachment ; filename=nvram.txt"
14246;
14247
14248#ifdef __CONFIG_WAPI_IAS__
14249char as_cert_download_hdr[] =
14250"Cache-Control: no-cache\r\n"
14251"Pragma: no-cache\r\n"
14252"Expires: 0\r\n"
14253"Content-Type: application/download\r\n"
14254"Content-Disposition: attachment ; filename=as.cer"
14255;
14256
14257char user_cert_download_hdr[] =
14258"Cache-Control: no-cache\r\n"
14259"Pragma: no-cache\r\n"
14260"Expires: 0\r\n"
14261"Content-Type: application/download\r\n"
14262"Content-Disposition: attachment ; filename=user.cer"
14263;
14264
14265#endif /* __CONFIG_WAPI_IAS__ */
14266
14267static void
14268do_apply_post(char *url, FILE *stream, int len, char *boundary)
14269{
14270	assert(url);
14271	assert(stream);
14272
14273	/* Get query */
14274	if (!fgets(post_buf, MIN(len + 1, sizeof(post_buf)), stream))
14275		return;
14276	len -= strlen(post_buf);
14277
14278	/* Initialize CGI */
14279	init_cgi(post_buf);
14280
14281	/* Slurp anything remaining in the request */
14282	while (len--)
14283		(void) fgetc(stream);
14284}
14285
14286static void
14287do_apply_cgi(char *url, FILE *stream)
14288{
14289	char *path=NULL, *query=NULL;
14290
14291	assert(url);
14292	assert(stream);
14293
14294	/* Parse path */
14295	query = url;
14296	path = strsep(&query, "?") ? : url;
14297
14298	apply_cgi(stream, NULL, NULL, 0, url, path, query);
14299
14300	/* Reset CGI */
14301	init_cgi(NULL);
14302}
14303
14304
14305static void
14306do_upgrade_post(char *url, FILE *stream, int len, char *boundary)
14307{
14308	char buf[1024];
14309
14310	assert(url);
14311	assert(stream);
14312
14313	ret_code = EINVAL;
14314
14315	/* Look for our part */
14316	while (len > 0) {
14317		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
14318			return;
14319		len -= strlen(buf);
14320		if (!strncasecmp(buf, "Content-Disposition:", 20) &&
14321		    strstr(buf, "name=\"file\""))
14322			break;
14323	}
14324
14325	/* Skip boundary and headers */
14326	while (len > 0) {
14327		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
14328			return;
14329		len -= strlen(buf);
14330		if (!strcmp(buf, "\n") || !strcmp(buf, "\r\n"))
14331			break;
14332	}
14333
14334	ret_code = sys_upgrade(NULL, stream, &len);
14335
14336	/* Slurp anything remaining in the request */
14337	while (len--)
14338		(void) fgetc(stream);
14339}
14340
14341static void
14342do_upgrade_cgi(char *url, FILE *stream)
14343{
14344	assert(url);
14345	assert(stream);
14346
14347	websHeader(stream);
14348	websWrite(stream, (char_t *) apply_header);
14349
14350	/* We could probably be more informative here... */
14351	if (ret_code)
14352		websWrite(stream, "Error during upgrade<br>");
14353	else
14354		websWrite(stream, "Upgrade complete. Rebooting...<br>");
14355
14356	websWrite(stream, (char_t *) apply_footer, "firmware.asp");
14357	websFooter(stream);
14358	websDone(stream, 200);
14359
14360	/* Reboot if successful */
14361	if (ret_code == 0)
14362		sys_reboot();
14363}
14364
14365#ifdef PLC
14366static char hex2nible(char c)
14367{
14368  switch (c)
14369  {
14370    case '0': case '1': case '2': case '3': case '4':
14371    case '5': case '6': case '7': case '8': case '9':
14372      return c - '0';
14373    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
14374      return 10 + c - 'a';
14375    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
14376      return 10 + c - 'A';
14377    default:
14378      return 0;
14379  }
14380}
14381
14382/**************************************************
14383 * Function name : static void BcmPostParse(char *url, FILE *stream, int len,
14384 *                     char *boundary)
14385 * Created by    : Toni Homedes i Saun
14386 * Date created  : 06-10-2010
14387 * Notes         : Public function
14388 *                 Restrictions (pre-conditions)
14389 *                 Odd modes (post-conditions)
14390 **************************************************/
14391/** \brief Parses post arguments in application/x-www-form-urlencoded form
14392 *
14393 *  The arguments are added to the file global BcmPostArgs variable.
14394 *
14395 *  The CGI function is responsible for frring this dictionnary
14396 *
14397 *  \param[in] url      unused
14398 *  \param[in] stream   socket to read from
14399 *  \param[in] len      len of args
14400 *  \param[in] boundary unused
14401 *
14402 **************************************************/
14403static void BcmPostParse(char *url, FILE *stream, int len, char *boundary)
14404{
14405  BcmPostArgs = DictNew();
14406  char line[512];
14407  int i = 1;
14408  int value_pos = 0;
14409
14410  bzero(line, sizeof line);
14411
14412  /* CheckBoxes say nothing when not checked */
14413  DictSet(BcmPostArgs, "plc_cfg_root", "");
14414
14415  while(len && !feof(stream))
14416  {
14417    int c;
14418
14419    c = fgetc(stream), --len;
14420
14421    if ('%' == c && len >= 2) /* percent encoded char follows */
14422    {
14423      char cc;
14424      c = fgetc(stream), --len;
14425      cc = hex2nible(c) << 4;
14426      c = fgetc(stream), --len;
14427      cc = hex2nible(c);
14428      c = cc;
14429    }
14430    else if ('&' == c || EOF == c || !len)
14431    {
14432      if ('&' != c && '=' != c && EOF != c)
14433      {
14434        if ('+' == c)
14435          c = ' ';
14436        line[i++] = c;
14437      }
14438      line[i++] = '\0';
14439
14440      DictSet(BcmPostArgs, line + 1, value_pos ? line + value_pos : "");
14441      memset(line, '\0', sizeof line);
14442      value_pos = i = 0;
14443
14444      if (!len || EOF == c)
14445        return;
14446    }
14447    else if ('=' == c)
14448    {
14449      c = '\0';
14450      value_pos = i + 1;
14451    }
14452    else if ('+' == c)
14453    {
14454      c = ' ';
14455    }
14456
14457    if (i < sizeof line - 1)
14458    {
14459      line[i++] = c;
14460    }
14461  }
14462}
14463#endif
14464
14465/* This utility routine builds the wl prefixes from wl_unit.
14466 * Input is expected to be a null terminated string
14467 *
14468 * Inputs -prefix: Pointer to prefix buffer
14469 *	  -prefix_size: Size of buffer
14470 *        -Mode flag: If set generates unit.subunit output
14471 *                    if not set generates unit only
14472 *	  -ifname: Optional interface name string
14473 *
14474 *
14475 * Returns - pointer to prefix, NULL if error.
14476 *
14477 *
14478*/
14479char *
14480make_wl_prefix(char *prefix,int prefix_size, int mode, char *ifname)
14481{
14482	int unit=-1,subunit=-1;
14483	char *wl_unit=NULL;
14484
14485	assert(prefix);
14486	assert(prefix_size);
14487
14488	if (ifname){
14489		assert(*ifname);
14490		wl_unit=ifname;
14491	}else{
14492		wl_unit=nvram_get("wl_unit");
14493
14494		if (!wl_unit)
14495			return NULL;
14496	}
14497
14498	if (get_ifname_unit(wl_unit,&unit,&subunit) < 0 )
14499		return NULL;
14500
14501	if (unit < 0) return NULL;
14502
14503	if  ((mode) && (subunit > 0 ))
14504		snprintf(prefix, prefix_size, "wl%d.%d_", unit,subunit);
14505	else
14506		snprintf(prefix, prefix_size, "wl%d_", unit);
14507
14508	return prefix;
14509}
14510
14511/* Format of the NVRAM text file is as follows
14512 * the following major sections
14513 * Header Block
14514 * Constraint Block
14515 * NVRAM variables
14516 *
14517 * Header consists of :
14518 *	LineCount
14519 *	Checksum
14520 *
14521 * Constraint block consists of :
14522 * Defined by NVRAM_CONSTRAINT_VARS
14523 *
14524 *
14525*/
14526
14527/* Get major os version. The nvram variable gives the whole thing.
14528 * this function avoids the messy parsing.
14529 * Used by NVRAM constraint validation routines.
14530 * The input argument is not used. This is used to maintain
14531 * argument list compatability with nvram_get().
14532 *
14533*/
14534static  char*
14535osversion_get(const char *name)
14536{
14537
14538	static char ret_string[32];
14539
14540	assert(name);
14541
14542 	snprintf(ret_string,sizeof(ret_string),"%d.%d",
14543  			ROUTER_MAJOR_VERSION, ROUTER_MINOR_VERSION);
14544
14545
14546	return ret_string;
14547
14548}
14549
14550/* This routine strips the CRLF from the HTTP stream */
14551/* Returns new length or -1 if there is an error*/
14552static int
14553remove_crlf(char *buf, int len)
14554{
14555
14556	int slen;
14557	if (!buf) return -1;
14558	if (!len) return 0;
14559
14560	slen = strlen(buf);
14561	len = len-slen;
14562	if ((buf[slen-1] == '\n' ) && (buf[slen-2] == '\r' )){
14563		buf[slen-1]='\0';
14564		buf[slen-2]='\0';
14565
14566	}
14567	else if ( buf[slen-1] == '\n' ) buf[slen-1]='\0';
14568
14569	return len;
14570}
14571/* Utility routine to add a string from a string buffer.
14572 *
14573 * Routine expects that the buffer is composed of text strings with
14574 * a null as the delimiter.
14575 *
14576 * Input is expected to be a null terminated string
14577 *
14578 * Inputs -Pointer to char buffer
14579 *        -NULL input terminated string
14580 *	  -Offset to end of used area. Including the NULL terminator
14581 *	  -Size of the buffer (to avoid running of the end of the buffer)
14582 *
14583 *
14584 * Returns - Number of bytes occupied including NULL terminator. -1 if error
14585 *
14586 *
14587*/
14588static int
14589add_string(char *buf, char *string, int start, int bufsize)
14590{
14591	int len;
14592
14593	assert(buf);
14594
14595	if (!string) return -1;
14596	if (!*string) return -1;
14597	if (!bufsize) return -1;
14598	if (start >=bufsize) return -1;
14599
14600	len = strlen(string);
14601
14602	if ( (start + len + 1) >= bufsize ) return -1;
14603
14604	strncpy(buf,string,len);
14605
14606	return start + len + 1;
14607}
14608static void
14609do_nvramul_post(char *url, FILE *stream, int len, char *boundary)
14610{
14611	char buf[1024];
14612	int  index,cur_entry;
14613	char *ptr=NULL;
14614	char *name=NULL;
14615	char tmp[NVRAM_MAX_STRINGSIZE];
14616	char file_checksum[NVRAM_SHA1BUFSIZE],checksum[NVRAM_SHA1BUFSIZE];
14617	unsigned char key[NVRAM_SHA1BUFSIZE];
14618	int  checksum_linenum = NVRAM_CHECKSUM_LINENUM;
14619	char salt[NVRAM_SALTSIZE];
14620	int  numlines=0;
14621	int  entries,offset,slen;
14622	unsigned char passphrase[]=NVRAM_PASSPHRASE;
14623	char nvram_file_header[][NVRAM_MAX_STRINGSIZE/2] = NVRAM_FILEHEADER;
14624	upload_constraints constraint_vars [] = NVRAM_CONSTRAINT_VARS;
14625	struct pb {
14626			char header[NVRAM_HEADER_LINECOUNT(nvram_file_header)][NVRAM_MAX_STRINGSIZE];
14627			char buf[MAX_NVRAM_SPACE];
14628		 }*tmpbuf=NULL;
14629#if !defined(WLTEST)
14630	struct variable *v = NULL;
14631#endif /* !WLTEST */
14632
14633	assert(stream);
14634
14635	entries = NVRAM_HEADER_LINECOUNT(nvram_file_header);
14636	ret_code = EINVAL;
14637
14638	/* Look for our part */
14639	while (len > 0) {
14640		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
14641			return;
14642
14643		/* Remove LF that fgets()drags in */
14644		len=remove_crlf(buf,len);
14645		/* look for start of attached file header */
14646
14647		if (*buf){
14648		  if (strstr(buf,NVRAM_BEGIN_WEBFILE)) break;
14649		}
14650
14651	}
14652
14653	if (!len) return;
14654
14655	/* loop thru the header lines until we get the blank line
14656	   that signifies the start of file contents */
14657	while (len > 0){
14658	 	if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
14659			return;
14660		/* Remove LF that fgets()drags in */
14661		len=remove_crlf(buf,len);
14662
14663		/* look for the blank line */
14664		if (*buf == NVRAM_END_WEBFILE)  break;
14665	}
14666
14667	if (!len) return;
14668
14669	/* Found start of upload file. Proceed with the upload */
14670	/* Look for start of upload data */
14671	if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
14672			return;
14673
14674	len = len - strlen(buf);
14675
14676	/* Get the number of NVRAM variables */
14677	sprintf(tmp,"%s=%s",nvram_file_header[NVRAM_LINECOUNT_LINENUM],"%d");
14678
14679	if ( (sscanf(buf,tmp,&numlines) != 1) || !len ){
14680		strncpy(posterr_msg,"Invalid NVRAM header<br>",ERR_MSG_SIZE);
14681	 	return ;
14682	}
14683
14684	if (numlines == 0) {
14685		strncpy(posterr_msg, "Invalid NVRAM header<br>", ERR_MSG_SIZE);
14686	 	return;
14687	}
14688
14689	tmpbuf = (struct pb *) malloc( sizeof(struct pb));
14690	if (!tmpbuf){
14691		strncpy(posterr_msg,"Memory allocation error<br>",ERR_MSG_SIZE);
14692	 	return;
14693	}
14694
14695	memset(tmpbuf,0,sizeof(struct pb));
14696
14697	/* Copy over the first line of the file. Needed for
14698	   proper checksum calculations */
14699
14700	strcpy(tmpbuf->header[0],buf);
14701
14702	/* read in checksum */
14703	if (!fgets(tmpbuf->header[1], MIN(len + 1,NVRAM_MAX_STRINGSIZE), stream))
14704			goto do_nvramul_post_cleanup0;
14705
14706	len = len - strlen(tmpbuf->header[1]);
14707
14708	/* start reading in the rest of the NVRAM contents into memory buffer*/
14709	offset = 0;
14710	for (index = 2 ; (len > 0) &&  (index < numlines); index++){
14711		char filebuf[NVRAM_MAX_STRINGSIZE];
14712
14713	 	if (!fgets(filebuf, MIN(len + 1,NVRAM_MAX_STRINGSIZE), stream))
14714			goto do_nvramul_post_cleanup0;
14715
14716		offset = add_string(&tmpbuf->buf[offset],filebuf,offset,
14717						sizeof(((struct pb *)0)->buf));
14718		if (offset < 0){
14719			snprintf(posterr_msg,ERR_MSG_SIZE,
14720				"Error processing NVRAM variable:%s<br>",filebuf);
14721	 		goto do_nvramul_post_cleanup0;
14722		}
14723		len = len - strlen(filebuf);
14724
14725		/* don't remove the LFs since the we are using  multipart
14726		   MIME encoding that does not touch the contents of the
14727		   uploaded file. LFs are actually part of the NVRAM var lines.
14728		*/
14729	}
14730
14731	/*  Bail if the number of actual lines is less than that
14732	    in the header
14733	*/
14734
14735	if ( !len && (index < numlines) ){
14736		strncpy(posterr_msg,"NVRAM file incomplete<br>",ERR_MSG_SIZE);
14737	 	goto do_nvramul_post_cleanup0;
14738	}
14739
14740	/* Save and decode checksum from file */
14741	ptr = tmpbuf->header[checksum_linenum];
14742
14743	sprintf(tmp,"%s=",nvram_file_header[checksum_linenum]);
14744
14745	if ( !strstr(ptr,tmp) ) {
14746		snprintf(posterr_msg,ERR_MSG_SIZE,
14747			"No checksum present at line %d<br>",checksum_linenum+1);
14748		goto do_nvramul_post_cleanup0 ;
14749	}
14750	ptr = &ptr[strlen(tmp)];
14751
14752	if ( b64_decode(ptr,(unsigned char *)tmp,NVRAM_MAX_STRINGSIZE) != NVRAM_FILECHKSUM_SIZE){
14753		strncpy(posterr_msg,"Invalid checksum.<br>",ERR_MSG_SIZE);
14754		goto do_nvramul_post_cleanup0 ;
14755	};
14756
14757	memset(file_checksum,0,sizeof(file_checksum));
14758	memc
14759
14760	/* Extract salt value from stored checksum*/
14761	memcpy(salt,&tmp[NVRAM_HASHSIZE],NVRAM_SALTSIZE);
14762
14763	/* Regenerate encryption key */
14764	memset(key,0,sizeof(key));
14765	fPRF(passphrase,strlen((char *)passphrase),NULL,0,
14766			(unsigned char*)salt,sizeof(salt),key,NVRAM_FILEKEYSIZE);
14767
14768	/* Plug in filler for checksum into read buffer*/
14769	memset(tmpbuf->header[checksum_linenum],0,NVRAM_MAX_STRINGSIZE);
14770	snprintf(tmpbuf->header[checksum_linenum],
14771			NVRAM_MAX_STRINGSIZE,"%s\n",NVRAM_CHECKSUM_FILLER);
14772
14773	/* Calculate checksum and compare with stored value*/
14774
14775	memset(checksum,0,sizeof(checksum));
14776	hmac_sha1((unsigned char*)tmpbuf,sizeof(struct pb) ,
14777	          key,NVRAM_FILEKEYSIZE,(unsigned char *)checksum);
14778
14779	if (memcmp(checksum,file_checksum,NVRAM_HASHSIZE)){
14780		memcpy(posterr_msg,"File checksum error<br>",ERR_MSG_SIZE);
14781		goto do_nvramul_post_cleanup0;
14782	}
14783
14784	/* Check constraints on the data */
14785
14786	cur_entry = NVRAM_HEADER_LINECOUNT(nvram_file_header);
14787	slen=0;
14788	name = tmpbuf->buf;
14789	for (index = 0  ; *constraint_vars[index].name && *name; index++,cur_entry++,name += slen + 1) {
14790		char *var=NULL,*ptr=NULL;
14791		int comparesize ;
14792
14793		slen = strlen(name);
14794
14795		if (cur_entry > numlines){
14796			memcpy(posterr_msg,
14797				"Constraints mismatch between file and running image<br>",
14798										ERR_MSG_SIZE);
14799			goto do_nvramul_post_cleanup0;
14800		}
14801
14802
14803		var = constraint_vars[index].get(constraint_vars[index].name);
14804
14805		if (!var){
14806			snprintf(posterr_msg,ERR_MSG_SIZE,
14807				"NVRAM variable:%s not found in running image<br>",
14808								constraint_vars[index].name);
14809			goto do_nvramul_post_cleanup0;
14810		}
14811
14812		if (!strstr(name,constraint_vars[index].name)){
14813			snprintf(posterr_msg,ERR_MSG_SIZE,
14814				"NVRAM variable:%s not found in uploaded file<br>",
14815								constraint_vars[index].name);
14816			goto do_nvramul_post_cleanup0;
14817		}
14818
14819		/*Move past separator*/
14820		ptr = &name[strlen(constraint_vars[index].name) + 1] ;
14821
14822		/* Ignore last character which is a \n */
14823		comparesize = strlen(ptr) -1;
14824
14825		/* If the primary match fails try for the secomdary matches */
14826		if (strncmp(ptr,var,comparesize)){
14827		int sec_fail=0;
14828
14829			/* If partial march is defined match altval pattern against
14830			   file and image values*/
14831			if (constraint_vars[index].flags & NVRAM_CONS_PARTIAL_MATCH){
14832				sec_fail=( !strstr(ptr,constraint_vars[index].altval) &&
14833							!strstr(var,constraint_vars[index].altval));
14834			}
14835			else if (constraint_vars[index].flags & NVRAM_CONS_ALT_MATCH){
14836				sec_fail=(strncmp(ptr,constraint_vars[index].altval,comparesize));
14837			}
14838			else sec_fail =1;
14839
14840		if (sec_fail){
14841			snprintf(posterr_msg,ERR_MSG_SIZE,
14842				"NVRAM constraint mismatch FILE:<b>%s=%s</b>  IMAGE:<b>%s=%s</b><br>",
14843					constraint_vars[index].name,ptr,constraint_vars[index].name,var);
14844			goto do_nvramul_post_cleanup0;
14845			}
14846		}
14847
14848	}
14849
14850	/* Process the NVRAM payload
14851	 *
14852	 * Remove the carriage returns at the end of the NVRAM variables
14853	 *
14854	*/
14855
14856	cur_entry = NVRAM_HEADER_LINECOUNT(nvram_file_header) + NVRAM_HEADER_LINECOUNT(constraint_vars);
14857
14858	slen=0;
14859	for (index = cur_entry ;(index < numlines) && *name; index++,name += slen + 1){
14860		int offset;
14861		char *ptr=NULL;
14862		char *varname=NULL;
14863		char *myptr=NULL;
14864
14865		offset = index * NVRAM_MAX_STRINGSIZE;
14866
14867		/* The length of the actual var must be saved here as the subsequent
14868		 * manipulation using strsep() changes the string buffer.
14869		 * This to ensure that the buffer (tmpbuf->buf) is correctly procesed
14870		 * This buffer separates the individual AVPs using a null character
14871		 */
14872
14873		slen =strlen(name);
14874		ptr = name;
14875
14876		/* Remove the CR at the end of the string */
14877		ptr[slen-1] = '\0';
14878
14879		/* Look for tag that indicates that the value is encrypted */
14880		if  (*ptr==NVRAM_ENCTAG){
14881			char buf[NVRAM_MAX_STRINGSIZE];
14882			int bufsize = sizeof(buf);
14883			char *varname=NULL;
14884
14885			varname=strsep(&ptr, "=");
14886
14887			/* Increment pointer to move past tag */
14888			varname++;
14889
14890			if (!decrypt_var(varname,ptr,strlen(ptr),buf,&bufsize,(char *)key,NVRAM_FILEKEYSIZE)){
14891				snprintf(posterr_msg,ERR_MSG_SIZE,
14892					"Error decrypting value %s at line %d<br>",ptr,index);
14893				goto do_nvramul_post_cleanup0;
14894			}
14895
14896		snprintf(name,NVRAM_MAX_STRINGSIZE,"%s=%s",varname,buf);
14897
14898		}
14899
14900		/*
14901		   Write out NVRAM variables.
14902		*/
14903
14904		myptr = name;
14905		varname=strsep(&myptr, "=");
14906
14907#if !defined(WLTEST)
14908		v=get_var_handle(varname);
14909
14910		/* Restore only those NVRAM vars in the validation table
14911		   Ignore those with the obvious flag set
14912		*/
14913		if (!v)
14914			continue;
14915
14916		if (v->ezc_flags & NVRAM_IGNORE)
14917			continue;
14918#endif /* !WLTEST */
14919
14920		if (nvram_set(varname,myptr))
14921			goto do_nvramul_post_cleanup0;
14922
14923	}
14924
14925	nvram_commit();
14926
14927	/* We are done */
14928	ret_code = 0;
14929
14930do_nvramul_post_cleanup0:
14931	/* Clear up any outstanding stuff */
14932	/* Slurp anything remaining in the request */
14933	while (len--)
14934		(void) fgetc(stream);
14935
14936	if (tmpbuf) free(tmpbuf);
14937
14938	return;
14939}
14940
14941static void
14942do_nvramul_cgi(char *url, FILE *stream)
14943{
14944	assert(stream);
14945	assert(url);
14946
14947	websHeader(stream);
14948	websWrite(stream, (char_t *) apply_header);
14949
14950	if (ret_code){
14951		websWrite(stream, "Error during NVRAM upload<br>");
14952		if (*posterr_msg){
14953			websWrite(stream, posterr_msg);
14954			memset(posterr_msg,0,ERR_MSG_SIZE);
14955		}
14956
14957	} else websWrite(stream, "NVRAM upload complete.<br>Rebooting....<br>");
14958
14959	websWrite(stream, (char_t *) apply_footer, "firmware.asp");
14960	websFooter(stream);
14961	websDone(stream, 200);
14962
14963	/* Reboot if successful */
14964	if (ret_code == 0)
14965		sys_reboot();
14966
14967}
14968
14969/*
14970   This routine validates and formats the NVRAM variable into the file output format.
14971   If the variable is not in the monster V-block or its allowed multi instance variants
14972   it is dropped
14973
14974   Returns number of characters printed or -1 on error
14975*/
14976static int
14977save_nvram_var(char *name, char *var_val,char *buf, int buflen,char *key, int keylen)
14978{
14979	char tmp[NVRAM_MAX_STRINGSIZE];
14980	int len=sizeof(tmp);
14981	int retval=0;
14982	struct variable *v = NULL;
14983
14984	assert(name);
14985	assert(buf);
14986	assert(key);
14987	assert(buflen);
14988	assert(keylen);
14989
14990
14991	/* If var_val is null, this forces the variable to be unset when the file is uploaded
14992	  If the variable is supposed to be encrypted but is null, skip it and do not
14993	  mark the string as encrypted.
14994
14995	  If var_val is null the variable does not exist. Skip and do not save in that case.
14996	*/
14997
14998	v = get_var_handle(name);
14999
15000	if (!v) {
15001#if defined(WLTEST)
15002		retval= snprintf(buf,buflen,"%s=%s\n", (char_t *)name, (char_t *)var_val);
15003		return retval;
15004#else
15005		return 0;
15006#endif /* WLTEST */
15007	}
15008
15009	if (v->ezc_flags & NVRAM_IGNORE)
15010		return 0;
15011
15012	if (var_val) {
15013			if (strlen(var_val) > NVRAM_MAX_STRINGSIZE){
15014				cprintf("get_nvram_var():String too long Len=%d String=%s\n",	strlen(var_val) ,var_val);
15015				return -1;
15016			}
15017
15018			if ( (v->ezc_flags & NVRAM_ENCRYPT) && (*var_val) ){
15019				var_val = encrypt_var(name,var_val,strlen(var_val),tmp,&len,key,keylen);
15020
15021				if (!var_val){
15022					cprintf("get_nvram_var():Error encrypting %s\n",name);
15023					return -1;
15024				}
15025
15026				retval=snprintf(buf,buflen,"%c%s=%s\n",
15027						NVRAM_ENCTAG,
15028						(char_t *)name,
15029						(char_t *)var_val);
15030		    } else retval=snprintf(buf,buflen,"%s=%s\n",
15031						(char_t *)name,
15032						(char_t *)var_val);
15033	}
15034	return retval;
15035}
15036
15037/* This is the cgi handler for the NVRAM download function
15038 * Inputs: -url of the calling file (not used but HTTPD expects this form)
15039 *         -Pointer to the post buffer
15040 *
15041 *
15042 *  Returns: None
15043*/
15044static void
15045do_nvramdl_cgi(char *url, FILE *stream)
15046{
15047	char checksum[NVRAM_SHA1BUFSIZE];
15048	unsigned char passphrase[]=NVRAM_PASSPHRASE;
15049	char salt[NVRAM_SALTSIZE];
15050	unsigned char key[NVRAM_SHA1BUFSIZE];
15051	int entries;
15052	char tmp[NVRAM_MAX_STRINGSIZE],tmp1[NVRAM_MAX_STRINGSIZE];
15053	char tmp_buf[NVRAM_MAX_STRINGSIZE];
15054	char *buf=NULL;
15055	char *var_val=NULL;
15056	char *var_name=NULL;
15057	char *name=NULL;
15058	char *ptr=NULL;
15059	int index;
15060	int retval;
15061	upload_constraints constraint_vars [] = NVRAM_CONSTRAINT_VARS;
15062	char nvram_file_header[][NVRAM_MAX_STRINGSIZE/2] = NVRAM_FILEHEADER;
15063	struct pb {
15064			char header[NVRAM_HEADER_LINECOUNT(nvram_file_header)][NVRAM_MAX_STRINGSIZE];
15065			char buf[MAX_NVRAM_SPACE];
15066		 } *post_buf=NULL;
15067
15068	int offset = 0;
15069
15070	assert(stream);
15071
15072	post_buf = (struct pb *)malloc(sizeof (struct pb));
15073
15074	if (!post_buf) {
15075		cprintf("do_nvramdl_cgi():Error allocating %d bytes for post_buf\n",
15076						sizeof (struct pb));
15077		goto do_nvramdl_cgi_error;
15078	}
15079
15080	buf = (char *)malloc(MAX_NVRAM_SPACE);
15081
15082	if (!buf) {
15083		cprintf("do_nvramdl_cgi():Error allocating %d bytes for buf\n",
15084						MAX_NVRAM_SPACE);
15085		goto do_nvramdl_cgi_error;
15086	}
15087
15088	memset (post_buf,0,sizeof(struct pb));
15089	memset (buf,0,MAX_NVRAM_SPACE);
15090
15091	assert(stream);
15092
15093	entries = NVRAM_HEADER_LINECOUNT(nvram_file_header);
15094	memset(tmp_buf,0,sizeof(tmp_buf));
15095
15096	memset(salt,0,sizeof(salt));
15097
15098	srand(time((time_t *)NULL));
15099	for (index = 0 ; index < 30 ; index ++) rand();
15100	index =rand();
15101	memcpy(&salt[sizeof(index)],&index,sizeof(index));
15102	for (index = 0 ; index < 30 ; index ++) rand();
15103	index =rand();
15104	memcpy(&salt,&index,sizeof(index));
15105
15106	/*
15107	   The first entry of the file is the number of variables
15108	   The second entry is the offset to the start of the NVRAM variables
15109	   The third entry is the SHA1 checksum
15110	*/
15111
15112	/* PopulateHeader info */
15113	offset = 0;
15114	for  (index =0 ;*constraint_vars[index].name;index++){
15115		entries++;
15116		var_val=constraint_vars[index].get(constraint_vars[index].name);
15117		snprintf(tmp_buf,NVRAM_MAX_STRINGSIZE,"%s=%s\n",
15118					constraint_vars[index].name,
15119					(var_val) ? var_val : "unknown");
15120		if (!offset) cprintf("Post_buf address = %p\n",&post_buf->buf[offset]);
15121		offset = add_string(&post_buf->buf[offset],tmp_buf,offset,sizeof(struct pb));
15122		if (offset < 0){
15123			cprintf("httpd: Error Adding NVRAM header info.\n");
15124			goto do_nvramdl_cgi_error;
15125		}
15126	};
15127
15128	memset(key,0,sizeof(key));
15129	fPRF(passphrase,strlen((char *)passphrase),NULL,0,
15130			(unsigned char*)salt,sizeof(salt),key,NVRAM_FILEKEYSIZE);
15131
15132	/* Plug in filler for checksum */
15133	snprintf(post_buf->header[NVRAM_CHECKSUM_LINENUM],NVRAM_MAX_STRINGSIZE,"%s\n",NVRAM_CHECKSUM_FILLER);
15134	/* Grab the NVRAM buffer */
15135
15136	nvram_getall(buf, MAX_NVRAM_SPACE);
15137
15138	for(name = buf; *name; name += strlen(name) + 1){
15139		var_val =tmp;
15140		strncpy(tmp,name,sizeof(tmp) - 1);
15141		tmp[sizeof(tmp) - 1] = '\0';
15142		var_name=strsep(&var_val,"=");
15143		retval = save_nvram_var(var_name,var_val,tmp_buf,
15144					sizeof(tmp_buf),(char *)key,NVRAM_FILEKEYSIZE);
15145
15146		if (retval <0){
15147			cprintf("httpd: Error Adding NVRAM variable info.\n");
15148			goto do_nvramdl_cgi_error;
15149		};
15150
15151		if  (retval > 0 ) {
15152			entries++;
15153			offset = add_string(&post_buf->buf[offset],tmp_buf,offset,sizeof(struct pb));
15154			if (offset < 0){
15155				cprintf("httpd: Error Adding NVRAM variable info.\n");
15156				goto do_nvramdl_cgi_error;
15157			}
15158		};
15159
15160		if (offset > MAX_NVRAM_SPACE) {
15161			cprintf("httpd: MAX_NVRAM_SPACE of %d (%d) exceeded\n",MAX_NVRAM_SPACE,offset);
15162			goto do_nvramdl_cgi_error;
15163		};
15164	}
15165
15166
15167	/* Add the header info */
15168	snprintf(post_buf->header[NVRAM_LINECOUNT_LINENUM],NVRAM_MAX_STRINGSIZE,"%s=%d\n",
15169					nvram_file_header[NVRAM_LINECOUNT_LINENUM],entries);
15170
15171	/*Generate the hash */
15172
15173	memset(checksum,0,sizeof(checksum));
15174	hmac_sha1((unsigned char*)post_buf,sizeof(struct pb),key,NVRAM_FILEKEYSIZE,
15175	          (unsigned char*)checksum);
15176
15177	memcpy(tmp,checksum,NVRAM_HASHSIZE);
15178	memcpy(&tmp[NVRAM_HASHSIZE],salt,NVRAM_SALTSIZE);
15179
15180	ptr = b64_encode((unsigned char *)tmp, NVRAM_FILECHKSUM_SIZE,
15181	                 (unsigned char *)buf, MAX_NVRAM_SPACE );
15182
15183	if (!ptr){
15184		cprintf("do_nvramdl_cgi():Error performing base-64 encode of NVRAM checksum.\n");
15185		goto do_nvramdl_cgi_error;
15186	}
15187
15188	strncpy(tmp1, ptr, sizeof(tmp1) - 1);
15189	tmp1[sizeof(tmp1) - 1] = '\0';
15190
15191	snprintf(post_buf->header[NVRAM_CHECKSUM_LINENUM],NVRAM_MAX_STRINGSIZE,"%s=%s\n",
15192					nvram_file_header[NVRAM_CHECKSUM_LINENUM],tmp1);
15193	/* Write out header */
15194	for (index =0; index < NVRAM_HEADER_LINECOUNT(nvram_file_header) ; index ++)
15195		websWrite(stream, "%s", post_buf->header[index]);
15196
15197	/* Write out rest of file */
15198
15199	for(name = post_buf->buf; *name; name += strlen(name) + 1){
15200		/*cprintf("Val->%s\n",name);*/
15201		websWrite(stream, "%s", name);
15202		};
15203
15204do_nvramdl_cgi_error:
15205
15206	if (post_buf)
15207		free(post_buf);
15208	if (buf)
15209		free(buf);
15210
15211	websDone(stream, 200);
15212
15213	return;
15214}
15215
15216#ifdef __CONFIG_WAPI_IAS__
15217#define LENGTH			255
15218#define RECVFROM_LEN		64*1024
15219
15220#define RECVTIMEOUT		5
15221
15222/* install certificate part */
15223#define AS_CERFILE		"as_cerfile" /* ASU Certificate File name in security.asp */
15224#define USER_CERFILE		"user_cerfile" /* User Certificate File name in security.asp */
15225#define AS_CERFILE_PATH		"/tmp/as_cerfile.cer" /* Temporary file to save ASU certificate */
15226#define USER_CERFILE_PATH	"/tmp/user_cerfile.cer" /* Temporary file to save User certificate */
15227#define CERT_START_SIGN		"-----BEGIN CERTIFICATE-----"
15228#define CERT_END_SIGN		"-----END CERTIFICATE-----"
15229#define USER_CERT_END_SIGN	"-----END EC PRIVATE KEY-----"
15230
15231#define START_SIGN_IS_DATA	0x1
15232#define END_SIGN_IS_DATA	0x2
15233
15234struct srv_info
15235{
15236	int fd;
15237	int port;
15238	struct sockaddr_in addr;
15239};
15240
15241struct _head_info
15242{
15243	unsigned short ver;
15244	unsigned short cmd;
15245	unsigned short reserve;
15246	unsigned short data_len;
15247};
15248
15249struct _packet_reset_srv
15250{
15251	struct _head_info head;
15252	unsigned char data[4096];
15253};
15254
15255#define VERSIONNOW		0x0001
15256#define AP_RELOAD		0x0212
15257#define AP_RELOAD_RESPONSE	0x0213
15258#define CHECK_CERT		0x0214
15259#define CHECK_CERT_RESPNOSE	0x0215
15260
15261/* X509 */
15262#define PEM_STRING_X509_ASU	"ASU CERTIFICATE"
15263#define PEM_STRING_X509_USER	"USER CERTIFICATE"
15264#define PEM_STRING_X509_BEGIN	"-----BEGIN "
15265#define PEM_STRING_X509_END	"-----END "
15266#define PEM_STRING_X509 	"CERTIFICATE"		/* define in include/bcmcrypto/pme.h */
15267#define PEM_STRING_PKCS8INF	"PRIVATE KEY"		/* define in include/bcmcrypto/pme.h */
15268#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY"	/* define in include/bcmcrypto/pme.h */
15269
15270
15271
15272/* process form */
15273#define MSEP_LF 0x0A
15274#define MSEP_CR 0x0D
15275
15276
15277/* This is the cgi handler for the WAPI AS certificate download function
15278 * Inputs: -url of the calling file (not used but HTTPD expects this form)
15279 *	 -Pointer to the post buffer
15280 *  Returns: None
15281*/
15282
15283static int
15284as_communicate(char *req, int req_len, char *rsp, int *rsp_len)
15285{
15286        struct sockaddr_in as_addr;
15287	struct timeval tv = {RECVTIMEOUT, 0};
15288	int fd = -1;
15289	fd_set fds;
15290	int ret = 0;
15291
15292	memset(&as_addr, 0, sizeof(struct sockaddr_in));
15293	as_addr.sin_family = AF_INET;
15294	as_addr.sin_port = htons(AS_UI_PORT);
15295	if (inet_aton(AS_UI_ADDR, &as_addr.sin_addr) < 0) {
15296		cprintf("Address translation error");
15297		return -1;
15298	}
15299
15300	fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
15301	/* send request to AS */
15302	sendto(fd, req, req_len, 0, (struct sockaddr *)&as_addr, sizeof(struct sockaddr_in));
15303
15304	/* receive response data */
15305	FD_ZERO(&fds);
15306	FD_SET(fd, &fds);
15307
15308	select(fd + 1, &fds, NULL, NULL, &tv);
15309
15310	if (FD_ISSET(fd, &fds)) {
15311		memset(rsp, 0, *rsp_len);
15312
15313		*rsp_len = recv(fd, rsp, *rsp_len, 0);
15314		if (*rsp_len == 0) {
15315			cprintf("receive no data\n");
15316			ret = -1;
15317		}
15318		rsp[*rsp_len] = 0;
15319	}
15320	else {
15321		cprintf("No data selected\n");
15322		ret = -1;
15323	}
15324
15325	if(fd > 0)
15326		close(fd);
15327
15328	return ret;
15329}
15330
15331/* revoke certificate*/
15332static int
15333cert_revoke(webs_t wp, char *sn_str)
15334{
15335	char cmd[40];
15336	char *rbuf = NULL;
15337	int rbuf_len = 128;
15338
15339	sprintf(cmd, "action=Revoke sn=%s", sn_str);
15340
15341	rbuf = malloc(rbuf_len);
15342	if (as_communicate(cmd, strlen(cmd), rbuf, &rbuf_len)) {
15343		websWrite(wp, "Communicate to AS server failed<br>");
15344	}
15345	else {
15346		if (rbuf_len == 0)
15347			websWrite(wp, "Revoke certificate(%s) failed<br>", sn_str);
15348		else
15349			websWrite(wp, "%s<br>", rbuf);
15350	}
15351
15352	if (rbuf)
15353		free(rbuf);
15354
15355        return 0;
15356}
15357
15358static int
15359ej_as_cer_display(int eid, webs_t wp, int argc, char_t **argv)
15360{
15361#define MAX_CERT_LENGTH		0xFFA8
15362	char *rbuf = NULL;
15363	int rbuf_len = MAX_CERT_LENGTH;
15364	int i, count, item;
15365	char *p;
15366	int ret = -1;
15367	char na[32+1], sn[32], dur[8], remain[8], status[16], type[16];
15368
15369	if (!nvram_match("as_mode", "enabled"))
15370		return 0;
15371
15372	rbuf = malloc(rbuf_len);
15373	if (as_communicate("action=Query", 13, rbuf, &rbuf_len)) {
15374		goto query_err;
15375	}
15376
15377	/* query string must start with 'count' string */
15378	if (rbuf_len < 5) {
15379		cprintf("data length incorrect");
15380		goto query_err;
15381	}
15382
15383	/* display certificate result */
15384	sscanf(rbuf, "count=%d", &count);
15385	p = rbuf;
15386	for (i = 0; i < count; i++) {
15387		p = strstr(p + 1, "item");
15388
15389		sscanf(p, "item%d=%s %s %s %s %s %s", &item, na, sn, dur, remain, type, status);
15390		websWrite(wp, "<tr>");
15391		websWrite(wp, "<td>%s</td>", na);
15392		websWrite(wp, "<td>%s</td>", sn);
15393		websWrite(wp, "<td>%s</td>", dur);
15394		websWrite(wp, "<td>%s</td>", remain);
15395		websWrite(wp, "<td>%s</td>", type);
15396		websWrite(wp, "<td>%s</td>", status);
15397
15398		if (strncmp(status, "Actived", 7) == 0) {
15399			websWrite(wp, "<form method=\"post\" action=\"apply.cgi\">");
15400			websWrite(wp, "<td>");
15401			websWrite(wp, "<input type=\"hidden\" name=\"sn\" value=\"%s\">", sn);
15402			websWrite(wp, "<input type=\"hidden\" name=\"page\" value=\"as.asp\">");
15403			websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"Revoke\">");
15404			websWrite(wp, "</td>");
15405			websWrite(wp, "</form>");
15406		}
15407		else {
15408			websWrite(wp, "<td></td>");
15409		}
15410
15411		websWrite(wp, "</tr>");
15412	}
15413
15414	ret = 0;
15415
15416query_err:
15417	if (rbuf)
15418		free(rbuf);
15419	return ret;
15420}
15421
15422/* request new user certificate */
15423static int
15424cert_ask(char *name, uint32 period, char *ret_msg)
15425{
15426	char cmd[100];
15427	char *rbuf = NULL;
15428	int rbuf_len = 128;
15429	int ret = -1;
15430
15431	sprintf(cmd, "action=Apply name=%s period=%d", name, period);
15432
15433	rbuf = malloc(rbuf_len);
15434	if (as_communicate(cmd, strlen(cmd), rbuf, &rbuf_len)) {
15435		sprintf(ret_msg, "Communicate to AS server failed");
15436	}
15437	else {
15438		if (rbuf_len == 0)
15439			sprintf(ret_msg, "Apply new certificate failed");
15440		else {
15441			/* retrieve user certificate location */
15442			sscanf(rbuf, "user_cer=%s", ret_msg);
15443			ret = 0;
15444		}
15445	}
15446
15447	if (rbuf)
15448		free(rbuf);
15449
15450        return ret;
15451}
15452
15453static char*
15454read_all_data(char *file, int size_min, int size_max)
15455{
15456	int size, count;
15457	char *data = NULL, *ptr;
15458	FILE *fp = NULL;
15459	struct stat stat;
15460
15461	if (!file) {
15462		cprintf("read_all_data():Invaild argument file\n");
15463		return NULL;
15464	}
15465
15466	/* open file for read */
15467	if ((fp = fopen(file, "r")) <= 0) {
15468		cprintf("read_all_data():Error open %s for read\n", file);
15469		return NULL;
15470	}
15471	if (fstat(fileno(fp), &stat) != 0) {
15472		cprintf("read_all_data():fstat file %s fail!\n", file);
15473		goto read_all_data_error;
15474	}
15475	size = stat.st_size;
15476	if ((size_min != -1 && size < size_min) || (size_max != -1 && size > size_max)) {
15477		cprintf("read_all_data():size %d check fail!\n", size);
15478		goto read_all_data_error;
15479	}
15480
15481	data = (char *)malloc(size + 1);
15482	if (!data) {
15483		cprintf("read_all_data():Error allocating %d bytes for buf\n", size);
15484		goto read_all_data_error;
15485	}
15486	memset (data, 0, size + 1);
15487
15488	ptr = data;
15489	while (size) {
15490		count = safe_fread(ptr, 1, size, fp);
15491		if (!count && (ferror(fp) || feof(fp)))
15492			break;
15493		size -= count;
15494		ptr += count;
15495	}
15496
15497	if (size) {
15498		cprintf("read_all_data():Read %s file fail, total size %d read size %d\n",
15499			file, (int)stat.st_size, (int)stat.st_size - size);
15500		goto read_all_data_error;
15501	}
15502
15503	if (fp)
15504		fclose(fp);
15505
15506	return data;
15507
15508read_all_data_error:
15509
15510	if (fp)
15511		fclose(fp);
15512	if (data)
15513		free(data);
15514
15515	return NULL;
15516}
15517
15518static void
15519do_as_x509_cert_dl_cgi(char *url, FILE *stream)
15520{
15521	char *data = NULL;
15522
15523	assert(stream);
15524
15525	/* get as certificate file */
15526	data = read_all_data(WAPI_AS_CER_FILE, -1, -1);
15527
15528	if (data) {
15529		/* Write out as cert data */
15530		websWrite(stream, "%s", data);
15531		free (data);
15532	}
15533
15534	websDone(stream, 200);
15535
15536	return;
15537}
15538
15539static void
15540do_user_x509_cert_dl_cgi(char *url, FILE *stream)
15541{
15542	char *owner = NULL;
15543	char *period_str = NULL;
15544	char *unit_str = NULL;
15545	char *rcv_msg = NULL;
15546	char *data = NULL;
15547	uint32 period = 0;
15548
15549	assert(stream);
15550
15551	owner = websGetVar(stream, "cer_owner", NULL);
15552	period_str = websGetVar(stream, "cer_period", NULL);
15553	unit_str = websGetVar(stream, "cer_period_unit", NULL);
15554
15555	if (owner == NULL || period_str == NULL || unit_str == NULL) {
15556		cprintf("do_user_x509_cert_dl_cgi():Wrong variables argument\n");
15557		goto do_user_x509_cert_dl_cgi_error;
15558	}
15559
15560	period = atoi(period_str) * atoi(unit_str) * 86400;
15561
15562	if ((rcv_msg = malloc(LENGTH)) == NULL) {
15563		cprintf("do_user_x509_cert_dl_cgi():buffer allocate error\n");
15564		goto do_user_x509_cert_dl_cgi_error;
15565	}
15566	memset(rcv_msg, 0, LENGTH);
15567
15568	if (cert_ask(owner, period, rcv_msg)) {
15569		cprintf("do_user_x509_cert_dl_cgi():%s\n", rcv_msg);
15570		goto do_user_x509_cert_dl_cgi_error;
15571	}
15572	else {
15573		/* retrieve data from received file path */
15574		if (rcv_msg[0] != 0)
15575			data = read_all_data(rcv_msg, -1, -1);
15576	}
15577
15578	if (data) {
15579		/* Write out as cert data */
15580		websWrite(stream, "%s", data);
15581		free(data);
15582	}
15583
15584do_user_x509_cert_dl_cgi_error:
15585
15586	websDone(stream, 200);
15587
15588	/* Reset CGI */
15589	init_cgi(NULL);
15590
15591	if (rcv_msg)
15592		free(rcv_msg);
15593
15594	return;
15595}
15596
15597/* return remain len or -1 is error */
15598static int
15599get_multipart(FILE *stream, int len, char *name, char *outfile, char *outbuf,
15600	char *start_sign, char *end_sign, int flag)
15601{
15602	int ret = 0;
15603	int last_line = 0;
15604	char buf[1024];
15605	FILE *fp = NULL;
15606
15607	assert(stream);
15608	assert(name);
15609	assert(start_sign);
15610
15611	if (!outfile && !outbuf)
15612		return -1;
15613
15614	/* look for "name" part */
15615	while (len > 0) {
15616		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream))
15617			return -1;
15618
15619		/* remove LF that fgets() drags in and update len value */
15620		len = remove_crlf(buf, len);
15621
15622		/* look for start of attached file header */
15623		if (*buf && strstr(buf, name))
15624			break;
15625	}
15626
15627	if (len <= 0)
15628		return -1;
15629
15630	/* open the outfile to write */
15631	if (outfile && (fp = fopen(outfile, "w")) == NULL)
15632		return errno;
15633
15634	/*
15635	 * loop thru the header lines until we get the "start_sign" line
15636	 * that signifies the start of "name" contents
15637	*/
15638	while (len > 0) {
15639		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream)) {
15640			ret = -1;
15641			goto get_multipart_done;
15642		}
15643
15644		if (strstr(buf, start_sign)) {
15645			/* write to "outfile" or "outbuf" */
15646			if (flag & START_SIGN_IS_DATA) {
15647				if (fp)
15648					safe_fwrite(buf, 1, strlen(buf), fp);
15649				else
15650					memcpy(outbuf, buf, strlen(buf));
15651			}
15652			len -= strlen(buf);
15653			break;
15654		}
15655		len -= strlen(buf);
15656	}
15657
15658	if (outbuf && !end_sign) {
15659		if (!(flag & START_SIGN_IS_DATA)) {
15660			if (len > 0 && fgets(buf, MIN(len + 1, sizeof(buf)), stream)) {
15661				memcpy(outbuf, buf, strlen(buf));
15662				len -= strlen(buf);
15663			} else {
15664				ret = -1;
15665				goto get_multipart_done;
15666			}
15667		}
15668
15669		ret = len;
15670		goto get_multipart_done;
15671	}
15672
15673	if (len <= 0) {
15674		ret = -1;
15675		goto get_multipart_done;
15676	}
15677
15678	/*
15679	 * loop thru the header lines until we get the "end_sing" line
15680	 * that signifies the end of "name" contents
15681	*/
15682	while (len > 0) {
15683		if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream)) {
15684			ret = -1;
15685			goto get_multipart_done;
15686		}
15687
15688		if (strstr(buf, end_sign)) {
15689			last_line = 1;
15690			len = remove_crlf(buf, len);
15691
15692		} else
15693			len -= strlen(buf);
15694
15695		if (fp && (!last_line || (last_line && (flag & END_SIGN_IS_DATA)))) {
15696			safe_fwrite(buf, 1, strlen(buf), fp);
15697		}
15698
15699		if (last_line)
15700			break;
15701	}
15702
15703	ret = len;
15704
15705get_multipart_done:
15706
15707	if (fp)
15708		fclose(fp);
15709
15710	return ret;
15711
15712}
15713
15714static int
15715check_cert_file(char *user_cert_data)
15716{
15717	if (user_cert_data != NULL && strstr(user_cert_data, "KEY-----") != NULL)
15718		return 0;
15719
15720	return -1;
15721}
15722
15723static char*
15724search_pem_str(char *in, char *name)
15725{
15726	char *p = NULL;
15727
15728	p = strstr(in, name);
15729	return p;
15730}
15731
15732static int
15733PEM_read_x509(char **data, int *datal, char *name, char *fcontent, int flen)
15734{
15735	char *p = fcontent;
15736	char *end = fcontent + flen;
15737	char *bdata = NULL;
15738	char *edata = NULL;
15739	int ret = 0;
15740
15741	do {
15742		bdata = search_pem_str(p, name);
15743		if ((bdata == NULL) || (bdata >end)) {
15744			ret = -1;
15745			break;
15746		}
15747		bdata +=strlen(name);
15748		if (strncmp(bdata, "-----", 5) != 0)
15749		{
15750			ret = -1;
15751			break;
15752		};
15753		bdata += 5;
15754
15755		edata = search_pem_str(bdata, PEM_STRING_X509_END);
15756		if ((edata == NULL) || (edata >end)) {
15757			ret = -2;
15758			break;
15759		}
15760		*data = bdata;
15761		*datal = edata-bdata;
15762	}while(0);
15763
15764	return ret ;
15765}
15766
15767static void
15768cp_cert_flag(char **buffer, char *str_x509, const char *str_cert)
15769{
15770	char *p = *buffer;
15771
15772	/*cp -----BEGIN ASU(USER) CERTIFICATE-----*/
15773	memcpy(p, str_x509, strlen(str_x509));
15774	p += strlen(str_x509);
15775	memcpy(p, str_cert, strlen(str_cert));
15776	p += strlen(str_cert);
15777	memcpy(p, "-----", 5);
15778	p += 5;
15779	*buffer = p;
15780}
15781static void
15782PEM_write(char **in, char *data,  int datal, const char *name)
15783{
15784	char *p = *in;
15785
15786	/*cp LF+CR */
15787	p[0] = MSEP_CR; p[1] = MSEP_LF; p +=2;
15788
15789	/*cp -----BEGIN ASU(USER) CERTIFICATE-----*/
15790	cp_cert_flag(&p, PEM_STRING_X509_BEGIN, name);
15791
15792	/*cp -----cert content-----*/
15793	memcpy(p, data, datal);
15794	p += datal;
15795
15796	/*cp -----END ASU(USER) CERTIFICATE-----*/
15797	cp_cert_flag(&p, PEM_STRING_X509_END, name);
15798
15799	/*cp LF+CR */
15800	p[0] = MSEP_CR; p[1] = MSEP_LF; p +=2;
15801
15802	*in = p;
15803}
15804
15805static int
15806x509_cert_converge(char *buffer, char *as_data, char *user_data)
15807{
15808	char *cert = NULL;
15809	char *p = buffer;
15810	int certl = 0;
15811	int ret = 0;
15812
15813	/* AS certificate */
15814	ret = PEM_read_x509(&cert, &certl, PEM_STRING_X509, as_data, strlen(as_data));
15815	if (ret != 0) {
15816		printf("ret = %d\n", ret);
15817		return 0;
15818	}
15819	PEM_write(&p, cert, certl, PEM_STRING_X509_ASU);
15820
15821	/* user cerfiticate */
15822	cert = NULL;
15823	certl = 0;
15824	ret = PEM_read_x509(&cert, &certl, PEM_STRING_X509, user_data, strlen(user_data));
15825	if (ret != 0) {
15826		printf("ret = %d\n", ret);
15827		return 0;
15828	}
15829	PEM_write(&p, cert, certl, PEM_STRING_X509_USER);
15830
15831	cert = NULL;
15832	certl = 0;
15833	if((PEM_read_x509(&cert, &certl, PEM_STRING_PKCS8INF, user_data, strlen(user_data))) == 0)
15834		PEM_write(&p, cert, certl, PEM_STRING_ECPRIVATEKEY);
15835
15836	return (p - buffer);
15837}
15838
15839static int
15840init_srv_info(struct srv_info *WAI_srv, const char *ip_addr)
15841{
15842	int ret = 0;
15843
15844	memset(&(WAI_srv->addr), 0, sizeof(struct sockaddr_in));
15845	WAI_srv ->fd = socket(AF_INET, SOCK_DGRAM, 0);
15846	WAI_srv->addr.sin_family = AF_INET;
15847	WAI_srv->addr.sin_port = htons(WAI_srv->port);
15848	ret = inet_aton(ip_addr, &(WAI_srv->addr.sin_addr));
15849	if (ret == 0) {
15850		printf("\nas IP_addr error!!!\n\n");
15851	}
15852
15853	return ret;
15854}
15855
15856static int
15857send_wapi_info(struct srv_info *WAI_srv, struct _packet_reset_srv *packet_reset_srv)
15858{
15859	int sendlen = 0;
15860	int data_len = 0;
15861	int ret = 0;
15862
15863	data_len = packet_reset_srv->head.data_len + sizeof(struct _head_info);
15864	packet_reset_srv->head.data_len = htons(packet_reset_srv->head.data_len);
15865	sendlen = sendto(WAI_srv->fd, (char *)packet_reset_srv, data_len, 0,
15866		(struct sockaddr *)&(WAI_srv->addr), sizeof(struct sockaddr_in));
15867	if (sendlen != data_len)
15868		ret = -1;
15869
15870	return ret;
15871}
15872static int
15873recv_wapi_info(struct srv_info *WAI_srv, struct _packet_reset_srv *recv_from_srv, int timeout)
15874{
15875	fd_set readfds;
15876	struct timeval tv;
15877	int bytes_read;
15878
15879
15880	/* First, setup a select() statement to poll for the data comming in */
15881	FD_ZERO(&readfds);
15882	FD_SET(WAI_srv->fd, &readfds);
15883
15884	tv.tv_sec = timeout;
15885	tv.tv_usec = 0;
15886
15887	select(WAI_srv->fd + 1, &readfds, NULL, NULL, &tv);
15888	if (FD_ISSET(WAI_srv->fd, &readfds)) {
15889		bytes_read = recv(WAI_srv->fd, (char *)recv_from_srv, RECVFROM_LEN, 0);
15890		return(bytes_read);
15891	}
15892
15893	return -1;
15894}
15895
15896static void
15897wapi_ntoh_data(struct _packet_reset_srv *recv_from_srv)
15898{
15899	recv_from_srv->head.ver = ntohs(recv_from_srv->head.ver);
15900	recv_from_srv->head.cmd = ntohs(recv_from_srv->head.cmd);
15901	recv_from_srv->head.data_len = ntohs(recv_from_srv->head.data_len);
15902}
15903
15904static int
15905process_wapi_info(struct _packet_reset_srv *recv_from_WAI)
15906{
15907	int ret = 0;
15908	unsigned short CMD = 0;
15909	unsigned char check_result = 0;
15910
15911	wapi_ntoh_data(recv_from_WAI);
15912	if (recv_from_WAI->head.ver != VERSIONNOW) {
15913		cprintf("Version error in data from , The Ver is %d\n", recv_from_WAI->head.ver );
15914		ret = -1;
15915		goto process_wapi_info_error;
15916	}
15917
15918	if (recv_from_WAI->head.data_len != 2) {
15919		cprintf("data_len error in data from , The Ver is %d\n", recv_from_WAI->head.data_len );
15920		ret = -1;
15921		goto process_wapi_info_error;
15922	}
15923
15924	CMD = recv_from_WAI->head.cmd;
15925	check_result = *((unsigned short *)recv_from_WAI->data);
15926	switch(CMD)
15927	{
15928		case CHECK_CERT_RESPNOSE:
15929		case AP_RELOAD_RESPONSE:
15930			if (check_result != 0) {
15931				ret = -1;
15932			}
15933			break;
15934		default:
15935			ret = -1;
15936			break;
15937	}
15938
15939process_wapi_info_error:
15940
15941	return ret;
15942}
15943
15944static int
15945save_certificate(const char *fname, char *fcontent, int flen)
15946{
15947	FILE *f;
15948	int ret = 0;
15949
15950	/* save certificate file */
15951	f = fopen(fname, "wb");
15952
15953	if (f == NULL)
15954		ret = 1;
15955
15956	if (fwrite(fcontent, flen, 1, f) != 1)
15957		ret = 2;
15958
15959	fclose(f);
15960
15961	confmtd_backup();
15962
15963	return ret;
15964}
15965
15966
15967static void
15968do_cert_ul_post(char *url, FILE *stream, int len, char *boundary)
15969{
15970	int bufl, ret = 0;
15971	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
15972	char cert_file[LENGTH] = "";
15973	char *as_data = NULL, *user_data = NULL;
15974	char *buffer;
15975	FILE *outfile = NULL;
15976
15977	struct _packet_reset_srv send_to_WAI;
15978	struct _packet_reset_srv recv_from_WAI;
15979	struct srv_info WAI_srv;
15980
15981	assert(url);
15982	assert(stream);
15983
15984	ret_code = EINVAL;
15985
15986	/* get wl prefix */
15987	sprintf(prefix, "wl%s_", nvram_get("wl_unit"));
15988
15989	/* get as_cerfile */
15990	len = get_multipart(stream, len, AS_CERFILE, AS_CERFILE_PATH, NULL,
15991		CERT_START_SIGN, CERT_END_SIGN, (START_SIGN_IS_DATA | END_SIGN_IS_DATA));
15992	if (len == 0 || len == -1) {
15993		strncpy(posterr_msg, "Invalid AS certificate file<br>", ERR_MSG_SIZE);
15994	 	return;
15995	}
15996
15997	/* get user_cerfile */
15998	len = get_multipart(stream, len, USER_CERFILE, USER_CERFILE_PATH, NULL,
15999		CERT_START_SIGN, USER_CERT_END_SIGN, (START_SIGN_IS_DATA | END_SIGN_IS_DATA));
16000	if (len == 0 || len == -1) {
16001		strncpy(posterr_msg, "Invalid user certificate file<br>", ERR_MSG_SIZE);
16002		return;
16003	}
16004
16005	/* read as and user certificate */
16006	if ((as_data = read_all_data(AS_CERFILE_PATH, -1, -1)) == NULL) {
16007		strncpy(posterr_msg, "Read AS certificate file fail<br>", ERR_MSG_SIZE);
16008		goto do_cert_ul_post_error;
16009	}
16010
16011	if ((user_data = read_all_data(USER_CERFILE_PATH, -1, -1)) == NULL) {
16012		strncpy(posterr_msg, "Read USER certificate file fail<br>", ERR_MSG_SIZE);
16013		goto do_cert_ul_post_error;
16014	}
16015
16016	/* check certificate files */
16017	if((check_cert_file(user_data)) != 0) {
16018		strncpy(posterr_msg, "Certificate file format error.<br>", ERR_MSG_SIZE);
16019		goto do_cert_ul_post_error;
16020	}
16021
16022	/* initial WAI service communicate structure */
16023	memset(&WAI_srv, 0, sizeof(struct srv_info));
16024	memset(&send_to_WAI, 0, sizeof(struct _packet_reset_srv));
16025	memset(&recv_from_WAI, 0, sizeof(struct _packet_reset_srv));
16026
16027	WAI_srv.fd = -1;
16028	/* integrate certificate */
16029	buffer = (char *)send_to_WAI.data;
16030
16031	bufl = x509_cert_converge(buffer, as_data, user_data);
16032	if (bufl == 0) {
16033		strncpy(posterr_msg, "X509 certificate converge fail.<br>", ERR_MSG_SIZE);
16034		goto do_cert_ul_post_error;
16035	}
16036
16037	/* send certificate to WAI service and check cert is Ap's certificate or not */
16038	WAI_srv.port = WAP_UI_PORT;
16039	ret = init_srv_info(&WAI_srv, WAI_UI_ADDR);
16040	if (ret == 0) {
16041		printf("\nAS IP_addr error!!!\n\n");
16042		strncpy(posterr_msg, "System error. installing certificate failed.<br>",
16043			ERR_MSG_SIZE);
16044		goto do_cert_ul_post_error;
16045	}
16046	send_to_WAI.head.ver = htons(VERSIONNOW);
16047	send_to_WAI.head.cmd = htons(CHECK_CERT);
16048	send_to_WAI.head.reserve = htons(1);
16049	send_to_WAI.head.data_len = bufl;
16050
16051	ret = send_wapi_info(&WAI_srv, &send_to_WAI);
16052	if (ret != 0) {
16053		cprintf("Call send_wapi_info for CHECK_CERT, WAI is disabled");
16054		strncpy(posterr_msg, "WAI is disabled.<br>", ERR_MSG_SIZE);
16055		goto do_cert_ul_post_error;
16056	}
16057
16058	/* read WAI srv response */
16059	ret = recv_wapi_info(&WAI_srv, &recv_from_WAI, RECVTIMEOUT);
16060	if (ret <= 0) {
16061		cprintf("Call recv_wapi_info for CHECK_CERT, WAI is disabled\n");
16062		strncpy(posterr_msg, "WAI is disabled.<br>", ERR_MSG_SIZE);
16063		goto do_cert_ul_post_error;
16064	}
16065
16066	/* process WAI srv response */
16067	ret = process_wapi_info(&recv_from_WAI);
16068	if (ret != 0) {
16069		strncpy(posterr_msg, "Certificate file format error.<br>", ERR_MSG_SIZE);
16070		goto do_cert_ul_post_error;
16071	}
16072
16073	/* get ap certificate file name */
16074	snprintf(cert_file, sizeof(cert_file), "%s/%s%s", WAPI_WAI_DIR, prefix, "apcert.cer");
16075
16076	/* save AP certificate */
16077	ret = save_certificate(cert_file, buffer, bufl);
16078	if (ret) {
16079		strncpy(posterr_msg, "Save certificate error.<br>", ERR_MSG_SIZE);
16080		goto do_cert_ul_post_error;
16081	}
16082
16083	/* save cert type and status */
16084	nvram_set(strcat_r(prefix, "wai_cert_index", tmp), "1");
16085	nvram_set("wl_wai_cert_index", "1");
16086	nvram_set(strcat_r(prefix, "wai_cert_status", tmp), "1");
16087	nvram_set("wl_wai_cert_status", "1");
16088	nvram_set(strcat_r(prefix, "wai_cert_name", tmp), cert_file);
16089	nvram_set("wl_wai_cert_name", cert_file);
16090	nvram_commit();
16091
16092	/* We are done */
16093	ret_code = 0;
16094
16095do_cert_ul_post_error:
16096
16097	/* remove temporary files */
16098	unlink(AS_CERFILE_PATH);
16099	unlink(USER_CERFILE_PATH);
16100
16101	if (as_data)
16102		free(as_data);
16103	if (user_data)
16104		free(user_data);
16105	if (WAI_srv.fd >= 0)
16106		close(WAI_srv.fd);
16107	if (outfile)
16108		fclose(outfile);
16109
16110	/* Clear up any outstanding stuff */
16111	/* Slurp anything remaining in the request */
16112	while (len--)
16113		(void) fgetc(stream);
16114
16115	return;
16116}
16117
16118static void
16119do_cert_ul_cgi(char *url, FILE *stream)
16120{
16121	assert(stream);
16122	assert(url);
16123
16124	websHeader(stream);
16125	websWrite(stream, (char_t *) apply_header);
16126
16127	if (ret_code){
16128		websWrite(stream, "Error during certificate upload<br>");
16129		if (*posterr_msg){
16130			websWrite(stream, posterr_msg);
16131			memset(posterr_msg,0,ERR_MSG_SIZE);
16132		}
16133	} else websWrite(stream, "Certificate upload complete.");
16134
16135	websWrite(stream, (char_t *) apply_footer, "security.asp");
16136	websFooter(stream);
16137	websDone(stream, 200);
16138
16139	/* Do system restart */
16140	if (ret_code == 0)
16141		sys_restart();
16142}
16143#endif /* __CONFIG_WAPI_IAS__ */
16144
16145/*
16146 * This routine takes the cipher text ctext and produces the plaintext ptext
16147 * using the provided key.
16148 *
16149 * This routine accepts the cipher text  in the MIME Base64 format.
16150 *
16151 * The plain text is 8 bytes less than the ciphertext
16152 */
16153static char*
16154decrypt_var(char *varname,char *ctext, int ctext_len, char *ptext, int *ptext_len,char *key, int keylen)
16155{
16156	unsigned char tmp[NVRAM_MAX_STRINGSIZE];
16157	int len;
16158	char *end=NULL;
16159
16160	assert(ptext);
16161	assert(ctext);
16162	assert(ptext_len);
16163	assert(key);
16164	if (keylen < 1 ) return NULL;
16165
16166	if (ctext_len > NVRAM_MAX_STRINGSIZE){
16167		cprintf("decrypt_var():Encrypted string is too long MAXSTRINGSIZE=%d Strlen=%d\n",
16168							NVRAM_MAX_STRINGSIZE,ctext_len);
16169	}
16170
16171	/* Cipher text must be more than 8 chars for this aes_unwrap() routine to work*/
16172	if (ctext_len < 8) return NULL;
16173
16174	len=b64_decode(ctext,tmp,NVRAM_MAX_STRINGSIZE);
16175
16176	if (!len) return NULL;
16177
16178	if (aes_unwrap(keylen,(unsigned char *)key,len,tmp,(unsigned char *)ptext))
16179		return NULL;
16180
16181	*ptext_len = len - 8;
16182
16183	end = strstr(ptext,varname);
16184
16185	if (end)
16186		(*end)= '\0';
16187	else
16188		return NULL;
16189
16190	return ptext;
16191}
16192/*
16193 * This routine takes the plaintext text ptext and produces the ciphertext ctext
16194 * using the provided key.
16195 *
16196 * It accepts the plaintext in binary form and produces ciphertext in MIME Base64 format.
16197 *
16198 *
16199 */
16200static char*
16201encrypt_var(char *varname,char *ptext, int ptext_len, char *ctext, int *ctext_len,char *key, int keylen)
16202{
16203	unsigned char tmp[NVRAM_MAX_STRINGSIZE];
16204	char *buf=NULL;
16205	int newlen;
16206	int varname_len;
16207
16208	assert(ptext);
16209	assert(ctext);
16210	assert(ctext_len);
16211	assert(key);
16212	if (keylen < 1 ) return NULL;
16213	if (ptext_len < 1) return NULL;
16214
16215	varname_len = strlen (varname);
16216
16217	 /* Include the NULL at the end */
16218	newlen = ptext_len + varname_len + 1;
16219	/* Align the incoming buffer to AES block length boundaries */
16220	if (newlen % AES_BLOCK_LEN)
16221		newlen = (1 + newlen /AES_BLOCK_LEN ) * AES_BLOCK_LEN;
16222
16223	/* Do a string length check. When the binary string is base-64 encoded
16224	   it becomes 30% larger as every 3 bytes are represented by 4 ascii
16225	   characters */
16226
16227	if ( (4*(1+(newlen+8)/3)) > NVRAM_MAX_STRINGSIZE )
16228	{
16229		cprintf("encrypt_var():The encrypted string is too long. MAXSTRINGSIZE=%d Strlen=%d\n",
16230				NVRAM_MAX_STRINGSIZE,(4*(1+(newlen+8)/3)));
16231		return NULL;
16232	}
16233
16234	buf  = malloc (newlen);
16235	if (!buf) return NULL;
16236	memset(buf,0,newlen);
16237	memcpy(buf,ptext,ptext_len);
16238	memcpy(buf + ptext_len,varname,varname_len);
16239
16240	if (aes_wrap(keylen,(unsigned char *)key,newlen,(unsigned char *)buf,
16241	             (unsigned char *)ctext)){
16242		if (buf) free(buf);
16243	 	return NULL;
16244	};
16245
16246	if (buf) free(buf);
16247
16248	buf = b64_encode((unsigned char *)ctext,newlen+8,tmp,NVRAM_MAX_STRINGSIZE-(ptext_len + 1));
16249
16250	if (buf){
16251		strncpy(ctext,buf,NVRAM_MAX_STRINGSIZE);
16252		*ctext_len = strlen(ctext) ;
16253		return ctext;
16254	} else {
16255		cprintf("encrypt_var():base-64 encode error\n");
16256		*ctext_len = 0;
16257		return NULL;
16258	}
16259}
16260
16261static void
16262do_wireless_asp(char *url, FILE *stream)
16263{
16264	char *path=NULL, *query=NULL;
16265
16266	assert(stream);
16267	assert(url);
16268
16269	/* Parse path */
16270	query = url;
16271	path = strsep(&query, "?") ? : url;
16272
16273	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
16274
16275	/* Reset CGI */
16276	init_cgi(NULL);
16277}
16278
16279static void
16280do_security_asp(char *url, FILE *stream)
16281{
16282	char *path=NULL, *query=NULL;
16283
16284	assert(stream);
16285	assert(url);
16286
16287	/* Parse path */
16288	query = url;
16289	path = strsep(&query, "?") ? : url;
16290
16291	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
16292
16293	/* Reset CGI */
16294	init_cgi(NULL);
16295}
16296
16297#ifdef __CONFIG_WPS__
16298static void
16299do_wps_asp(char *url, FILE *stream)
16300{
16301	char *path=NULL, *query=NULL;
16302
16303	assert(stream);
16304	assert(url);
16305
16306	/* Parse path */
16307	query = url;
16308	path = strsep(&query, "?") ? : url;
16309	printf("do_wps_asp\n");
16310	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
16311
16312	/* Reset CGI */
16313	init_cgi(NULL);
16314}
16315#endif /* #ifdef __CONFIG_WPS__ */
16316
16317#if defined(__CONFIG_SAMBA__) || defined(__CONFIG_DLNA_DMS__)
16318static int
16319do_storage(webs_t wp, char_t *urlPrefix, char_t *webDir,
16320	int arg, char_t *url, char_t *path, char_t *query)
16321{
16322
16323	if ((websGetVar(wp, "action", NULL))) {
16324
16325		ret_code = 0;
16326
16327		return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query);
16328	}
16329
16330	return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query);
16331}
16332
16333static void
16334do_storage_asp(char *url, FILE *stream)
16335{
16336	char *path=NULL, *query=NULL;
16337
16338	assert(url);
16339	assert(stream);
16340
16341	/* Parse path */
16342	query = url;
16343	path = strsep(&query, "?") ? : url;
16344
16345	do_storage(stream, NULL, NULL, 0, url, path, query);
16346
16347	/* Reset CGI */
16348	init_cgi(NULL);
16349}
16350#endif
16351
16352static void
16353do_media_asp(char *url, FILE *stream)
16354{
16355	char *path=NULL, *query=NULL;
16356
16357	assert(stream);
16358	assert(url);
16359
16360	/* Parse path */
16361	query = url;
16362	path = strsep(&query, "?") ? : url;
16363
16364	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
16365
16366	/* Reset CGI */
16367	init_cgi(NULL);
16368}
16369
16370static void
16371do_internal_asp(char *url, FILE *stream)
16372{
16373	char *path=NULL, *query=NULL;
16374
16375	assert(stream);
16376	assert(url);
16377
16378	/* Parse path */
16379	query = url;
16380	path = strsep(&query, "?") ? : url;
16381
16382	copy_wl_index_to_unindex(stream, NULL, NULL, 0, url, path, query);
16383
16384	/* Reset CGI */
16385	init_cgi(NULL);
16386}
16387
16388#ifdef __CONFIG_NAT__
16389static void
16390do_wan_asp(char *url, FILE *stream)
16391{
16392	char *path=NULL, *query=NULL;
16393
16394	assert(stream);
16395	assert(url);
16396
16397	/* Parse path */
16398	query = url;
16399	path = strsep(&query, "?") ? : url;
16400
16401	wan_asp(stream, NULL, NULL, 0, url, path, query);
16402
16403	/* Reset CGI */
16404	init_cgi(NULL);
16405}
16406#endif	/* __CONFIG_NAT__ */
16407
16408struct mime_handler mime_handlers[] = {
16409#if defined(__CONFIG_TREND_IQOS__) && defined(CONFIG_TREND_IQOS_ENABLED)
16410	{ "iQoS.cgi*", "application/json", no_cache, do_iqos_post, do_iqos_get, do_auth },
16411#endif /* __CONFIG_TREND_IQOS__ && CONFIG_TREND_IQOS_ENABLED */
16412#ifdef __CONFIG_NAT__
16413	{ "wan.asp", "text/html", no_cache, do_apply_post, do_wan_asp, do_auth },
16414#endif	/* __CONFIG_NAT__ */
16415	{ "radio.asp", "text/html", no_cache, do_apply_post, do_wireless_asp, do_auth },
16416	{ "ssid.asp", "text/html", no_cache, do_apply_post, do_wireless_asp, do_auth },
16417#ifdef __CONFIG_HSPOT__
16418	{"passpoint.asp", "text/html", no_cache, do_apply_post, do_passpoint_asp, do_auth},
16419	{"iconupload.cgi*", "text/html", no_cache, do_uploadIcons_post, do_uploadIcons_cgi, do_auth },
16420#endif /* __CONFIG_HSPOT__ */
16421	{ "security.asp", "text/html", no_cache, do_apply_post, do_security_asp, do_auth },
16422#if defined(__CONFIG_VISUALIZATION__) && defined(CONFIG_VISUALIZATION_ENABLED)
16423	{ "json.cgi*", "application/json", no_cache, vis_do_json_set, vis_do_json_get, do_auth },
16424	{ "visdata.db*", NULL, g_vis_download_db_hdr, NULL, vis_do_visdbdwnld_cgi, do_auth },
16425#endif	/* (__CONFIG_VISUALIZATION__) && (CONFIG_VISUALIZATION_ENABLED) */
16426#ifdef __CONFIG_WPS__
16427	{ "wps.asp", "text/html", no_cache, do_apply_post, do_wps_asp, do_auth },
16428#endif /* __CONFIG_WPS__ */
16429	{ "internal.asp", "text/html", no_cache, do_apply_post, do_internal_asp, do_auth },
16430#ifdef __CONFIG_EZC__
16431	{ "ezconfig.asp", "text/html", ezc_version, do_apply_ezconfig_post, do_ezconfig_asp, do_auth },
16432#endif /* __CONFIG_EZC__ */
16433#if defined(__CONFIG_SAMBA__) || defined(__CONFIG_DLNA_DMS__)
16434	{ "storage.asp", "text/html", no_cache, do_apply_post, do_storage_asp, do_auth },
16435#endif /* __CONFIG_DLNA_DMS__ */
16436	{ "media.asp", "text/html", no_cache, do_apply_post, do_media_asp, do_auth },
16437	{ "**.asp", "text/html", no_cache, NULL, do_ej, do_auth },
16438	{ "**.css", "text/css", NULL, NULL, do_file, do_auth },
16439	{ "**.gif", "image/gif", NULL, NULL, do_file, do_auth },
16440	{ "**.png", "image/png", NULL, NULL, do_file, do_auth },
16441	{ "**.jpg", "image/jpeg", NULL, NULL, do_file, do_auth },
16442	{ "**.ico", "image/ico", NULL, NULL, do_file, do_auth },
16443	{ "**.js", "text/javascript", NULL, NULL, do_file, do_auth },
16444	{ "**apply.cgi*", "text/html", no_cache, do_apply_post, do_apply_cgi, do_auth },
16445	{ "upgrade.cgi*", "text/html", no_cache, do_upgrade_post, do_upgrade_cgi, do_auth },
16446	/* set MIME type to NULL to override the one built into the webserver. download_hdr
16447	   defines its content type
16448	*/
16449	{ "nvramdl.cgi*", NULL, download_hdr, NULL, do_nvramdl_cgi, do_auth },
16450	{ "nvramul.cgi*", NULL, "text/html", do_nvramul_post,do_nvramul_cgi , do_auth },
16451#ifdef __CONFIG_WAPI_IAS__
16452	{ "cert_ul.cgi*", NULL, "text/html", do_cert_ul_post, do_cert_ul_cgi , do_auth },
16453	{ "as_x509_cert_dl.cgi*", NULL, as_cert_download_hdr, NULL, do_as_x509_cert_dl_cgi, do_auth },
16454	{ "user_x509_cert_dl.cgi*", NULL, user_cert_download_hdr, do_apply_post, do_user_x509_cert_dl_cgi, do_auth },
16455#endif /* __CONFIG_WAPI_IAS__ */
16456#ifdef PLC
16457	{ "plc.cgi*", "text/html", no_cache, BcmPostParse, do_plc_cgi, do_auth },
16458	{ "plc-restart.cgi*", "text/html", no_cache, BcmPostParse, do_plc_cgi_restart, do_auth },
16459#endif
16460	{ NULL, NULL, NULL, NULL, NULL, NULL }
16461};
16462
16463struct ej_handler ej_handlers[] = {
16464	{ "nvram_get", ej_nvram_get },
16465	{ "nvram_match", ej_nvram_match },
16466	{ "nvram_match_bitflag", ej_nvram_match_bitflag },
16467	{ "nvram_get_bitflag", ej_nvram_get_bitflag },
16468	{ "nvram_invmatch", ej_nvram_invmatch },
16469	{ "nvram_list", ej_nvram_list },
16470	{ "nvram_inlist", ej_nvram_inlist },
16471	{ "nvram_invinlist", ej_nvram_invinlist },
16472	{ "nvram_indexmatch", ej_nvram_indexmatch },
16473#ifdef __CONFIG_HSPOT__
16474	{ "print_wl_wanmetrics", ej_print_wl_wanmetrics },
16475	{ "print_wl_oplist", ej_print_wl_oplist },
16476	{ "print_wl_homeqlist", ej_print_wl_homeqlist },
16477	{ "print_wl_concaplist", ej_print_wl_concaplist },
16478	{ "print_wl_osuplist", ej_print_wl_osuplist},
16479	{ "print_popup_osup", ej_print_popup_osup},
16480	{ "icon_change", ej_icon_change},
16481	{ "print_iconlist", ej_print_iconlist},
16482	{ "print_wl_qosmapie", ej_print_wl_qosmapie},
16483	/* ---- 802.11u -----------------------------------  */
16484	{ "print_wl_netauthlist", ej_print_wl_netauthlist },
16485	{ "print_wl_realmlist", ej_print_wl_realmlist},
16486	{ "print_popup_realm", ej_print_popup_realm},
16487	{ "authid_change", ej_authid_change},
16488	{ "print_wl_venuegrp_type", ej_print_wl_venuegrp_type},
16489	{ "vanuegrp_change", ej_vanuegrp_change},
16490	{ "print_wl_venuelist", ej_print_wl_venuelist },
16491	{ "print_wl_ouilist", ej_print_wl_ouilist },
16492	{ "print_wl_3gpplist", ej_print_wl_3gpplist },
16493#endif /* __CONFIG_HSPOT__ */
16494#ifdef __CONFIG_NAT__
16495	{ "wan_list", ej_wan_list },
16496	{ "wan_iflist", ej_wan_iflist },
16497	{ "wan_route", ej_wan_route },
16498	{ "wan_link", ej_wan_link },
16499	{ "wan_lease", ej_wan_lease },
16500	{ "filter_client", ej_filter_client },
16501	{ "filter_url", ej_filter_url },
16502	{ "forward_port", ej_forward_port },
16503	{ "autofw_port_display", ej_autofw_port_display },
16504#endif	/*  __CONFIG_NAT__ */
16505	{ "dfs_reentry_display", ej_dfs_reentry_display },
16506	{ "trf_mgmt_display", ej_trf_mgmt_display },
16507	{ "wps_psk_window_display", ej_wps_psk_window_display },
16508	{ "wps_current_psk_window_display", ej_wps_current_psk_window_display },
16509	{ "wps_config_change_display", ej_wps_config_change_display },
16510	{ "wps_display", ej_wps_display },
16511	{ "wps_closed_check_display", ej_wps_closed_check_display },
16512	{ "wps_wep_change_display", ej_wps_wep_change_display },
16513	{ "wps_security_pre_submit_display", ej_wps_security_pre_submit_display },
16514	{ "wps_get_ap_config_submit_display", ej_wps_get_ap_config_submit_display },
16515	{ "wps_akm_change_display", ej_wps_akm_change_display },
16516	{ "wps_refresh", ej_wps_refresh },
16517	{ "localtime", ej_localtime },
16518	{ "sysuptime", ej_sysuptime },
16519	{ "dumplog", ej_dumplog },
16520	{ "syslog", ej_syslog },
16521#if defined(__CONFIG_DLNA_DMS__)
16522	{ "get_mnt_path", ej_get_mnt_path },
16523#endif
16524	{ "wl_list", ej_wl_list },
16525	{ "wl_bssid_list", ej_wl_bssid_list},
16526	{ "wl_get_bridge", ej_wl_get_bridge},
16527	{ "wl_phytypes", ej_wl_phytypes },
16528	{ "wl_radioid", ej_wl_radioid },
16529	{ "wl_corerev", ej_wl_corerev },
16530	{ "wl_cur_chanspec", ej_wl_cur_chanspec },
16531	{ "wl_cur_channel", ej_wl_cur_channel },
16532	{ "wl_cur_bw", ej_wl_cur_bw },
16533	{ "wl_cur_nctrlsb", ej_wl_cur_nctrlsb },
16534	{ "wl_cur_phytype", ej_wl_cur_phytype },
16535	{ "wl_cur_regrev", ej_wl_cur_regrev }, /* add country_rev in config page */
16536	{ "wl_cur_country", ej_wl_cur_country },
16537	{ "wl_country_list", ej_wl_country_list },
16538	{ "wl_country_rev_list", ej_wl_country_rev_list }, /* add country_rev in config page */
16539	{ "wl_chanspec_list", ej_wl_chanspec_list },
16540	{ "wl_auth_list", ej_wl_auth_list },
16541	{ "wl_mode_list", ej_wl_mode_list },
16542	{ "wl_bw_cap_list", ej_wl_bw_cap_list},
16543	{ "wl_inlist", ej_wl_inlist },
16544	{ "wl_wds_status", ej_wl_wds_status },
16545	{ "wl_radio_roam_option", ej_wl_radio_roam_option},
16546	{ "wl_ure_list", ej_ure_list },
16547	{ "wl_ure_enabled", ej_ure_enabled },
16548	{ "wl_ure_any_enabled", ej_ure_any_enabled },
16549	{ "wl_ibss_mode", ej_wl_ibss_mode },
16550	{ "ses_button_display", ej_ses_button_display},
16551	{ "ses_cl_button_display", ej_ses_cl_button_display},
16552	{ "ses_wds_mode_list", ej_ses_wds_mode_list},
16553	{ "wl_nphyrates", ej_wl_nphyrates },
16554	{ "wl_txchains_list", ej_wl_txchains_list },
16555	{ "wl_rxchains_list", ej_wl_rxchains_list },
16556	{ "wl_cur_band", ej_wl_cur_band },
16557	{ "wl_nmode_enabled", ej_wl_nmode_enabled },
16558	{ "wl_nphy_set", ej_wl_nphy_set },
16559	{ "wl_nphy_comment_beg", ej_wl_nphy_comment_beg },
16560	{ "wl_nphy_comment_end", ej_wl_nphy_comment_end },
16561	{ "wl_phytype_name", ej_wl_phytype_name },
16562	{ "wl_protection", ej_wl_protection },
16563	{ "wl_mimo_preamble", ej_wl_mimo_preamble },
16564	{ "wl_legacy_string", ej_wl_legacy_string },
16565	{ "wl_crypto", ej_wl_crypto },
16566	{ "wl_wep", ej_wl_wep },
16567	{ "lan_route", ej_lan_route },
16568	{ "emf_enable_display", ej_emf_enable_display },
16569	{ "emf_entries_display", ej_emf_entries_display },
16570	{ "emf_uffp_entries_display", ej_emf_uffp_entries_display },
16571	{ "emf_rtport_entries_display", ej_emf_rtport_entries_display },
16572	{ "lan_guest_iflist", ej_lan_guest_iflist },
16573	{ "lan_leases", ej_lan_leases },
16574	{ "asp_list", ej_asp_list },
16575	{ "kernel_version", ej_kernel_version },
16576#ifdef __CONFIG_WAPI_IAS__
16577	{ "as_cer_display", ej_as_cer_display },
16578#endif
16579/*
16580*/
16581#ifdef __CONFIG_WFI__
16582	{ "wl_invite_list", ej_wl_invite_list },
16583	{ "wl_wfi_mode", ej_wl_wfi_mode },
16584#endif	/*  __CONFIG_WFI__ */
16585/*
16586*/
16587#ifdef PLC
16588	{ "ggl_avln_list", ej_ggl_get_avln_list },
16589	{ "ggl_get_version", ej_ggl_cgi_version },
16590	{ "ggl_plc_get_autoconf_root", ej_ggl_plc_get_autoconf_root },
16591	{ "ggl_plc_get_info", ej_ggl_plc_get_info },
16592	{ "ggl_plc_get_mac", ej_ggl_plc_get_mac },
16593	{ "ggl_plc_get_nets", ej_ggl_plc_get_nets },
16594	{ "ggl_plc_get_nick", ej_ggl_plc_get_nick },
16595	{ "ggl_plc_get_role", ej_ggl_plc_get_role },
16596	{ "ggl_plc_get_stas", ej_ggl_plc_get_stas },
16597	{ "ggl_plc_get_uptime", ej_ggl_plc_get_uptime },
16598#endif
16599	{ "wl_auth_display", ej_wl_auth_display },
16600	{ "wet_tunnel_display", ej_wet_tunnel_display },
16601#ifdef TRAFFIC_MGMT_RSSI_POLICY
16602	{ "trf_mgmt_rssi_policy_display", ej_trf_mgmt_rssi_policy_display },
16603#endif /* TRAFFIC_MGMT_RSSI_POLICY */
16604	{ "wl_txbf_capable", ej_wl_txbf_capable },
16605	{ "trf_mgmt_dwm_display", ej_trf_mgmt_dwm_display },
16606	{ NULL, NULL }
16607};
16608
16609#endif /* !WEBS */
16610
16611/*
16612 * Country names and abbreviations from ISO 3166
16613 */
16614country_name_t country_names[] = {
16615
16616{"COUNTRY Z1",		 "Z1"},
16617{"COUNTRY Z2",		 "Z2"},
16618{"AFGHANISTAN",		 "AF"},
16619{"ALBANIA",		 "AL"},
16620{"ALGERIA",		 "DZ"},
16621{"AMERICAN SAMOA", 	 "AS"},
16622{"ANDORRA",		 "AD"},
16623{"ANGOLA",		 "AO"},
16624{"ANGUILLA",		 "AI"},
16625{"ANTARCTICA",		 "AQ"},
16626{"ANTIGUA AND BARBUDA",	 "AG"},
16627{"ARGENTINA",		 "AR"},
16628{"ARMENIA",		 "AM"},
16629{"ARUBA",		 "AW"},
16630{"ASCENSION ISLAND",		 "AC"},
16631{"ASHMORE AND BARBUDA",		 "AG"},
16632{"AUSTRALIA",		 "AU"},
16633{"AUSTRIA",		 "AT"},
16634{"AZERBAIJAN",		 "AZ"},
16635{"BAHAMAS",		 "BS"},
16636{"BAHRAIN",		 "BH"},
16637{"BAKER ISLAND",		 "Z2"},
16638{"BANGLADESH",		 "BD"},
16639{"BARBADOS",		 "BB"},
16640{"BELARUS",		 "BY"},
16641{"BELGIUM",		 "BE"},
16642{"BELIZE",		 "BZ"},
16643{"BENIN",		 "BJ"},
16644{"BERMUDA",		 "BM"},
16645{"BHUTAN",		 "BT"},
16646{"BOLIVIA",		 "BO"},
16647{"BOSNIA AND HERZEGOVINA","BA"},
16648{"BOTSWANA",		 "BW"},
16649{"BOUVET ISLAND",	 "BV"},
16650{"BRAZIL",		 "BR"},
16651{"BRITISH INDIAN OCEAN TERRITORY", 	"IO"},
16652{"BRUNEI DARUSSALAM",	 "BN"},
16653{"BULGARIA",		 "BG"},
16654{"BURKINA FASO",	 "BF"},
16655{"BURUNDI",		 "BI"},
16656{"CAMBODIA",		 "KH"},
16657{"CAMEROON",		 "CM"},
16658{"CANADA",		 "CA"},
16659{"CAPE VERDE",		 "CV"},
16660{"CAYMAN ISLANDS",	 "KY"},
16661{"CENTRAL AFRICAN REPUBLIC","CF"},
16662{"CHAD",		 "TD"},
16663{"CHANNEL ISLANDS",		 "Z1"},
16664{"CHILE",		 "CL"},
16665{"CHINA",		 "CN"},
16666{"CHRISTMAS ISLAND",	 "CX"},
16667{"CLIPPERTON ISLAND",	 "CP"},
16668{"COCOS (KEELING) ISLANDS","CC"},
16669{"COLOMBIA",		 "CO"},
16670{"COMOROS",		 "KM"},
16671{"CONGO",		 "CG"},
16672{"CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD"},
16673{"COOK ISLANDS",	 "CK"},
16674{"COSTA RICA",		 "CR"},
16675{"COTE D'IVOIRE",	 "CI"},
16676{"CROATIA",		 "HR"},
16677{"CUBA",		 "CU"},
16678{"CYPRUS",		 "CY"},
16679{"CZECH REPUBLIC",	 "CZ"},
16680{"DENMARK",		 "DK"},
16681{"DIEGO GARCIA",	 "Z1"},
16682{"DJIBOUTI",		 "DJ"},
16683{"DOMINICA",		 "DM"},
16684{"DOMINICAN REPUBLIC", 	 "DO"},
16685{"ECUADOR",		 "EC"},
16686{"EGYPT",		 "EG"},
16687{"EL SALVADOR",		 "SV"},
16688{"EQUATORIAL GUINEA",	 "GQ"},
16689{"ERITREA",		 "ER"},
16690{"ESTONIA",		 "EE"},
16691{"ETHIOPIA",		 "ET"},
16692{"FALKLAND ISLANDS (MALVINAS)",	"FK"},
16693{"FAROE ISLANDS",	 "FO"},
16694{"FIJI",		 "FJ"},
16695{"FINLAND",		 "FI"},
16696{"FRANCE",		 "FR"},
16697{"FRENCH GUIANA",	 "GF"},
16698{"FRENCH POLYNESIA",	 "PF"},
16699{"FRENCH SOUTHERN TERRITORIES",	 "TF"},
16700{"GABON",		 "GA"},
16701{"GAMBIA",		 "GM"},
16702{"GEORGIA",		 "GE"},
16703{"GERMANY",		 "DE"},
16704{"GHANA",		 "GH"},
16705{"GIBRALTAR",		 "GI"},
16706{"GREECE",		 "GR"},
16707{"GREENLAND",		 "GL"},
16708{"GRENADA",		 "GD"},
16709{"GUADELOUPE",		 "GP"},
16710{"GUAM",		 "GU"},
16711{"GUANTANAMO BAY",		 "Z1"},
16712{"GUATEMALA",		 "GT"},
16713{"GUERNSEY",		 "GG"},
16714{"GUINEA",		 "GN"},
16715{"GUINEA-BISSAU",	 "GW"},
16716{"GUYANA",		 "GY"},
16717{"HAITI",		 "HT"},
16718{"HEARD ISLAND AND MCDONALD ISLANDS",	"HM"},
16719{"HOLY SEE (VATICAN CITY STATE)", 	"VA"},
16720{"HONDURAS",		 "HN"},
16721{"HONG KONG",		 "HK"},
16722{"HOWLAND ISLAND",		 "Z2"},
16723{"HUNGARY",		 "HU"},
16724{"ICELAND",		 "IS"},
16725{"INDIA",		 "IN"},
16726{"INDONESIA",		 "ID"},
16727{"IRAN, ISLAMIC REPUBLIC OF",		"IR"},
16728{"IRAQ",		 "IQ"},
16729{"IRELAND",		 "IE"},
16730{"ISRAEL",		 "IL"},
16731{"ITALY",		 "IT"},
16732{"JAMAICA",		 "JM"},
16733{"JAN MAYEN AMAICA",		 "Z1"},
16734{"JAPAN",		 "JP"},
16735{"JAPAN_1",		 "J1"},
16736{"JAPAN_2",		 "J2"},
16737{"JAPAN_3",		 "J3"},
16738{"JAPAN_4",		 "J4"},
16739{"JAPAN_5",		 "J5"},
16740{"JAPAN_6",		 "J6"},
16741{"JAPAN_7",		 "J7"},
16742{"JAPAN_8",		 "J8"},
16743{"JARVIS ISLAND",		 "Z2"},
16744{"JERSEY",		 "JE"},
16745{"JOHNSTON ATOLL",		 "Z2"},
16746{"JORDON",		 "JO"},
16747{"KAZAKHSTAN",		 "KZ"},
16748{"KENYA",		 "KE"},
16749{"KINGMAN REEF",		 "Z2"},
16750{"KIRIBATI",		 "KI"},
16751{"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP"},
16752{"KOREA, REPUBLIC OF",	 "KR"},
16753{"KUWAIT",		 "KW"},
16754{"KYRGYZSTAN",		 "KG"},
16755{"LAO PEOPLE'S DEMOCRATIC REPUBLIC", 	"LA"},
16756{"LATVIA",		 "LV"},
16757{"LEBANON",		 "LB"},
16758{"LESOTHO",		 "LS"},
16759{"LIBERIA",		 "LR"},
16760{"LIBYAN ARAB JAMAHIRIYA","LY"},
16761{"LIECHTENSTEIN",	 "LI"},
16762{"LITHUANIA",		 "LT"},
16763{"LUXEMBOURG",		 "LU"},
16764{"MACAO",		 "MO"},
16765{"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF",	 "MK"},
16766{"MADAGASCAR",		 "MG"},
16767{"MALAWI",		 "MW"},
16768{"MALAYSIA",		 "MY"},
16769{"MALDIVES",		 "MV"},
16770{"MALI",		 "ML"},
16771{"MALTA",		 "MT"},
16772{"MAN, ISLE OF",		 "IM"},
16773{"MARSHALL ISLANDS",	 "MH"},
16774{"MARTINIQUE",		 "MQ"},
16775{"MAURITANIA",		 "MR"},
16776{"MAURITIUS",		 "MU"},
16777{"MAYOTTE",		 "YT"},
16778{"MEXICO",		 "MX"},
16779{"MICRONESIA, FEDERATED STATES OF", 	"FM"},
16780{"MIDWAY ISLANDS", 	"Z2"},
16781{"MOLDOVA, REPUBLIC OF", "MD"},
16782{"MONACO",		 "MC"},
16783{"MONGOLIA",		 "MN"},
16784{"MONTSERRAT",		 "MS"},
16785{"MOROCCO",		 "MA"},
16786{"MOZAMBIQUE",		 "MZ"},
16787{"MYANMAR",		 "MM"},
16788{"NAMIBIA",		 "NA"},
16789{"NAURU",		 "NR"},
16790{"NEPAL",		 "NP"},
16791{"NETHERLANDS",		 "NL"},
16792{"NETHERLANDS ANTILLES", "AN"},
16793{"NEW CALEDONIA",	 "NC"},
16794{"NEW ZEALAND",		 "NZ"},
16795{"NICARAGUA",		 "NI"},
16796{"NIGER",		 "NE"},
16797{"NIGERIA",		 "NG"},
16798{"NIUE",		 "NU"},
16799{"NORFOLK ISLAND",	 "NF"},
16800{"NORTHERN MARIANA ISLANDS","MP"},
16801{"NORWAY",		 "NO"},
16802{"OMAN",		 "OM"},
16803{"PAKISTAN",		 "PK"},
16804{"PALAU",		 "PW"},
16805{"PALESTINIAN TERRITORY, OCCUPIED", 	"PS"},
16806{"PALMYRA ATOLL", 	"Z2"},
16807{"PANAMA",		 "PA"},
16808{"PAPUA NEW GUINEA",	 "PG"},
16809{"PARAGUAY",		 "PY"},
16810{"PERU",		 "PE"},
16811{"PHILIPPINES",		 "PH"},
16812{"PITCAIRN",		 "PN"},
16813{"POLAND",		 "PL"},
16814{"PORTUGAL",		 "PT"},
16815{"PUERTO RICO",		 "PR"},
16816{"QATAR",		 "QA"},
16817{"Q1",		 "Q1"},
16818{"REUNION",		 "RE"},
16819{"ROMANIA",		 "RO"},
16820{"ROTA ISLAND",		 "Z1"},
16821{"RUSSIAN FEDERATION",	 "RU"},
16822{"RWANDA",		 "RW"},
16823{"SAINT HELENA",	 "SH"},
16824{"SAINT KITTS AND NEVIS","KN"},
16825{"SAINT LUCIA",		 "LC"},
16826{"SAINT PIERRE AND MIQUELON",	 	"PM"},
16827{"SAINT VINCENT AND THE GRENADINES", 	"VC"},
16828{"SAIPAN", 	"Z1"},
16829{"SAMOA",		 "WS"},
16830{"SAN MARINO",		 "SM"},
16831{"SAO TOME AND PRINCIPE","ST"},
16832{"SAUDI ARABIA",	 "SA"},
16833{"SENEGAL",		 "SN"},
16834{"SEYCHELLES",		 "SC"},
16835{"SIERRA LEONE",	 "SL"},
16836{"SINGAPORE",		 "SG"},
16837{"SLOVAKIA",		 "SK"},
16838{"SLOVENIA",		 "SI"},
16839{"SOLOMON ISLANDS",	 "SB"},
16840{"SOMALIA",		 "SO"},
16841{"SOUTH AFRICA",	 "ZA"},
16842{"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS"},
16843{"SPAIN",		 "ES"},
16844{"SRI LANKA",		 "LK"},
16845{"SUDAN",		 "SD"},
16846{"SURINAME",		 "SR"},
16847{"SVALBARD AND JAN MAYEN","SJ"},
16848{"SWAZILAND",		 "SZ"},
16849{"SWEDEN",		 "SE"},
16850{"SWITZERLAND",		 "CH"},
16851{"SYRIAN ARAB REPUBLIC", "SY"},
16852{"TAIWAN, PROVINCE OF CHINA", 		"TW"},
16853{"TAJIKISTAN",		 "TJ"},
16854{"TANZANIA, UNITED REPUBLIC OF",	"TZ"},
16855{"THAILAND",		 "TH"},
16856{"TIMOR-LESTE",		 "TL"},
16857{"TINIAN ISLAND",	 "Z1"},
16858{"TOGO",		 "TG"},
16859{"TOKELAU",		 "TK"},
16860{"TONGA",		 "TO"},
16861{"TRINIDAD AND TOBAGO",	 "TT"},
16862{"TRISTAN DA CUNHA",	 "TA"},
16863{"TUNISIA",		 "TN"},
16864{"TURKEY",		 "TR"},
16865{"TURKMENISTAN",	 "TM"},
16866{"TURKS AND CAICOS ISLANDS",		"TC"},
16867{"TUVALU",		 "TV"},
16868{"UGANDA",		 "UG"},
16869{"UKRAINE",		 "UA"},
16870{"UNITED ARAB EMIRATES", "AE"},
16871{"UNITED KINGDOM",	 "GB"},
16872{"UNITED STATES",	 "US"},
16873{"UNITED STATES MINOR OUTLYING ISLANDS","UM"},
16874{"URUGUAY",		 "UY"},
16875{"UZBEKISTAN",		 "UZ"},
16876{"VANUATU",		 "VU"},
16877{"VENEZUELA",		 "VE"},
16878{"VIET NAM",		 "VN"},
16879{"VIRGIN ISLANDS, BRITISH", "VG"},
16880{"VIRGIN ISLANDS, U.S.", "VI"},
16881{"WAKE ISLAND", 	 "Z1"},
16882{"WALLIS AND FUTUNA",	 "WF"},
16883{"WESTERN SAHARA", 	 "EH"},
16884{"YEMEN",		 "YE"},
16885{"YUGOSLAVIA",		 "YU"},
16886{"ZAMBIA",		 "ZM"},
16887{"ZIMBABWE",		 "ZW"},
16888{"ALL",		 	 "ALL"},
16889{"RADAR CHANNELS",	 "RDR"},
16890{"XA (EUROPE / APAC 2005)",      "XA"},
16891{"XB (NORTH AND SOUTH AMERICA AND TAIWAN)",      "XB"},
16892{"X0 (FCC WORLDWIDE)",   "X0"},
16893{"X1 (WORLDWIDE APAC)",  "X1"},
16894{"X2 (WORLDWIDE ROW 2)", "X2"},
16895{"X3 (ETSI)",            "X3"},
16896{"EU (EUROPEAN UNION)",  "EU"},
16897{"XW (WORLDWIDE LOCALE FOR LINUX DRIVER)",       "XW"},
16898{"XX (WORLDWIDE LOCALE (PASSIVE Ch12-14))",      "XX"},
16899{"XY (FAKE COUNTRY CODE)",       "XY"},
16900{"XZ (WORLDWIDE LOCALE (PASSIVE Ch12-14))",      "XZ"},
16901{"XU (EUROPEAN LOCALE 0dBi ANTENNA IN 2.4GHz)",  "XU"},
16902{"XV (WORLDWIDE SAFE MODE LOCALE (PASSIVE Ch12-14))",    "XV"},
16903{"XT (SINGLE SKU fOR PC-OEMs)",  "XT"},
16904{NULL, 			 NULL}
16905};
16906