From 60bd997bde1f9f7658151969eb5d396d0e836e13 Mon Sep 17 00:00:00 2001
From: Howard M. Harte <hharte@broadcom.com>
Date: Mon, 1 Aug 2011 19:38:54 -0700
Subject: [PATCH 523/696] net: wireless: bcmdhd: add support for mkeepalive.
 Fix p2p group add issue.
 Change-Id: Ieb8fba54e04912b4002837243c00ba90fd150e5d
 Signed-off-by: Howard M. Harte <hharte@broadcom.com>

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
---
 drivers/net/wireless/bcmdhd/dhd_common.c      |   64 ++++++++-----------
 drivers/net/wireless/bcmdhd/dhd_linux.c       |   10 ++-
 drivers/net/wireless/bcmdhd/include/wlioctl.h |   13 ++++-
 drivers/net/wireless/bcmdhd/wl_cfg80211.c     |   80 +++++-------------------
 drivers/net/wireless/bcmdhd/wl_cfg80211.h     |    3 +-
 drivers/net/wireless/bcmdhd/wl_cfgp2p.h       |    2 +
 6 files changed, 67 insertions(+), 105 deletions(-)

diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 2e6a53e..2a68965 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -92,7 +92,7 @@ bool ap_cfg_running = FALSE;
 bool ap_fw_loaded = FALSE;
 
 #if defined(KEEP_ALIVE)
-int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on);
+int dhd_keep_alive_onoff(dhd_pub_t *dhd);
 #endif /* KEEP_ALIVE */
 
 /* Packet alignment for most efficient SDIO (can change based on platform) */
@@ -1674,7 +1674,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #if defined(SOFTAP)
 	if (ap_fw_loaded == FALSE)
 #endif
-		if ((res = dhd_keep_alive_onoff(dhd, 1)) < 0)
+		if ((res = dhd_keep_alive_onoff(dhd)) < 0)
 			DHD_ERROR(("%s set keeplive failed %d\n",
 			__FUNCTION__, res));
 	}
@@ -2260,49 +2260,39 @@ dhd_pno_get_status(dhd_pub_t *dhd)
 #endif /* PNO_SUPPORT */
 
 #if defined(KEEP_ALIVE)
-int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on)
+int dhd_keep_alive_onoff(dhd_pub_t *dhd)
 {
-	char buf[256];
-	char *buf_ptr = buf;
-	wl_keep_alive_pkt_t keep_alive_pkt;
-	char * str;
-	int str_len, buf_len;
-	int res = -1;
-	int keep_alive_period = KEEP_ALIVE_PERIOD; /* in ms */
+	char			buf[256];
+	const char		*str;
+	wl_mkeep_alive_pkt_t	mkeep_alive_pkt;
+	wl_mkeep_alive_pkt_t	*mkeep_alive_pktp;
+	int			buf_len;
+	int			str_len;
+	int res			= -1;
 
-	DHD_TRACE(("%s: param=%d\n", __FUNCTION__, ka_on));
+	DHD_ERROR(("%s Enter\n", __FUNCTION__));
 
-	if (ka_on) { /* on suspend */
-		keep_alive_pkt.period_msec = keep_alive_period;
-
-	} else {
-		/* on resume, turn off keep_alive packets  */
-		keep_alive_pkt.period_msec = 0;
-	}
-
-	/* IOC var name  */
-	str = "keep_alive";
+	str = "mkeep_alive";
 	str_len = strlen(str);
 	strncpy(buf, str, str_len);
-	buf[str_len] = '\0';
+	buf[ str_len ] = '\0';
+	mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
+	mkeep_alive_pkt.period_msec = KEEP_ALIVE_PERIOD;
 	buf_len = str_len + 1;
+	mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
+	mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
+	/* Setup keep alive zero for null packet generation */
+	mkeep_alive_pkt.keep_alive_id = 0;
+	mkeep_alive_pkt.len_bytes = 0;
+	buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+	/* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
+	 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
+	 * guarantee that the buffer is properly aligned.
+	 */
+	memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
 
-	/* set ptr to IOCTL payload after the var name */
-	buf_ptr += buf_len; /* include term Z */
-
-	/* copy Keep-alive attributes from local var keep_alive_pkt */
-	str = NULL_PKT_STR;
-	keep_alive_pkt.len_bytes = strlen(str);
-
-	memcpy(buf_ptr, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN);
-	buf_ptr += WL_KEEP_ALIVE_FIXED_LEN;
-
-	/* copy packet data */
-	memcpy(buf_ptr, str, keep_alive_pkt.len_bytes);
-	buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes);
-/*
 	res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
-*/
+
 	return res;
 }
 #endif /* defined(KEEP_ALIVE) */
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 690384a..ba1f6a2 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -967,13 +967,17 @@ dhd_op_if(dhd_if_t *ifp)
 		}
 		if (ret == 0) {
 			strncpy(ifp->net->name, ifp->name, IFNAMSIZ);
+			ifp->net->name[IFNAMSIZ - 1] = '\0';
+			memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
 #ifdef WL_CFG80211
 			if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
-				wl_cfg80211_notify_ifadd(ifp->net);
+				if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, dhd_net_attach)) {
+					ifp->state = 0;
+					return;
+			}
+
 #endif
 
