bcm4329: Sync with kernel SHA1: e3e6e272c600d7fa3d8722351129b04b0697e608

Change-Id: I1bef51c1ccfafd7822267523833e710ca17e022d
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c
index ef529e7..ec211ac 100644
--- a/bcm4329/src/dhd/sys/dhd_linux.c
+++ b/bcm4329/src/dhd/sys/dhd_linux.c
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.60 2010/02/23 00:18:36 Exp $
+ * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.60.4.4 2010/03/25 05:07:49 Exp $
  */
 
 #ifdef CONFIG_WIFI_CONTROL_FUNC
@@ -812,8 +812,30 @@
 		dhd_os_wake_lock(&dhd->pub);
 		for (i = 0; i < DHD_MAX_IFS; i++) {
 			if (dhd->iflist[i]) {
+#ifdef SOFTAP
+				bool in_ap = (ap_net_dev != NULL);
+#endif /* SOFTAP */
+
 				if (dhd->iflist[i]->state)
 					dhd_op_if(dhd->iflist[i]);
+
+#ifdef SOFTAP
+				if (dhd->iflist[i] == NULL) {
+					DHD_TRACE(("%s: interface %d just been removed!\n\n", __FUNCTION__, i));
+					continue;
+				}
+
+				if (in_ap && dhd->set_macaddress) {
+					DHD_TRACE(("attempt to set MAC for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name));
+					dhd->set_multicast = FALSE;
+					continue;
+				} else if (in_ap && dhd->set_multicast) {
+					DHD_TRACE(("attempt to set MULTICAST list for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name));
+					dhd->set_macaddress = FALSE;
+					continue;
+				}
+#endif /* SOFTAP */
+
 				if (dhd->set_multicast) {
 					dhd->set_multicast = FALSE;
 					_dhd_set_multicast_list(dhd, i);
@@ -916,7 +938,8 @@
 
 	/* Reject if down */
 	if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) {
-		DHD_ERROR(("%s: xmit rejected due to dhd bus down status \n", __FUNCTION__));
+		DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n",
+			 __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
 		netif_stop_queue(net);
 		return -ENODEV;
 	}
diff --git a/bcm4329/src/include/epivers.h b/bcm4329/src/include/epivers.h
index 8137f60..4957e1a 100644
--- a/bcm4329/src/include/epivers.h
+++ b/bcm4329/src/include/epivers.h
@@ -33,16 +33,16 @@
 
 #define	EPI_RC_NUMBER		204
 
-#define	EPI_INCREMENTAL_NUMBER	1
+#define	EPI_INCREMENTAL_NUMBER	3
 
 #define	EPI_BUILD_NUMBER	0
 
-#define	EPI_VERSION		4, 218, 204, 1
+#define	EPI_VERSION		4, 218, 204, 3
 
-#define	EPI_VERSION_NUM		0x04dacc01
+#define	EPI_VERSION_NUM		0x04dacc03
 
 
-#define	EPI_VERSION_STR		"4.218.204.1"
-#define	EPI_ROUTER_VERSION_STR	"4.219.204.1"
+#define	EPI_VERSION_STR		"4.218.204.3"
+#define	EPI_ROUTER_VERSION_STR	"4.219.204.3"
 
 #endif 
diff --git a/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c
index e324dd3..f44fba9 100644
--- a/bcm4329/src/wl/sys/wl_iw.c
+++ b/bcm4329/src/wl/sys/wl_iw.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wl_iw.c,v 1.51.4.9.2.6.4.84.2.3 2010/03/16 22:09:45 Exp $
+ * $Id: wl_iw.c,v 1.51.4.9.2.6.4.84.2.10 2010/03/25 07:22:21 Exp $
  */
 
 
@@ -77,6 +77,7 @@
 
 static int		g_onoff = G_WLAN_SET_ON;
 static struct mutex	wl_start_lock;
+static struct mutex	wl_cache_lock;
 
 extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status,
 	uint32 reason, char* stringBuf, uint buflen);
@@ -1875,7 +1876,6 @@
 	if (!extra)
 		return -EINVAL;
 
-	
 	list = kmalloc(buflen, GFP_KERNEL);
 	if (!list)
 		return -ENOMEM;
@@ -1929,7 +1929,6 @@
 		
 		dwrq->flags = 1;
 	}
-
 	return 0;
 }
 
@@ -2004,7 +2003,6 @@
 		
 		dwrq->flags = 1;
 	}
-
 	return 0;
 }
 
@@ -2101,7 +2099,7 @@
 	wl_scan_results_t *results;
 	uint32 status;
 
-	
+	mutex_lock(&wl_cache_lock);
 	if (iscan->list_cur) {
 		buf = iscan->list_cur;
 		iscan->list_cur = buf->next;
@@ -2111,6 +2109,7 @@
 		if (!buf) {
 			WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \
 						__FUNCTION__));
+			mutex_unlock(&wl_cache_lock);
 			return WL_SCAN_RESULTS_NO_MEM;
 		}
 		buf->next = NULL;
