1/*
2 * Broadcom Home Gateway Reference Design
3 * Web Page Configuration Support Routines
4 *
5 * Copyright 2004, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: broadcom.c,v 1.1.1.1 2008/10/15 03:31:33 james26_jang Exp $
13 */
14
15#ifdef WEBS
16#include <webs.h>
17#include <uemf.h>
18#include <ej.h>
19#else /* !WEBS */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <ctype.h>
24#include <errno.h>
25#include <unistd.h>
26#include <limits.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <assert.h>
33#include <httpd.h>
34
35extern int conn_fd;
36#endif /* WEBS */
37
38
39#include <typedefs.h>
40#include <proto/ethernet.h>
41#include <bcmnvram.h>
42#include <bcmutils.h>
43#include <shutils.h>
44#include <netconf.h>
45#include <nvparse.h>
46#include <wlutils.h>
47
48static char * rfctime(const time_t *timep);
49static char * reltime(unsigned int seconds);
50
51#define wan_prefix(unit, prefix)	snprintf(prefix, sizeof(prefix), "wan%d_", unit)
52
53/* For Backup/Restore settings */
54#define BACKUP_SETTING_FILENAME	"s5config.dat"
55
56/*
57 * Country names and abbreviations from ISO 3166
58 */
59typedef struct {
60	char *name;     /* Long name */
61	char *abbrev;   /* Abbreviation */
62} country_name_t;
63country_name_t country_names[];     /* At end of this file */
64
65//char ibuf[WLC_IOCTL_MAXLEN];
66//char ibuf2[WLC_IOCTL_MAXLEN];
67static int ezc_error = 0;
68
69struct variable {
70	char *name;
71	char *longname;
72	void (*validate)(webs_t wp, char *value, struct variable *v);
73	char **argv;
74	int nullok;
75	int ezc_flags;
76};
77
78struct variable variables[];
79extern struct nvram_tuple router_defaults[];
80
81#define ARGV(args...) ((char *[]) { args, NULL })
82#define XSTR(s) STR(s)
83#define STR(s) #s
84
85enum {
86	NOTHING,
87	REBOOT,
88	RESTART,
89};
90
91#define EZC_FLAGS_READ		0x0001
92#define EZC_FLAGS_WRITE		0x0002
93#define EZC_FLAGS_CRYPT		0x0004
94
95#define EZC_CRYPT_KEY		"620A83A6960E48d1B05D49B0288A2C1F"
96
97#define EZC_SUCCESS	 	0
98#define EZC_ERR_NOT_ENABLED 	1
99#define EZC_ERR_INVALID_STATE 	2
100#define EZC_ERR_INVALID_DATA 	3
101#ifndef NOUSB
102static const char * const apply_header =
103"<head>"
104"<title>Broadcom Home Gateway Reference Design: Apply</title>"
105"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
106"<style type=\"text/css\">"
107"body { background: white; color: black; font-family: arial, sans-serif; font-size: 9pt }"
108".title	{ font-family: arial, sans-serif; font-size: 13pt; font-weight: bold }"
109".subtitle { font-family: arial, sans-serif; font-size: 11pt }"
110".label { color: #306498; font-family: arial, sans-serif; font-size: 7pt }"
111"</style>"
112"</head>"
113"<body>"
114"<p>"
115"<span class=\"title\">APPLY</span><br>"
116"<span class=\"subtitle\">This screen notifies you of any errors "
117"that were detected while changing the router's settings.</span>"
118"<form method=\"get\" action=\"apply.cgi\">"
119"<p>"
120;
121
122static const char * const apply_footer =
123"<p>"
124"<input type=\"button\" name=\"action\" value=\"Continue\" OnClick=\"document.location.href='%s';\">"
125"</form>"
126"<p class=\"label\">&#169;2001-2004 Broadcom Corporation. All rights reserved.</p>"
127"</body>"
128;
129#endif
130
131#if defined(linux)
132
133#include <fcntl.h>
134#include <signal.h>
135#include <time.h>
136#include <sys/klog.h>
137#include <sys/wait.h>
138#include <sys/ioctl.h>
139#include <net/if.h>
140
141typedef u_int64_t u64;
142typedef u_int32_t u32;
143typedef u_int16_t u16;
144typedef u_int8_t u8;
145#include <linux/ethtool.h>
146#include <linux/sockios.h>
147#include <net/if_arp.h>
148
149#define sys_restart() kill(1, SIGHUP)
150#define sys_reboot() kill(1, SIGTERM)
151#define sys_stats(url) eval("stats", (url))
152
153#ifndef WEBS
154
155#define MIN_BUF_SIZE	4096
156
157/* Upgrade from remote server or socket stream */
158static int
159sys_upgrade(char *url, FILE *stream, int *total)
160{
161	char upload_fifo[] = "/tmp/uploadXXXXXX";
162	FILE *fifo = NULL;
163	char *write_argv[] = { "write", upload_fifo, "linux", NULL };
164	pid_t pid;
165	char *buf = NULL;
166	int count, ret = 0;
167	long flags = -1;
168	int size = BUFSIZ;
169
170	if (url)
171		return eval("write", url, "linux");
172
173	/* Feed write from a temporary FIFO */
174	if (!mktemp(upload_fifo) ||
175	    mkfifo(upload_fifo, S_IRWXU) < 0||
176	    (ret = _eval(write_argv, NULL, 0, &pid)) ||
177	    !(fifo = fopen(upload_fifo, "w"))) {
178		if (!ret)
179			ret = errno;
180		goto err;
181	}
182
183	/* Set nonblock on the socket so we can timeout */
184	/*if ((flags = fcntl(fileno(stream), F_GETFL)) < 0 ||
185	    fcntl(fileno(stream), F_SETFL, flags | O_NONBLOCK) < 0) {//*/
186	if ((flags = fcntl(conn_fd, F_GETFL)) < 0 ||
187	    fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
188		ret = errno;
189		goto err;
190	}
191
192	/*
193	* The buffer must be at least as big as what the stream file is
194	* using so that it can read all the data that has been buffered
195	* in the stream file. Otherwise it would be out of sync with fn
196	* select specially at the end of the data stream in which case
197	* the select tells there is no more data available but there in
198	* fact is data buffered in the stream file's buffer. Since no
199	* one has changed the default stream file's buffer size, let's
200	* use the constant BUFSIZ until someone changes it.
201	*/
202	if (size < MIN_BUF_SIZE)
203		size = MIN_BUF_SIZE;
204	if ((buf = malloc(size)) == NULL) {
205		ret = ENOMEM;
206		goto err;
207	}
208
209	/* Pipe the rest to the FIFO */
210	cprintf("Upgrading");
211	while (total && *total) {
212		//if (waitfor(fileno(stream), 5) <= 0)
213		if (waitfor(conn_fd, 5) <= 0)
214			break;
215		count = safe_fread(buf, 1, size, stream);
216		if (!count && (ferror(stream) || feof(stream)))
217			break;
218		*total -= count;
219		safe_fwrite(buf, 1, count, fifo);
220		cprintf(".");
221	}
222	fclose(fifo);
223	fifo = NULL;
224
225	/* Wait for write to terminate */
226	waitpid(pid, &ret, 0);
227	cprintf("done\n");
228
229	/* Reset nonblock on the socket */
230	//if (fcntl(fileno(stream), F_SETFL, flags) < 0) {
231	if (fcntl(conn_fd, F_SETFL, flags) < 0) {
232		ret = errno;
233		goto err;
234	}
235
236 err:
237 	if (buf)
238		free(buf);
239	if (fifo)
240		fclose(fifo);
241	unlink(upload_fifo);
242	return ret;
243}
244
245#endif
246
247int
248sys_send_signal(char *pidfile, int sig)
249{
250
251	FILE *fp;
252	pid_t pid;
253	fp=fopen(pidfile,"r");
254	if (fp!=NULL)
255	{
256	    	fscanf(fp, "%d", &pid);
257	    	kill(pid, sig);
258	    	fclose(fp);
259		return 0;
260	}
261	return 1;
262}
263
264void
265sys_refresh_lease(void)
266{
267	char sigusr1[] = "-XX";
268
269	/* Write out leases file */
270	sprintf(sigusr1, "-%d", SIGUSR1);
271	eval("killall", sigusr1, "udhcpd");
272}
273
274/* Dump firewall log */
275static int
276ej_dumplog(int eid, webs_t wp, int argc, char_t **argv)
277{
278	char buf[4096], *line, *next, *s;
279	int len, ret = 0;
280
281	time_t tm;
282	char *verdict, *src, *dst, *proto, *spt, *dpt;
283
284	if (klogctl(3, buf, 4096) < 0) {
285		websError(wp, 400, "Insufficient memory\n");
286		return -1;
287	}
288
289	for (next = buf; (line = strsep(&next, "\n"));) {
290		if (!strncmp(line, "<4>DROP", 7))
291			verdict = "denied";
292		else if (!strncmp(line, "<4>ACCEPT", 9))
293			verdict = "accepted";
294		else
295			continue;
296
297		/* Parse into tokens */
298		s = line;
299		len = strlen(s);
300		while (strsep(&s, " "));
301
302		/* Initialize token values */
303		time(&tm);
304		src = dst = proto = spt = dpt = "n/a";
305
306		/* Set token values */
307		for (s = line; s < &line[len] && *s; s += strlen(s) + 1) {
308			if (!strncmp(s, "TIME=", 5))
309				tm = strtoul(&s[5], NULL, 10);
310			else if (!strncmp(s, "SRC=", 4))
311				src = &s[4];
312			else if (!strncmp(s, "DST=", 4))
313				dst = &s[4];
314			else if (!strncmp(s, "PROTO=", 6))
315				proto = &s[6];
316			else if (!strncmp(s, "SPT=", 4))
317				spt = &s[4];
318			else if (!strncmp(s, "DPT=", 4))
319				dpt = &s[4];
320		}
321
322		ret += websWrite(wp, "%s %s connection %s to %s:%s from %s:%s\n",
323				 rfctime(&tm), proto, verdict, dst, dpt, src, spt);
324		ret += websWrite(wp, "<br>");
325	}
326
327	return ret;
328}
329
330struct lease_t {
331	unsigned char chaddr[16];
332	u_int32_t yiaddr;
333	u_int32_t expires;
334	char hostname[64];
335};
336
337/* Dump leases in <tr><td>hostname</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
338int
339ej_lan_leases(int eid, webs_t wp, int argc, char_t **argv)
340{
341	FILE *fp = NULL;
342	struct lease_t lease;
343	int i;
344	struct in_addr addr;
345	unsigned long expires = 0;
346	int ret = 0;
347
348        ret += websWrite(wp, "Host Name       Mac Address       IP Address      Lease\n");
349
350	/* Write out leases file */
351	if (!(fp = fopen("/tmp/udhcpd-br0.leases", "r")))
352		return ret;
353
354	while (fread(&lease, sizeof(lease), 1, fp)) {
355		/* Do not display reserved leases */
356		if (ETHER_ISNULLADDR(lease.chaddr))
357			continue;
358
359		//printf("lease: %s %d\n", lease.hostname, strlen(lease.hostname));
360		ret += websWrite(wp, "%-16s", lease.hostname);
361		for (i = 0; i < 6; i++) {
362			ret += websWrite(wp, "%02X", lease.chaddr[i]);
363			if (i != 5) ret += websWrite(wp, ":");
364		}
365		addr.s_addr = lease.yiaddr;
366		ret += websWrite(wp, " %-15s ", inet_ntoa(addr));
367		expires = ntohl(lease.expires);
368
369		if (expires==0xffffffff) ret += websWrite(wp, "Manual\n");
370		else if (!expires) ret += websWrite(wp, "Expired\n");
371		else ret += websWrite(wp, "%s\n", reltime(expires));
372	}
373	fclose(fp);
374
375#ifdef GUEST_ACCOUNT
376	if(nvram_invmatch("wl_guest_enable", "1")) return ret;
377
378	/* Write out leases file */
379	if (!(fp = fopen("/tmp/udhcpd-br1.leases", "r")))
380		return ret;
381
382	while (fread(&lease, sizeof(lease), 1, fp)) {
383		/* Do not display reserved leases */
384		if (ETHER_ISNULLADDR(lease.chaddr))
385			continue;
386
387		//printf("lease: %s %d\n", lease.hostname, strlen(lease.hostname));
388		ret += websWrite(wp, "%-16s", lease.hostname);
389		for (i = 0; i < 6; i++) {
390			ret += websWrite(wp, "%02X", lease.chaddr[i]);
391			if (i != 5) ret += websWrite(wp, ":");
392		}
393		addr.s_addr = lease.yiaddr;
394		ret += websWrite(wp, " %-15s ", inet_ntoa(addr));
395		expires = ntohl(lease.expires);
396
397		if (expires==0xffffffff) ret += websWrite(wp, "Manual\n");
398		else if (!expires) ret += websWrite(wp, "Expired\n");
399		else ret += websWrite(wp, "%s\n", reltime(expires));
400	}
401	fclose(fp);
402#endif
403
404	return ret;
405}
406
407/* Renew lease */
408int
409sys_renew(void)
410{
411	int unit;
412	char tmp[100];
413	char *str;
414	int pid;
415
416	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
417		unit = 0;
418
419#ifdef REMOVE
420	snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit);
421	if ((str = file2str(tmp))) {
422		pid = atoi(str);
423		free(str);
424		return kill(pid, SIGUSR1);
425	}
426	return -1;
427#else
428	snprintf(tmp, sizeof(tmp), "wan_connect,%d", unit);
429	nvram_set("rc_service", tmp);
430	kill(1, SIGUSR1);
431	return 0;
432#endif
433}
434
435/* Release lease */
436int
437sys_release(void)
438{
439	int unit;
440	char tmp[100];
441	char *str;
442	int pid;
443
444	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
445		unit = 0;
446
447#ifdef REMOVE
448	snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit);
449	if ((str = file2str(tmp))) {
450		pid = atoi(str);
451		free(str);
452		return kill(pid, SIGUSR2);
453	}
454	return -1;
455#else
456	snprintf(tmp, sizeof(tmp), "wan_disconnect,%d", unit);
457	nvram_set("rc_service", tmp);
458	kill(1, SIGUSR1);
459	return 0;
460#endif
461}
462
463#ifndef NOUSB
464static int
465wan_restore_mac(webs_t wp)
466{
467	char tmp[50], tmp2[50], prefix[] = "wanXXXXXXXXXX_", *t2;
468	int unit, errf = -1;
469	char wan_ea[ETHER_ADDR_LEN];
470
471	unit = atoi(websGetVar(wp, "wan_unit", NULL));
472	if (unit >= 0)
473	{
474		strcpy(tmp2, nvram_safe_get("wan_ifname"));
475		if (!strncmp(tmp2, "eth", 3))
476		{
477			sprintf(tmp, "et%dmacaddr", atoi(tmp2 + 3));
478			t2 = nvram_safe_get(tmp);
479			if (t2 && t2[0] != 0)
480			{
481				ether_atoe(t2, wan_ea);
482				ether_etoa(wan_ea, tmp2);
483				wan_prefix(unit, prefix);
484				nvram_set("wan_hwaddr", tmp2);
485				nvram_set(strcat_r(prefix, "hwaddr", tmp), tmp2);
486				nvram_commit();
487				errf = 0;
488			}
489		}
490	}
491
492	return errf;
493}
494
495#define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
496
497/* Return WAN link state */
498static int
499ej_wan_link(int eid, webs_t wp, int argc, char_t **argv)
500{
501	char *wan_ifname;
502	int s;
503	struct ifreq ifr;
504	struct ethtool_cmd ecmd;
505	FILE *fp;
506	int unit;
507	char tmp[100], prefix[] = "wanXXXXXXXXXX_";
508
509	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
510		unit = 0;
511	wan_prefix(unit, prefix);
512
513	/* non-exist and disabled */
514	if (nvram_match(strcat_r(prefix, "proto", tmp), "") ||
515	    nvram_match(strcat_r(prefix, "proto", tmp), "disabled")) {
516		return websWrite(wp, "N/A");
517	}
518	/* PPPoE connection status */
519	else if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) {
520		wan_ifname = nvram_safe_get(strcat_r(prefix, "pppoe_ifname", tmp));
521		if ((fp = fopen(strcat_r("/tmp/ppp/link.", wan_ifname, tmp), "r"))) {
522			fclose(fp);
523			return websWrite(wp, "Connected");
524		} else
525			return websWrite(wp, "Disconnected");
526	}
527	/* Get real interface name */
528	else
529		wan_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
530
531	/* Open socket to kernel */
532	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
533		return websWrite(wp, "N/A");
534
535	/* Check for hardware link */
536	strncpy(ifr.ifr_name, wan_ifname, IFNAMSIZ);
537	ifr.ifr_data = (void *) &ecmd;
538	ecmd.cmd = ETHTOOL_GSET;
539	if (ioctl(s, SIOCETHTOOL, &ifr) < 0) {
540		close(s);
541		return websWrite(wp, "Unknown");
542	}
543	if (!ecmd.speed) {
544		close(s);
545		return websWrite(wp, "Disconnected");
546	}
547
548	/* Check for valid IP address */
549	strncpy(ifr.ifr_name, wan_ifname, IFNAMSIZ);
550	if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
551		close(s);
552		return websWrite(wp, "Connecting");
553	}
554
555	/* Otherwise we are probably configured */
556	close(s);
557	return websWrite(wp, "Connected");
558}
559
560/* Display IP Address lease */
561static int
562ej_wan_lease(int eid, webs_t wp, int argc, char_t **argv)
563{
564	unsigned long expires = 0;
565	int ret = 0;
566	int unit;
567	char tmp[100], prefix[] = "wanXXXXXXXXXX_";
568
569	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
570		unit = 0;
571	wan_prefix(unit, prefix);
572
573	if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) {
574		char *str;
575		time_t now;
576
577		snprintf(tmp, sizeof(tmp), "/tmp/udhcpc%d.expires", unit);
578		if ((str = file2str(tmp))) {
579			expires = atoi(str);
580			free(str);
581		}
582		time(&now);
583		if (expires <= now)
584			ret += websWrite(wp, "Expired");
585		else
586			ret += websWrite(wp, "%s", reltime(expires - now));
587	} else
588		ret += websWrite(wp, "N/A");
589
590	return ret;
591}
592
593
594/* Return a list of wan interfaces (eth0/eth1/eth2/eth3) */
595static int
596ej_wan_iflist(int eid, webs_t wp, int argc, char_t **argv)
597{
598	char name[IFNAMSIZ], *next;
599	int ret = 0;
600	int unit;
601	char tmp[100], prefix[] = "wanXXXXXXXXXX_";
602	char ea[64];
603	int s;
604	struct ifreq ifr;
605
606	/* current unit # */
607	if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0)
608		unit = 0;
609	wan_prefix(unit, prefix);
610
611	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
612		return errno;
613
614	/* build wan interface name list */
615	foreach(name, nvram_safe_get("wan_ifnames"), next) {
616		strncpy(ifr.ifr_name, name, IFNAMSIZ);
617		if (ioctl(s, SIOCGIFHWADDR, &ifr))
618			continue;
619		ret += websWrite(wp, "<option value=\"%s\" %s>%s (%s)</option>", name,
620				 nvram_match(strcat_r(prefix, "ifname", tmp), name) ? "selected" : "",
621				 name, ether_etoa(ifr.ifr_hwaddr.sa_data, ea));
622	}
623
624	close(s);
625
626	return ret;
627}
628
629#endif
630#endif
631
632
633#ifdef REMOVE
634static int
635ej_wl_parse_str(int eid, webs_t wp, int argc, char_t **argv)
636{
637	char *var, *match, *next;
638	int unit, val = 0;
639	char tmp[100], prefix[] = "wlXXXXXXXXXX_";
640	char *name;
641	char str[100];
642
643	if (ejArgs(argc, argv, "%s %s", &var, &match) < 1) {
644		websError(wp, 400, "Insufficient args\n");
645		return -1;
646	}
647
648	if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0)
649		return -1;
650
651	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
652	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
653
654	if (wl_get_val(name, var, (void *)tmp, 100))
655		return -1;
656
657	foreach(str, tmp, next) {
658		if (strncmp(str, match, sizeof(str)) == 0) {
659			val = 1;
660			break;
661		}
662	}
663
664	return websWrite(wp, "%u", val);
665}
666#endif
667
668int
669ej_wl_sta_status(int eid, webs_t wp, char *ifname)
670{
671	int ret, i;
672	char bssid[32];
673	char bssinfobuf[2000];
674	wl_bss_info_t *info;
675	int val;
676
677	// Get bssid
678	ret=wl_ioctl(ifname, WLC_GET_BSSID, bssid, sizeof(bssid));
679	//wl_scan_results();
680
681	if (ret==0 && !(bssid[0]==0&&bssid[1]==0&&bssid[2]==0
682		&&bssid[3]==0&&bssid[4]==0&&bssid[5]==0))
683	{
684		return(websWrite(wp, "Status	: Connect to %s\n", nvram_safe_get("wl0_ssid")));
685	}
686	return(websWrite(wp, "Status	: Connecting to %s\n", nvram_safe_get("wl0_ssid")));
687}
688
689
690int
691ej_wl_status(int eid, webs_t wp, int argc, char_t **argv)
692{
693	int unit;
694	char tmp[100], prefix[] = "wlXXXXXXXXXX_";
695	char *name;
696	struct maclist *auth, *assoc, *authorized;
697	int max_sta_count, maclist_size;
698	int i, j, ret, val;
699	channel_info_t ci;
700
701	if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0)
702		return -1;
703
704	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
705	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
706
707	wl_ioctl(name, WLC_GET_RADIO, &val, sizeof(val));
708
709	if (val==1)
710	{
711		ret+=websWrite(wp, "Radio is disabled\n");
712		return 0;
713	}
714
715	wl_ioctl(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
716
717
718	if (nvram_match(strcat_r(prefix, "mode", tmp), "ap"))
719	{
720		if (nvram_match("wl_lazywds", "1") ||
721			nvram_match("wl_wdsapply_x", "1"))
722			ret+=websWrite(wp, "Mode	: Hybrid\n");
723		else    ret+=websWrite(wp, "Mode	: AP Only\n");
724
725		ret+=websWrite(wp, "Channel	: %d\n", ci.target_channel);
726
727	}
728	else if (nvram_match(strcat_r(prefix, "mode", tmp), "wds"))
729	{
730		ret+=websWrite(wp, "Mode	: WDS Only\n");
731		ret+=websWrite(wp, "Channel	: %d\n", ci.target_channel);
732	}
733	else if (nvram_match(strcat_r(prefix, "mode", tmp), "sta"))
734	{
735		ret+=websWrite(wp, "Mode	: Stations\n");
736		ret+=websWrite(wp, "Channel	: %d\n", ci.target_channel);
737		ret+=ej_wl_sta_status(eid, wp, name);
738		return ret;
739	}
740	else if (nvram_match(strcat_r(prefix, "mode", tmp), "wet"))
741	{
742		ret+=websWrite(wp, "Mode	: Ethernet Bridge\n");
743		ret+=websWrite(wp, "Channel	: %d\n", ci.target_channel);
744		ret+=ej_wl_sta_status(eid, wp, name);
745		return ret;
746	}
747
748	/* buffers and length */
749	max_sta_count = 256;
750	maclist_size = sizeof(auth->count) + max_sta_count * sizeof(struct ether_addr);
751
752	auth = malloc(maclist_size);
753	assoc = malloc(maclist_size);
754	authorized = malloc(maclist_size);
755
756	if (!auth || !assoc || !authorized)
757		goto exit;
758
759	/* query wl for authenticated sta list */
760	strcpy((char*)auth, "authe_sta_list");
761	if (wl_ioctl(name, WLC_GET_VAR, auth, maclist_size))
762		goto exit;
763
764	/* query wl for associated sta list */
765	assoc->count = max_sta_count;
766	if (wl_ioctl(name, WLC_GET_ASSOCLIST, assoc, maclist_size))
767		goto exit;
768
769	/* query wl for authorized sta list */
770	strcpy((char*)authorized, "autho_sta_list");
771	if (wl_ioctl(name, WLC_GET_VAR, authorized, maclist_size))
772		goto exit;
773
774
775	websWrite(wp, "\n");
776	websWrite(wp, "Stations List                           \n");
777	websWrite(wp, "----------------------------------------\n");
778	//             00:00:00:00:00:00 associated authorized
779
780	/* build authenticated/associated/authorized sta list */
781	for (i = 0; i < auth->count; i ++) {
782		char ea[ETHER_ADDR_STR_LEN];
783
784		websWrite(wp, "%s ", ether_etoa((void *)&auth->ea[i], ea));
785
786		for (j = 0; j < assoc->count; j ++) {
787			if (!bcmp((void *)&auth->ea[i], (void *)&assoc->ea[j], ETHER_ADDR_LEN)) {
788				websWrite(wp, " associated");
789				break;
790			}
791		}
792
793		for (j = 0; j < authorized->count; j ++) {
794			if (!bcmp((void *)&auth->ea[i], (void *)&authorized->ea[j], ETHER_ADDR_LEN)) {
795				websWrite(wp, " authorized");
796				break;
797			}
798		}
799		websWrite(wp, "\n");
800	}
801
802	/* error/exit */
803exit:
804	if (auth) free(auth);
805	if (assoc) free(assoc);
806	if (authorized) free(authorized);
807
808	return 0;
809}
810
811/* Dump NAT table <tr><td>destination</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
812int
813ej_nat_table(int eid, webs_t wp, int argc, char_t **argv)
814{
815    	int needlen = 0, listlen, i, ret;
816    	netconf_nat_t *nat_list = 0;
817	netconf_nat_t **plist, *cur;
818	char line[256], tstr[32];
819
820	ret += websWrite(wp, "Destination     Proto.  Port Range  Redirect to\n");
821
822    	netconf_get_nat(NULL, &needlen);
823
824    	if (needlen > 0)
825	{
826
827		nat_list = (netconf_nat_t *) malloc(needlen);
828		if (nat_list) {
829	    		memset(nat_list, 0, needlen);
830	    		listlen = needlen;
831	    		if (netconf_get_nat(nat_list, &listlen) == 0 && needlen == listlen) {
832				listlen = needlen/sizeof(netconf_nat_t);
833
834				for(i=0;i<listlen;i++)
835				{
836				//printf("%d %d %d\n", nat_list[i].target,
837			        //		nat_list[i].match.ipproto,
838				//		nat_list[i].match.dst.ipaddr.s_addr);
839				if (nat_list[i].target==NETCONF_DNAT)
840				{
841					if (nat_list[i].match.dst.ipaddr.s_addr==0)
842					{
843						sprintf(line, "%-15s", "all");
844					}
845					else
846					{
847						sprintf(line, "%-15s", inet_ntoa(nat_list[i].match.dst.ipaddr));
848					}
849
850
851					if (ntohs(nat_list[i].match.dst.ports[0])==0)
852						sprintf(line, "%s %-7s", line, "ALL");
853					else if (nat_list[i].match.ipproto==IPPROTO_TCP)
854						sprintf(line, "%s %-7s", line, "TCP");
855					else sprintf(line, "%s %-7s", line, "UDP");
856
857					if (nat_list[i].match.dst.ports[0] == nat_list[i].match.dst.ports[1])
858					{
859						if (ntohs(nat_list[i].match.dst.ports[0])==0)
860						sprintf(line, "%s %-11s", line, "ALL");
861						else
862						sprintf(line, "%s %-11d", line, ntohs(nat_list[i].match.dst.ports[0]));
863					}
864					else
865					{
866						sprintf(tstr, "%d:%d", ntohs(nat_list[i].match.dst.ports[0]),
867ntohs(nat_list[i].match.dst.ports[1]));
868						sprintf(line, "%s %-11s", line, tstr);
869					}
870					sprintf(line, "%s %s\n", line, inet_ntoa(nat_list[i].ipaddr));
871					ret += websWrite(wp, line);
872
873				}
874				}
875	    		}
876	    		free(nat_list);
877		}
878    	}
879	return 0;
880}
881
882int
883ej_route_table(int eid, webs_t wp, int argc, char_t **argv)
884{
885	char buff[256];
886	int  nl = 0 ;
887	struct in_addr dest;
888	struct in_addr gw;
889	struct in_addr mask;
890	int flgs, ref, use, metric, ret;
891	char flags[4];
892	unsigned long int d,g,m;
893	char sdest[16], sgw[16];
894	FILE *fp;
895
896        ret += websWrite(wp, "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface\n");
897
898	if (!(fp = fopen("/proc/net/route", "r"))) return 0;
899
900	while(fgets(buff, sizeof(buff), fp) != NULL )
901	{
902		if(nl)
903		{
904			int ifl = 0;
905			while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
906				ifl++;
907			buff[ifl]=0;    /* interface */
908			if(sscanf(buff+ifl+1, "%lx%lx%d%d%d%d%lx",
909			   &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
910				//error_msg_and_die( "Unsuported kernel route format\n");
911				//continue;
912			}
913
914			ifl = 0;        /* parse flags */
915			if(flgs&1)
916				flags[ifl++]='U';
917			if(flgs&2)
918				flags[ifl++]='G';
919			if(flgs&4)
920				flags[ifl++]='H';
921			flags[ifl]=0;
922			dest.s_addr = d;
923			gw.s_addr   = g;
924			mask.s_addr = m;
925			strcpy(sdest,  (dest.s_addr==0 ? "default" :
926					inet_ntoa(dest)));
927			strcpy(sgw,    (gw.s_addr==0   ? "*"       :
928					inet_ntoa(gw)));
929			if(nvram_match("wan_proto","pppoe") && (strstr(buff, "eth0")))
930				continue;
931			if (strstr(buff, "br0") || strstr(buff, "wl0"))
932			{
933				ret += websWrite(wp, "%-16s%-16s%-16s%-6s%-6d %-2d %7d LAN\n",
934				sdest, sgw,
935				inet_ntoa(mask),
936				flags, metric, ref, use);
937			}
938			else if(!strstr(buff, "lo"))
939			{
940				ret += websWrite(wp, "%-16s%-16s%-16s%-6s%-6d %-2d %7d WAN\n",
941				sdest, sgw,
942				inet_ntoa(mask),
943				flags, metric, ref, use);
944			}
945		}
946		nl++;
947	}
948	fclose(fp);
949
950	return 0;
951}
952