-			ifp->net->name[IFNAMSIZ - 1] = '\0';
-			memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
 			if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
 				DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
 					__FUNCTION__, err));
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index f1af5b1..a441eab 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -1747,7 +1747,18 @@ struct wl_msglevel2 {
 	uint32 high;
 };
 
-
+typedef struct wl_mkeep_alive_pkt {
+	uint16	version;
+	uint16	length;
+	uint32	period_msec;
+	uint16	len_bytes;
+	uint8	keep_alive_id;
+	uint8	data[1];
+} wl_mkeep_alive_pkt_t;
+
+#define WL_MKEEP_ALIVE_VERSION          1
+#define WL_MKEEP_ALIVE_FIXED_LEN        OFFSETOF(wl_mkeep_alive_pkt_t, data)
+#define WL_MKEEP_ALIVE_PRECISION        500
 
 #define WLC_ROAM_TRIGGER_DEFAULT    0 
 #define WLC_ROAM_TRIGGER_BANDWIDTH  1 
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index cc5d86e..366ce22 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -213,10 +213,6 @@ static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
 	struct net_device *dev, bool enabled,
 	s32 timeout);
-static s32 wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
-	struct net_device *dev,
-	const u8 *addr,
-	const struct cfg80211_bitrate_mask *mask);
 static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 	struct cfg80211_connect_params *sme);
 static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
@@ -883,6 +879,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
 	struct wl_priv *wl = WL_PRIV_GET();
 	struct net_device *_ndev;
 	dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+	int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
 
 	WL_DBG(("if name: %s, type: %d\n", name, type));
 	switch (type) {
@@ -985,6 +982,16 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
 			wl->p2p->vif_created = true;
 			set_mode_by_netdev(wl, _ndev, mode);
 			wl = wdev_to_wl(vwdev);
+			net_attach =  wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
+			rtnl_unlock();
+			if (net_attach && !net_attach(dhd, _ndev->ifindex))
+				WL_DBG((" virtual interface(%s) is "
+					"created\n", wl->p2p->vir_ifname));
+			else {
+				rtnl_lock();
+				goto fail;
+			}
+			rtnl_lock();
 			return _ndev;
 
 		} else {
@@ -994,6 +1001,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
 			wl->p2p->vif_created = false;
 		}
 	}
+fail:
 	return ERR_PTR(-ENODEV);
 }
 
@@ -1110,11 +1118,12 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
 }
 
 s32
-wl_cfg80211_notify_ifadd(struct net_device *net)
+wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx,
+int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
 {
 	struct wl_priv *wl = WL_PRIV_GET();
 	s32 ret = BCME_OK;
-	if (!net || !net->name) {
+	if (!net) {
 		WL_ERR(("net is NULL\n"));
 		return 0;
 	}
@@ -1126,7 +1135,9 @@ wl_cfg80211_notify_ifadd(struct net_device *net)
 		wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net;
 		wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) =
 			P2PAPI_BSSCFG_CONNECTION;
+		wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach;
 		wl_clr_p2p_status(wl, IF_ADD);
+		net->ifindex = idx;
 		wake_up_interruptible(&wl->dongle_event_wait);
 	}
 	return ret;
