Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfg80211: introduce capability for 4addr mode

It's very likely that not many devices will support
four-address mode in station or AP mode so introduce
capability bits for both modes, set them in mac80211
and check them when userspace tries to use the mode.
Also, keep track of 4addr in cfg80211 (wireless_dev)
and not in mac80211 any more. mac80211 can also be
improved for the VLAN case by not looking at the
4addr flag but maintaining the station pointer for
it correctly. However, keep track of use_4addr for
station mode in mac80211 to avoid all the derefs.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Johannes Berg and committed by
John W. Linville
9bc383de 5be83de5

+82 -30
+11
include/net/cfg80211.h
··· 1134 1134 * by default -- this flag will be set depending on the kernel's default 1135 1135 * on wiphy_new(), but can be changed by the driver if it has a good 1136 1136 * reason to override the default 1137 + * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station 1138 + * on a VLAN interface) 1139 + * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station 1137 1140 */ 1138 1141 enum wiphy_flags { 1139 1142 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), ··· 1144 1141 WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), 1145 1142 WIPHY_FLAG_NETNS_OK = BIT(3), 1146 1143 WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), 1144 + WIPHY_FLAG_4ADDR_AP = BIT(5), 1145 + WIPHY_FLAG_4ADDR_STATION = BIT(6), 1147 1146 }; 1148 1147 1149 1148 /** ··· 1371 1366 * @ssid_len: (private) Used by the internal configuration code 1372 1367 * @wext: (private) Used by the internal wireless extensions compat code 1373 1368 * @wext_bssid: (private) Used by the internal wireless extensions compat code 1369 + * @use_4addr: indicates 4addr mode is used on this interface, must be 1370 + * set by driver (if supported) on add_interface BEFORE registering the 1371 + * netdev and may otherwise be used by driver read-only, will be update 1372 + * by cfg80211 on change_interface 1374 1373 */ 1375 1374 struct wireless_dev { 1376 1375 struct wiphy *wiphy; ··· 1387 1378 struct mutex mtx; 1388 1379 1389 1380 struct work_struct cleanup_work; 1381 + 1382 + bool use_4addr; 1390 1383 1391 1384 /* currently used for IBSS and SME - might be rearranged later */ 1392 1385 u8 ssid[IEEE80211_MAX_SSID_LEN];
+8 -13
net/mac80211/cfg.c
··· 42 42 if (!nl80211_type_check(type)) 43 43 return false; 44 44 45 - if (params->use_4addr > 0) { 46 - switch(type) { 47 - case NL80211_IFTYPE_AP_VLAN: 48 - case NL80211_IFTYPE_STATION: 49 - break; 50 - default: 51 - return false; 52 - } 53 - } 54 45 return true; 55 46 } 56 47 ··· 98 107 params->mesh_id_len, 99 108 params->mesh_id); 100 109 101 - if (params->use_4addr >= 0) 102 - sdata->use_4addr = !!params->use_4addr; 103 - 104 110 if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) 105 111 return 0; 112 + 113 + if (type == NL80211_IFTYPE_AP_VLAN && 114 + params && params->use_4addr == 0) 115 + rcu_assign_pointer(sdata->u.vlan.sta, NULL); 116 + else if (type == NL80211_IFTYPE_STATION && 117 + params && params->use_4addr >= 0) 118 + sdata->u.mgd.use_4addr = params->use_4addr; 106 119 107 120 sdata->u.mntr_flags = *flags; 108 121 return 0; ··· 822 827 return -EINVAL; 823 828 } 824 829 825 - if (vlansdata->use_4addr) { 830 + if (params->vlan->ieee80211_ptr->use_4addr) { 826 831 if (vlansdata->u.vlan.sta) 827 832 return -EBUSY; 828 833
+2 -2
net/mac80211/ieee80211_i.h
··· 312 312 } mfp; /* management frame protection */ 313 313 314 314 int wmm_last_param_set; 315 + 316 + u8 use_4addr; 315 317 }; 316 318 317 319 enum ieee80211_ibss_request { ··· 460 458 461 459 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ 462 460 int max_ratectrl_rateidx; /* max TX rateidx for rate control */ 463 - 464 - bool use_4addr; /* use 4-address frames */ 465 461 466 462 union { 467 463 struct ieee80211_if_ap ap;
+8 -4
net/mac80211/iface.c
··· 752 752 ieee80211_mandatory_rates(sdata->local, 753 753 sdata->local->hw.conf.channel->band); 754 754 sdata->drop_unencrypted = 0; 755 - sdata->use_4addr = 0; 755 + if (type == NL80211_IFTYPE_STATION) 756 + sdata->u.mgd.use_4addr = false; 756 757 757 758 return 0; 758 759 } ··· 811 810 /* setup type-dependent data */ 812 811 ieee80211_setup_sdata(sdata, type); 813 812 813 + if (params) { 814 + ndev->ieee80211_ptr->use_4addr = params->use_4addr; 815 + if (type == NL80211_IFTYPE_STATION) 816 + sdata->u.mgd.use_4addr = params->use_4addr; 817 + } 818 + 814 819 ret = register_netdevice(ndev); 815 820 if (ret) 816 821 goto fail; ··· 826 819 ieee80211_sdata_set_mesh_id(sdata, 827 820 params->mesh_id_len, 828 821 params->mesh_id); 829 - 830 - if (params && params->use_4addr >= 0) 831 - sdata->use_4addr = !!params->use_4addr; 832 822 833 823 mutex_lock(&local->iflist_mtx); 834 824 list_add_tail_rcu(&sdata->list, &local->interfaces);
+3 -1
net/mac80211/main.c
··· 328 328 if (!wiphy) 329 329 return NULL; 330 330 331 - wiphy->flags |= WIPHY_FLAG_NETNS_OK; 331 + wiphy->flags |= WIPHY_FLAG_NETNS_OK | 332 + WIPHY_FLAG_4ADDR_AP | 333 + WIPHY_FLAG_4ADDR_STATION; 332 334 wiphy->privid = mac80211_wiphy_privid; 333 335 334 336 /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
+9 -5
net/mac80211/rx.c
··· 1192 1192 struct net_device *dev = sdata->dev; 1193 1193 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 1194 1194 1195 - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && 1196 - ieee80211_has_a4(hdr->frame_control)) 1195 + if (ieee80211_has_a4(hdr->frame_control) && 1196 + sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) 1197 1197 return -1; 1198 - if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1)) 1198 + 1199 + if (is_multicast_ether_addr(hdr->addr1) && 1200 + ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) || 1201 + (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr))) 1199 1202 return -1; 1200 1203 1201 1204 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); ··· 1248 1245 if ((sdata->vif.type == NL80211_IFTYPE_AP || 1249 1246 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && 1250 1247 !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && 1251 - (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) { 1248 + (rx->flags & IEEE80211_RX_RA_MATCH) && 1249 + (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { 1252 1250 if (is_multicast_ether_addr(ehdr->h_dest)) { 1253 1251 /* 1254 1252 * send multicast frames both to higher layers in ··· 2011 2007 2012 2008 switch (sdata->vif.type) { 2013 2009 case NL80211_IFTYPE_STATION: 2014 - if (!bssid && !sdata->use_4addr) 2010 + if (!bssid && !sdata->u.mgd.use_4addr) 2015 2011 return 0; 2016 2012 if (!multicast && 2017 2013 compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
+3 -4
net/mac80211/tx.c
··· 1051 1051 1052 1052 hdr = (struct ieee80211_hdr *) skb->data; 1053 1053 1054 - if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr) 1054 + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1055 1055 tx->sta = rcu_dereference(sdata->u.vlan.sta); 1056 1056 if (!tx->sta) 1057 1057 tx->sta = sta_info_get(local, hdr->addr1); ··· 1632 1632 switch (sdata->vif.type) { 1633 1633 case NL80211_IFTYPE_AP_VLAN: 1634 1634 rcu_read_lock(); 1635 - if (sdata->use_4addr) 1636 - sta = rcu_dereference(sdata->u.vlan.sta); 1635 + sta = rcu_dereference(sdata->u.vlan.sta); 1637 1636 if (sta) { 1638 1637 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); 1639 1638 /* RA TA DA SA */ ··· 1726 1727 #endif 1727 1728 case NL80211_IFTYPE_STATION: 1728 1729 memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); 1729 - if (sdata->use_4addr && ethertype != ETH_P_PAE) { 1730 + if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { 1730 1731 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); 1731 1732 /* RA TA DA SA */ 1732 1733 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+33 -1
net/wireless/nl80211.c
··· 968 968 return 0; 969 969 } 970 970 971 + static 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 + 971 993 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 972 994 { 973 995 struct cfg80211_registered_device *rdev; ··· 1033 1011 if (info->attrs[NL80211_ATTR_4ADDR]) { 1034 1012 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1035 1013 change = true; 1014 + err = nl80211_valid_4addr(rdev, params.use_4addr, ntype); 1015 + if (err) 1016 + goto unlock; 1036 1017 } else { 1037 1018 params.use_4addr = -1; 1038 1019 } ··· 1058 1033 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params); 1059 1034 else 1060 1035 err = 0; 1036 + 1037 + if (!err && params.use_4addr != -1) 1038 + dev->ieee80211_ptr->use_4addr = params.use_4addr; 1061 1039 1062 1040 unlock: 1063 1041 dev_put(dev); ··· 1109 1081 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1110 1082 } 1111 1083 1112 - if (info->attrs[NL80211_ATTR_4ADDR]) 1084 + if (info->attrs[NL80211_ATTR_4ADDR]) { 1113 1085 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1086 + err = nl80211_valid_4addr(rdev, params.use_4addr, type); 1087 + if (err) 1088 + goto unlock; 1089 + } 1114 1090 1115 1091 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 1116 1092 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+5
net/wireless/util.c
··· 659 659 return -EOPNOTSUPP; 660 660 661 661 if (ntype != otype) { 662 + dev->ieee80211_ptr->use_4addr = false; 663 + 662 664 switch (otype) { 663 665 case NL80211_IFTYPE_ADHOC: 664 666 cfg80211_leave_ibss(rdev, dev, false); ··· 683 681 ntype, flags, params); 684 682 685 683 WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); 684 + 685 + if (!err && params && params->use_4addr != -1) 686 + dev->ieee80211_ptr->use_4addr = params->use_4addr; 686 687 687 688 return err; 688 689 }