diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 93 |
1 files changed, 90 insertions, 3 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index db71150b8040..37902a54e9c1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -153,6 +153,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
153 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, | 153 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, |
154 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, | 154 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, |
155 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, | 155 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, |
156 | |||
157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | ||
158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | ||
156 | }; | 159 | }; |
157 | 160 | ||
158 | /* policy for the attributes */ | 161 | /* policy for the attributes */ |
@@ -869,6 +872,34 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
869 | goto bad_res; | 872 | goto bad_res; |
870 | } | 873 | } |
871 | 874 | ||
875 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { | ||
876 | enum nl80211_tx_power_setting type; | ||
877 | int idx, mbm = 0; | ||
878 | |||
879 | if (!rdev->ops->set_tx_power) { | ||
880 | result = -EOPNOTSUPP; | ||
881 | goto bad_res; | ||
882 | } | ||
883 | |||
884 | idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING; | ||
885 | type = nla_get_u32(info->attrs[idx]); | ||
886 | |||
887 | if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] && | ||
888 | (type != NL80211_TX_POWER_AUTOMATIC)) { | ||
889 | result = -EINVAL; | ||
890 | goto bad_res; | ||
891 | } | ||
892 | |||
893 | if (type != NL80211_TX_POWER_AUTOMATIC) { | ||
894 | idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL; | ||
895 | mbm = nla_get_u32(info->attrs[idx]); | ||
896 | } | ||
897 | |||
898 | result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); | ||
899 | if (result) | ||
900 | goto bad_res; | ||
901 | } | ||
902 | |||
872 | changed = 0; | 903 | changed = 0; |
873 | 904 | ||
874 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | 905 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { |
@@ -1107,7 +1138,7 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | |||
1107 | enum nl80211_iftype iftype) | 1138 | enum nl80211_iftype iftype) |
1108 | { | 1139 | { |
1109 | if (!use_4addr) { | 1140 | if (!use_4addr) { |
1110 | if (netdev && netdev->br_port) | 1141 | if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT)) |
1111 | return -EBUSY; | 1142 | return -EBUSY; |
1112 | return 0; | 1143 | return 0; |
1113 | } | 1144 | } |
@@ -2738,6 +2769,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2738 | 2769 | ||
2739 | nla_put_failure: | 2770 | nla_put_failure: |
2740 | genlmsg_cancel(msg, hdr); | 2771 | genlmsg_cancel(msg, hdr); |
2772 | nlmsg_free(msg); | ||
2741 | err = -EMSGSIZE; | 2773 | err = -EMSGSIZE; |
2742 | out: | 2774 | out: |
2743 | /* Cleanup */ | 2775 | /* Cleanup */ |
@@ -2929,6 +2961,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
2929 | 2961 | ||
2930 | nla_put_failure: | 2962 | nla_put_failure: |
2931 | genlmsg_cancel(msg, hdr); | 2963 | genlmsg_cancel(msg, hdr); |
2964 | nlmsg_free(msg); | ||
2932 | err = -EMSGSIZE; | 2965 | err = -EMSGSIZE; |
2933 | out: | 2966 | out: |
2934 | mutex_unlock(&cfg80211_mutex); | 2967 | mutex_unlock(&cfg80211_mutex); |
@@ -3955,6 +3988,55 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3955 | } | 3988 | } |
3956 | } | 3989 | } |
3957 | 3990 | ||
3991 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | ||
3992 | u8 *rates = | ||
3993 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
3994 | int n_rates = | ||
3995 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
3996 | struct ieee80211_supported_band *sband = | ||
3997 | wiphy->bands[ibss.channel->band]; | ||
3998 | int i, j; | ||
3999 | |||
4000 | if (n_rates == 0) { | ||
4001 | err = -EINVAL; | ||
4002 | goto out; | ||
4003 | } | ||
4004 | |||
4005 | for (i = 0; i < n_rates; i++) { | ||
4006 | int rate = (rates[i] & 0x7f) * 5; | ||
4007 | bool found = false; | ||
4008 | |||
4009 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4010 | if (sband->bitrates[j].bitrate == rate) { | ||
4011 | found = true; | ||
4012 | ibss.basic_rates |= BIT(j); | ||
4013 | break; | ||
4014 | } | ||
4015 | } | ||
4016 | if (!found) { | ||
4017 | err = -EINVAL; | ||
4018 | goto out; | ||
4019 | } | ||
4020 | } | ||
4021 | } else { | ||
4022 | /* | ||
4023 | * If no rates were explicitly configured, | ||
4024 | * use the mandatory rate set for 11b or | ||
4025 | * 11a for maximum compatibility. | ||
4026 | */ | ||
4027 | struct ieee80211_supported_band *sband = | ||
4028 | wiphy->bands[ibss.channel->band]; | ||
4029 | int j; | ||
4030 | u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ? | ||
4031 | IEEE80211_RATE_MANDATORY_A : | ||
4032 | IEEE80211_RATE_MANDATORY_B; | ||
4033 | |||
4034 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4035 | if (sband->bitrates[j].flags & flag) | ||
4036 | ibss.basic_rates |= BIT(j); | ||
4037 | } | ||
4038 | } | ||
4039 | |||
3958 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 4040 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
3959 | 4041 | ||
3960 | out: | 4042 | out: |
@@ -4653,7 +4735,8 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | |||
4653 | if (err) | 4735 | if (err) |
4654 | goto unlock_rtnl; | 4736 | goto unlock_rtnl; |
4655 | 4737 | ||
4656 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4738 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4739 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
4657 | err = -EOPNOTSUPP; | 4740 | err = -EOPNOTSUPP; |
4658 | goto out; | 4741 | goto out; |
4659 | } | 4742 | } |
@@ -4681,6 +4764,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4681 | struct net_device *dev; | 4764 | struct net_device *dev; |
4682 | struct ieee80211_channel *chan; | 4765 | struct ieee80211_channel *chan; |
4683 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 4766 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
4767 | bool channel_type_valid = false; | ||
4684 | u32 freq; | 4768 | u32 freq; |
4685 | int err; | 4769 | int err; |
4686 | void *hdr; | 4770 | void *hdr; |
@@ -4702,7 +4786,8 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4702 | goto out; | 4786 | goto out; |
4703 | } | 4787 | } |
4704 | 4788 | ||
4705 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4789 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4790 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
4706 | err = -EOPNOTSUPP; | 4791 | err = -EOPNOTSUPP; |
4707 | goto out; | 4792 | goto out; |
4708 | } | 4793 | } |
@@ -4722,6 +4807,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4722 | err = -EINVAL; | 4807 | err = -EINVAL; |
4723 | goto out; | 4808 | goto out; |
4724 | } | 4809 | } |
4810 | channel_type_valid = true; | ||
4725 | } | 4811 | } |
4726 | 4812 | ||
4727 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4813 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
@@ -4745,6 +4831,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4745 | goto free_msg; | 4831 | goto free_msg; |
4746 | } | 4832 | } |
4747 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, | 4833 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, |
4834 | channel_type_valid, | ||
4748 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4835 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
4749 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4836 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
4750 | &cookie); | 4837 | &cookie); |