diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-10 09:55:01 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-11 12:32:52 -0500 |
commit | 79d3eef89190ee0a7ee585e3949873241bc382e3 (patch) | |
tree | 69da0c1b02fd45dea359624c5d876412d22dd40d /drivers/net/wireless/iwlwifi | |
parent | 868a5f719d730866564d9bd73a8f4a8d89bdc71a (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.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; |