aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-11-10 09:55:01 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-11 12:32:52 -0500
commit79d3eef89190ee0a7ee585e3949873241bc382e3 (patch)
tree69da0c1b02fd45dea359624c5d876412d22dd40d /drivers/net/wireless/iwlwifi
parent868a5f719d730866564d9bd73a8f4a8d89bdc71a (diff)
iwlagn: add P2P NoA to probe responses
Whether to use NoA or not is entire controlled by the uCode right now, and it also adds the attribute to beacons. We do need to add it to probe responses in the driver though. Keep track of the NoA notification from the uCode and add the data to probe responses when such are transmitted. Use RCU to manage the lifetime. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h8
4 files changed, 68 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index 5af9e6258a16..f0d6d9429be7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -1032,6 +1032,50 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
1032 return 0; 1032 return 0;
1033} 1033}
1034 1034
1035static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
1036 struct iwl_rx_mem_buffer *rxb,
1037 struct iwl_device_cmd *cmd)
1038{
1039 struct iwl_wipan_noa_data *new_data, *old_data;
1040 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1041 struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->u.raw;
1042
1043 /* no condition -- we're in softirq */
1044 old_data = rcu_dereference_protected(priv->noa_data, true);
1045
1046 if (noa_notif->noa_active) {
1047 u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
1048 u32 copylen = len;
1049
1050 /* EID, len, OUI, subtype */
1051 len += 1 + 1 + 3 + 1;
1052 /* P2P id, P2P length */
1053 len += 1 + 2;
1054 copylen += 1 + 2;
1055
1056 new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
1057 if (new_data) {
1058 new_data->length = len;
1059 new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
1060 new_data->data[1] = len - 2; /* not counting EID, len */
1061 new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
1062 new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
1063 new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
1064 new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
1065 memcpy(&new_data->data[6], &noa_notif->noa_attribute,
1066 copylen);
1067 }
1068 } else
1069 new_data = NULL;
1070
1071 rcu_assign_pointer(priv->noa_data, new_data);
1072
1073 if (old_data)
1074 kfree_rcu(old_data, rcu_head);
1075
1076 return 0;
1077}
1078
1035/** 1079/**
1036 * iwl_setup_rx_handlers - Initialize Rx handler callbacks 1080 * iwl_setup_rx_handlers - Initialize Rx handler callbacks
1037 * 1081 *
@@ -1055,6 +1099,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
1055 handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif; 1099 handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif;
1056 handlers[REPLY_ADD_STA] = iwl_add_sta_callback; 1100 handlers[REPLY_ADD_STA] = iwl_add_sta_callback;
1057 1101
1102 handlers[REPLY_WIPAN_NOA_NOTIFICATION] = iwlagn_rx_noa_notification;
1103
1058 /* 1104 /*
1059 * The same handler is used for both the REPLY to a discrete 1105 * The same handler is used for both the REPLY to a discrete
1060 * statistics request from the host as well as for the periodic 1106 * statistics request from the host as well as for the periodic
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 35a6b71f358c..014b98ab6816 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -283,6 +283,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
283 IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); 283 IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
284#endif 284#endif
285 285
286 if (unlikely(ieee80211_is_probe_resp(fc))) {
287 struct iwl_wipan_noa_data *noa_data =
288 rcu_dereference(priv->noa_data);
289
290 if (noa_data &&
291 pskb_expand_head(skb, 0, noa_data->length,
292 GFP_ATOMIC) == 0) {
293 memcpy(skb_put(skb, noa_data->length),
294 noa_data->data, noa_data->length);
295 hdr = (struct ieee80211_hdr *)skb->data;
296 }
297 }
298
286 hdr_len = ieee80211_hdrlen(fc); 299 hdr_len = ieee80211_hdrlen(fc);
287 300
288 /* For management frames use broadcast id to do not break aggregation */ 301 /* For management frames use broadcast id to do not break aggregation */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 9d463cf40380..3c0f4e6c9357 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3069,6 +3069,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
3069 kmem_cache_destroy(priv->tx_cmd_pool); 3069 kmem_cache_destroy(priv->tx_cmd_pool);
3070 kfree(priv->scan_cmd); 3070 kfree(priv->scan_cmd);
3071 kfree(priv->beacon_cmd); 3071 kfree(priv->beacon_cmd);
3072 kfree(rcu_dereference_raw(priv->noa_data));
3072#ifdef CONFIG_IWLWIFI_DEBUGFS 3073#ifdef CONFIG_IWLWIFI_DEBUGFS
3073 kfree(priv->wowlan_sram); 3074 kfree(priv->wowlan_sram);
3074#endif 3075#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 6c00a447963d..ef8620b10bbc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -824,6 +824,12 @@ struct iwl_testmode_trace {
824}; 824};
825#endif 825#endif
826 826
827struct iwl_wipan_noa_data {
828 struct rcu_head rcu_head;
829 u32 length;
830 u8 data[];
831};
832
827struct iwl_priv { 833struct iwl_priv {
828 834
829 /*data shared among all the driver's layers */ 835 /*data shared among all the driver's layers */
@@ -883,6 +889,8 @@ struct iwl_priv {
883 /* init calibration results */ 889 /* init calibration results */
884 struct iwl_calib_result calib_results[IWL_CALIB_MAX]; 890 struct iwl_calib_result calib_results[IWL_CALIB_MAX];
885 891
892 struct iwl_wipan_noa_data __rcu *noa_data;
893
886 /* Scan related variables */ 894 /* Scan related variables */
887 unsigned long scan_start; 895 unsigned long scan_start;
888 unsigned long scan_start_tsf; 896 unsigned long scan_start_tsf;