aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c171
1 files changed, 132 insertions, 39 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c27bef8e0c11..ec1b4a896c6e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -588,6 +588,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
588 i++; 588 i++;
589 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 589 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
590 } 590 }
591 CMD(set_channel, SET_CHANNEL);
591 592
592#undef CMD 593#undef CMD
593 594
@@ -688,10 +689,90 @@ static int parse_txq_params(struct nlattr *tb[],
688 return 0; 689 return 0;
689} 690}
690 691
692static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
693{
694 /*
695 * You can only set the channel explicitly for AP, mesh
696 * and WDS type interfaces; all others have their channel
697 * managed via their respective "establish a connection"
698 * command (connect, join, ...)
699 *
700 * Monitors are special as they are normally slaved to
701 * whatever else is going on, so they behave as though
702 * you tried setting the wiphy channel itself.
703 */
704 return !wdev ||
705 wdev->iftype == NL80211_IFTYPE_AP ||
706 wdev->iftype == NL80211_IFTYPE_WDS ||
707 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
708 wdev->iftype == NL80211_IFTYPE_MONITOR;
709}
710
711static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
712 struct wireless_dev *wdev,
713 struct genl_info *info)
714{
715 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
716 u32 freq;
717 int result;
718
719 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
720 return -EINVAL;
721
722 if (!nl80211_can_set_dev_channel(wdev))
723 return -EOPNOTSUPP;
724
725 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
726 channel_type = nla_get_u32(info->attrs[
727 NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
728 if (channel_type != NL80211_CHAN_NO_HT &&
729 channel_type != NL80211_CHAN_HT20 &&
730 channel_type != NL80211_CHAN_HT40PLUS &&
731 channel_type != NL80211_CHAN_HT40MINUS)
732 return -EINVAL;
733 }
734
735 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
736
737 mutex_lock(&rdev->devlist_mtx);
738 if (wdev) {
739 wdev_lock(wdev);
740 result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
741 wdev_unlock(wdev);
742 } else {
743 result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
744 }
745 mutex_unlock(&rdev->devlist_mtx);
746
747 return result;
748}
749
750static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
751{
752 struct cfg80211_registered_device *rdev;
753 struct net_device *netdev;
754 int result;
755
756 rtnl_lock();
757
758 result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
759 if (result)
760 goto unlock;
761
762 result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
763
764 unlock:
765 rtnl_unlock();
766
767 return result;
768}
769
691static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) 770static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
692{ 771{
693 struct cfg80211_registered_device *rdev; 772 struct cfg80211_registered_device *rdev;
694 int result = 0, rem_txq_params = 0; 773 struct net_device *netdev = NULL;
774 struct wireless_dev *wdev;
775 int result, rem_txq_params = 0;
695 struct nlattr *nl_txq_params; 776 struct nlattr *nl_txq_params;
696 u32 changed; 777 u32 changed;
697 u8 retry_short = 0, retry_long = 0; 778 u8 retry_short = 0, retry_long = 0;
@@ -700,16 +781,50 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
700 781
701 rtnl_lock(); 782 rtnl_lock();
702 783
784 /*
785 * Try to find the wiphy and netdev. Normally this
786 * function shouldn't need the netdev, but this is
787 * done for backward compatibility -- previously
788 * setting the channel was done per wiphy, but now
789 * it is per netdev. Previous userland like hostapd
790 * also passed a netdev to set_wiphy, so that it is
791 * possible to let that go to the right netdev!
792 */
703 mutex_lock(&cfg80211_mutex); 793 mutex_lock(&cfg80211_mutex);
704 794
705 rdev = __cfg80211_rdev_from_info(info); 795 if (info->attrs[NL80211_ATTR_IFINDEX]) {
706 if (IS_ERR(rdev)) { 796 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
707 mutex_unlock(&cfg80211_mutex); 797
708 result = PTR_ERR(rdev); 798 netdev = dev_get_by_index(genl_info_net(info), ifindex);
709 goto unlock; 799 if (netdev && netdev->ieee80211_ptr) {
800 rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
801 mutex_lock(&rdev->mtx);
802 } else
803 netdev = NULL;
710 } 804 }
711 805
712 mutex_lock(&rdev->mtx); 806 if (!netdev) {
807 rdev = __cfg80211_rdev_from_info(info);
808 if (IS_ERR(rdev)) {
809 mutex_unlock(&cfg80211_mutex);
810 result = PTR_ERR(rdev);
811 goto unlock;
812 }
813 wdev = NULL;
814 netdev = NULL;
815 result = 0;
816
817 mutex_lock(&rdev->mtx);
818 } else if (netif_running(netdev) &&
819 nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
820 wdev = netdev->ieee80211_ptr;
821 else
822 wdev = NULL;
823
824 /*
825 * end workaround code, by now the rdev is available
826 * and locked, and wdev may or may not be NULL.
827 */
713 828
714 if (info->attrs[NL80211_ATTR_WIPHY_NAME]) 829 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
715 result = cfg80211_dev_rename( 830 result = cfg80211_dev_rename(
@@ -748,26 +863,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
748 } 863 }
749 864
750 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 865 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
751 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 866 result = __nl80211_set_channel(rdev, wdev, info);
752 u32 freq;
753
754 result = -EINVAL;
755
756 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
757 channel_type = nla_get_u32(info->attrs[
758 NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
759 if (channel_type != NL80211_CHAN_NO_HT &&
760 channel_type != NL80211_CHAN_HT20 &&
761 channel_type != NL80211_CHAN_HT40PLUS &&
762 channel_type != NL80211_CHAN_HT40MINUS)
763 goto bad_res;
764 }
765
766 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
767
768 mutex_lock(&rdev->devlist_mtx);
769 result = rdev_set_freq(rdev, NULL, freq, channel_type);
770 mutex_unlock(&rdev->devlist_mtx);
771 if (result) 867 if (result)
772 goto bad_res; 868 goto bad_res;
773 } 869 }
@@ -864,6 +960,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
864 960
865 bad_res: 961 bad_res:
866 mutex_unlock(&rdev->mtx); 962 mutex_unlock(&rdev->mtx);
963 if (netdev)
964 dev_put(netdev);
867 unlock: 965 unlock:
868 rtnl_unlock(); 966 rtnl_unlock();
869 return result; 967 return result;
@@ -3561,9 +3659,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3561{ 3659{
3562 struct cfg80211_registered_device *rdev; 3660 struct cfg80211_registered_device *rdev;
3563 struct net_device *dev; 3661 struct net_device *dev;
3564 struct wireless_dev *wdev;
3565 struct cfg80211_crypto_settings crypto; 3662 struct cfg80211_crypto_settings crypto;
3566 struct ieee80211_channel *chan, *fixedchan; 3663 struct ieee80211_channel *chan;
3567 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; 3664 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
3568 int err, ssid_len, ie_len = 0; 3665 int err, ssid_len, ie_len = 0;
3569 bool use_mfp = false; 3666 bool use_mfp = false;
@@ -3606,16 +3703,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3606 goto out; 3703 goto out;
3607 } 3704 }
3608 3705
3609 mutex_lock(&rdev->devlist_mtx);
3610 wdev = dev->ieee80211_ptr;
3611 fixedchan = rdev_fixed_channel(rdev, wdev);
3612 if (fixedchan && chan != fixedchan) {
3613 err = -EBUSY;
3614 mutex_unlock(&rdev->devlist_mtx);
3615 goto out;
3616 }
3617 mutex_unlock(&rdev->devlist_mtx);
3618
3619 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3706 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3620 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3707 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3621 3708
@@ -5185,6 +5272,12 @@ static struct genl_ops nl80211_ops[] = {
5185 .policy = nl80211_policy, 5272 .policy = nl80211_policy,
5186 .flags = GENL_ADMIN_PERM, 5273 .flags = GENL_ADMIN_PERM,
5187 }, 5274 },
5275 {
5276 .cmd = NL80211_CMD_SET_CHANNEL,
5277 .doit = nl80211_set_channel,
5278 .policy = nl80211_policy,
5279 .flags = GENL_ADMIN_PERM,
5280 },
5188}; 5281};
5189 5282
5190static struct genl_multicast_group nl80211_mlme_mcgrp = { 5283static struct genl_multicast_group nl80211_mlme_mcgrp = {