diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 8 |
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 | ||
1035 | static 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 | ||
827 | struct iwl_wipan_noa_data { | ||
828 | struct rcu_head rcu_head; | ||
829 | u32 length; | ||
830 | u8 data[]; | ||
831 | }; | ||
832 | |||
827 | struct iwl_priv { | 833 | struct 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; |