@@ -2704,62 +2715,6 @@ static __used u32 wl_find_msb(u16 bit16)
 	return ret;
 }
 
-static s32
-wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
-	const u8 *addr,
-	const struct cfg80211_bitrate_mask *mask)
-{
-	struct wl_rateset rateset;
-	s32 rate;
-	s32 val;
-	s32 err_bg;
-	s32 err_a;
-	u32 legacy;
-	s32 err = 0;
-
-	CHECK_SYS_UP();
-	/* addr param is always NULL. ignore it */
-	/* Get current rateset */
-	err = wldev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
-		sizeof(rateset), false);
-	if (unlikely(err)) {
-		WL_ERR(("could not get current rateset (%d)\n", err));
-		return err;
-	}
-
-	rateset.count = dtoh32(rateset.count);
-
-	legacy = wl_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy);
-	if (!legacy)
-		legacy = wl_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy);
-
-	val = wl_g_rates[legacy - 1].bitrate * 100000;
-
-	if (val < rateset.count) {
-		/* Select rate by rateset index */
-		rate = rateset.rates[val] & 0x7f;
-	} else {
-		/* Specified rate in bps */
-		rate = val / 500000;
-	}
-
-	WL_DBG(("rate %d mbps\n", (rate / 2)));
-
-	/*
-	 *
-	 *      Set rate override,
-	 *      Since the is a/b/g-blind, both a/bg_rate are enforced.
-	 */
-	err_bg = wl_dev_intvar_set(dev, "bg_rate", rate);
-	err_a = wl_dev_intvar_set(dev, "a_rate", rate);
-	if (unlikely(err_bg && err_a)) {
-		WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a));
-		return err_bg | err_a;
-	}
-
-	return err;
-}
-
 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
 {
 	struct wl_priv *wl = WL_PRIV_GET();
@@ -3837,7 +3792,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
 	.set_default_key = wl_cfg80211_config_default_key,
 	.set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
 	.set_power_mgmt = wl_cfg80211_set_power_mgmt,
-	.set_bitrate_mask = wl_cfg80211_set_bitrate_mask,
 	.connect = wl_cfg80211_connect,
 	.disconnect = wl_cfg80211_disconnect,
 	.suspend = wl_cfg80211_suspend,
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index f9de60f..4dea132 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -499,7 +499,8 @@ extern void wl_cfg80211_set_sdio_func(void *func);	/* set sdio function info */
 extern struct sdio_func *wl_cfg80211_get_sdio_func(void);	/* set sdio function info */
 extern s32 wl_cfg80211_up(void);	/* dongle up */
 extern s32 wl_cfg80211_down(void);	/* dongle down */
-extern s32 wl_cfg80211_notify_ifadd(struct net_device *net);
+extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, 
+int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
 extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
 extern s32 wl_cfg80211_notify_ifdel(struct net_device *net);
 extern s32 wl_cfg80211_is_progress_ifadd(void);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index 971633a..d62f542 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -61,6 +61,7 @@ struct p2p_bss {
 	u32 bssidx;
 	struct net_device *dev;
 	struct p2p_saved_ie saved_ie;
+	void *private_data;
 };
 
 struct p2p_info {
@@ -94,6 +95,7 @@ enum wl_cfgp2p_status {
 #define wl_to_p2p_bss_ndev(w, type) 	((wl)->p2p->bss_idx[type].dev)
 #define wl_to_p2p_bss_bssidx(w, type) 	((wl)->p2p->bss_idx[type].bssidx)
 #define wl_to_p2p_bss_saved_ie(w, type) 	((wl)->p2p->bss_idx[type].saved_ie)
+#define wl_to_p2p_bss_private(w, type)  ((wl)->p2p->bss_idx[type].private_data)
 #define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
 #define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
 									&(wl)->p2p->status))
-- 
1.7.1


