aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index e0cd3e27a0d9..581dc9f10273 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2937,6 +2937,91 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
2937 mutex_unlock(&priv->mutex); 2937 mutex_unlock(&priv->mutex);
2938} 2938}
2939 2939
2940static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
2941 struct ieee80211_channel *chan,
2942 enum nl80211_channel_type channel_type,
2943 unsigned int wait)
2944{
2945 struct iwl_priv *priv = hw->priv;
2946 int ret;
2947
2948 /* Not supported if we don't have PAN */
2949 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) {
2950 ret = -EOPNOTSUPP;
2951 goto free;
2952 }
2953
2954 /* Not supported on pre-P2P firmware */
2955 if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
2956 BIT(NL80211_IFTYPE_P2P_CLIENT))) {
2957 ret = -EOPNOTSUPP;
2958 goto free;
2959 }
2960
2961 mutex_lock(&priv->mutex);
2962
2963 if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) {
2964 /*
2965 * If the PAN context is free, use the normal
2966 * way of doing remain-on-channel offload + TX.
2967 */
2968 ret = 1;
2969 goto out;
2970 }
2971
2972 /* TODO: queue up if scanning? */
2973 if (test_bit(STATUS_SCANNING, &priv->status) ||
2974 priv->_agn.offchan_tx_skb) {
2975 ret = -EBUSY;
2976 goto out;
2977 }
2978
2979 /*
2980 * max_scan_ie_len doesn't include the blank SSID or the header,
2981 * so need to add that again here.
2982 */
2983 if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) {
2984 ret = -ENOBUFS;
2985 goto out;
2986 }
2987
2988 priv->_agn.offchan_tx_skb = skb;
2989 priv->_agn.offchan_tx_timeout = wait;
2990 priv->_agn.offchan_tx_chan = chan;
2991
2992 ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif,
2993 IWL_SCAN_OFFCH_TX, chan->band);
2994 if (ret)
2995 priv->_agn.offchan_tx_skb = NULL;
2996 out:
2997 mutex_unlock(&priv->mutex);
2998 free:
2999 if (ret < 0)
3000 kfree_skb(skb);
3001
3002 return ret;
3003}
3004
3005static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw)
3006{
3007 struct iwl_priv *priv = hw->priv;
3008 int ret;
3009
3010 mutex_lock(&priv->mutex);
3011
3012 if (!priv->_agn.offchan_tx_skb)
3013 return -EINVAL;
3014
3015 priv->_agn.offchan_tx_skb = NULL;
3016
3017 ret = iwl_scan_cancel_timeout(priv, 200);
3018 if (ret)
3019 ret = -EIO;
3020 mutex_unlock(&priv->mutex);
3021
3022 return ret;
3023}
3024
2940/***************************************************************************** 3025/*****************************************************************************
2941 * 3026 *
2942 * mac80211 entry point functions 3027 * mac80211 entry point functions
@@ -3815,6 +3900,8 @@ struct ieee80211_ops iwlagn_hw_ops = {
3815 .tx_last_beacon = iwl_mac_tx_last_beacon, 3900 .tx_last_beacon = iwl_mac_tx_last_beacon,
3816 .remain_on_channel = iwl_mac_remain_on_channel, 3901 .remain_on_channel = iwl_mac_remain_on_channel,
3817 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, 3902 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
3903 .offchannel_tx = iwl_mac_offchannel_tx,
3904 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
3818}; 3905};
3819 3906
3820static void iwl_hw_detect(struct iwl_priv *priv) 3907static void iwl_hw_detect(struct iwl_priv *priv)