mwifiex: retrieve IEs from cfg80211_beacon_data and send to firmware
authorAvinash Patil <patila@marvell.com>
Wed, 9 May 2012 01:30:29 +0000 (18:30 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 16 May 2012 16:46:37 +0000 (12:46 -0400)
This patch adds logic for setting tail beacon IE, probe response IE
and assoc response IE from cfg80211_ap_settings parameter of
start_ap handler into FW.

RSN IE is also retrieved from tail IE buffer and sent to firmware.

Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/ie.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h

index d305b373aee020c68a5fe13482f3882f9c764afe..2d0952dc593a167158018e5e92e87965bd4d21c7 100644 (file)
@@ -952,6 +952,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
 
        if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
                return -1;
+       if (mwifiex_set_mgmt_ies(priv, params))
+               return -1;
 
        bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
        if (!bss_cfg)
index 0cb2b0cc3ee82f7523b048e97310ab1415c4d5c8..9f674bbebe65afc2f3fa2edf001af0d414cd8b4d 100644 (file)
@@ -97,6 +97,13 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define UAP_CUSTOM_IE_I                                1
 #define MWIFIEX_AUTO_IDX_MASK                  0xffff
 #define MWIFIEX_DELETE_MASK                    0x0000
+#define MGMT_MASK_ASSOC_REQ                    0x01
+#define MGMT_MASK_REASSOC_REQ                  0x04
+#define MGMT_MASK_ASSOC_RESP                   0x02
+#define MGMT_MASK_REASSOC_RESP                 0x08
+#define MGMT_MASK_PROBE_REQ                    0x10
+#define MGMT_MASK_PROBE_RESP                   0x20
+#define MGMT_MASK_BEACON                       0x100
 
 #define TLV_TYPE_UAP_SSID                      0x0000
 
index 772bf3e57006f9ffa9fda708a6b1d43ed77d6f87..ca9ebcf8ab229105a43fab78231f95a68c03c174 100644 (file)
@@ -147,3 +147,179 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
 
        return 0;
 }
