diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 626dc3b5fd8d..cbbef88a8ebd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -5591,6 +5591,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5591 | if (err) | 5591 | if (err) |
5592 | return err; | 5592 | return err; |
5593 | 5593 | ||
5594 | if (netif_carrier_ok(dev)) | ||
5595 | return -EBUSY; | ||
5596 | |||
5594 | if (wdev->cac_started) | 5597 | if (wdev->cac_started) |
5595 | return -EBUSY; | 5598 | return -EBUSY; |
5596 | 5599 | ||
@@ -5634,15 +5637,26 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5634 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; | 5637 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; |
5635 | u8 radar_detect_width = 0; | 5638 | u8 radar_detect_width = 0; |
5636 | int err; | 5639 | int err; |
5640 | bool need_new_beacon = false; | ||
5637 | 5641 | ||
5638 | if (!rdev->ops->channel_switch || | 5642 | if (!rdev->ops->channel_switch || |
5639 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) | 5643 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) |
5640 | return -EOPNOTSUPP; | 5644 | return -EOPNOTSUPP; |
5641 | 5645 | ||
5642 | /* may add IBSS support later */ | 5646 | switch (dev->ieee80211_ptr->iftype) { |
5643 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 5647 | case NL80211_IFTYPE_AP: |
5644 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 5648 | case NL80211_IFTYPE_P2P_GO: |
5649 | need_new_beacon = true; | ||
5650 | |||
5651 | /* useless if AP is not running */ | ||
5652 | if (!wdev->beacon_interval) | ||
5653 | return -EINVAL; | ||
5654 | break; | ||
5655 | case NL80211_IFTYPE_ADHOC: | ||
5656 | break; | ||
5657 | default: | ||
5645 | return -EOPNOTSUPP; | 5658 | return -EOPNOTSUPP; |
5659 | } | ||
5646 | 5660 | ||
5647 | memset(¶ms, 0, sizeof(params)); | 5661 | memset(¶ms, 0, sizeof(params)); |
5648 | 5662 | ||
@@ -5651,15 +5665,16 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5651 | return -EINVAL; | 5665 | return -EINVAL; |
5652 | 5666 | ||
5653 | /* only important for AP, IBSS and mesh create IEs internally */ | 5667 | /* only important for AP, IBSS and mesh create IEs internally */ |
5654 | if (!info->attrs[NL80211_ATTR_CSA_IES]) | 5668 | if (need_new_beacon && |
5655 | return -EINVAL; | 5669 | (!info->attrs[NL80211_ATTR_CSA_IES] || |
5656 | 5670 | !info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON])) | |
5657 | /* useless if AP is not running */ | ||
5658 | if (!wdev->beacon_interval) | ||
5659 | return -EINVAL; | 5671 | return -EINVAL; |
5660 | 5672 | ||
5661 | params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); | 5673 | params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); |
5662 | 5674 | ||
5675 | if (!need_new_beacon) | ||
5676 | goto skip_beacons; | ||
5677 | |||
5663 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); | 5678 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); |
5664 | if (err) | 5679 | if (err) |
5665 | return err; | 5680 | return err; |
@@ -5699,6 +5714,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5699 | return -EINVAL; | 5714 | return -EINVAL; |
5700 | } | 5715 | } |
5701 | 5716 | ||
5717 | skip_beacons: | ||
5702 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); | 5718 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); |
5703 | if (err) | 5719 | if (err) |
5704 | return err; | 5720 | return err; |
@@ -5706,12 +5722,17 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5706 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | 5722 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) |
5707 | return -EINVAL; | 5723 | return -EINVAL; |
5708 | 5724 | ||
5709 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | 5725 | /* DFS channels are only supported for AP/P2P GO ... for now. */ |
5710 | if (err < 0) { | 5726 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || |
5711 | return err; | 5727 | dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { |
5712 | } else if (err) { | 5728 | err = cfg80211_chandef_dfs_required(wdev->wiphy, |
5713 | radar_detect_width = BIT(params.chandef.width); | 5729 | ¶ms.chandef); |
5714 | params.radar_required = true; | 5730 | if (err < 0) { |
5731 | return err; | ||
5732 | } else if (err) { | ||
5733 | radar_detect_width = BIT(params.chandef.width); | ||
5734 | params.radar_required = true; | ||
5735 | } | ||
5715 | } | 5736 | } |
5716 | 5737 | ||
5717 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | 5738 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
@@ -10740,7 +10761,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
10740 | wdev_lock(wdev); | 10761 | wdev_lock(wdev); |
10741 | 10762 | ||
10742 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | 10763 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && |
10743 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | 10764 | wdev->iftype != NL80211_IFTYPE_P2P_GO && |
10765 | wdev->iftype != NL80211_IFTYPE_ADHOC)) | ||
10744 | goto out; | 10766 | goto out; |
10745 | 10767 | ||
10746 | wdev->channel = chandef->chan; | 10768 | wdev->channel = chandef->chan; |