1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * ASUS Home Gateway Reference Design
19 * Web Page Configuration Support Routines
20 *
21 * Copyright 2004, ASUSTeK Inc.
22 * All Rights Reserved.
23 *
24 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
25 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
26 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
28 */
29
30#ifdef WEBS
31#include <webs.h>
32#include <uemf.h>
33#include <ej.h>
34#else /* !WEBS */
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39#include <errno.h>
40#include <unistd.h>
41#include <limits.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <assert.h>
48#include <httpd.h>
49#endif /* WEBS */
50#include <typedefs.h>
51#include <bcmnvram.h>
52#include <bcmutils.h>
53#include <shutils.h>
54#include <ralink.h>
55#include <iwlib.h>
56#include <stapriv.h>
57#include <ethutils.h>
58#include <shared.h>
59#include <sys/mman.h>
60#ifndef O_BINARY
61#define O_BINARY 	0
62#endif
63#ifndef MAP_FAILED
64#define MAP_FAILED (-1)
65#endif
66
67#define wan_prefix(unit, prefix)	snprintf(prefix, sizeof(prefix), "wan%d_", unit)
68//static char * rfctime(const time_t *timep);
69//static char * reltime(unsigned int seconds);
70void reltime(unsigned int seconds, char *buf);
71static int wl_status(int eid, webs_t wp, int argc, char_t **argv, int unit);
72
73#include <fcntl.h>
74#include <signal.h>
75#include <time.h>
76#include <sys/klog.h>
77#include <sys/wait.h>
78#include <sys/ioctl.h>
79#include <net/if.h>
80#include <linux/sockios.h>
81#include <net/if_arp.h>
82
83#include <dirent.h>
84
85
86/************************ CONSTANTS & MACROS ************************/
87
88/*
89 * Constants fof WE-9->15
90 */
91#define IW15_MAX_FREQUENCIES	16
92#define IW15_MAX_BITRATES	8
93#define IW15_MAX_TXPOWER	8
94#define IW15_MAX_ENCODING_SIZES	8
95#define IW15_MAX_SPY		8
96#define IW15_MAX_AP		8
97
98/****************************** TYPES ******************************/
99
100/*
101 *	Struct iw_range up to WE-15
102 */
103struct	iw15_range
104{
105	__u32		throughput;
106	__u32		min_nwid;
107	__u32		max_nwid;
108	__u16		num_channels;
109	__u8		num_frequency;
110	struct iw_freq	freq[IW15_MAX_FREQUENCIES];
111	__s32		sensitivity;
112	struct iw_quality	max_qual;
113	__u8		num_bitrates;
114	__s32		bitrate[IW15_MAX_BITRATES];
115	__s32		min_rts;
116	__s32		max_rts;
117	__s32		min_frag;
118	__s32		max_frag;
119	__s32		min_pmp;
120	__s32		max_pmp;
121	__s32		min_pmt;
122	__s32		max_pmt;
123	__u16		pmp_flags;
124	__u16		pmt_flags;
125	__u16		pm_capa;
126	__u16		encoding_size[IW15_MAX_ENCODING_SIZES];
127	__u8		num_encoding_sizes;
128	__u8		max_encoding_tokens;
129	__u16		txpower_capa;
130	__u8		num_txpower;
131	__s32		txpower[IW15_MAX_TXPOWER];
132	__u8		we_version_compiled;
133	__u8		we_version_source;
134	__u16		retry_capa;
135	__u16		retry_flags;
136	__u16		r_time_flags;
137	__s32		min_retry;
138	__s32		max_retry;
139	__s32		min_r_time;
140	__s32		max_r_time;
141	struct iw_quality	avg_qual;
142};
143
144/*
145 * Union for all the versions of iwrange.
146 * Fortunately, I mostly only add fields at the end, and big-bang
147 * reorganisations are few.
148 */
149union	iw_range_raw
150{
151	struct iw15_range	range15;	/* WE 9->15 */
152	struct iw_range		range;		/* WE 16->current */
153};
154
155/*
156 * Offsets in iw_range struct
157 */
158#define iwr15_off(f)	( ((char *) &(((struct iw15_range *) NULL)->f)) - \
159			  (char *) NULL)
160#define iwr_off(f)	( ((char *) &(((struct iw_range *) NULL)->f)) - \
161			  (char *) NULL)
162
163/* Disable runtime version warning in ralink_get_range_info() */
164int	iw_ignore_version_sp = 0;
165
166/*------------------------------------------------------------------*/
167/*
168 * Get the range information out of the driver
169 */
170int
171ralink_get_range_info(iwrange *	range, char* buffer, int length)
172{
173  union iw_range_raw *	range_raw;
174
175  /* Point to the buffer */
176  range_raw = (union iw_range_raw *) buffer;
177
178  /* For new versions, we can check the version directly, for old versions
179   * we use magic. 300 bytes is a also magic number, don't touch... */
180  if (length < 300)
181    {
182      /* That's v10 or earlier. Ouch ! Let's make a guess...*/
183      range_raw->range.we_version_compiled = 9;
184    }
185
186  /* Check how it needs to be processed */
187  if (range_raw->range.we_version_compiled > 15)
188    {
189      /* This is our native format, that's easy... */
190      /* Copy stuff at the right place, ignore extra */
191      memcpy((char *) range, buffer, sizeof(iwrange));
192    }
193  else
194    {
195      /* Zero unknown fields */
196      bzero((char *) range, sizeof(struct iw_range));
197
198      /* Initial part unmoved */
199      memcpy((char *) range,
200	     buffer,
201	     iwr15_off(num_channels));
202      /* Frequencies pushed futher down towards the end */
203      memcpy((char *) range + iwr_off(num_channels),
204	     buffer + iwr15_off(num_channels),
205	     iwr15_off(sensitivity) - iwr15_off(num_channels));
206      /* This one moved up */
207      memcpy((char *) range + iwr_off(sensitivity),
208	     buffer + iwr15_off(sensitivity),
209	     iwr15_off(num_bitrates) - iwr15_off(sensitivity));
210      /* This one goes after avg_qual */
211      memcpy((char *) range + iwr_off(num_bitrates),
212	     buffer + iwr15_off(num_bitrates),
213	     iwr15_off(min_rts) - iwr15_off(num_bitrates));
214      /* Number of bitrates has changed, put it after */
215      memcpy((char *) range + iwr_off(min_rts),
216	     buffer + iwr15_off(min_rts),
217	     iwr15_off(txpower_capa) - iwr15_off(min_rts));
218      /* Added encoding_login_index, put it after */
219      memcpy((char *) range + iwr_off(txpower_capa),
220	     buffer + iwr15_off(txpower_capa),
221	     iwr15_off(txpower) - iwr15_off(txpower_capa));
222      /* Hum... That's an unexpected glitch. Bummer. */
223      memcpy((char *) range + iwr_off(txpower),
224	     buffer + iwr15_off(txpower),
225	     iwr15_off(avg_qual) - iwr15_off(txpower));
226      /* Avg qual moved up next to max_qual */
227      memcpy((char *) range + iwr_off(avg_qual),
228	     buffer + iwr15_off(avg_qual),
229	     sizeof(struct iw_quality));
230    }
231
232  /* We are now checking much less than we used to do, because we can
233   * accomodate more WE version. But, there are still cases where things
234   * will break... */
235  if (!iw_ignore_version_sp)
236    {
237      /* We don't like very old version (unfortunately kernel 2.2.X) */
238      if (range->we_version_compiled <= 10)
239	{
240	  fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", "raxx");
241	  fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
242	  fprintf(stderr, "Some things may be broken...\n\n");
243	}
244
245      /* We don't like future versions of WE, because we can't cope with
246       * the unknown */
247      if (range->we_version_compiled > WE_MAX_VERSION)
248	{
249	  fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", "raxx", range->we_version_compiled);
250	  fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_VERSION);
251	  fprintf(stderr, "Some things may be broken...\n\n");
252	}
253
254      /* Driver version verification */
255      if ((range->we_version_compiled > 10) &&
256	 (range->we_version_compiled < range->we_version_source))
257	{
258	  fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", "raxx", range->we_version_source);
259	  fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
260	  fprintf(stderr, "may not be available...\n\n");
261	}
262      /* Note : we are only trying to catch compile difference, not source.
263       * If the driver source has not been updated to the latest, it doesn't
264       * matter because the new fields are set to zero */
265    }
266
267  /* Don't complain twice.
268   * In theory, the test apply to each individual driver, but usually
269   * all drivers are compiled from the same kernel. */
270  iw_ignore_version_sp = 1;
271
272  return (0);
273}
274
275
276char* GetBW(int BW)
277{
278	switch(BW)
279	{
280		case BW_10:
281			return "10M";
282
283		case BW_20:
284			return "20M";
285
286		case BW_40:
287			return "40M";
288
289#if defined(RTAC52U) || defined(RTAC51U) || defined(RTN54U) || defined(RTAC1200HP) || defined(RTAC54U)
290		case BW_80:
291			return "80M";
292#endif
293
294		default:
295			return "N/A";
296	}
297}
298
299char* GetPhyMode(int Mode)
300{
301	switch(Mode)
302	{
303		case MODE_CCK:
304			return "CCK";
305
306		case MODE_OFDM:
307			return "OFDM";
308		case MODE_HTMIX:
309			return "HTMIX";
310
311		case MODE_HTGREENFIELD:
312			return "GREEN";
313
314#if defined(RTAC52U) || defined(RTAC51U)  || defined(RTN54U) || defined(RTAC1200HP) || defined(RTAC54U)
315		case MODE_VHT:
316			return "VHT";
317#endif
318
319		default:
320			return "N/A";
321	}
322}
323
324int MCSMappingRateTable[] =
325	{2,  4,   11,  22, // CCK
326	12, 18,   24,  36, 48, 72, 96, 108, // OFDM
327	13, 26,   39,  52,  78, 104, 117, 130, 26,  52,  78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15
328	39, 78,  117, 156, 234, 312, 351, 390,										  // 20MHz, 800ns GI, MCS: 16 ~ 23
329	27, 54,   81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15
330	81, 162, 243, 324, 486, 648, 729, 810,										  // 40MHz, 800ns GI, MCS: 16 ~ 23
331	14, 29,   43,  57,  87, 115, 130, 144, 29, 59,   87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15
332	43, 87,  130, 173, 260, 317, 390, 433,										  // 20MHz, 400ns GI, MCS: 16 ~ 23
333	30, 60,   90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15
334	90, 180, 270, 360, 540, 720, 810, 900,
335	13, 26,   39,  52,  78, 104, 117, 130, 156, /* 11ac: 20Mhz, 800ns GI, MCS: 0~8 */
336	27, 54,   81, 108, 162, 216, 243, 270, 324, 360, /*11ac: 40Mhz, 800ns GI, MCS: 0~9 */
337	59, 117, 176, 234, 351, 468, 527, 585, 702, 780, /*11ac: 80Mhz, 800ns GI, MCS: 0~9 */
338	14, 29,   43,  57,  87, 115, 130, 144, 173, /* 11ac: 20Mhz, 400ns GI, MCS: 0~8 */
339	30, 60,   90, 120, 180, 240, 270, 300, 360, 400, /*11ac: 40Mhz, 400ns GI, MCS: 0~9 */
340	65, 130, 195, 260, 390, 520, 585, 650, 780, 867 /*11ac: 80Mhz, 400ns GI, MCS: 0~9 */
341	};
342
343
344#define FN_GETRATE(_fn_, _st_)						\
345_fn_(_st_ HTSetting)							\
346{									\
347	int rate_count = sizeof(MCSMappingRateTable)/sizeof(int);	\
348	int rate_index = 0;						\
349									\
350	if (HTSetting.field.MODE >= MODE_VHT)				\
351	{								\
352		if (HTSetting.field.BW == BW_20) {			\
353			rate_index = 108 +				\
354			((unsigned char)HTSetting.field.ShortGI * 29) +	\
355			((unsigned char)HTSetting.field.MCS);		\
356		}							\
357		else if (HTSetting.field.BW == BW_40) {			\
358			rate_index = 117 +				\
359			((unsigned char)HTSetting.field.ShortGI * 29) +	\
360			((unsigned char)HTSetting.field.MCS);		\
361		}							\
362		else if (HTSetting.field.BW == BW_80) {			\
363			rate_index = 127 +				\
364			((unsigned char)HTSetting.field.ShortGI * 29) +	\
365			((unsigned char)HTSetting.field.MCS);		\
366		}							\
367	}								\
368	else								\
369	if (HTSetting.field.MODE >= MODE_HTMIX)				\
370	{								\
371		rate_index = 12 + ((unsigned char)HTSetting.field.BW *24) + ((unsigned char)HTSetting.field.ShortGI *48) + ((unsigned char)HTSetting.field.MCS);	\
372	}								\
373	else								\
374	if (HTSetting.field.MODE == MODE_OFDM)				\
375		rate_index = (unsigned char)(HTSetting.field.MCS) + 4;	\
376	else if (HTSetting.field.MODE == MODE_CCK)			\
377		rate_index = (unsigned char)(HTSetting.field.MCS);	\
378									\
379	if (rate_index < 0)						\
380		rate_index = 0;						\
381									\
382	if (rate_index >= rate_count)					\
383		rate_index = rate_count-1;				\
384									\
385	return (MCSMappingRateTable[rate_index] * 5)/10;		\
386}
387
388#if defined(RTCONFIG_HAS_5G)
389int FN_GETRATE(getRate,      MACHTTRANSMIT_SETTING_for_5G)		//getRate   (MACHTTRANSMIT_SETTING_for_5G)
390#endif	/* RTCONFIG_HAS_5G */
391int FN_GETRATE(getRate_2g,   MACHTTRANSMIT_SETTING_for_2G)		//getRate_2g(MACHTTRANSMIT_SETTING_for_2G)
392
393
394
395int
396ej_wl_status(int eid, webs_t wp, int argc, char_t **argv, int unit)
397{
398	int retval = 0;
399	int ii = 0;
400	char word[256], *next;
401
402	foreach (word, nvram_safe_get("wl_ifnames"), next) {
403		retval += wl_status(eid, wp, argc, argv, ii);
404		retval += websWrite(wp, "\n");
405
406		ii++;
407	}
408
409	return retval;
410}
411
412int
413ej_wl_status_2g(int eid, webs_t wp, int argc, char_t **argv)
414{
415	return ej_wl_status(eid, wp, argc, argv, 0);
416}
417
418static int
419wl_status(int eid, webs_t wp, int argc, char_t **argv, int unit)
420{
421	int ret = 0;
422	int channel;
423	struct iw_range	range;
424	double freq;
425	struct iwreq wrq0;
426	struct iwreq wrq1;
427	struct iwreq wrq2;
428	struct iwreq wrq3;
429	unsigned long phy_mode;
430	char tmp[128], prefix[] = "wlXXXXXXXXXX_", *ifname;
431	int wl_mode_x;
432	int r;
433
434	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
435	ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
436
437#if 0
438	if (nvram_match(strcat_r(prefix, "radio", tmp), "0"))
439	{
440		ret+=websWrite(wp, "%s radio is disabled\n",
441			nvram_match(strcat_r(prefix, "nband", tmp), "1") ? "5 GHz" : "2.4 GHz");
442		return ret;
443	}
444#else
445	if (!get_radio_status(ifname))
446	{
447#if defined(BAND_2G_ONLY)
448		ret+=websWrite(wp, "2.4 GHz radio is disabled\n");
449#else
450		ret+=websWrite(wp, "%s radio is disabled\n",
451			nvram_match(strcat_r(prefix, "nband", tmp), "1") ? "5 GHz" : "2.4 GHz");
452#endif
453		return ret;
454	}
455#endif
456
457	if (wl_ioctl(ifname, SIOCGIWAP, &wrq0) < 0)
458	{
459#if defined(BAND_2G_ONLY)
460		ret+=websWrite(wp, "2.4 GHz radio is disabled\n");
461#else
462		ret+=websWrite(wp, "%s radio is disabled\n",
463			nvram_match(strcat_r(prefix, "nband", tmp), "1") ? "5 GHz" : "2.4 GHz");
464#endif
465		return ret;
466	}
467
468	wrq0.u.ap_addr.sa_family = ARPHRD_ETHER;
469	ret+=websWrite(wp, "MAC address	: %02X:%02X:%02X:%02X:%02X:%02X\n",
470			(unsigned char)wrq0.u.ap_addr.sa_data[0],
471			(unsigned char)wrq0.u.ap_addr.sa_data[1],
472			(unsigned char)wrq0.u.ap_addr.sa_data[2],
473			(unsigned char)wrq0.u.ap_addr.sa_data[3],
474			(unsigned char)wrq0.u.ap_addr.sa_data[4],
475			(unsigned char)wrq0.u.ap_addr.sa_data[5]);
476
477	if (wl_ioctl(ifname, SIOCGIWFREQ, &wrq1) < 0)
478		return ret;
479
480	char buffer[sizeof(iwrange) * 2];
481	bzero(buffer, sizeof(buffer));
482	wrq2.u.data.pointer = (caddr_t) buffer;
483	wrq2.u.data.length = sizeof(buffer);
484	wrq2.u.data.flags = 0;
485
486	if (wl_ioctl(ifname, SIOCGIWRANGE, &wrq2) < 0)
487		return ret;
488
489	if (ralink_get_range_info(&range, buffer, wrq2.u.data.length) < 0)
490		return ret;
491
492#if defined(RTN65U)
493	if (unit == 0 && get_model() == MODEL_RTN65U)
494	{
495		FILE *fp;
496		phy_mode = 0;
497		if((fp = fopen("/etc/Wireless/iNIC/iNIC_ap.dat", "r")) != NULL)
498		{
499			while(fgets(tmp, sizeof(tmp), fp) != NULL)
500			{
501				if(strncmp(tmp, "WirelessMode=", 13) == 0)
502				{
503					phy_mode = atoi(tmp + 13);
504					break;
505				}
506			}
507			fclose(fp);
508		}
509	}
510	else
511	{
512#endif	/* RTN65U */
513	bzero(buffer, sizeof(unsigned long));
514	wrq2.u.data.length = sizeof(unsigned long);
515	wrq2.u.data.pointer = (caddr_t) buffer;
516	wrq2.u.data.flags = RT_OID_GET_PHY_MODE;
517
518	if (wl_ioctl(ifname, RT_PRIV_IOCTL, &wrq2) < 0)
519		return ret;
520
521	if(wrq2.u.mode == (__u32) buffer) //.u.mode is at the same location as u.data.pointer
522	{ //new wifi driver
523		phy_mode = 0;
524		memcpy(&phy_mode, wrq2.u.data.pointer, wrq2.u.data.length);
525	}
526	else
527		phy_mode=wrq2.u.mode;
528#if defined(RTN65U)
529	}
530#endif	/* RTN65U */
531
532	freq = iw_freq2float(&(wrq1.u.freq));
533	if (freq < KILO)
534		channel = (int) freq;
535	else
536	{
537		channel = iw_freq_to_channel(freq, &range);
538		if (channel < 0)
539			return ret;
540	}
541
542	wl_mode_x = nvram_get_int(strcat_r(prefix, "mode_x", tmp));
543	if	(wl_mode_x == 1)
544		ret+=websWrite(wp, "OP Mode		: WDS Only\n");
545	else if (wl_mode_x == 2)
546		ret+=websWrite(wp, "OP Mode		: Hybrid\n");
547	else
548		ret+=websWrite(wp, "OP Mode		: AP\n");
549
550#if defined(RTAC52U) || defined(RTAC51U) || defined(RTN54U)  || defined(RTAC1200HP) || defined(RTAC54U)
551	if (unit == 1)
552	{
553		char *p = tmp;
554		if(phy_mode & WMODE_A)
555			p += sprintf(p, "/a");
556		if(phy_mode & WMODE_B)
557			p += sprintf(p, "/b");
558		if(phy_mode & WMODE_G)
559			p += sprintf(p, "/g");
560		if(phy_mode & WMODE_GN)
561			p += sprintf(p, "/n");	//N in 2G
562		if(phy_mode & WMODE_AN)
563			p += sprintf(p, "/n");	//N in 5G
564		if(phy_mode & WMODE_AC)
565			p += sprintf(p, "/ac");
566		if(p != tmp)
567			ret+=websWrite(wp, "Phy Mode	: 11%s\n", tmp+1); // skip first '/'
568	}
569	else
570#endif
571	if (phy_mode==PHY_11BG_MIXED)
572		ret+=websWrite(wp, "Phy Mode	: 11b/g\n");
573	else if (phy_mode==PHY_11B)
574		ret+=websWrite(wp, "Phy Mode	: 11b\n");
575	else if (phy_mode==PHY_11A)
576		ret+=websWrite(wp, "Phy Mode	: 11a\n");
577	else if (phy_mode==PHY_11ABG_MIXED)
578		ret+=websWrite(wp, "Phy Mode	: 11a/b/g\n");
579	else if (phy_mode==PHY_11G)
580		ret+=websWrite(wp, "Phy Mode	: 11g\n");
581	else if (phy_mode==PHY_11ABGN_MIXED)
582		ret+=websWrite(wp, "Phy Mode	: 11a/b/g/n\n");
583	else if (phy_mode==PHY_11N)
584		ret+=websWrite(wp, "Phy Mode	: 11n\n");
585	else if (phy_mode==PHY_11GN_MIXED)
586		ret+=websWrite(wp, "Phy Mode	: 11g/n\n");
587	else if (phy_mode==PHY_11AN_MIXED)
588		ret+=websWrite(wp, "Phy Mode	: 11a/n\n");
589	else if (phy_mode==PHY_11BGN_MIXED)
590		ret+=websWrite(wp, "Phy Mode	: 11b/g/n\n");
591	else if (phy_mode==PHY_11AGN_MIXED)
592		ret+=websWrite(wp, "Phy Mode	: 11a/g/n\n");
593
594	ret+=websWrite(wp, "Channel		: %d\n", channel);
595
596	char data[16384];
597	memset(data, 0, sizeof(data));
598	wrq3.u.data.pointer = data;
599	wrq3.u.data.length = sizeof(data);
600	wrq3.u.data.flags = 0;
601
602	if ((r = wl_ioctl(ifname, RTPRIV_IOCTL_GET_MAC_TABLE, &wrq3)) < 0) {
603		_dprintf("%s: Take MAC table from i/f %s fail! ret %d, errno %d (%s)\n",
604			__func__, r, errno, strerror(errno));
605		return ret;
606	}
607
608	RT_802_11_MAC_TABLE_5G* mp =(RT_802_11_MAC_TABLE_5G*)wrq3.u.data.pointer;
609	RT_802_11_MAC_TABLE_2G* mp2=(RT_802_11_MAC_TABLE_2G*)wrq3.u.data.pointer;
610	int i;
611
612	ret+=websWrite(wp, "\nStations List			   \n");
613	ret+=websWrite(wp, "----------------------------------------\n");
614	ret+=websWrite(wp, "%-18s%-4s%-8s%-4s%-4s%-4s%-5s%-5s%-12s\n",
615			   "MAC", "PSM", "PhyMode", "BW", "MCS", "SGI", "STBC", "Rate", "Connect Time");
616
617#define SHOW_STA_INFO(_p,_i,_st, _gr) {											\
618		int hr, min, sec;											\
619		_st *Entry = ((_st *)(_p)) + _i;									\
620		hr = Entry->ConnectedTime/3600;										\
621		min = (Entry->ConnectedTime % 3600)/60;									\
622		sec = Entry->ConnectedTime - hr*3600 - min*60;								\
623		ret+=websWrite(wp, "%02X:%02X:%02X:%02X:%02X:%02X %s %-7s %s %3d %s %s  %3dM %02d:%02d:%02d\n",		\
624				Entry->Addr[0], Entry->Addr[1],								\
625				Entry->Addr[2], Entry->Addr[3],								\
626				Entry->Addr[4], Entry->Addr[5],								\
627				Entry->Psm ? "Yes" : "NO ",								\
628				GetPhyMode(Entry->TxRate.field.MODE),							\
629				GetBW(Entry->TxRate.field.BW),								\
630				Entry->TxRate.field.MCS,								\
631				Entry->TxRate.field.ShortGI ? "Yes" : "NO ",						\
632				Entry->TxRate.field.STBC ? "Yes" : "NO ",						\
633				_gr(Entry->TxRate),									\
634				hr, min, sec										\
635		);													\
636	}
637
638	if (!strcmp(ifname, WIF_2G)) {
639		for (i=0;i<mp->Num;i++) {
640			SHOW_STA_INFO(mp2->Entry, i, RT_802_11_MAC_ENTRY_for_2G, getRate_2g);
641		}
642	}
643#if defined(RTCONFIG_HAS_5G)
644	else {
645		for (i=0;i<mp->Num;i++) {
646			SHOW_STA_INFO(mp->Entry, i, RT_802_11_MAC_ENTRY_for_5G, getRate);
647		}
648	}
649#endif	/* RTCONFIG_HAS_5G */
650
651	return ret;
652}
653
654typedef struct PACKED _WSC_CONFIGURED_VALUE {
655    unsigned short WscConfigured;	// 1 un-configured; 2 configured
656    unsigned char WscSsid[32 + 1];
657    unsigned short WscAuthMode;		// mandatory, 0x01: open, 0x02: wpa-psk, 0x04: shared, 0x08:wpa, 0x10: wpa2, 0x
658    unsigned short WscEncrypType;	// 0x01: none, 0x02: wep, 0x04: tkip, 0x08: aes
659    unsigned char DefaultKeyIdx;
660    unsigned char WscWPAKey[64 + 1];
661} WSC_CONFIGURED_VALUE;
662
663void getWPSAuthMode(WSC_CONFIGURED_VALUE *result, char *ret_str)
664{
665	if (result->WscAuthMode & 0x1)
666		strcat(ret_str, "Open System");
667	if (result->WscAuthMode & 0x2)
668		strcat(ret_str, "WPA-Personal");
669	if (result->WscAuthMode & 0x4)
670		strcat(ret_str, "Shared Key");
671	if (result->WscAuthMode & 0x8)
672		strcat(ret_str, "WPA-Enterprise");
673	if (result->WscAuthMode & 0x10)
674		strcat(ret_str, "WPA2-Enterprise");
675	if (result->WscAuthMode & 0x20)
676		strcat(ret_str, "WPA2-Personal");
677}
678
679void getWPSEncrypType(WSC_CONFIGURED_VALUE *result, char *ret_str)
680{
681	if (result->WscEncrypType & 0x1)
682		strcat(ret_str, "None");
683	if (result->WscEncrypType & 0x2)
684		strcat(ret_str, "WEP");
685	if (result->WscEncrypType & 0x4)
686		strcat(ret_str, "TKIP");
687	if (result->WscEncrypType & 0x8)
688		strcat(ret_str, "AES");
689}
690
691/*
692 * these definitions are from rt2860v2 driver include/wsc.h
693 */
694char *getWscStatusStr(int status)
695{
696	switch(status) {
697	case 0:
698		return "Not used";
699	case 1:
700		return "Idle";
701	case 2:
702#if 0
703		return "WPS Fail(Ignore this if Intel/Marvell registrar used)";
704#else
705		return "Idle";
706#endif
707	case 3:
708		return "Start WPS Process";
709	case 4:
710		return "Received EAPOL-Start";
711	case 5:
712		return "Sending EAP-Req(ID)";
713	case 6:
714		return "Receive EAP-Rsp(ID)";
715	case 7:
716		return "Receive EAP-Req with wrong WPS SMI Vendor Id";
717	case 8:
718		return "Receive EAP-Req with wrong WPS Vendor Type";
719	case 9:
720		return "Sending EAP-Req(WPS_START)";
721	case 10:
722		return "Send M1";
723	case 11:
724		return "Received M1";
725	case 12:
726		return "Send M2";
727	case 13:
728		return "Received M2";
729	case 14:
730		return "Received M2D";
731	case 15:
732		return "Send M3";
733	case 16:
734		return "Received M3";
735	case 17:
736		return "Send M4";
737	case 18:
738		return "Received M4";
739	case 19:
740		return "Send M5";
741	case 20:
742		return "Received M5";
743	case 21:
744		return "Send M6";
745	case 22:
746		return "Received M6";
747	case 23:
748		return "Send M7";
749	case 24:
750		return "Received M7";
751	case 25:
752		return "Send M8";
753	case 26:
754		return "Received M8";
755	case 27:
756		return "Processing EAP Response (ACK)";
757	case 28:
758		return "Processing EAP Request (Done)";
759	case 29:
760		return "Processing EAP Response (Done)";
761	case 30:
762		return "Sending EAP-Fail";
763	case 31:
764		return "WPS_ERROR_HASH_FAIL";
765	case 32:
766		return "WPS_ERROR_HMAC_FAIL";
767	case 33:
768		return "WPS_ERROR_DEV_PWD_AUTH_FAIL";
769	case 34:
770//		return "Configured";
771		return "Success";
772	case 35:
773		return "SCAN AP";
774	case 36:
775		return "EAPOL START SENT";
776	case 37:
777		return "WPS_EAP_RSP_DONE_SENT";
778	case 38:
779		return "WAIT PINCODE";
780	case 39:
781		return "WSC_START_ASSOC";
782	case 0x101:
783		return "PBC:TOO MANY AP";
784	case 0x102:
785		return "PBC:NO AP";
786	case 0x103:
787		return "EAP_FAIL_RECEIVED";
788	case 0x104:
789		return "EAP_NONCE_MISMATCH";
790	case 0x105:
791		return "EAP_INVALID_DATA";
792	case 0x106:
793		return "PASSWORD_MISMATCH";
794	case 0x107:
795		return "EAP_REQ_WRONG_SMI";
796	case 0x108:
797		return "EAP_REQ_WRONG_VENDOR_TYPE";
798	case 0x109:
799		return "PBC_SESSION_OVERLAP";
800	default:
801		return "Unknown";
802	}
803}
804
805int getWscStatus(int unit)
806{
807	int data = 0;
808	struct iwreq wrq;
809	char tmp[128], prefix[] = "wlXXXXXXXXXX_";
810
811	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
812
813	wrq.u.data.length = sizeof(data);
814	wrq.u.data.pointer = (caddr_t) &data;
815	wrq.u.data.flags = RT_OID_WSC_QUERY_STATUS;
816
817	if (wl_ioctl(nvram_safe_get(strcat_r(prefix, "ifname", tmp)), RT_PRIV_IOCTL, &wrq) < 0)
818		fprintf(stderr, "errors in getting WSC status\n");
819
820	return data;
821}
822
823unsigned int getAPPIN(int unit)
824{
825	unsigned int data = 0;
826	struct iwreq wrq;
827	char tmp[128], prefix[] = "wlXXXXXXXXXX_";
828
829	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
830
831	wrq.u.data.length = sizeof(data);
832	wrq.u.data.pointer = (caddr_t) &data;
833	wrq.u.data.flags = RT_OID_WSC_PIN_CODE;
834
835	if (wl_ioctl(nvram_safe_get(strcat_r(prefix, "ifname", tmp)), RT_PRIV_IOCTL, &wrq) < 0)
836		fprintf(stderr, "errors in getting AP PIN\n");
837
838	return data;
839}
840
841int
842wl_wps_info(int eid, webs_t wp, int argc, char_t **argv, int unit)
843{
844	int i, j = -1, u = unit;
845	char tmpstr[128], tmpstr2[256];
846	WSC_CONFIGURED_VALUE result;
847	int retval=0;
848	struct iwreq wrq;
849	char tmp[128], prefix[] = "wlXXXXXXXXXX_";
850	char *wps_sta_pin;
851	char tag1[] = "<wps_infoXXXXXX>", tag2[] = "</wps_infoXXXXXX>";
852
853#if defined(RTCONFIG_WPSMULTIBAND)
854	for (j = -1; j < MAX_NR_WL_IF; ++j) {
855#endif
856		switch (j) {
857		case 0: /* fall through */
858		case 1:
859			u = j;
860			sprintf(tag1, "<wps_info%d>", j);
861			sprintf(tag2, "</wps_info%d>", j);
862			break;
863		case -1: /* fall through */
864		default:
865			u = unit;
866			strcpy(tag1, "<wps_info>");
867			strcpy(tag2, "</wps_info>");
868		}
869
870		snprintf(prefix, sizeof(prefix), "wl%d_", u);
871		wrq.u.data.length = sizeof(WSC_CONFIGURED_VALUE);
872		wrq.u.data.pointer = (caddr_t) &result;
873		wrq.u.data.flags = 0;
874		strcpy((char *)&result, "get_wsc_profile");
875
876#if defined(RTCONFIG_WPSMULTIBAND)
877		if (!nvram_get(strcat_r(prefix, "ifname", tmp)))
878			continue;
879#endif
880
881		if (wl_ioctl(nvram_safe_get(strcat_r(prefix, "ifname", tmp)), RTPRIV_IOCTL_WSC_PROFILE, &wrq) < 0) {
882			fprintf(stderr, "errors in getting WSC profile\n");
883			return 0;
884		}
885
886		if (j == -1)
887			retval += websWrite(wp, "<wps>\n");
888
889		//0. WSC Status
890		retval += websWrite(wp, "%s%s%s\n", tag1, getWscStatusStr(getWscStatus(u)), tag2);
891
892		//1. WPSConfigured
893		if (result.WscConfigured==2)
894			retval += websWrite(wp, "%s%s%s\n", tag1, "Yes", tag2);
895		else
896			retval += websWrite(wp, "%s%s%s\n", tag1, "No", tag2);
897
898		//2. WPSSSID
899		memset(tmpstr, 0, sizeof(tmpstr));
900		char_to_ascii(tmpstr, result.WscSsid);
901		retval += websWrite(wp, "%s%s%s\n", tag1, tmpstr, tag2);
902
903		//3. WPSAuthMode
904		memset(tmpstr, 0, sizeof(tmpstr));
905		getWPSAuthMode(&result, tmpstr);
906		retval += websWrite(wp, "%s%s%s\n", tag1, tmpstr, tag2);
907
908		//4. EncrypType
909		memset(tmpstr, 0, sizeof(tmpstr));
910		getWPSEncrypType(&result, tmpstr);
911		retval += websWrite(wp, "%s%s%s\n", tag1, tmpstr, tag2);
912
913		//5. DefaultKeyIdx
914		memset(tmpstr, 0, sizeof(tmpstr));
915		sprintf(tmpstr, "%d", result.DefaultKeyIdx);
916		retval += websWrite(wp, "%s%s%s\n", tag1, tmpstr, tag2);
917
918		//6. WPAKey
919		memset(tmpstr, 0, sizeof(tmpstr));
920		for (i=0; i<64; i++)	// WPA key default length is 64 (defined & hardcode in driver)
921		{
922			sprintf(tmpstr, "%s%c", tmpstr, result.WscWPAKey[i]);
923		}
924		if (!strlen(tmpstr))
925			retval += websWrite(wp, "%sNone%s\n", tag1, tag2);
926		else
927		{
928			char_to_ascii(tmpstr2, tmpstr);
929			retval += websWrite(wp, "%s%s%s\n", tag1, tmpstr2, tag2);
930		}
931
932		//7. AP PIN Code
933		retval += websWrite(wp, "%s%08d%s\n", tag1, getAPPIN(u), tag2);
934
935		//8. Saved WPAKey
936		if (!strlen(nvram_safe_get(strcat_r(prefix, "wpa_psk", tmp))))
937			retval += websWrite(wp, "%s%s%s\n", tag1, "None", tag2);
938		else
939		{
940			char_to_ascii(tmpstr, nvram_safe_get(strcat_r(prefix, "wpa_psk", tmp)));
941			retval += websWrite(wp, "%s%s%s\n", tag1, tmpstr, tag2);
942		}
943
944		//9. WPS enable?
945		if (!strcmp(nvram_safe_get(strcat_r(prefix, "wps_mode", tmp)), "enabled"))
946			retval += websWrite(wp, "%s%s%s\n", tag1, "None", tag2);
947		else
948			retval += websWrite(wp, "%s%s%s\n", tag1, nvram_safe_get("wps_enable"), tag2);
949
950		//A. WPS mode
951		wps_sta_pin = nvram_safe_get("wps_sta_pin");
952		if (strlen(wps_sta_pin) && strcmp(wps_sta_pin, "00000000"))
953			retval += websWrite(wp, "%s%s%s\n", tag1, "1", tag2);
954		else
955			retval += websWrite(wp, "%s%s%s\n", tag1, "2", tag2);
956
957		//B. current auth mode
958		if (!strlen(nvram_safe_get(strcat_r(prefix, "auth_mode_x", tmp))))
959			retval += websWrite(wp, "%s%s%s\n", tag1, "None", tag2);
960		else
961			retval += websWrite(wp, "%s%s%s\n", tag1, nvram_safe_get(strcat_r(prefix, "auth_mode_x", tmp)), tag2);
962
963		//C. WPS band
964		retval += websWrite(wp, "%s%d%s\n", tag1, u, tag2);
965#if defined(RTCONFIG_WPSMULTIBAND)
966	}
967#endif
968
969	retval += websWrite(wp, "</wps>");
970
971	return retval;
972}
973
974int
975ej_wps_info(int eid, webs_t wp, int argc, char_t **argv)
976{
977	return wl_wps_info(eid, wp, argc, argv, 1);
978}
979
980int
981ej_wps_info_2g(int eid, webs_t wp, int argc, char_t **argv)
982{
983	return wl_wps_info(eid, wp, argc, argv, 0);
984}
985
986// Wireless Client List		 /* Start --Alicia, 08.09.23 */
987
988int ej_wl_sta_list_2g(int eid, webs_t wp, int argc, char_t **argv)
989{
990	struct iwreq wrq;
991	int i, firstRow;
992	char data[16384];
993	char mac[ETHER_ADDR_STR_LEN];
994	RT_802_11_MAC_TABLE_2G *mp2;
995	char *value;
996	int rssi, cnt;
997	int from_app = 0;
998
999	from_app = check_user_agent(user_agent);
1000
1001	memset(mac, 0, sizeof(mac));
1002
1003	/* query wl for authenticated sta list */
1004	memset(data, 0, sizeof(data));
1005	wrq.u.data.pointer = data;
1006	wrq.u.data.length = sizeof(data);
1007	wrq.u.data.flags = 0;
1008	if (wl_ioctl(WIF_2G, RTPRIV_IOCTL_GET_MAC_TABLE, &wrq) < 0)
1009		goto exit;
1010
1011	/* build wireless sta list */
1012	firstRow = 1;
1013	mp2 = (RT_802_11_MAC_TABLE_2G *)wrq.u.data.pointer;
1014	for (i = 0; i<mp2->Num; i++)
1015	{
1016		rssi = cnt = 0;
1017		if (mp2->Entry[i].AvgRssi0) {
1018			rssi += mp2->Entry[i].AvgRssi0;
1019			cnt++;
1020		}
1021		if (mp2->Entry[i].AvgRssi1) {
1022			rssi += mp2->Entry[i].AvgRssi1;
1023			cnt++;
1024		}
1025		if (mp2->Entry[i].AvgRssi2) {
1026			rssi += mp2->Entry[i].AvgRssi2;
1027			cnt++;
1028		}
1029		if (cnt == 0)
1030			continue;	//skip this sta info
1031
1032		if (firstRow == 1)
1033			firstRow = 0;
1034		else
1035			websWrite(wp, ", ");
1036
1037		if (from_app == 0)
1038			websWrite(wp, "[");
1039
1040		sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
1041				mp2->Entry[i].Addr[0], mp2->Entry[i].Addr[1],
1042				mp2->Entry[i].Addr[2], mp2->Entry[i].Addr[3],
1043				mp2->Entry[i].Addr[4], mp2->Entry[i].Addr[5]);
1044		websWrite(wp, "\"%s\"", mac);
1045
1046		if (from_app != 0) {
1047			websWrite(wp, ":{");
1048			websWrite(wp, "\"isWL\":");
1049		}
1050
1051		value = "Yes";
1052		if (from_app == 0)
1053			websWrite(wp, ", \"%s\"", value);
1054		else
1055			websWrite(wp, "\"%s\"", value);
1056
1057		value = "";
1058		if (from_app == 0)
1059			websWrite(wp, ", \"%s\"", value);
1060
1061		if (from_app != 0)
1062			websWrite(wp, ",\"rssi\":");
1063
1064		rssi = rssi / cnt;
1065		if (from_app == 0)
1066			websWrite(wp, ", \"%d\"", rssi);
1067		else
1068			websWrite(wp, "\"%d\"", rssi);
1069
1070
1071		if (from_app == 0)
1072			websWrite(wp, "]");
1073		else
1074			websWrite(wp, "}");
1075	}
1076
1077	/* error/exit */
1078exit:
1079	return 0;
1080}
1081
1082int ej_wl_sta_list_5g(int eid, webs_t wp, int argc, char_t **argv)
1083{
1084#if defined(RTCONFIG_HAS_5G)
1085	struct iwreq wrq;
1086	int i, firstRow;
1087	char data[16384];
1088	char mac[ETHER_ADDR_STR_LEN];
1089	RT_802_11_MAC_TABLE_5G *mp;
1090	char *value;
1091	int rssi, cnt;
1092	int from_app = 0;
1093
1094	from_app = check_user_agent(user_agent);
1095
1096	memset(mac, 0, sizeof(mac));
1097
1098	/* query wl for authenticated sta list */
1099	memset(data, 0, sizeof(data));
1100	wrq.u.data.pointer = data;
1101	wrq.u.data.length = sizeof(data);
1102	wrq.u.data.flags = 0;
1103	if (wl_ioctl(WIF_5G, RTPRIV_IOCTL_GET_MAC_TABLE, &wrq) < 0)
1104		goto exit;
1105
1106	/* build wireless sta list */
1107	firstRow = 1;
1108	mp = (RT_802_11_MAC_TABLE_5G *)wrq.u.data.pointer;
1109	for (i = 0; i<mp->Num; i++)
1110	{
1111		rssi = cnt = 0;
1112		if (mp->Entry[i].AvgRssi0) {
1113			rssi += mp->Entry[i].AvgRssi0;
1114			cnt++;
1115		}
1116		if (mp->Entry[i].AvgRssi1) {
1117			rssi += mp->Entry[i].AvgRssi1;
1118			cnt++;
1119		}
1120		if (mp->Entry[i].AvgRssi2) {
1121			rssi += mp->Entry[i].AvgRssi2;
1122			cnt++;
1123		}
1124		if (cnt == 0)
1125			continue;	//skip this sta info
1126
1127		if (firstRow == 1)
1128			firstRow = 0;
1129		else
1130			websWrite(wp, ", ");
1131
1132		if (from_app == 0)
1133			websWrite(wp, "[");
1134
1135		sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
1136				mp->Entry[i].Addr[0], mp->Entry[i].Addr[1],
1137				mp->Entry[i].Addr[2], mp->Entry[i].Addr[3],
1138				mp->Entry[i].Addr[4], mp->Entry[i].Addr[5]);
1139		websWrite(wp, "\"%s\"", mac);
1140
1141		if (from_app != 0) {
1142			websWrite(wp, ":{");
1143			websWrite(wp, "\"isWL\":");
1144		}
1145
1146		value = "Yes";
1147		if (from_app == 0)
1148			websWrite(wp, ", \"%s\"", value);
1149		else
1150			websWrite(wp, "\"%s\"", value);
1151
1152		value = "";
1153		if (from_app == 0)
1154			websWrite(wp, ", \"%s\"", value);
1155
1156		if (from_app != 0)
1157			websWrite(wp, ",\"rssi\":");
1158
1159		rssi = rssi / cnt;
1160		if (from_app == 0)
1161			websWrite(wp, ", \"%d\"", rssi);
1162		else
1163			websWrite(wp, "\"%d\"", rssi);
1164
1165
1166		if (from_app == 0)
1167			websWrite(wp, "]");
1168		else
1169			websWrite(wp, "}");
1170	}
1171
1172	/* error/exit */
1173#endif	/* RTCONFIG_HAS_5G */
1174exit:
1175	return 0;
1176}
1177
1178int ej_wl_auth_list(int eid, webs_t wp, int argc, char_t **argv)
1179{
1180	struct iwreq wrq;
1181	int i, firstRow;
1182	char data[16384];
1183	char mac[ETHER_ADDR_STR_LEN];
1184	RT_802_11_MAC_TABLE_5G *mp;
1185	RT_802_11_MAC_TABLE_2G *mp2;
1186	char *value;
1187
1188	memset(mac, 0, sizeof(mac));
1189
1190	/* query wl for authenticated sta list */
1191	memset(data, 0, sizeof(data));
1192	wrq.u.data.pointer = data;
1193	wrq.u.data.length = sizeof(data);
1194	wrq.u.data.flags = 0;
1195	if (wl_ioctl(WIF_2G, RTPRIV_IOCTL_GET_MAC_TABLE, &wrq) < 0)
1196		goto exit;
1197
1198	/* build wireless sta list */
1199	firstRow = 1;
1200	mp2 = (RT_802_11_MAC_TABLE_2G *)wrq.u.data.pointer;
1201	for (i = 0; i<mp2->Num; i++)
1202	{
1203		if (firstRow == 1)
1204			firstRow = 0;
1205		else
1206			websWrite(wp, ", ");
1207		websWrite(wp, "[");
1208
1209		sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
1210				mp2->Entry[i].Addr[0], mp2->Entry[i].Addr[1],
1211				mp2->Entry[i].Addr[2], mp2->Entry[i].Addr[3],
1212				mp2->Entry[i].Addr[4], mp2->Entry[i].Addr[5]);
1213		websWrite(wp, "\"%s\"", mac);
1214
1215		value = "Yes";
1216		websWrite(wp, ", \"%s\"", value);
1217
1218		value = "";
1219		websWrite(wp, ", \"%s\"", value);
1220
1221		websWrite(wp, "]");
1222	}
1223
1224#if defined(RTCONFIG_HAS_5G)
1225	/* query wl for authenticated sta list */
1226	memset(data, 0, sizeof(data));
1227	wrq.u.data.pointer = data;
1228	wrq.u.data.length = sizeof(data);
1229	wrq.u.data.flags = 0;
1230	if (wl_ioctl(WIF_5G, RTPRIV_IOCTL_GET_MAC_TABLE, &wrq) < 0)
1231		goto exit;
1232
1233	/* build wireless sta list */
1234	mp = (RT_802_11_MAC_TABLE_5G *)wrq.u.data.pointer;
1235	for (i = 0; i<mp->Num; i++)
1236	{
1237		if (firstRow == 1)
1238			firstRow = 0;
1239		else
1240			websWrite(wp, ", ");
1241		websWrite(wp, "[");
1242
1243		sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
1244				mp->Entry[i].Addr[0], mp->Entry[i].Addr[1],
1245				mp->Entry[i].Addr[2], mp->Entry[i].Addr[3],
1246				mp->Entry[i].Addr[4], mp->Entry[i].Addr[5]);
1247		websWrite(wp, "\"%s\"", mac);
1248
1249		value = "Yes";
1250		websWrite(wp, ", \"%s\"", value);
1251
1252		value = "";
1253		websWrite(wp, ", \"%s\"", value);
1254
1255		websWrite(wp, "]");
1256	}
1257#endif	/* RTCONFIG_HAS_5G */
1258
1259	/* error/exit */
1260exit:
1261	return 0;
1262}
1263#if defined(RTN65U)
1264static void convertToUpper(char *str)
1265{
1266	if(str == NULL)
1267		return;
1268	while(*str)
1269	{
1270		if(*str >= 'a' && *str <= 'z')
1271		{
1272			*str &= (unsigned char)~0x20;
1273		}
1274		str++;
1275	}
1276}
1277#endif
1278static int wl_scan(int eid, webs_t wp, int argc, char_t **argv, int unit)
1279{
1280	int retval = 0, i = 0, apCount = 0;
1281	char data[8192];
1282	char ssid_str[256];
1283	char header[128];
1284	struct iwreq wrq;
1285	SSA *ssap;
1286	char tmp[128], prefix[] = "wlXXXXXXXXXX_";
1287	int lock;
1288
1289	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
1290	memset(data, 0x00, 255);
1291	strcpy(data, "SiteSurvey=1");
1292	wrq.u.data.length = strlen(data)+1;
1293	wrq.u.data.pointer = data;
1294	wrq.u.data.flags = 0;
1295
1296	lock = file_lock("nvramcommit");
1297	if (wl_ioctl(nvram_safe_get(strcat_r(prefix, "ifname", tmp)), RTPRIV_IOCTL_SET, &wrq) < 0)
1298	{
1299		file_unlock(lock);
1300		dbg("Site Survey fails\n");
1301		return 0;
1302	}
1303	file_unlock(lock);
1304	dbg("Please wait");
1305	sleep(1);
1306	dbg(".");
1307	sleep(1);
1308	dbg(".");
1309	sleep(1);
1310	dbg(".");
1311	sleep(1);
1312	dbg(".\n\n");
1313	memset(data, 0, 8192);
1314	strcpy(data, "");
1315	wrq.u.data.length = 8192;
1316	wrq.u.data.pointer = data;
1317	wrq.u.data.flags = 0;
1318	if (wl_ioctl(nvram_safe_get(strcat_r(prefix, "ifname", tmp)), RTPRIV_IOCTL_GSITESURVEY, &wrq) < 0)
1319	{
1320		dbg("errors in getting site survey result\n");
1321		return 0;
1322	}
1323	memset(header, 0, sizeof(header));
1324	//sprintf(header, "%-3s%-33s%-18s%-8s%-15s%-9s%-8s%-2s\n", "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", "NT");
1325#if 0// defined(RTN14U)
1326	sprintf(header, "%-4s%-33s%-18s%-9s%-16s%-9s%-8s%-4s%-5s\n", "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode"," WPS", " DPID");
1327#else
1328	sprintf(header, "%-4s%-33s%-18s%-9s%-16s%-9s%-8s\n", "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode");
1329#endif
1330	dbg("\n%s", header);
1331	if (wrq.u.data.length > 0)
1332	{
1333#if defined(RTN65U)
1334		if (unit == 0 && get_model() == MODEL_RTN65U)
1335		{
1336			char *encryption;
1337			SITE_SURVEY_RT3352_iNIC *pSsap, *ssAP;
1338
1339			pSsap = ssAP = (SITE_SURVEY_RT3352_iNIC *) (1 /* '\n' */ + wrq.u.data.pointer +  sizeof(SITE_SURVEY_RT3352_iNIC) /* header */);
1340			while(((unsigned int)wrq.u.data.pointer + wrq.u.data.length) > (unsigned int) ssAP)
1341			{
1342				ssAP->channel   [sizeof(ssAP->channel)    -1] = '\0';
1343				ssAP->ssid      [32                         ] = '\0';
1344				ssAP->bssid     [17                         ] = '\0';
1345				ssAP->encryption[sizeof(ssAP->encryption) -1] = '\0';
1346				if((encryption = strchr(ssAP->authmode, '/')) != NULL)
1347				{
1348					memmove(ssAP->encryption, encryption +1, sizeof(ssAP->encryption) -1);
1349					memset(encryption, ' ', sizeof(ssAP->authmode) - (encryption - ssAP->authmode));
1350					*encryption = '\0';
1351				}
1352				ssAP->authmode  [sizeof(ssAP->authmode)   -1] = '\0';
1353				ssAP->signal    [sizeof(ssAP->signal)     -1] = '\0';
1354				ssAP->wmode     [sizeof(ssAP->wmode)      -1] = '\0';
1355				ssAP->extch     [sizeof(ssAP->extch)      -1] = '\0';
1356				ssAP->nt        [sizeof(ssAP->nt)         -1] = '\0';
1357				ssAP->wps       [sizeof(ssAP->wps)        -1] = '\0';
1358				ssAP->dpid      [sizeof(ssAP->dpid)       -1] = '\0';
1359
1360				convertToUpper(ssAP->bssid);
1361				ssAP++;
1362				apCount++;
1363			}
1364
1365			if (apCount)
1366			{
1367				retval += websWrite(wp, "[");
1368				for (i = 0; i < apCount; i++)
1369				{
1370					dbg("%-4s%-33s%-18s%-9s%-16s%-9s%-8s\n",
1371						pSsap[i].channel,
1372						pSsap[i].ssid,
1373						pSsap[i].bssid,
1374						pSsap[i].encryption,
1375						pSsap[i].authmode,
1376						pSsap[i].signal,
1377						pSsap[i].wmode
1378					);
1379
1380					memset(ssid_str, 0, sizeof(ssid_str));
1381					char_to_ascii(ssid_str, trim_r(pSsap[i].ssid));
1382
1383					if (!i)
1384						retval += websWrite(wp, "[\"%s\", \"%s\"]", ssid_str, pSsap[i].bssid);
1385					else
1386						retval += websWrite(wp, ", [\"%s\", \"%s\"]", ssid_str, pSsap[i].bssid);
1387				}
1388				retval += websWrite(wp, "]");
1389				dbg("\n");
1390			}
1391			else
1392				retval += websWrite(wp, "[]");
1393			return retval;
1394		}
1395#endif
1396		ssap=(SSA *)(wrq.u.data.pointer+strlen(header)+1);
1397		int len = strlen(wrq.u.data.pointer+strlen(header))-1;
1398		char *sp, *op;
1399 		op = sp = wrq.u.data.pointer+strlen(header)+1;
1400		while (*sp && ((len - (sp-op)) >= 0))
1401		{
1402			ssap->SiteSurvey[i].channel[3] = '\0';
1403			ssap->SiteSurvey[i].ssid[32] = '\0';
1404			ssap->SiteSurvey[i].bssid[17] = '\0';
1405			ssap->SiteSurvey[i].encryption[8] = '\0';
1406			ssap->SiteSurvey[i].authmode[15] = '\0';
1407			ssap->SiteSurvey[i].signal[8] = '\0';
1408			ssap->SiteSurvey[i].wmode[7] = '\0';
1409#if 0//defined(RTN14U)
1410			ssap->SiteSurvey[i].wps[3] = '\0';
1411			ssap->SiteSurvey[i].dpid[4] = '\0';
1412#endif
1413			sp+=strlen(header);
1414			apCount=++i;
1415		}
1416		if (apCount)
1417		{
1418			retval += websWrite(wp, "[");
1419			for (i = 0; i < apCount; i++)
1420			{
1421			   	dbg("\napCount=%d\n",i);
1422				dbg(
1423#if 0//defined(RTN14U)
1424				"%-4s%-33s%-18s%-9s%-16s%-9s%-8s%-4s%-5s\n",
1425#else
1426				"%-4s%-33s%-18s%-9s%-16s%-9s%-8s\n",
1427#endif
1428					ssap->SiteSurvey[i].channel,
1429					(char*)ssap->SiteSurvey[i].ssid,
1430					ssap->SiteSurvey[i].bssid,
1431					ssap->SiteSurvey[i].encryption,
1432					ssap->SiteSurvey[i].authmode,
1433					ssap->SiteSurvey[i].signal,
1434					ssap->SiteSurvey[i].wmode
1435#if 0//defined(RTN14U)
1436					, ssap->SiteSurvey[i].wps
1437					, ssap->SiteSurvey[i].dpid
1438#endif
1439				);
1440
1441				memset(ssid_str, 0, sizeof(ssid_str));
1442				char_to_ascii(ssid_str, trim_r(ssap->SiteSurvey[i].ssid));
1443
1444				if (!i)
1445//					retval += websWrite(wp, "\"%s\"", ssap->SiteSurvey[i].bssid);
1446					retval += websWrite(wp, "[\"%s\", \"%s\"]", ssid_str, ssap->SiteSurvey[i].bssid);
1447				else
1448//					retval += websWrite(wp, ", \"%s\"", ssap->SiteSurvey[i].bssid);
1449					retval += websWrite(wp, ", [\"%s\", \"%s\"]", ssid_str, ssap->SiteSurvey[i].bssid);
1450			}
1451			retval += websWrite(wp, "]");
1452			dbg("\n");
1453		}
1454		else
1455			retval += websWrite(wp, "[]");
1456	}
1457	return retval;
1458}
1459
1460int
1461ej_wl_scan(int eid, webs_t wp, int argc, char_t **argv)
1462{
1463	return wl_scan(eid, wp, argc, argv, 0);
1464}
1465
1466int
1467ej_wl_scan_2g(int eid, webs_t wp, int argc, char_t **argv)
1468{
1469	return wl_scan(eid, wp, argc, argv, 0);
1470}
1471
1472int
1473ej_wl_scan_5g(int eid, webs_t wp, int argc, char_t **argv)
1474{
1475	return wl_scan(eid, wp, argc, argv, 1);
1476}
1477
1478
1479static int ej_wl_channel_list(int eid, webs_t wp, int argc, char_t **argv, int unit)
1480{
1481	int retval = 0;
1482	char tmp[128], prefix[] = "wlXXXXXXXXXX_";
1483	char *country_code;
1484	char chList[256];
1485	int band;
1486
1487	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
1488	country_code = nvram_get(strcat_r(prefix, "country_code", tmp));
1489	band = unit;
1490
1491	if (country_code == NULL || strlen(country_code) != 2) return retval;
1492
1493	if (band != 0 && band != 1) return retval;
1494
1495	//try getting channel list via wifi driver first
1496	if(get_channel_list_via_driver(unit, chList, sizeof(chList)) > 0)
1497	{
1498		retval += websWrite(wp, "[%s]", chList);
1499	}
1500	else if(get_channel_list_via_country(unit, country_code, chList, sizeof(chList)) > 0)
1501	{
1502		retval += websWrite(wp, "[%s]", chList);
1503	}
1504	return retval;
1505}
1506
1507
1508int
1509ej_wl_channel_list_2g(int eid, webs_t wp, int argc, char_t **argv)
1510{
1511	return ej_wl_channel_list(eid, wp, argc, argv, 0);
1512}
1513
1514int
1515ej_wl_channel_list_5g(int eid, webs_t wp, int argc, char_t **argv)
1516{
1517	return ej_wl_channel_list(eid, wp, argc, argv, 1);
1518}
1519
1520
1521static int ej_wl_rate(int eid, webs_t wp, int argc, char_t **argv, int unit)
1522{
1523	struct iwreq wrq;
1524	int retval = 0;
1525	char tmp[256], prefix[] = "wlXXXXXXXXXX_";
1526	char *name;
1527	char word[256], *next;
1528	int unit_max = 0;
1529	int rate=0;
1530	int status;
1531	char rate_buf[32];
1532	int sw_mode = nvram_get_int("sw_mode");
1533	int wlc_band = nvram_get_int("wlc_band");
1534
1535	sprintf(rate_buf, "0 Mbps");
1536
1537	foreach (word, nvram_safe_get("wl_ifnames"), next)
1538		unit_max++;
1539
1540	if (unit > (unit_max - 1))
1541		goto ERROR;
1542
1543	if (wlc_band == unit && (sw_mode == SW_MODE_REPEATER || sw_mode == SW_MODE_HOTSPOT))
1544		snprintf(prefix, sizeof(prefix), "wl%d.1_", unit);
1545	else
1546#if 0
1547		snprintf(prefix, sizeof(prefix), "wl%d_", unit);
1548
1549	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1550
1551	wrq.u.bitrate.value=-1;
1552	if (wl_ioctl(name, SIOCGIWRATE, &wrq))
1553	{
1554		dbG("can not get rate info of %s\n", name);
1555		goto ERROR;
1556	}
1557
1558	rate = wrq.u.bitrate.value;
1559	if ((rate == -1) || (rate == 0))
1560		sprintf(rate_buf, "auto");
1561	else
1562		sprintf(rate_buf, "%d Mbps", (rate / 1000000));
1563#else
1564		goto ERROR;
1565	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
1566
1567	memset(tmp, 0x00, sizeof(tmp));
1568	wrq.u.data.length = sizeof(tmp);
1569	wrq.u.data.pointer = (caddr_t) tmp;
1570	wrq.u.data.flags = ASUS_SUBCMD_CONN_STATUS;
1571
1572	if (wl_ioctl(name, RTPRIV_IOCTL_ASUSCMD, &wrq) < 0)
1573	{
1574		dbg("%s: errors in getting %s CONN_STATUS result\n", __func__, name);
1575		goto ERROR;
1576	}
1577	status = ((int*)tmp)[0];
1578	rate   = ((int*)tmp)[1];
1579
1580	if(status == 6)
1581		sprintf(rate_buf, "%d Mbps", rate);
1582#endif
1583
1584ERROR:
1585	retval += websWrite(wp, "%s", rate_buf);
1586	return retval;
1587}
1588
1589
1590int
1591ej_wl_rate_2g(int eid, webs_t wp, int argc, char_t **argv)
1592{
1593   	if(nvram_match("sw_mode", "2"))
1594		return ej_wl_rate(eid, wp, argc, argv, 0);
1595	else
1596	   	return 0;
1597}
1598
1599int
1600ej_wl_rate_5g(int eid, webs_t wp, int argc, char_t **argv)
1601{
1602   	if(nvram_match("sw_mode", "2"))
1603		return ej_wl_rate(eid, wp, argc, argv, 1);
1604	else
1605	   	return 0;
1606}
1607
1608#ifdef RTCONFIG_PROXYSTA
1609int
1610ej_wl_auth_psta(int eid, webs_t wp, int argc, char_t **argv)
1611{
1612	int retval = 0;
1613
1614	if(nvram_match("wlc_state", "2"))	//connected
1615		retval += websWrite(wp, "wlc_state=1;wlc_state_auth=0;");
1616	//else if(?)				//authorization failed
1617	//	retval += websWrite(wp, "wlc_state=2;wlc_state_auth=1;");
1618	else					//disconnected
1619		retval += websWrite(wp, "wlc_state=0;wlc_state_auth=0;");
1620
1621	return retval;
1622}
1623#endif
1624