aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;