Update BCM4329 Wifi drivers to the glacier version
/drivers/net/wireless/bcm4329_204/wl_iw.c
blob:511889a8a78eaf546aa71e1cf881947f589085af -> blob:b0c3128b989a344f06e42608a7d98921209c3f53
--- drivers/net/wireless/bcm4329_204/wl_iw.c
+++ drivers/net/wireless/bcm4329_204/wl_iw.c
@@ -52,10 +52,11 @@ typedef const struct si_pub si_t;
#include <dngl_stats.h>
#include <dhd.h>
#define WL_ERROR(x) myprintf x
-#define WL_TRACE(x)
+#define WL_TRACE(x) //myprintf x
#define WL_ASSOC(x)
#define WL_INFORM(x)
#define WL_WSEC(x)
+#define WL_SCAN(x) //myprintf x
#include <wl_iw.h>
@@ -100,6 +101,21 @@ static bool ap_cfg_running = FALSE;
static bool ap_fw_loaded = FALSE;
static int ap_mode = 0;
#endif
+
+#ifdef SOFTAP_PROTECT
+#define AP_PROTECT_TIME 5000
+#define AP_MAX_FAIL_COUNT 2
+typedef struct ap_info {
+ struct timer_list timer;
+ uint32 timer_on;
+ long ap_pid;
+ struct semaphore ap_sem;
+ struct completion ap_exited;
+} ap_info_t;
+ap_info_t *g_ap_protect = NULL;
+static void wl_iw_ap_restart(void);
+#endif
+
static struct net_device *priv_dev;
#ifdef WLAN_AUTO_RSSI
@@ -122,7 +138,7 @@ extern bool wl_iw_conn_status_str(uint32
extern void dhd_customer_gpio_wlan_ctrl(int onoff);
extern uint dhd_dev_reset(struct net_device *dev, uint8 flag);
extern void dhd_dev_init_ioctl(struct net_device *dev);
-
+extern int wifi_get_cscan_enable(void);
uint wl_msg_level = WL_ERROR_VAL;
#define MAX_WLIW_IOCTL_LEN 1024
@@ -225,12 +241,15 @@ typedef struct iscan_info {
uint32 scan_flag;
- char ioctlbuf[WLC_IOCTL_SMLEN];
+ char ioctlbuf[WLC_IOCTL_MEDLEN];
+ wl_iscan_params_t *iscan_ex_params_p;
+ int iscan_ex_param_size;
} iscan_info_t;
static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
static void wl_iw_bt_release(void);
static int wl_iw_fixed_scan(struct net_device *dev);
+static int wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan);
typedef enum bt_coex_status {
BT_DHCP_IDLE = 0,
@@ -450,6 +469,10 @@ dev_wlc_ioctl(
#ifdef WLAN_PROTECT
void wl_iw_set_busdown(int busdown)
{
+#ifdef CONFIG_BCM4329_SOFTAP
+ if (ap_mode) /* handle by ap recover */
+ return;
+#endif
wl_iw_busdown = busdown;
}
#endif
@@ -785,7 +808,13 @@ wl_iw_del_pfn(
return 0;
}
- strncpy(ssid, extra + ssid_offset+1,
+ if (ssid_size > 32) {
+ WL_ERROR(("%s: ssid too long: %s\n", __FUNCTION__,
+ (char *)extra + ssid_offset + 1));
+ return 0;
+ }
+
+ strncpy(ssid, extra + ssid_offset + 1,
MIN(ssid_size, sizeof(ssid)));
WL_ERROR(("%s: remove ssid: %s\n", __FUNCTION__, ssid));
@@ -798,6 +827,57 @@ wl_iw_del_pfn(
}
#endif
+#ifdef WLAN_LOW_RSSI_IND
+static int
+wl_iw_low_rssi_set(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ char *p = extra;
+ int low_rssi_trigger;
+ int low_rssi_duration;
+ int trigger_offset;
+ int duration_offset;
+ char tran_buf[16] = {0};
+ char *pp;
+ int err = 0;
+ WL_TRACE(("%s\n", __FUNCTION__));
+
+ trigger_offset = strcspn(extra, " ");
+ duration_offset = strcspn(extra+trigger_offset + 1, " ");
+
+ // myprintf("%s: %s, t_off: %d, dur: %d\n", __func__, extra, trigger_offset, duration_offset);
+
+ pp = extra+trigger_offset+1;
+
+ memcpy(tran_buf, pp, duration_offset);
+ low_rssi_trigger = bcm_strtoul(tran_buf, NULL, 10);
+
+ err |= dev_wlc_intvar_set(dev, "low_rssi_trigger", low_rssi_trigger);
+
+ memset(tran_buf, 0, 16);
+ pp = extra+trigger_offset+duration_offset+2;
+ memcpy(tran_buf, pp, strlen(extra) - (trigger_offset+duration_offset+1));
+ low_rssi_duration = bcm_strtoul(tran_buf, NULL, 10);
+ err |= dev_wlc_intvar_set(dev, "low_rssi_duration", low_rssi_duration);
+
+ myprintf("set low rssi trigger %d, duration %d\n",low_rssi_trigger, low_rssi_duration);
+
+ if (err) {
+ WL_ERROR(("set low rssi ind fail!\n"));
+ p += snprintf(p, MAX_WX_STRING, "FAIL");
+ } else
+ p += snprintf(p, MAX_WX_STRING, "OK");
+ wrqu->data.length = p - extra + 1;
+
+
+ return 0;
+}
+#endif
+
static int
wl_iw_set_country(
struct net_device *dev,
@@ -911,7 +991,7 @@ static int btcoex_dhcp_timer_start(struc
char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
char buf_reg12va_sco_time[4] = { 12, 0, 0, 0};
- int sco_lasttime;
+ int sco_lasttime = 0;
int ret;
bcm_mkiovar("btc_params", (char*)&buf_reg12va_sco_time[0], sizeof(buf_reg12va_sco_time), ioctlbuf, sizeof(ioctlbuf));
@@ -1030,6 +1110,15 @@ wl_iw_set_power_mode(
dhdhtc_set_power_control(1, DHDHTC_POWER_CTRL_USER_CONFIG);
dhdhtc_update_wifi_power_mode(screen_off);
break;
+ /* for fota download */
+ case 30:
+ dhdhtc_set_power_control(0, DHDHTC_POWER_CTRL_FOTA_DOWNLOADING);
+ dhdhtc_update_wifi_power_mode(screen_off);
+ break;
+ case 31:
+ dhdhtc_set_power_control(1, DHDHTC_POWER_CTRL_FOTA_DOWNLOADING);
+ dhdhtc_update_wifi_power_mode(screen_off);
+ break;
case 99: /* For debug. power active or not while usb plugin */
dhdcdc_power_active_while_plugin = !dhdcdc_power_active_while_plugin;
dhdhtc_update_wifi_power_mode(screen_off);
@@ -1540,11 +1629,13 @@ _wl_control_sysioc_thread_wl_off(void *d
dhd_dev_reset(wl_ctl->dev, 1);
#if defined(WL_IW_USE_ISCAN)
+ if(!wifi_get_cscan_enable())
+ {
wl_iw_free_ss_cache();
wl_iw_run_ss_cache_timer(0);
memset(g_scan, 0, G_SCAN_RESULTS);
-
g_ss_cache_ctrl.m_link_down = 1;
+ }
g_scan_specified_ssid = 0;
g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
@@ -1661,8 +1752,11 @@ wl_iw_control_wl_off(
dhd_dev_reset(dev, 1);
#if defined(WL_IW_USE_ISCAN)
+ if(!wifi_get_cscan_enable())
+ {
wl_iw_free_ss_cache();
wl_iw_run_ss_cache_timer(0);
+ }
memset(g_scan, 0, G_SCAN_RESULTS);
g_ss_cache_ctrl.m_link_down = 1;
@@ -2805,26 +2899,25 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssi
return -EINVAL;
}
- if (ssid && ssid->SSID_len) {
- params_size += sizeof(wlc_ssid_t);
+ if (ssid && ssid->SSID_len) {
+ params_size += sizeof(wlc_ssid_t);
}
- params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
+ params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
if (params == NULL) {
return -ENOMEM;
}
memset(params, 0, params_size);
ASSERT(params_size < WLC_IOCTL_SMLEN);
+ if(!wifi_get_cscan_enable()){
+ err = wl_iw_iscan_prep(&params->params, ssid);
- err = wl_iw_iscan_prep(&params->params, ssid);
-
- if (!err) {
- params->version = htod32(ISCAN_REQ_VERSION);
- params->action = htod16(action);
- params->scan_duration = htod16(0);
-
+ if (!err) {
+ params->version = htod32(ISCAN_REQ_VERSION);
+ params->action = htod16(action);
+ params->scan_duration = htod16(0);
iscan_retry:
- err = dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size,
+ err = dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size,
iscan->ioctlbuf, WLC_IOCTL_SMLEN);
if (err&&(retry < 2)) {
retry++;
@@ -2835,10 +2928,38 @@ iscan_retry:
if (err)
WL_ERROR(("iscan fail!\n"));
- }
+ }
+ }
+ else{
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(action);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
+
+ WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
+ WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
+ WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
+ WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
+ WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
+ WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
+ WL_SCAN(("channel_num=%d\n", iscan->iscan_ex_params_p->params.channel_num&WL_SCAN_PARAMS_COUNT_MASK));
- kfree(params);
- return err;
+
+
+cscan_retry:
+ err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \
+ iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf));
+ if (err&&(retry < 2)) {
+ retry++;
+ WL_ERROR(("iscan retry!\n"));
+ bcm_mdelay(500);
+ goto cscan_retry;
+ }
+
+ if (err)
+ WL_ERROR(("iscan fail!\n"));
+ }
+ kfree(params);
+ return err;
}
static void
@@ -2865,6 +2986,19 @@ static void wl_iw_set_event_mask(struct
iovbuf, sizeof(iovbuf));
}
+static void wl_iw_set_event_mask_deauth(struct net_device *dev)
+{
+ char eventmask[WL_EVENTING_MASK_LEN];
+ char iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+ WL_SOFTAP(("set deauth event!\n"));
+ dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
+ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
+ setbit(eventmask, WLC_E_DEAUTH);
+ dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+}
+
static uint32
wl_iw_iscan_get(iscan_info_t *iscan)
{
@@ -2874,6 +3008,7 @@ wl_iw_iscan_get(iscan_info_t *iscan)
wl_iscan_results_t list;
wl_scan_results_t *results;
uint32 status;
+ int res = 0;
mutex_lock(&wl_cache_lock);
if (iscan->list_cur) {
@@ -2908,20 +3043,28 @@ wl_iw_iscan_get(iscan_info_t *iscan)
memset(&list, 0, sizeof(list));
list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
- (void) dev_iw_iovar_getbuf(
+ res = dev_iw_iovar_getbuf(
iscan->dev,
"iscanresults",
&list,
WL_ISCAN_RESULTS_FIXED_SIZE,
buf->iscan_buf,
WLC_IW_ISCAN_MAXLEN);
- results->buflen = dtoh32(results->buflen);
- results->version = dtoh32(results->version);
- results->count = dtoh32(results->count);
- WL_TRACE(("results->count = %d\n", results->count));
+ if (res == 0) {
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ results->count = dtoh32(results->count);
+ WL_TRACE(("results->count = %d\n", results->count));
+
+ WL_TRACE(("results->buflen = %d\n", results->buflen));
+ status = dtoh32(list_buf->status);
+ }
+ else {
+ WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
+
+ status = WL_SCAN_RESULTS_NO_MEM;
+ }
- WL_TRACE(("results->buflen = %d\n", results->buflen));
- status = dtoh32(list_buf->status);
mutex_unlock(&wl_cache_lock);
return status;
}
@@ -2949,6 +3092,7 @@ static void wl_iw_send_scan_complete(isc
if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
WL_TRACE(("Send Event ISCAN complete\n"));
+ printk (KERN_INFO"[WLAN] Send Event ISCAN complete\n");
#endif
}
@@ -3022,14 +3166,21 @@ _iscan_sysioc_thread(void *data)
iscan->timer_on = 1;
break;
case WL_SCAN_RESULTS_ABORTED:
- WL_TRACE(("iscanresults aborted\n"));
+ WL_ERROR(("iscanresults aborted\n"));
iscan->iscan_state = ISCAN_STATE_IDLE;
+#if 0
if (g_scan_specified_ssid == 0)
wl_iw_send_scan_complete(iscan);
else {
iscan_pass_abort = TRUE;
wl_iw_force_specific_scan(iscan);
}
+#else
+ /* scan again
+ */
+ iscan_pass_abort = TRUE;
+ wl_iw_force_specific_scan(iscan);
+#endif
break;
case WL_SCAN_RESULTS_NO_MEM:
WL_TRACE(("iscanresults can't alloc memory: skip\n"));
@@ -3221,6 +3372,8 @@ wl_iw_add_bss_to_ss_cache(wl_scan_result
leaf = kmalloc(WLC_IW_SS_CACHE_MAXLEN, GFP_KERNEL);
if (!leaf) {
mutex_unlock(&wl_cache_lock);
+ WL_ERROR(("Memory alloc failure %d\n", \
+ bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
return -ENOMEM;
}
@@ -3322,6 +3475,11 @@ wl_iw_set_scan(
int ret, retry = 0;
WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
+ if(wifi_get_cscan_enable()){
+ WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported (Using CSCAN)\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
#if defined(CONFIG_BCM4329_SOFTAP)
if (ap_cfg_running) {
WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
@@ -3384,6 +3542,154 @@ specific_retry:
return 0;
}
+int
+wl_iw_CSCAN_first(struct net_device *dev)
+{
+ int res = -1;
+ iscan_info_t *iscan = g_iscan;
+ int nssid = 0;
+ int nchan = 0,datalength;
+ cscan_tlv_t *cscan_tlv_temp;
+ wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
+ char type;
+ char *str_ptr;
+ int tlv_size_left;
+ char *temp;
+ char tlv_in_firstscan[] = { 'C', 'S', 'C', 'A', 'N', ' ', \
+ 0x53, 0x01, 0x00, 0x00,
+ 'S',0x00,
+ 'C',0x01,'C',0x02,'C',0x03,'C',0x04,'C',0x05,'C',0x06,'C',0x07,'C',0x08,'C',0x09,
+ 'C',0x10,'C',0x11
+ };
+ datalength = sizeof(tlv_in_firstscan);
+
+ if (!(temp = kmalloc(datalength, GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ return -1;
+ }
+
+ memcpy(temp, tlv_in_firstscan, sizeof(tlv_in_firstscan));
+
+ str_ptr = temp;
+ str_ptr += strlen(CSCAN_COMMAND);
+ tlv_size_left = datalength - strlen(CSCAN_COMMAND);
+
+ cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
+ memset(ssids_local, 0, sizeof(ssids_local));
+
+ if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \
+ (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \
+ (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
+ {
+ str_ptr += sizeof(cscan_tlv_t);
+ tlv_size_left -= sizeof(cscan_tlv_t);
+
+
+ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
+ WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
+ WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
+ goto exit_proc;
+ }
+ else {
+
+ memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
+
+
+ wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
+
+
+ while (tlv_size_left > 0)
+ {
+ type = str_ptr[0];
+ switch (type) {
+ case CSCAN_TLV_TYPE_CHANNEL_IE:
+
+ if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.channel_list[0], \
+ WL_NUMCHANNELS, &tlv_size_left)) == -1) {
+ WL_ERROR(("%s missing channel list\n", \
+ __FUNCTION__));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_NPROBE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.nprobes, \
+ sizeof(iscan->iscan_ex_params_p->params.nprobes), \
+ type, sizeof(char), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_ACTIVE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.active_time, \
+ sizeof(iscan->iscan_ex_params_p->params.active_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_PASSIVE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.passive_time, \
+ sizeof(iscan->iscan_ex_params_p->params.passive_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_HOME_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.home_time, \
+ sizeof(iscan->iscan_ex_params_p->params.home_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_STYPE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.scan_type, \
+ sizeof(iscan->iscan_ex_params_p->params.scan_type), \
+ type, sizeof(char), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+
+ default :
+ WL_ERROR(("%s get unkwown type %X\n", \
+ __FUNCTION__, type));
+ goto exit_proc;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+ res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
+
+exit_proc:
+
+ return res;
+}
+
#ifdef WL_IW_USE_ISCAN
int
wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
@@ -3415,13 +3721,18 @@ wl_iw_iscan_set_scan_broadcast_prep(stru
if (flag)
rtnl_lock();
#endif
-
+ if(!wifi_get_cscan_enable()){
dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag));
wl_iw_set_event_mask(dev);
WL_TRACE(("+++: Set Broadcast ISCAN\n"));
ret = wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
+ }else
+ {
+ printk(KERN_INFO"Try to do scan first (CSCAN) !");
+ ret=wl_iw_CSCAN_first(dev);
+ }
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
if (flag)
@@ -3449,6 +3760,11 @@ wl_iw_iscan_set_scan(
WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
+ if(wifi_get_cscan_enable()){
+ WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported (Due to Using CSCAN)\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
if (dev_wlc_ioctl_off) {
WL_ERROR(("%s: wl driver going down!\n", __FUNCTION__));
return -EINVAL;
@@ -3498,11 +3814,13 @@ wl_iw_iscan_set_scan(
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
int as = 0;
struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ if(!wifi_get_cscan_enable()){
if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
WL_TRACE(("%s First ISCAN in progress : ignoring SC = %s\n", \
__FUNCTION__, req->essid));
return -EBUSY;
}
+ }
ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
memcpy(ssid.SSID, req->essid, ssid.SSID_len);
ssid.SSID_len = htod32(ssid.SSID_len);
@@ -3824,8 +4142,13 @@ wl_iw_get_scan(
if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
return error;
ci.scan_channel = dtoh32(ci.scan_channel);
- if (ci.scan_channel)
+ if (ci.scan_channel) {
+ if(!wifi_get_cscan_enable()){
+ WL_ERROR(("%s: scan is running. channel: %d\n", __func__, ci.scan_channel));
+ wl_iw_fixed_scan(dev);
+ }
return -EAGAIN;
+ }
if (g_ss_cache_ctrl.m_timer_expired) {
wl_iw_free_ss_cache();
@@ -3879,12 +4202,12 @@ wl_iw_get_scan(
wl_iw_fixed_scan(dev);
return -EINVAL;
}
+ if(!wifi_get_cscan_enable()){
+ if (g_scan_specified_ssid) {
- if (g_scan_specified_ssid) {
-
- wl_iw_add_bss_to_ss_cache(list);
- kfree(list);
- }
+ wl_iw_add_bss_to_ss_cache(list);
+ kfree(list);
+ }
mutex_lock(&wl_cache_lock);
#if defined(WL_IW_USE_ISCAN)
@@ -3915,9 +4238,38 @@ wl_iw_get_scan(
len_ret += merged_len;
wl_iw_run_ss_cache_timer(0);
wl_iw_run_ss_cache_timer(1);
+ }else
+ {
+ if (g_scan_specified_ssid) {
+ WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
+ len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
+ kfree(list);
#if defined(WL_IW_USE_ISCAN)
+ p_buf = iscan->list_hdr;
+ while (p_buf != iscan->list_cur) {
+ list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
+ WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
+ if (list_merge->count > 0)
+ len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
+ extra+len_ret, buflen_from_user -len_ret);
+ p_buf = p_buf->next;
+ }
+#else
+ list_merge = (wl_scan_results_t *) g_scan;
+ WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
+ if (list_merge->count > 0)
+ len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
+ buflen_from_user -len_ret);
+#endif
+ }
+ else {
+ list = (wl_scan_results_t *) g_scan;
+ len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
+ }
+ }
+#if defined(WL_IW_USE_ISCAN)
g_scan_specified_ssid = 0;
#endif
@@ -4030,6 +4382,7 @@ wl_iw_iscan_get_scan(
uint32 counter = 0;
__u16 merged_len = 0;
uint buflen_from_user = dwrq->length;
+ uint8 channel;
WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
@@ -4049,18 +4402,18 @@ wl_iw_iscan_get_scan(
WL_ERROR(("%s: wl driver going down!\n", __FUNCTION__));
return -EINVAL;
}
-
+ if(!wifi_get_cscan_enable()){
if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) {
- WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \
- dev->name, __FUNCTION__));
+ WL_ERROR(("%s %s: first ISCAN results are NOT ready yet \n", \
+ dev->name, __func__));
return -EAGAIN;
}
-
+ }
if ((!iscan) || (iscan->sysioc_pid < 0)) {
WL_TRACE(("%ssysioc_pid\n", __FUNCTION__));
return wl_iw_get_scan(dev, info, dwrq, extra);
}
-
+ if(!wifi_get_cscan_enable()){
if (g_ss_cache_ctrl.m_timer_expired) {
wl_iw_free_ss_cache();
g_ss_cache_ctrl.m_timer_expired ^= 1;
@@ -4080,7 +4433,7 @@ wl_iw_iscan_get_scan(
g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
g_ss_cache_ctrl.m_cons_br_scan_cnt++;
}
-
+ }
WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
apcnt = 0;
p_buf = iscan->list_hdr;
@@ -4131,6 +4484,7 @@ wl_iw_iscan_get_scan(
iwe.cmd = SIOCGIWFREQ;
+ if(!wifi_get_cscan_enable()){
#ifdef CUSTOMER_HW2
if (dtoh32(bi->version) != 107 && bi->n_cap)
{
@@ -4142,6 +4496,13 @@ wl_iw_iscan_get_scan(
iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
+ }else
+ {
+ channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
+ iwe.u.freq.m = wf_channel2mhz(channel,
+ channel <= CH_MAX_2G_CHANNEL ?
+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
+ }
iwe.u.freq.e = 6;
event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
@@ -4186,15 +4547,15 @@ wl_iw_iscan_get_scan(
dwrq->length = event - extra;
dwrq->flags = 0;
-
- wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
- dwrq->length += merged_len;
- wl_iw_run_ss_cache_timer(0);
- wl_iw_run_ss_cache_timer(1);
-
- g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
-
- WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
+ if(!wifi_get_cscan_enable()){
+ wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
+ dwrq->length += merged_len;
+ wl_iw_run_ss_cache_timer(0);
+ wl_iw_run_ss_cache_timer(1);
+
+ g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
+ }
+ myprintf("[WLAN] %s return to WE %d bytes APs=%d\n", __func__, dwrq->length, counter);
if (!dwrq->length)
return -EAGAIN;
@@ -5620,6 +5981,405 @@ int get_user_params(char *user_params, s
return ret;
}
+#if defined(CSCAN)
+
+
+
+static int
+wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
+{
+ int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
+ int err = 0;
+ char *p;
+ int i;
+ iscan_info_t *iscan = g_iscan;
+
+ WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
+
+ if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
+ WL_ERROR(("%s error exit\n", __FUNCTION__));
+ err = -1;
+ }
+
+ params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+
+
+ if (nssid > 0) {
+ i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
+ i = ROUNDUP(i, sizeof(uint32));
+ if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
+ printk(KERN_INFO"additional ssids exceed params_size\n");
+ err = -1;
+ goto exit;
+ }
+
+ p = ((char*)&iscan->iscan_ex_params_p->params) + i;
+ memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
+ p += nssid * sizeof(wlc_ssid_t);
+ } else {
+ p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
+ }
+
+
+ iscan->iscan_ex_params_p->params.channel_num = \
+ htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \
+ (nchan & WL_SCAN_PARAMS_COUNT_MASK));
+
+ nssid = \
+ (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \
+ WL_SCAN_PARAMS_COUNT_MASK);
+
+
+ params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
+ iscan->iscan_ex_param_size = params_size;
+
+ iscan->list_cur = iscan->list_hdr;
+ iscan->iscan_state = ISCAN_STATE_SCANING;
+ wl_iw_set_event_mask(dev);
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
+
+ iscan->timer_on = 1;
+
+#define SCAN_DUMP 0
+#ifdef SCAN_DUMP
+ {
+ int i;
+ WL_SCAN(("\n### List of SSIDs to scan ###\n"));
+ for (i = 0; i < nssid; i++) {
+ if (!ssids_local[i].SSID_len)
+ WL_SCAN(("%d: Broadcast scan\n", i));
+ else
+ WL_SCAN(("%d: scan for %s size =%d\n", i, \
+ ssids_local[i].SSID, ssids_local[i].SSID_len));
+ }
+ WL_SCAN(("### List of channels to scan ###\n"));
+ for (i = 0; i < nchan; i++)
+ {
+ WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
+ }
+ WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
+ WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
+ WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
+ WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
+ WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
+ WL_SCAN(("\n###################\n"));
+ }
+#endif
+
+ if (params_size > WLC_IOCTL_MEDLEN) {
+ printk (KERN_INFO"[WLAN] error1\n");
+ WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", \
+ __FUNCTION__, params_size));
+ err = -1;
+ }
+
+ if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \
+ iscan->iscan_ex_param_size, \
+ iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
+ printk (KERN_INFO"[WLAN] error2\n");
+ WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
+ err = -1;
+ }
+
+exit:
+
+ return err;
+}
+
+
+static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, \
+ union iwreq_data *wrqu, char *ext)
+{
+ int res = 0;
+ char *extra = NULL;
+ iscan_info_t *iscan = g_iscan;
+ wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
+ int nssid = 0;
+ int nchan = 0;
+
+
+ WL_TRACE(("\%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+ __FUNCTION__, info->cmd, info->flags,
+ wrqu->data.pointer, wrqu->data.length));
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ return -1;
+ }
+
+ if (wrqu->data.length != 0) {
+
+ char *str_ptr;
+
+ if (!iscan->iscan_ex_params_p) {
+ return -EFAULT;
+ }
+
+ if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
+ kfree(extra);
+ return -EFAULT;
+ }
+
+ extra[wrqu->data.length] = 0;
+ WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
+
+ str_ptr = extra;
+
+
+ if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
+ WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
+ goto exit_proc;
+ }
+ str_ptr += strlen(GET_SSID);
+ nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, \
+ WL_SCAN_PARAMS_SSID_MAX);
+
+ if (nssid == -1) {
+ WL_ERROR(("%s wrong ssid list", __FUNCTION__));
+ return -1;
+ }
+
+ memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
+ ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN);
+
+
+ wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
+
+
+ if ((nchan = wl_iw_parse_channel_list(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.channel_list[0], \
+ WL_NUMCHANNELS)) == -1) {
+ WL_ERROR(("%s missing channel list\n", __FUNCTION__));
+ return -1;
+ }
+
+
+ get_parmeter_from_string(&str_ptr, \
+ GET_NPROBE, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.nprobes, 2);
+
+ get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.active_time, 4);
+
+ get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.passive_time, 4);
+
+ get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.home_time, 4);
+
+ get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.scan_type, 1);
+
+
+ res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
+
+ } else {
+
+ WL_ERROR(("IWPRIV argument len = 0 \n"));
+ return -1;
+ }
+
+exit_proc:
+
+ kfree(extra);
+
+ return res;
+}
+
+
+static int
+wl_iw_set_cscan(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int res = -1;
+ iscan_info_t *iscan = g_iscan;
+ wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
+ int nssid = 0;
+ int nchan = 0;
+ cscan_tlv_t *cscan_tlv_temp;
+ char type;
+ char *str_ptr;
+ int tlv_size_left;
+#ifdef TLV_DEBUG
+ int i;
+ char tlv_in_example[] = { 'C', 'S', 'C', 'A', 'N', ' ', \
+ 0x53, 0x01, 0x00, 0x00,
+ 'S',
+ 0x00,
+ 'S',
+ 0x04,
+ 'B', 'R', 'C', 'M',
+ 'C',
+ 0x06,
+ //0x00,
+ //'P',
+ 'A',
+ 0x94,
+ 0x11,
+ 'T',
+ //0x01
+ 0x00
+ };
+#endif
+ WL_SCAN(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+ __FUNCTION__, info->cmd, info->flags,
+ wrqu->data.pointer, wrqu->data.length));
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ return -1;
+ }
+
+
+ if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
+ WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \
+ wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t)));
+ return -1;
+ }
+
+#ifdef TLV_DEBUG
+ memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
+ wrqu->data.length = sizeof(tlv_in_example);
+ for (i = 0; i < wrqu->data.length; i++)
+ printk(KERN_INFO"%02X ", extra[i]);
+ printk(KERN_INFO"--\n");
+#endif
+
+ str_ptr = extra;
+ str_ptr += strlen(CSCAN_COMMAND);
+ tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
+
+ cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
+ memset(ssids_local, 0, sizeof(ssids_local));
+
+ if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \
+ (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \
+ (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
+ {
+ str_ptr += sizeof(cscan_tlv_t);
+ tlv_size_left -= sizeof(cscan_tlv_t);
+
+
+ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
+ WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
+ WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
+ goto exit_proc;
+ }
+ else {
+
+ memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
+
+
+ wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
+
+
+ while (tlv_size_left > 0)
+ {
+ type = str_ptr[0];
+ switch (type) {
+ case CSCAN_TLV_TYPE_CHANNEL_IE:
+
+ if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.channel_list[0], \
+ WL_NUMCHANNELS, &tlv_size_left)) == -1) {
+ WL_ERROR(("%s missing channel list\n", \
+ __FUNCTION__));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_NPROBE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.nprobes, \
+ sizeof(iscan->iscan_ex_params_p->params.nprobes), \
+ type, sizeof(char), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_ACTIVE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.active_time, \
+ sizeof(iscan->iscan_ex_params_p->params.active_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_PASSIVE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.passive_time, \
+ sizeof(iscan->iscan_ex_params_p->params.passive_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_HOME_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.home_time, \
+ sizeof(iscan->iscan_ex_params_p->params.home_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_STYPE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.scan_type, \
+ sizeof(iscan->iscan_ex_params_p->params.scan_type), \
+ type, sizeof(char), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+
+ default :
+ WL_ERROR(("%s get unkwown type %X\n", \
+ __FUNCTION__, type));
+ goto exit_proc;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+ //if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
+ // WL_ERROR(("%s First ISCAN in progress : ignoring\n", __FUNCTION__));
+ // return -EBUSY;
+ //}
+
+
+ res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
+
+exit_proc:
+
+ return res;
+}
+
+#endif
+
#ifdef CONFIG_BCM4329_SOFTAP
@@ -5877,6 +6637,8 @@ get_channel_retry:
ap_mode = 1;
}
#endif
+ wl_iw_set_event_mask_deauth(dev);
+
return res;
}
@@ -6194,7 +6956,7 @@ int get_parmeter_from_string(
char *param_str_end;
char *orig_str = *str_ptr;
- if (!strncmp(*str_ptr, token, strlen(token))) {
+ if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) {
strsep(str_ptr, "=,");
param_str_begin = *str_ptr;
@@ -6306,6 +7068,12 @@ static int iwpriv_softap_stop(struct net
res = wl_iw_softap_deassoc_stations(dev);
ap_mode = 0;
wl_iw_send_priv_event(priv_dev, "AP_DOWN");
+#ifdef SOFTAP_PROTECT
+ if (g_ap_protect&&g_ap_protect->timer_on) {
+ g_ap_protect->timer_on = 0;
+ del_timer_sync(&g_ap_protect->timer);
+ }
+#endif
#else
res = wl_iw_softap_deassoc_stations(ap_net_dev);
@@ -6760,6 +7528,10 @@ static int wl_iw_set_priv(
ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
ret = wl_iw_control_wl_off(dev, info);
+#if defined(CSCAN)
+ else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
+ ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
+#endif
#ifdef CUSTOMER_HW2
else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
@@ -6804,6 +7576,12 @@ static int wl_iw_set_priv(
set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
}
#endif
+#ifdef WLAN_LOW_RSSI_IND
+ else if (strnicmp(extra, "LOW_RSSI_IND_SET", strlen("LOW_RSSI_IND_SET")) == 0) {
+ WL_TRACE(("set LOW_RSSI_IND_SET\n"));
+ wl_iw_low_rssi_set(dev, info, (union iwreq_data *)dwrq, extra);
+ }
+#endif
/* for packet filter rule
*/
else if (strnicmp(extra, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0 ||
@@ -6952,7 +7730,10 @@ static const iw_handler wl_iw_priv_handl
NULL,
(iw_handler)iwpriv_fw_reload,
-
+#if defined(CSCAN)
+ NULL,
+ (iw_handler)iwpriv_set_cscan,
+#endif
NULL,
(iw_handler)iwpriv_settxpower
@@ -7060,6 +7841,14 @@ static const struct iw_priv_args wl_iw_p
"AP_TX_POWER"
},
#endif
+#if defined(CSCAN)
+ {
+ WL_COMBO_SCAN,
+ IW_PRIV_TYPE_CHAR | 1024,
+ 0,
+ "CSCAN"
+ },
+#endif
};
const struct iw_handler_def wl_iw_handler_def =
@@ -7373,6 +8162,7 @@ wl_iw_event(struct net_device *dev, wl_e
case WLC_E_DEAUTH_IND:
case WLC_E_DISASSOC_IND:
#if defined(CONFIG_BCM4329_SOFTAP)
+ case WLC_E_DEAUTH:
WL_SOFTAP(("STA disconnect received %d\n", event_type));
if (ap_mode) {
//wl_iw_send_priv_event(priv_dev, "STA_LEAVE");
@@ -7386,11 +8176,15 @@ wl_iw_event(struct net_device *dev, wl_e
wl_iw_send_priv_event(priv_dev, mac_buf);
return;
}
+ if (event_type != WLC_E_DEAUTH) {
#endif
cmd = SIOCGIWAP;
bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
bzero(&extra, ETHER_ADDR_LEN);
+#if defined(CONFIG_BCM4329_SOFTAP)
+ }
+#endif
break;
case WLC_E_LINK:
case WLC_E_NDIS_LINK:
@@ -7404,6 +8198,12 @@ wl_iw_event(struct net_device *dev, wl_e
#endif
WL_SOFTAP(("AP DOWN %d\n", event_type));
wl_iw_send_priv_event(priv_dev, "AP_DOWN");
+#ifdef SOFTAP_PROTECT
+ if (g_ap_protect&&g_ap_protect->timer_on) {
+ g_ap_protect->timer_on = 0;
+ del_timer_sync(&g_ap_protect->timer);
+ }
+#endif
} else {
WL_TRACE(("STA_Link Down\n"));
if (g_ss_cache_ctrl.last_rssi == 0)
@@ -7434,6 +8234,13 @@ wl_iw_event(struct net_device *dev, wl_e
#endif
WL_SOFTAP(("AP UP %d\n", event_type));
wl_iw_send_priv_event(priv_dev, "AP_UP");
+#ifdef SOFTAP_PROTECT
+ if (g_ap_protect->timer_on == 0) {
+ g_ap_protect->timer_on = 1;
+ mod_timer(&g_ap_protect->timer, jiffies + AP_PROTECT_TIME*HZ/1000);
+ WL_SOFTAP(("%s Start AP Timer\n", __FUNCTION__));
+ }
+#endif
} else
#endif
{
@@ -7548,6 +8355,14 @@ wl_iw_event(struct net_device *dev, wl_e
break;
}
#endif
+#ifdef WLAN_LOW_RSSI_IND
+ case WLC_E_RSSI_LOW:
+ {
+ myprintf("Recevied RSSI LOW event!\n");
+ wl_iw_send_priv_event(priv_dev, "LOW_RSSI");
+ break;
+ }
+#endif
case WLC_E_SCAN_COMPLETE:
#if defined(WL_IW_USE_ISCAN)
if ((g_iscan) && (g_iscan->sysioc_pid >= 0) &&
@@ -7833,8 +8648,139 @@ wl_iw_bt_init(struct net_device *dev)
return 0;
}
+#ifdef SOFTAP_PROTECT
+static void
+wl_iw_ap_timerfunc(ulong data)
+{
+ ap_info_t *ap_local = (ap_info_t *)data;
+ ap_local->timer_on = 0;
+ WL_TRACE(("%s\n", __FUNCTION__));
+
+ up(&ap_local->ap_sem);
+}
+
+static int ap_fail_count = 0;
+static int
+_ap_protect_sysioc_thread(void *data)
+{
+ int isup;
+ int ret = 0;
+ DAEMONIZE("ap_sysioc");
+
+ while (down_interruptible(&g_ap_protect->ap_sem) == 0) {
+
+ net_os_wake_lock(priv_dev);
+
+ if (g_ap_protect->timer_on) {
+ g_ap_protect->timer_on = 0;
+ del_timer_sync(&g_ap_protect->timer);
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ rtnl_lock();
+#endif
+ if ((ret = dev_wlc_ioctl(priv_dev, WLC_GET_UP, &isup, sizeof(isup))) != 0)
+ ap_fail_count++;
+ else
+ ap_fail_count = 0;
+
+ if (ap_fail_count == AP_MAX_FAIL_COUNT) {
+ wl_iw_restart(priv_dev);
+ wl_iw_ap_restart();
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ rtnl_unlock();
+#endif
+ mod_timer(&g_ap_protect->timer, jiffies + AP_PROTECT_TIME*HZ/1000);
+ g_ap_protect->timer_on = 1;
+
+ net_os_wake_unlock(priv_dev);
+ }
+
+ if (g_ap_protect->timer_on) {
+ g_ap_protect->timer_on = 0;
+ del_timer_sync(&g_ap_protect->timer);
+ }
+
+ complete_and_exit(&g_ap_protect->ap_exited, 0);
+}
+
+static int
+wl_iw_ap_init(void)
+{
+ ap_info_t *ap_protect = NULL;
+
+ ap_protect = kmalloc(sizeof(ap_info_t), GFP_KERNEL);
+ if (!ap_protect)
+ return -ENOMEM;
+
+ memset(ap_protect, 0, sizeof(ap_info_t));
+ ap_protect->ap_pid = -1;
+ g_ap_protect = ap_protect;
+
+
+ init_timer(&ap_protect->timer);
+ ap_protect->timer.data = (ulong)ap_protect;
+ ap_protect->timer.function = wl_iw_ap_timerfunc;
+ ap_protect->timer_on = 0;
+
+ sema_init(&ap_protect->ap_sem, 0);
+ init_completion(&ap_protect->ap_exited);
+ ap_protect->ap_pid = kernel_thread(_ap_protect_sysioc_thread, ap_protect, 0);
+ if (ap_protect->ap_pid < 0) {
+ WL_ERROR(("Failed in %s\n", __FUNCTION__));
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+
+static void
+wl_iw_ap_release(void)
+{
+ ap_info_t *ap_local = g_ap_protect;
+
+ if (!ap_local) {
+ return;
+ }
+
+ if (ap_local->ap_pid >= 0) {
+ KILL_PROC(ap_local->ap_pid, SIGTERM);
+ wait_for_completion(&ap_local->ap_exited);
+ }
+ kfree(ap_local);
+ g_ap_protect = NULL;
+}
+
+
+static void wl_iw_ap_restart(void)
+{
+ WL_SOFTAP(("Enter %s...\n", __FUNCTION__));
+
+ ap_mode = 0;
+ ap_cfg_running = FALSE;
+ ap_net_dev = NULL;
+
+ set_ap_cfg(priv_dev, &my_ap);
+
+ WL_SOFTAP(("SOFTAP - ENABLE BSS \n"));
+
+#ifndef AP_ONLY
+ if (ap_net_dev == NULL) {
+ printk("ERROR: SOFTAP net_dev* is NULL !!!\n");
+ } else {
+ iwpriv_en_ap_bss(ap_net_dev, NULL, NULL, NULL);
+ }
+#endif
+}
+
+#endif
+
int wl_iw_attach(struct net_device *dev, void * dhdp)
{
+ int params_size;
wl_iw_t *iw;
#if defined(WL_IW_USE_ISCAN)
iscan_info_t *iscan = NULL;
@@ -7847,10 +8793,24 @@ int wl_iw_attach(struct net_device *dev,
if (!dev)
return 0;
+
+ if(wifi_get_cscan_enable()){
+ params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
+ (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+ }else{
+ params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
+ }
+
iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
if (!iscan)
return -ENOMEM;
memset(iscan, 0, sizeof(iscan_info_t));
+ if(wifi_get_cscan_enable()){
+ iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
+ if (!iscan->iscan_ex_params_p)
+ return -ENOMEM;
+ iscan->iscan_ex_param_size = params_size;
+ }
iscan->sysioc_pid = -1;
g_iscan = iscan;
@@ -7882,10 +8842,14 @@ int wl_iw_attach(struct net_device *dev,
memset(g_scan, 0, G_SCAN_RESULTS);
g_scan_specified_ssid = 0;
- wl_iw_init_ss_cache_ctrl();
+ if(!wifi_get_cscan_enable()){
+ wl_iw_init_ss_cache_ctrl();
+ }
wl_iw_bt_init(dev);
-
+#ifdef SOFTAP_PROTECT
+ wl_iw_ap_init();
+#endif
// perf_lock_init(&wl_wificall_perf_lock, PERF_LOCK_HIGHEST, "wifi-call");
mutex_init(&wl_wificall_mutex);
@@ -7911,6 +8875,9 @@ void wl_iw_detach(void)
kfree(iscan->list_hdr);
iscan->list_hdr = buf;
}
+ if(wifi_get_cscan_enable())
+ kfree(iscan->iscan_ex_params_p);
+
kfree(iscan);
g_iscan = NULL;
mutex_unlock(&wl_cache_lock);
@@ -7920,8 +8887,13 @@ void wl_iw_detach(void)
kfree(g_scan);
g_scan = NULL;
+ if(!wifi_get_cscan_enable()){
wl_iw_release_ss_cache_ctrl();
+ }
wl_iw_bt_release();
+#ifdef SOFTAP_PROTECT
+ wl_iw_ap_release();
+#endif
#ifdef CONFIG_BCM4329_SOFTAP
if (ap_mode) {
WL_TRACE(("\n%s AP is going down\n", __FUNCTION__));