@@ -2147,6 +2146,7 @@
 
 	WL_TRACE(("results->buflen = %d\n", results->buflen));
 	status = dtoh32(list_buf->status);
+	mutex_unlock(&wl_cache_lock);
 	return status;
 }
 
@@ -2312,6 +2312,7 @@
 
 	WL_TRACE(("%s called\n", __FUNCTION__));
 
+	mutex_lock(&wl_cache_lock);
 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
 	node = *spec_scan_head;
 
@@ -2322,6 +2323,7 @@
 		kfree(cur);
 	}
 	*spec_scan_head = NULL;
+	mutex_unlock(&wl_cache_lock);
 }
 
 
@@ -2367,6 +2369,7 @@
 	wl_iw_ss_cache_t *node, *prev, *cur;
 	wl_iw_ss_cache_t **spec_scan_head;
 
+	mutex_lock(&wl_cache_lock);
 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
 	node = *spec_scan_head;
 	prev = node;
@@ -2393,7 +2396,7 @@
 		prev = node;
 		node = node->next;
 	}
-
+	mutex_unlock(&wl_cache_lock);
 }
 
 
@@ -2406,13 +2409,13 @@
 	wl_bss_info_t *bi = NULL;
 	int i;
 
-	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
-	
 	if (!ss_list->count) {
 		return 0;
 	}
 
-	
+	mutex_lock(&wl_cache_lock);
+	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
+
 	for (i = 0; i < ss_list->count; i++) {
 
 		node = *spec_scan_head;
@@ -2437,6 +2440,7 @@
 		}
 		leaf = kmalloc(WLC_IW_SS_CACHE_MAXLEN, GFP_KERNEL);
 		if (!leaf) {
+			mutex_unlock(&wl_cache_lock);
 			return -ENOMEM;
 		}
 
@@ -2459,8 +2463,8 @@
 			prev->next = leaf;
 		}
 	}
+	mutex_unlock(&wl_cache_lock);
 	return 0;
-
 }
 
 
@@ -2471,6 +2475,7 @@
 	wl_iw_ss_cache_t *node;
 	wl_scan_results_t *list_merge;
 
+	mutex_lock(&wl_cache_lock);
 	node = g_ss_cache_ctrl.m_cache_head;
 	for (;node;) {
 		list_merge = (wl_scan_results_t *)node;
@@ -2485,6 +2490,7 @@
 		}
 		node = node->next;
 	}
+	mutex_unlock(&wl_cache_lock);
 	return 0;
 }
 
@@ -2496,6 +2502,7 @@
 	wl_iw_ss_cache_t *node, *prev;
 	wl_iw_ss_cache_t **spec_scan_head;
 
+	mutex_lock(&wl_cache_lock);
 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
 	node = *spec_scan_head;
 	prev = node;
@@ -2518,8 +2525,8 @@
 	}
 
 	memset(addr, 0, ETHER_ADDR_LEN);
+	mutex_unlock(&wl_cache_lock);
 	return 0;
-
 }
 
 
@@ -2915,7 +2922,6 @@
 	iscan_buf_t * p_buf;
 	uint32 counter = 0;
 #endif
-
 	WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
 
 	if (!extra) {
@@ -2988,6 +2994,7 @@
 		kfree(list);
 	}
 
+	mutex_lock(&wl_cache_lock);
 #if defined(WL_IW_USE_ISCAN)
 	if (g_scan_specified_ssid)
 		WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count));
