diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 87 |
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 | ||
2940 | static 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 | |||
3005 | static 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 | ||
3820 | static void iwl_hw_detect(struct iwl_priv *priv) | 3907 | static void iwl_hw_detect(struct iwl_priv *priv) |