aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c34
-rw-r--r--net/wireless/util.c5
2 files changed, 38 insertions, 1 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6634188f9453..b7b0f67b0c61 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -968,6 +968,28 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
968 return 0; 968 return 0;
969} 969}
970 970
971static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
972 u8 use_4addr, enum nl80211_iftype iftype)
973{
974 if (!use_4addr)
975 return 0;
976
977 switch (iftype) {
978 case NL80211_IFTYPE_AP_VLAN:
979 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
980 return 0;
981 break;
982 case NL80211_IFTYPE_STATION:
983 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
984 return 0;
985 break;
986 default:
987 break;
988 }
989
990 return -EOPNOTSUPP;
991}
992
971static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 993static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
972{ 994{
973 struct cfg80211_registered_device *rdev; 995 struct cfg80211_registered_device *rdev;
@@ -1011,6 +1033,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1011 if (info->attrs[NL80211_ATTR_4ADDR]) { 1033 if (info->attrs[NL80211_ATTR_4ADDR]) {
1012 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1034 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1013 change = true; 1035 change = true;
1036 err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
1037 if (err)
1038 goto unlock;
1014 } else { 1039 } else {
1015 params.use_4addr = -1; 1040 params.use_4addr = -1;
1016 } 1041 }
@@ -1034,6 +1059,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1034 else 1059 else
1035 err = 0; 1060 err = 0;
1036 1061
1062 if (!err && params.use_4addr != -1)
1063 dev->ieee80211_ptr->use_4addr = params.use_4addr;
1064
1037 unlock: 1065 unlock:
1038 dev_put(dev); 1066 dev_put(dev);
1039 cfg80211_unlock_rdev(rdev); 1067 cfg80211_unlock_rdev(rdev);
@@ -1081,8 +1109,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1081 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1109 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1082 } 1110 }
1083 1111
1084 if (info->attrs[NL80211_ATTR_4ADDR]) 1112 if (info->attrs[NL80211_ATTR_4ADDR]) {
1085 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1113 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1114 err = nl80211_valid_4addr(rdev, params.use_4addr, type);
1115 if (err)
1116 goto unlock;
1117 }
1086 1118
1087 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 1119 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
1088 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 1120 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 5aa39f7cf9b9..17a7a4cfc617 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -659,6 +659,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
659 return -EOPNOTSUPP; 659 return -EOPNOTSUPP;
660 660
661 if (ntype != otype) { 661 if (ntype != otype) {
662 dev->ieee80211_ptr->use_4addr = false;
663
662 switch (otype) { 664 switch (otype) {
663 case NL80211_IFTYPE_ADHOC: 665 case NL80211_IFTYPE_ADHOC:
664 cfg80211_leave_ibss(rdev, dev, false); 666 cfg80211_leave_ibss(rdev, dev, false);
@@ -682,5 +684,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
682 684
683 WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); 685 WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
684 686
687 if (!err && params && params->use_4addr != -1)
688 dev->ieee80211_ptr->use_4addr = params->use_4addr;
689
685 return err; 690 return err;
686} 691}