@@ -3007,11 +3014,11 @@
 	list_merge = (wl_scan_results_t *) g_scan;
 	len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user);
 #endif
+	mutex_unlock(&wl_cache_lock);
 	if (g_ss_cache_ctrl.m_link_down) {
-		
 		wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
 	}
-	
+
 	wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len);
 	len_ret += merged_len;
 	wl_iw_run_ss_cache_timer(0);
@@ -3078,8 +3085,6 @@
 		return wl_iw_get_scan(dev, info, dwrq, extra);
 	}
 
-	
-
 	if (g_ss_cache_ctrl.m_timer_expired) {
 		wl_iw_free_ss_cache();
 		g_ss_cache_ctrl.m_timer_expired ^= 1;
@@ -3089,12 +3094,11 @@
 	}
 	else {
 		if (g_ss_cache_ctrl.m_link_down) {
-			
 			wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
 		}
 		if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
 			g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
-			
+
 			wl_iw_reset_ss_cache();
 		}
 		g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
@@ -3198,7 +3202,6 @@
 	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);
@@ -3208,7 +3211,6 @@
 
 	WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
 
-	
 	if (!dwrq->length)
 		return -EAGAIN;
 
@@ -4728,11 +4730,24 @@
 	ASSERT(iolen);
 	res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen);
 
+	if (res != 0) {
+		WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n",
+			res, __FUNCTION__));
+		return res;
+	}
+
 	if (!ap_cfg_running) {
 		kernel_thread(thr_wait_for_2nd_eth_dev, 0, 0);
 	} else {
-		WL_TRACE(("%s: Configure security & restart AP bss \n", __FUNCTION__));
-		res |= wl_iw_set_ap_security(dev, &my_ap);
+		if (ap_net_dev == NULL) {
+			WL_ERROR(("%s: ERROR: ap_net_dev is NULL !!!\n",__FUNCTION__));
+			return -1;
+		}
+
+		/* if  the AP interface wl0.1 already exists we call security & bss UP in here */
+		WL_ERROR(("%s: %s Configure security & restart AP bss\n", __FUNCTION__, ap_net_dev->name));
+
+		res |= wl_iw_set_ap_security(ap_net_dev, &my_ap);
 		res |= dev_iw_write_cfg1_bss_var(dev, 1);
 	}
 	return res;
@@ -4964,21 +4979,70 @@
 }
 
 
+static int wl_iw_softap_deassoc_stations(struct net_device *dev)
+{
+	int i;
+	int res = 0;
+	char mac_buf[128] = {0};
+	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
+
+	memset(assoc_maclist, 0, sizeof(mac_buf));
+	assoc_maclist->count = 8;
+
+	res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128);
+	if (res != 0) {
+		WL_SOFTAP((" Error:%d in :%s, Couldn't get ASSOC List\n", res, __FUNCTION__));
+		return res;
+	}
+
+	if (assoc_maclist->count) {
+		for (i = 0; i < assoc_maclist->count; i++) {
+			scb_val_t scbval;
+
+			scbval.val = htod32(1);
+			bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN);
+
+			WL_SOFTAP(("deauth STA:%d \n", i));
+			res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
+					&scbval, sizeof(scb_val_t));
+		}
+	} else {
+		WL_SOFTAP((" STA ASSOC list is empty\n"));
+	}
+
+	if (res != 0)
+		WL_SOFTAP((" Error:%d in :%s\n", res, __FUNCTION__));
+	return res;
+}
+
+
 static int iwpriv_softap_stop(struct net_device *dev,
 	struct iw_request_info *info,
 	union iwreq_data *wrqu,
 	char *ext)
 {
-	int res;
+	int res = 0;
+	char buf[128];
 
-	WL_SOFTAP((" iw_handler SOFTAP_STP \n"));
+	WL_SOFTAP(("got iwpriv AP_BSS_STOP\n"));
 
-	ap_mode = 0;
-	ap_cfg_running = FALSE;
+	if ((!dev) && (!ap_net_dev)) {
+		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
+		return res;
+	}
 
-	res = dev_iw_write_cfg1_bss_var(dev, 2);
+	/* Make sure that interface is UP */
+	strcpy(buf, "cur_etheraddr");
+	dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf));
+
+	res = wl_iw_softap_deassoc_stations(ap_net_dev);
+
+	bcm_mdelay(200);
+	res |= dev_iw_write_cfg1_bss_var(dev, 2);
 
 	wrqu->data.length = 0;