+
+/* Copy individual custom IEs for beacon, probe response and assoc response
+ * and prepare single structure for IE setting.
+ * This function also updates allocated IE indices from driver.
+ */
+static int
+mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
+                            struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
+                            struct mwifiex_ie *pr_ie, u16 *probe_idx,
+                            struct mwifiex_ie *ar_ie, u16 *assoc_idx)
+{
+       struct mwifiex_ie_list *ap_custom_ie;
+       u8 *pos;
+       u16 len;
+       int ret;
+
+       ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+       if (!ap_custom_ie)
+               return -ENOMEM;
+
+       ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
+       pos = (u8 *)ap_custom_ie->ie_list;
+
+       if (beacon_ie) {
+               len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
+                     le16_to_cpu(beacon_ie->ie_length);
+               memcpy(pos, beacon_ie, len);
+               pos += len;
+               le16_add_cpu(&ap_custom_ie->len, len);
+       }
+       if (pr_ie) {
+               len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
+                     le16_to_cpu(pr_ie->ie_length);
+               memcpy(pos, pr_ie, len);
+               pos += len;
+               le16_add_cpu(&ap_custom_ie->len, len);
+       }
+       if (ar_ie) {
+               len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
+                     le16_to_cpu(ar_ie->ie_length);
+               memcpy(pos, ar_ie, len);
+               pos += len;
+               le16_add_cpu(&ap_custom_ie->len, len);
+       }
+
+       ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
+
+       pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
+       if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
+               /* save beacon ie index after auto-indexing */
+               *beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
+               len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
+                     le16_to_cpu(beacon_ie->ie_length);
+               pos += len;
+       }
+       if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
+               /* save probe resp ie index after auto-indexing */
+               *probe_idx = *((u16 *)pos);
+               len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
+                     le16_to_cpu(pr_ie->ie_length);
+               pos += len;
+       }
+       if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
+               /* save assoc resp ie index after auto-indexing */
+               *assoc_idx = *((u16 *)pos);
+
+       return ret;
+}
+
+/* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs,
+ * association response IEs from cfg80211_ap_settings function and sets these IE
+ * to FW.
+ */
+int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
+                        struct cfg80211_ap_settings *params)
+{
+       struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
+       struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
+       struct ieee_types_header *ie = NULL;
+       u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
+       u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+       u16 mask;
+       int ret = 0;
+
+       if (params->beacon.tail && params->beacon.tail_len) {
+               ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail,
+                                             params->beacon.tail_len);
+               if (ie) {
+                       rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+                       if (!rsn_ie)
+                               return -ENOMEM;
+
+                       rsn_ie->ie_index = cpu_to_le16(rsn_idx);
+                       mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+                              MGMT_MASK_ASSOC_RESP;
+                       rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask);
+                       rsn_ie->ie_length = cpu_to_le16(ie->len + 2);
+                       memcpy(rsn_ie->ie_buffer, ie, ie->len + 2);
+
+                       if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx,
+                                                        NULL, NULL,
+                                                        NULL, NULL)) {
+                               ret = -1;
+                               goto done;
+                       }
+
+                       priv->rsn_idx = rsn_idx;
+               }
+       }
+
+       if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) {
+               beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+               if (!beacon_ie) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               beacon_ie->ie_index = cpu_to_le16(beacon_idx);
+               beacon_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON);
+               beacon_ie->ie_length =
+                               cpu_to_le16(params->beacon.beacon_ies_len);
+               memcpy(beacon_ie->ie_buffer, params->beacon.beacon_ies,
+                      params->beacon.beacon_ies_len);
+       }
+
+       if (params->beacon.proberesp_ies && params->beacon.proberesp_ies_len) {
+               pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+               if (!pr_ie) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               pr_ie->ie_index = cpu_to_le16(pr_idx);
+               pr_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_PROBE_RESP);
+               pr_ie->ie_length =
+                               cpu_to_le16(params->beacon.proberesp_ies_len);
+               memcpy(pr_ie->ie_buffer, params->beacon.proberesp_ies,
+                      params->beacon.proberesp_ies_len);
+       }
+
+       if (params->beacon.assocresp_ies && params->beacon.assocresp_ies_len) {
+               ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+               if (!ar_ie) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               ar_ie->ie_index = cpu_to_le16(ar_idx);
+               mask = MGMT_MASK_ASSOC_RESP | MGMT_MASK_REASSOC_RESP;
+               ar_ie->mgmt_subtype_mask = cpu_to_le16(mask);
+               ar_ie->ie_length =
+                               cpu_to_le16(params->beacon.assocresp_ies_len);
+               memcpy(ar_ie->ie_buffer, params->beacon.assocresp_ies,
+                      params->beacon.assocresp_ies_len);
+       }
+
+       if (beacon_ie || pr_ie || ar_ie) {
+               ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
+                                                  &beacon_idx, pr_ie,
+                                                  &pr_idx, ar_ie, &ar_idx);
+               if (ret)
+                       goto done;
+       }
+
+       priv->beacon_idx = beacon_idx;
+       priv->proberesp_idx = pr_idx;
+       priv->assocresp_idx = ar_idx;
+
+done:
+       kfree(beacon_ie);
+       kfree(pr_ie);
+       kfree(ar_ie);
+       kfree(rsn_ie);
+
+       return ret;
+}
index 49598e6c181fc5a933dcafae26fc987404721158..3192855c31c05df94e55360824f463ff0fbccfb8 100644 (file)
@@ -642,6 +642,10 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
        memset(&priv->nick_name, 0, sizeof(priv->nick_name));
        memset(priv->mgmt_ie, 0,
               sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
+       priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
+       priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
+       priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
+       priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
        priv->num_tx_timeout = 0;
        memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
 }
index 988d31d6504c20da71601df257b7565866ecfe3c..7d882eea2171eed020432fc39990ec4f5870551b 100644 (file)
@@ -478,6 +478,10 @@ struct mwifiex_private {
        u32 cqm_rssi_hyst;
        u8 subsc_evt_rssi_state;
        struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX];
+       u16 beacon_idx;
+       u16 proberesp_idx;
+       u16 assocresp_idx;
+       u16 rsn_idx;
 };
 
 enum mwifiex_ba_status {
@@ -1001,6 +1005,8 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
 
 void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
 
+int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
+                        struct cfg80211_ap_settings *params);
 u8 *mwifiex_11d_code_2_region(u8 code);
 
 #ifdef CONFIG_DEBUG_FS