mwifiex: add support for P2P GO in interface type change
When cfg80211 calls to change interface type for P2P GO, send
P2P mode config commands to firmware and set bss role and bss
mode accordingly.
Signed-off-by: Stone Piao <piaoyun@marvell.com>
Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 4990603..94ac40c 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -679,6 +679,9 @@
{
u16 mode = P2P_MODE_DISABLE;
+ if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
+ mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
+
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
HostCmd_ACT_GEN_SET, 0, &mode))
return -1;
@@ -713,6 +716,35 @@
}
/*
+ * This function initializes the functionalities for P2P GO.
+ * The P2P GO initialization sequence is:
+ * disable -> device -> GO
+ */
+static int
+mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
+{
+ u16 mode;
+
+ if (mwifiex_cfg80211_deinit_p2p(priv))
+ return -1;
+
+ mode = P2P_MODE_DEVICE;
+ if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode))
+ return -1;
+
+ mode = P2P_MODE_GO;
+ if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode))
+ return -1;
+
+ if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
+ mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP);
+
+ return 0;
+}
+
+/*
* CFG802.11 operation handler to change interface type.
*/
static int
@@ -749,6 +781,11 @@
return -EFAULT;
dev->ieee80211_ptr->iftype = type;
return 0;
+ case NL80211_IFTYPE_P2P_GO:
+ if (mwifiex_cfg80211_init_p2p_go(priv))
+ return -EFAULT;
+ dev->ieee80211_ptr->iftype = type;
+ return 0;
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
@@ -775,6 +812,7 @@
}
break;
case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
switch (type) {
case NL80211_IFTYPE_STATION:
if (mwifiex_cfg80211_deinit_p2p(priv))
@@ -1135,7 +1173,7 @@
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
+ if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) {
wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__);
return -EINVAL;
}
@@ -1223,7 +1261,7 @@
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
u8 config_bands = 0;
- if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
+ if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
return -1;
if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon))
return -1;
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 7887848..857af0f 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -1379,6 +1379,7 @@
#define CONNECTION_TYPE_INFRA 0
#define CONNECTION_TYPE_ADHOC 1
+#define CONNECTION_TYPE_AP 2
struct host_cmd_ds_set_bss_mode {
u8 con_type;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index fa96dc3..b5d37a8 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -144,7 +144,7 @@
* Additionally, it also initializes all the locks and sets up all the
* lists.
*/
-static int mwifiex_init_priv(struct mwifiex_private *priv)
+int mwifiex_init_priv(struct mwifiex_private *priv)
{
u32 i;
@@ -649,6 +649,17 @@
}
/*
+ * This function frees the private structure, including cleans
+ * up the TX and RX queues and frees the BSS priority tables.
+ */
+void mwifiex_free_priv(struct mwifiex_private *priv)
+{
+ mwifiex_clean_txrx(priv);
+ mwifiex_delete_bss_prio_tbl(priv);
+ mwifiex_free_curr_bcn(priv);
+}
+
+/*
* This function is used to shutdown the driver.
*
* The following operations are performed sequentially -
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 89ba66e..956312f 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -736,6 +736,9 @@
void mwifiex_wake_up_net_dev_queue(struct net_device *netdev,
struct mwifiex_adapter *adapter);
+int mwifiex_init_priv(struct mwifiex_private *priv);
+void mwifiex_free_priv(struct mwifiex_private *priv);
+
int mwifiex_init_fw(struct mwifiex_adapter *adapter);
int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter);
@@ -1018,6 +1021,8 @@
enum nl80211_channel_type *channel_type,
unsigned int duration);
+int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role);
+
int mwifiex_get_stats_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_stats *log);
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 704cfaa..5d87195 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1261,6 +1261,8 @@
else if (priv->bss_mode == NL80211_IFTYPE_STATION)
cmd_ptr->params.bss_mode.con_type =
CONNECTION_TYPE_INFRA;
+ else if (priv->bss_mode == NL80211_IFTYPE_AP)
+ cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP;
cmd_ptr->size = cpu_to_le16(sizeof(struct
host_cmd_ds_set_bss_mode) + S_DS_GEN);
ret = 0;
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index fd09a21..0c9f70b 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -1072,6 +1072,36 @@
return roc_cfg.status;
}
+int
+mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role)
+{
+ if (GET_BSS_ROLE(priv) == bss_role) {
+ dev_dbg(priv->adapter->dev,
+ "info: already in the desired role.\n");
+ return 0;
+ }
+
+ mwifiex_free_priv(priv);
+ mwifiex_init_priv(priv);
+
+ priv->bss_role = bss_role;
+ switch (bss_role) {
+ case MWIFIEX_BSS_ROLE_UAP:
+ priv->bss_mode = NL80211_IFTYPE_AP;
+ break;
+ case MWIFIEX_BSS_ROLE_STA:
+ case MWIFIEX_BSS_ROLE_ANY:
+ default:
+ priv->bss_mode = NL80211_IFTYPE_STATION;
+ break;
+ }
+
+ mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+
+ return mwifiex_sta_init_cmd(priv, false);
+}
+
/*
* Sends IOCTL request to get statistics information.
*