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 * Copyright 2012, ASUSTeK Inc.
18 * All Rights Reserved.
19 *
20 * THIS SOFTWARE IS OFFERED "AS IS", AND ASUS GRANTS NO WARRANTIES OF ANY
21 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
22 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
23 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
24 *
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/time.h>
31#include <unistd.h>
32#include <bcmnvram.h>
33#include <bcmutils.h>
34#include <wlutils.h>
35#include <shutils.h>
36#include <shared.h>
37#include <wlioctl.h>
38#ifdef PSTA_DEBUG
39#include <rc.h>
40#else
41#include <signal.h>
42#endif
43
44#include <wlscan.h>
45#ifdef RTCONFIG_BCM_7114
46#include <bcmutils.h>
47#include <bcmendian.h>
48#include <security_ipc.h>
49#endif
50
51#ifdef RTCONFIG_BCMWL6
52#ifdef RTCONFIG_PROXYSTA
53
54#define NORMAL_PERIOD	30
55#define	MAX_STA_COUNT	128
56#define	NVRAM_BUFSIZE	100
57
58int psta_debug = 0;
59int count_bss_down = 0;
60#ifdef PSTA_DEBUG
61static int count = -1;
62#endif
63
64/* WPS ENR mode APIs */
65typedef struct wlc_ap_list_info
66{
67#if 0
68	bool	used;
69#endif
70	uint8	ssid[33];
71	uint8	ssidLen;
72	uint8	BSSID[6];
73#if 0
74	uint8	*ie_buf;
75	uint32	ie_buflen;
76#endif
77	uint8	channel;
78#if 0
79	uint8	wep;
80#endif
81} wlc_ap_list_info_t;
82
83#define WLC_SCAN_RETRY_TIMES		5
84#define NUMCHANS			64
85#define MAX_SSID_LEN			32
86
87static wlc_ap_list_info_t ap_list[MAX_NUMBER_OF_APINFO];
88static char scan_result[WLC_SCAN_RESULT_BUF_LEN];
89
90/* The below macro handle endian mis-matches between wl utility and wl driver. */
91static bool g_swap = FALSE;
92#define htod32(i) (g_swap?bcmswap32(i):(uint32)(i))
93#define dtoh32(i) (g_swap?bcmswap32(i):(uint32)(i))
94
95#ifdef RTCONFIG_BCM_7114
96typedef struct escan_wksp_s {
97	uint8 packet[4096];
98	int event_fd;
99} escan_wksp_t;
100
101static escan_wksp_t *d_info;
102
103/* open a UDP packet to event dispatcher for receiving/sending data */
104static int
105escan_open_eventfd()
106{
107	int reuse = 1;
108	struct sockaddr_in sockaddr;
109	int fd = -1;
110
111	d_info->event_fd = -1;
112
113	/* open loopback socket to communicate with event dispatcher */
114	memset(&sockaddr, 0, sizeof(sockaddr));
115	sockaddr.sin_family = AF_INET;
116	sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
117	sockaddr.sin_port = htons(EAPD_WKSP_DCS_UDP_SPORT);
118
119	if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
120		dbg("Unable to create loopback socket\n");
121		goto exit;
122	}
123
124	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) {
125		dbg("Unable to setsockopt to loopback socket %d.\n", fd);
126		goto exit;
127	}
128
129	if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
130		dbg("Unable to bind to loopback socket %d\n", fd);
131		goto exit;
132	}
133
134	d_info->event_fd = fd;
135
136	return 0;
137
138	/* error handling */
139exit:
140	if (fd != -1) {
141		close(fd);
142	}
143
144	return errno;
145}
146
147static bool escan_swap = FALSE;
148#define htod16(i) (escan_swap?bcmswap16(i):(uint16)(i))
149#define WL_EVENT_TIMEOUT 10
150
151struct escan_bss {
152	struct escan_bss *next;
153	wl_bss_info_t bss[1];
154};
155#define ESCAN_BSS_FIXED_SIZE 4
156
157/* listen to sockets and receive escan results */
158static int
159get_scan_escan(char *scan_buf, uint buf_len)
160{
161	fd_set fdset;
162	int fd;
163	struct timeval tv;
164	uint8 *pkt;
165	int len;
166	int retval;
167	wl_escan_result_t *escan_data;
168	struct escan_bss *escan_bss_head = NULL;
169	struct escan_bss *escan_bss_tail = NULL;
170	struct escan_bss *result;
171
172	d_info = (escan_wksp_t*)malloc(sizeof(escan_wksp_t));
173
174	escan_open_eventfd();
175
176	if (d_info->event_fd == -1) {
177		return -1;
178	}
179
180	fd = d_info->event_fd;
181
182	FD_ZERO(&fdset);
183	FD_SET(fd, &fdset);
184
185	pkt = d_info->packet;
186	len = sizeof(d_info->packet);
187
188	tv.tv_sec = WL_EVENT_TIMEOUT;
189	tv.tv_usec = 0;
190
191	/* listen to data availible on all sockets */
192	while ((retval = select(fd+1, &fdset, NULL, NULL, &tv)) > 0) {
193		bcm_event_t *pvt_data;
194		uint32 evt_type;
195		uint32 status;
196
197		if (recv(fd, pkt, len, 0) <= 0)
198			continue;
199
200		pvt_data = (bcm_event_t *)(pkt + IFNAMSIZ);
201		evt_type = ntoh32(pvt_data->event.event_type);
202
203		if (evt_type == WLC_E_ESCAN_RESULT) {
204			escan_data = (wl_escan_result_t*)(pvt_data + 1);
205			status = ntoh32(pvt_data->event.status);
206
207			if (status == WLC_E_STATUS_PARTIAL) {
208				wl_bss_info_t *bi = &escan_data->bss_info[0];
209				wl_bss_info_t *bss = NULL;
210
211				/* check if we've received info of same BSSID */
212				for (result = escan_bss_head; result; result = result->next) {
213					bss = result->bss;
214
215					if (!memcmp(bi->BSSID.octet, bss->BSSID.octet,
216						ETHER_ADDR_LEN) &&
217						CHSPEC_BAND(bi->chanspec) ==
218						CHSPEC_BAND(bss->chanspec) &&
219						bi->SSID_len == bss->SSID_len &&
220						!memcmp(bi->SSID, bss->SSID, bi->SSID_len))
221						break;
222					}
223
224				if (!result) {
225					/* New BSS. Allocate memory and save it */
226					struct escan_bss *ebss = (struct escan_bss *)malloc(
227						OFFSETOF(struct escan_bss, bss)	+ bi->length);
228
229					if (!ebss) {
230						dbg("can't allocate memory for bss");
231						goto exit;
232					}
233
234					ebss->next = NULL;
235					memcpy(&ebss->bss, bi, bi->length);
236					if (escan_bss_tail) {
237						escan_bss_tail->next = ebss;
238					}
239					else {
240						escan_bss_head = ebss;
241					}
242					escan_bss_tail = ebss;
243				}
244				else if (bi->RSSI != WLC_RSSI_INVALID) {
245					/* We've got this BSS. Update rssi if necessary */
246					if (((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
247						(bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) &&
248					    ((bss->RSSI == WLC_RSSI_INVALID) ||
249						(bss->RSSI < bi->RSSI))) {
250						/* preserve max RSSI if the measurements are
251						 * both on-channel or both off-channel
252						 */
253						bss->RSSI = bi->RSSI;
254						bss->SNR = bi->SNR;
255						bss->phy_noise = bi->phy_noise;
256					} else if ((bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
257						(bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
258						/* preserve the on-channel rssi measurement
259						 * if the new measurement is off channel
260						*/
261						bss->RSSI = bi->RSSI;
262						bss->SNR = bi->SNR;
263						bss->phy_noise = bi->phy_noise;
264						bss->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
265					}
266				}
267			}
268			else if (status == WLC_E_STATUS_SUCCESS) {
269				/* Escan finished. Let's go dump the results. */
270				break;
271			}
272			else {
273				dbg("sync_id: %d, status:%d, misc. error/abort\n",
274					escan_data->sync_id, status);
275				goto exit;
276			}
277		}
278	}
279
280	if (retval > 0) {
281		wl_scan_results_t* s_result = (wl_scan_results_t*)scan_buf;
282		wl_bss_info_t *bi = s_result->bss_info;
283		wl_bss_info_t *bss;
284
285		s_result->count = 0;
286		len = buf_len - WL_SCAN_RESULTS_FIXED_SIZE;
287
288		for (result = escan_bss_head; result; result = result->next) {
289			bss = result->bss;
290			if (buf_len < bss->length) {
291				dbg("Memory not enough for scan results\n");
292				break;
293			}
294			memcpy(bi, bss, bss->length);
295			bi = (wl_bss_info_t*)((int8*)bi + bss->length);
296			len -= bss->length;
297			s_result->count++;
298		}
299	} else if (retval == 0) {
300		dbg("Scan timeout!\n");
301	} else {
302		dbg("Receive scan results failed!\n");
303	}
304
305exit:
306	if (d_info) {
307		if (d_info->event_fd != -1) {
308			close(d_info->event_fd);
309			d_info->event_fd = -1;
310		}
311
312		free(d_info);
313	}
314
315	/* free scan results */
316	result = escan_bss_head;
317	while (result) {
318		struct escan_bss *tmp = result->next;
319		free(result);
320		result = tmp;
321	}
322
323	return (retval > 0) ? BCME_OK : BCME_ERROR;
324}
325
326static char *
327wl_get_scan_results_escan(int unit)
328{
329	int ret, retry_times = 0;
330	wl_escan_params_t *params = NULL;
331	int params_size = WL_SCAN_PARAMS_FIXED_SIZE + NUMCHANS * sizeof(uint16);
332	wlc_ssid_t wst = {0, ""};
333	int org_scan_time = 20, scan_time = 40;
334	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
335	char *ifname = NULL;
336
337	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
338	wst.SSID_len = strlen(nvram_safe_get(strcat_r(prefix, "ssid", tmp)));
339	if (wst.SSID_len <= MAX_SSID_LEN)
340		memcpy(wst.SSID, nvram_safe_get(strcat_r(prefix, "ssid", tmp)), wst.SSID_len);
341	else
342		wst.SSID_len = 0;
343
344	params = (wl_escan_params_t*)malloc(params_size);
345	if (params == NULL) {
346		return NULL;
347	}
348
349	memset(params, 0, params_size);
350	params->params.ssid = wst;
351	params->params.bss_type = DOT11_BSSTYPE_ANY;
352	memcpy(&params->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
353	params->params.scan_type = -1;
354	params->params.nprobes = -1;
355	params->params.active_time = -1;
356	params->params.passive_time = -1;
357	params->params.home_time = -1;
358	params->params.channel_num = 0;
359
360	params->version = htod32(ESCAN_REQ_VERSION);
361	params->action = htod16(WL_SCAN_ACTION_START);
362
363	srand((unsigned int)uptime());
364	params->sync_id = htod16(rand() & 0xffff);
365
366	params_size += OFFSETOF(wl_escan_params_t, params);
367
368	ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
369	/* extend scan channel time to get more AP probe resp */
370	wl_ioctl(ifname, WLC_GET_SCAN_CHANNEL_TIME, &org_scan_time, sizeof(org_scan_time));
371	if (org_scan_time < scan_time)
372		wl_ioctl(ifname, WLC_SET_SCAN_CHANNEL_TIME, &scan_time,	sizeof(scan_time));
373
374retry:
375	ret = wl_iovar_set(ifname, "escan", params, params_size);
376	if (ret < 0) {
377		if (retry_times++ < WLC_SCAN_RETRY_TIMES) {
378			if (psta_debug)
379			dbg("set escan command failed, retry %d\n", retry_times);
380			sleep(1);
381			goto retry;
382		}
383	}
384
385	sleep(2);
386
387	ret = get_scan_escan(scan_result, WLC_SCAN_RESULT_BUF_LEN);
388	if (ret < 0 && retry_times++ < WLC_SCAN_RETRY_TIMES) {
389		if (psta_debug)
390		dbg("get scan result failed, retry %d\n", retry_times);
391		sleep(1);
392		goto retry;
393	}
394
395	free(params);
396
397	/* restore original scan channel time */
398	wl_ioctl(ifname, WLC_SET_SCAN_CHANNEL_TIME, &org_scan_time, sizeof(org_scan_time));
399
400	if (ret < 0)
401		return NULL;
402
403	return scan_result;
404}
405
406#else
407
408static char *
409wl_get_scan_results(int unit)
410{
411	int ret, retry_times = 0;
412	wl_scan_params_t *params;
413	wl_scan_results_t *list = (wl_scan_results_t*)scan_result;
414	int params_size = WL_SCAN_PARAMS_FIXED_SIZE + NUMCHANS * sizeof(uint16);
415	wlc_ssid_t wst = {0, ""};
416	int org_scan_time = 20, scan_time = 40;
417	char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
418	char *ifname = NULL;
419
420	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
421	wst.SSID_len = strlen(nvram_safe_get(strcat_r(prefix, "ssid", tmp)));
422	if (wst.SSID_len <= MAX_SSID_LEN)
423		memcpy(wst.SSID, nvram_safe_get(strcat_r(prefix, "ssid", tmp)), wst.SSID_len);
424	else
425		wst.SSID_len = 0;
426
427	params = (wl_scan_params_t*)malloc(params_size);
428	if (params == NULL) {
429		return NULL;
430	}
431
432	memset(params, 0, params_size);
433	params->ssid = wst;
434	params->bss_type = DOT11_BSSTYPE_ANY;
435	memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
436	params->scan_type = -1;
437	params->nprobes = -1;
438	params->active_time = -1;
439	params->passive_time = -1;
440	params->home_time = -1;
441	params->channel_num = 0;
442
443	ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
444	/* extend scan channel time to get more AP probe resp */
445	wl_ioctl(ifname, WLC_GET_SCAN_CHANNEL_TIME, &org_scan_time, sizeof(org_scan_time));
446	if (org_scan_time < scan_time)
447		wl_ioctl(ifname, WLC_SET_SCAN_CHANNEL_TIME, &scan_time,	sizeof(scan_time));
448
449retry:
450	ret = wl_ioctl(ifname, WLC_SCAN, params, params_size);
451	if (ret < 0) {
452		if (retry_times++ < WLC_SCAN_RETRY_TIMES) {
453			if (psta_debug)
454			dbg("set scan command failed, retry %d\n", retry_times);
455			sleep(1);
456			goto retry;
457		}
458	}
459
460	sleep(2);
461
462	list->buflen = WLC_SCAN_RESULT_BUF_LEN;
463	ret = wl_ioctl(ifname, WLC_SCAN_RESULTS, scan_result, WLC_SCAN_RESULT_BUF_LEN);
464	if (ret < 0 && retry_times++ < WLC_SCAN_RETRY_TIMES) {
465		if (psta_debug)
466		dbg("get scan result failed, retry %d\n", retry_times);
467		sleep(1);
468		goto retry;
469	}
470
471	free(params);
472
473	/* restore original scan channel time */
474	wl_ioctl(ifname, WLC_SET_SCAN_CHANNEL_TIME, &org_scan_time, sizeof(org_scan_time));
475
476	if (ret < 0)
477		return NULL;
478
479	return scan_result;
480}
481#endif
482
483static int
484wl_scan(int unit)
485{
486	wl_scan_results_t *list = (wl_scan_results_t*)scan_result;
487	wl_bss_info_t *bi;
488	wl_bss_info_107_t *old_bi;
489	uint i, ap_count = 0;
490	char ssid_str[128], macstr[18];
491
492#ifdef RTCONFIG_BCM_7114
493	if (wl_get_scan_results_escan(unit) == NULL)
494#else
495	if (wl_get_scan_results(unit) == NULL)
496#endif
497		return 0;
498
499	if (list->count == 0)
500		return 0;
501#ifndef RTCONFIG_BCM_7114
502	else if (list->version != WL_BSS_INFO_VERSION &&
503			list->version != LEGACY_WL_BSS_INFO_VERSION &&
504			list->version != LEGACY2_WL_BSS_INFO_VERSION) {
505		dbg("Sorry, your driver has bss_info_version %d "
506		    "but this program supports only version %d.\n",
507		    list->version, WL_BSS_INFO_VERSION);
508		return 0;
509	}
510#endif
511
512	memset(ap_list, 0, sizeof(ap_list));
513	bi = list->bss_info;
514	for (i = 0; i < list->count; i++) {
515		/* Convert version 107 to 109 */
516		if (dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION) {
517			old_bi = (wl_bss_info_107_t *)bi;
518			bi->chanspec = CH20MHZ_CHSPEC(old_bi->channel);
519			bi->ie_length = old_bi->ie_length;
520			bi->ie_offset = sizeof(wl_bss_info_107_t);
521		}
522
523		if (bi->ie_length) {
524			if (ap_count < MAX_NUMBER_OF_APINFO) {
525#if 0
526				ap_list[ap_count].used = TRUE;
527#endif
528				memcpy(ap_list[ap_count].BSSID, (uint8 *)&bi->BSSID, 6);
529				strncpy((char *)ap_list[ap_count].ssid, (char *)bi->SSID, bi->SSID_len);
530				ap_list[ap_count].ssid[bi->SSID_len] = '\0';
531				ap_list[ap_count].ssidLen= bi->SSID_len;
532#if 0
533				ap_list[ap_count].ie_buf = (uint8 *)(((uint8 *)bi) + bi->ie_offset);
534				ap_list[ap_count].ie_buflen = bi->ie_length;
535#endif
536				if (dtoh32(bi->version) != LEGACY_WL_BSS_INFO_VERSION && bi->n_cap)
537					ap_list[ap_count].channel= bi->ctl_ch;
538				else
539					ap_list[ap_count].channel= (bi->chanspec & WL_CHANSPEC_CHAN_MASK);
540#if 0
541				ap_list[ap_count].wep = bi->capability & DOT11_CAP_PRIVACY;
542#endif
543				ap_count++;
544			}
545		}
546		bi = (wl_bss_info_t*)((int8*)bi + bi->length);
547	}
548
549	if (ap_count)
550	{
551		if (psta_debug)
552		dbg("%-4s%-33s%-18s\n", "Ch", "SSID", "BSSID");
553
554		for (i = 0; i < ap_count; i++)
555		{
556			memset(ssid_str, 0, sizeof(ssid_str));
557			char_to_ascii(ssid_str, (const char *) trim_r(ap_list[i].ssid));
558
559			ether_etoa((const unsigned char *) &ap_list[i].BSSID, macstr);
560			if (psta_debug)
561			dbg("%-4d%-33s%-18s\n",
562				ap_list[i].channel,
563				ap_list[i].ssid,
564				macstr
565			);
566		}
567	}
568
569	return ap_count;
570}
571
572static struct itimerval itv;
573static void
574alarmtimer(unsigned long sec, unsigned long usec)
575{
576	itv.it_value.tv_sec  = sec;
577	itv.it_value.tv_usec = usec;
578	itv.it_interval = itv.it_value;
579	setitimer(ITIMER_REAL, &itv, NULL);
580}
581
582static int
583wl_autho(char *name, struct ether_addr *ea)
584{
585	char buf[sizeof(sta_info_t)];
586
587	strcpy(buf, "sta_info");
588	memcpy(buf + strlen(buf) + 1, (unsigned char *)ea, ETHER_ADDR_LEN);
589
590	if (!wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))) {
591		sta_info_t *sta = (sta_info_t *)buf;
592		uint32 f = sta->flags;
593
594		if (f & WL_STA_AUTHO)
595			return 1;
596	}
597
598	return 0;
599}
600#ifdef PSTA_DEBUG
601static void check_wl_rate(const char *ifname)
602{
603	int rate = 0;
604	char rate_buf[32];
605
606	sprintf(rate_buf, "0 Mbps");
607
608	if (wl_ioctl(ifname, WLC_GET_RATE, &rate, sizeof(int)))
609	{
610		dbG("can not get rate info of %s\n", ifname);
611		goto ERROR;
612	}
613	else
614	{
615		rate = dtoh32(rate);
616		if ((rate == -1) || (rate == 0))
617			sprintf(rate_buf, "auto");
618		else
619			sprintf(rate_buf, "%d%s Mbps", (rate / 2), (rate & 1) ? ".5" : "");
620	}
621
622ERROR:
623	logmessage(LOGNAME, "wl interface %s data rate: %s", ifname, rate_buf);
624}
625#endif
626static void
627psta_keepalive(int ex)
628{
629	char tmp[NVRAM_BUFSIZE], tmp2[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_";
630	char *name = NULL;
631	struct maclist *mac_list = NULL;
632	int mac_list_size, i, unit;
633	int psta = 0;
634	struct ether_addr bssid;
635	unsigned char bssid_null[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
636	char macaddr[18];
637	char band_var[16];
638
639	sprintf(band_var, "wlc_band%s", ex ? "_ex" : "");
640	unit = nvram_get_int(band_var);
641	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
642
643	if (!nvram_match(strcat_r(prefix, "mode", tmp), "psta") &&
644	    !nvram_match(strcat_r(prefix, "mode", tmp2), "psr"))
645		goto PSTA_ERR;
646
647	name = nvram_safe_get(strcat_r(prefix, "ifname", tmp));
648
649	if (wl_ioctl(name, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) != 0)
650		goto PSTA_ERR;
651	else if (!memcmp(&bssid, bssid_null, 6))
652		goto PSTA_ERR;
653
654	/* buffers and length */
655	mac_list_size = sizeof(mac_list->count) + MAX_STA_COUNT * sizeof(struct ether_addr);
656	mac_list = malloc(mac_list_size);
657
658	if (!mac_list)
659		goto PSTA_ERR;
660
661	/* query wl for authenticated sta list */
662	strcpy((char*)mac_list, "authe_sta_list");
663	if (wl_ioctl(name, WLC_GET_VAR, mac_list, mac_list_size)) {
664		free(mac_list);
665		goto PSTA_ERR;
666	}
667
668	/* query sta_info for each STA and output one table row each */
669	if (mac_list->count)
670	{
671		if (nvram_match(strcat_r(prefix, "akm", tmp), ""))
672			psta = 1;
673		else
674		for (i = 0; i < mac_list->count; i++) {
675			if (wl_autho(name, &mac_list->ea[i]))
676			{
677				psta = 1;
678				break;
679			}
680		}
681	}
682
683PSTA_ERR:
684	if (psta)
685	{
686		count_bss_down = 0;
687		ether_etoa((const unsigned char *) &bssid, macaddr);
688		if (psta_debug) dbg("psta send keepalive nulldata to %s\n", macaddr);
689		eval("wl", "-i", name, "send_nulldata", macaddr);
690#ifdef PSTA_DEBUG
691		count = (count + 1) % 10;
692		if (!count) check_wl_rate(name);
693#endif
694	}
695	else
696	{
697		if (psta_debug) dbg("psta disconnected\n");
698		if (++count_bss_down > 9)
699		{
700			count_bss_down = 0;
701			if (wl_scan(unit))
702			{
703				eval("wlconf", name, "down");
704				eval("wlconf", name, "up");
705				eval("wlconf", name, "start");
706			}
707		}
708		else
709		{
710			eval("wl", "-i", name, "bss", "down");
711			eval("wl", "-i", name, "down");
712			eval("wl", "-i", name, "up");
713			eval("wl", "-i", name, "bss", "up");
714		}
715	}
716
717	if (mac_list) free(mac_list);
718}
719
720static void
721psta_monitor(int sig)
722{
723	if (sig == SIGALRM)
724	{
725		psta_keepalive(0);
726#ifdef PXYSTA_DUALBAND
727		if (!nvram_match("dpsta_ifnames", ""))
728			psta_keepalive(1);
729#endif
730		alarm(NORMAL_PERIOD);
731	}
732}
733
734static void
735psta_monitor_exit(int sig)
736{
737	if (sig == SIGTERM)
738	{
739		alarmtimer(0, 0);
740		remove("/var/run/psta_monitor.pid");
741		exit(0);
742	}
743}
744
745int
746psta_monitor_main(int argc, char *argv[])
747{
748	FILE *fp;
749	sigset_t sigs_to_catch;
750
751	if (!psta_exist() && !psr_exist())
752		return 0;
753#ifdef RTCONFIG_QTN
754	if (nvram_get_int("wlc_band") == 1)
755		return 0;
756#endif
757	/* write pid */
758	if ((fp = fopen("/var/run/psta_monitor.pid", "w")) != NULL)
759	{
760		fprintf(fp, "%d", getpid());
761		fclose(fp);
762	}
763
764	if (nvram_match("psta_debug", "1"))
765		psta_debug = 1;
766
767	/* set the signal handler */
768	sigemptyset(&sigs_to_catch);
769	sigaddset(&sigs_to_catch, SIGALRM);
770	sigaddset(&sigs_to_catch, SIGTERM);
771	sigprocmask(SIG_UNBLOCK, &sigs_to_catch, NULL);
772
773	signal(SIGALRM, psta_monitor);
774	signal(SIGTERM, psta_monitor_exit);
775
776	/* turn off wireless led of other bands under psta mode */
777	if (is_psta(nvram_get_int("wlc_band")))
778	setWlOffLed();
779
780	alarm(NORMAL_PERIOD);
781
782	/* Most of time it goes to sleep */
783	while (1)
784	{
785		pause();
786	}
787
788	return 0;
789}
790#endif
791#endif
792