+	ap_mode = 0;
+	ap_cfg_running = FALSE;
 
 	return res;
 }
@@ -6114,13 +6178,11 @@
 #endif
 
 	if (set == TRUE) {
-		
-		dev_wlc_bufvar_set(dev, "btc_flags", \
+		dev_wlc_bufvar_set(dev, "btc_flags",
 					(char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on));
 	}
 	else  {
-		
-		dev_wlc_bufvar_set(dev, "btc_flags", \
+		dev_wlc_bufvar_set(dev, "btc_flags",
 					(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
 	}
 
@@ -6135,7 +6197,7 @@
 	bt_info_t  *bt_local = (bt_info_t *)data;
 	bt_local->timer_on = 0;
 	WL_TRACE(("%s\n", __FUNCTION__));
-	
+
 	up(&bt_local->bt_sem);
 }
 
@@ -6155,13 +6217,12 @@
 
 		switch (g_bt->bt_state) {
 			case BT_DHCP_START:
-				
 				g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW;
 				mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000);
 				g_bt->timer_on = 1;
 				break;
+
 			case BT_DHCP_OPPORTUNITY_WINDOW:
-				
 				WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \
 						__FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM));
 				if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE);
@@ -6169,8 +6230,8 @@
 				mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
 				g_bt->timer_on = 1;
 				break;
+
 			case BT_DHCP_FLAG_FORCE_TIMEOUT:
-				
 				WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \
 						__FUNCTION__, BT_DHCP_FLAG_FORCE_TIME));
 				
@@ -6178,6 +6239,7 @@
 				g_bt->bt_state = BT_DHCP_IDLE;
 				g_bt->timer_on = 0;
 				break;
+
 			default:
 				WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, \
 				          g_bt->bt_state));
@@ -6252,7 +6314,12 @@
 	wl_iw_t *iw;
 #if defined(WL_IW_USE_ISCAN)
 	iscan_info_t *iscan = NULL;
+#endif
 
+	mutex_init(&wl_cache_lock);
+	mutex_init(&wl_start_lock);
+
+#if defined(WL_IW_USE_ISCAN)
 	if (!dev)
 		return 0;
 
@@ -6268,7 +6335,6 @@
 	g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
 	g_iscan->scan_flag = 0;
 
-	
 	iscan->timer_ms    = 3000;
 	init_timer(&iscan->timer);
 	iscan->timer.data = (ulong)iscan;
@@ -6279,14 +6345,12 @@
 	iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0);
 	if (iscan->sysioc_pid < 0)
 		return -ENOMEM;
-#endif 
-	mutex_init(&wl_start_lock);
+#endif
 
 	iw = *(wl_iw_t **)netdev_priv(dev);
 	iw->pub = (dhd_pub_t *)dhdp;
 	g_scan = NULL;
 
-	
 	g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
 	if (!g_scan)
 		return -ENOMEM;
@@ -6295,7 +6359,7 @@
 	g_scan_specified_ssid = 0;
 
 	wl_iw_init_ss_cache_ctrl();
-	
+
 	wl_iw_bt_init(dev);
 
 #ifdef SOFTAP
@@ -6317,7 +6381,7 @@
 		KILL_PROC(iscan->sysioc_pid, SIGTERM);
 		wait_for_completion(&iscan->sysioc_exited);
 	}
-
+	mutex_lock(&wl_cache_lock);
 	while (iscan->list_hdr) {
 		buf = iscan->list_hdr->next;
 		kfree(iscan->list_hdr);
@@ -6325,6 +6389,7 @@
 	}
 	kfree(iscan);
 	g_iscan = NULL;
+	mutex_unlock(&wl_cache_lock);
 #endif
 
 	if (g_scan)
@@ -6333,7 +6398,6 @@
 	g_scan = NULL;
 	wl_iw_release_ss_cache_ctrl();
 	wl_iw_bt_release();
-
 #ifdef SOFTAP
 	if (ap_mode) {
 		WL_TRACE(("\n%s AP is going down\n", __FUNCTION__));