aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-19 05:55:19 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-19 11:08:53 -0500
commit9bc383de37090ba7ca3ff32a12c9d809dc5867f0 (patch)
tree2b502b918f585427b45357e5a9a781ea9f06c263
parent5be83de54c16944dea9c16c6a5a53c1fa75ed304 (diff)
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>
-rw-r--r--include/net/cfg80211.h11
-rw-r--r--net/mac80211/cfg.c21
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/iface.c12
-rw-r--r--net/mac80211/main.c4
-rw-r--r--net/mac80211/rx.c14
-rw-r--r--net/mac80211/tx.c7
-rw-r--r--net/wireless/nl80211.c34
-rw-r--r--net/wireless/util.c5
9 files changed, 82 insertions, 30 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index eca36abca8f5..d1e05aeb0c09 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1134,6 +1134,9 @@ struct cfg80211_ops {
1134 * by default -- this flag will be set depending on the kernel's default 1134 * by default -- this flag will be set depending on the kernel's default
1135 * on wiphy_new(), but can be changed by the driver if it has a good 1135 * on wiphy_new(), but can be changed by the driver if it has a good
1136 * reason to override the default 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 */
1138enum wiphy_flags { 1141enum wiphy_flags {
1139 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), 1142 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1141,6 +1144,8 @@ enum wiphy_flags {
1141 WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), 1144 WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
1142 WIPHY_FLAG_NETNS_OK = BIT(3), 1145 WIPHY_FLAG_NETNS_OK = BIT(3),
1143 WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), 1146 WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
1147 WIPHY_FLAG_4ADDR_AP = BIT(5),
1148 WIPHY_FLAG_4ADDR_STATION = BIT(6),
1144}; 1149};
1145 1150
1146/** 1151/**
@@ -1366,6 +1371,10 @@ struct cfg80211_cached_keys;
1366 * @ssid_len: (private) Used by the internal configuration code 1371 * @ssid_len: (private) Used by the internal configuration code
1367 * @wext: (private) Used by the internal wireless extensions compat code 1372 * @wext: (private) Used by the internal wireless extensions compat code
1368 * @wext_bssid: (private) Used by the internal wireless extensions compat code 1373 * @wext_bssid: (private) Used by the internal wireless extensions compat code
1374 * @use_4addr: indicates 4addr mode is used on this interface, must be
1375 * set by driver (if supported) on add_interface BEFORE registering the
1376 * netdev and may otherwise be used by driver read-only, will be update
1377 * by cfg80211 on change_interface
1369 */ 1378 */
1370struct wireless_dev { 1379struct wireless_dev {
1371 struct wiphy *wiphy; 1380 struct wiphy *wiphy;
@@ -1379,6 +1388,8 @@ struct wireless_dev {
1379 1388
1380 struct work_struct cleanup_work; 1389 struct work_struct cleanup_work;
1381 1390
1391 bool use_4addr;
1392
1382 /* currently used for IBSS and SME - might be rearranged later */ 1393 /* currently used for IBSS and SME - might be rearranged later */
1383 u8 ssid[IEEE80211_MAX_SSID_LEN]; 1394 u8 ssid[IEEE80211_MAX_SSID_LEN];
1384 u8 ssid_len; 1395 u8 ssid_len;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7d591816ed10..c484a882140e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl80211_iftype type,
42 if (!nl80211_type_check(type)) 42 if (!nl80211_type_check(type))
43 return false; 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 return true; 45 return true;
55} 46}
56 47
@@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
107 params->mesh_id_len, 98 params->mesh_id_len,
108 params->mesh_id); 99 params->mesh_id);
109 100
110 if (params->use_4addr >= 0)
111 sdata->use_4addr = !!params->use_4addr;
112
113 if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) 101 if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
114 return 0; 102 return 0;
115 103
104 if (type == NL80211_IFTYPE_AP_VLAN &&
105 params && params->use_4addr == 0)
106 rcu_assign_pointer(sdata->u.vlan.sta, NULL);
107 else if (type == NL80211_IFTYPE_STATION &&
108 params && params->use_4addr >= 0)
109 sdata->u.mgd.use_4addr = params->use_4addr;
110
116 sdata->u.mntr_flags = *flags; 111 sdata->u.mntr_flags = *flags;
117 return 0; 112 return 0;
118} 113}
@@ -827,7 +822,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
827 return -EINVAL; 822 return -EINVAL;
828 } 823 }
829 824
830 if (vlansdata->use_4addr) { 825 if (params->vlan->ieee80211_ptr->use_4addr) {
831 if (vlansdata->u.vlan.sta) 826 if (vlansdata->u.vlan.sta)
832 return -EBUSY; 827 return -EBUSY;
833 828
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 87d27f450a05..f13d76c9b575 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -312,6 +312,8 @@ struct ieee80211_if_managed {
312 } mfp; /* management frame protection */ 312 } mfp; /* management frame protection */
313 313
314 int wmm_last_param_set; 314 int wmm_last_param_set;
315
316 u8 use_4addr;
315}; 317};
316 318
317enum ieee80211_ibss_request { 319enum ieee80211_ibss_request {
@@ -459,8 +461,6 @@ struct ieee80211_sub_if_data {
459 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ 461 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
460 int max_ratectrl_rateidx; /* max TX rateidx for rate control */ 462 int max_ratectrl_rateidx; /* max TX rateidx for rate control */
461 463
462 bool use_4addr; /* use 4-address frames */
463
464 union { 464 union {
465 struct ieee80211_if_ap ap; 465 struct ieee80211_if_ap ap;
466 struct ieee80211_if_wds wds; 466 struct ieee80211_if_wds wds;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1f02b0610e82..1bf12a26b45e 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
752 ieee80211_mandatory_rates(sdata->local, 752 ieee80211_mandatory_rates(sdata->local,
753 sdata->local->hw.conf.channel->band); 753 sdata->local->hw.conf.channel->band);
754 sdata->drop_unencrypted = 0; 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 return 0; 758 return 0;
758} 759}
@@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
810 /* setup type-dependent data */ 811 /* setup type-dependent data */
811 ieee80211_setup_sdata(sdata, type); 812 ieee80211_setup_sdata(sdata, type);
812 813
814 if (params) {
815 ndev->ieee80211_ptr->use_4addr = params->use_4addr;
816 if (type == NL80211_IFTYPE_STATION)
817 sdata->u.mgd.use_4addr = params->use_4addr;
818 }
819
813 ret = register_netdevice(ndev); 820 ret = register_netdevice(ndev);
814 if (ret) 821 if (ret)
815 goto fail; 822 goto fail;
@@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
820 params->mesh_id_len, 827 params->mesh_id_len,
821 params->mesh_id); 828 params->mesh_id);
822 829
823 if (params && params->use_4addr >= 0)
824 sdata->use_4addr = !!params->use_4addr;
825
826 mutex_lock(&local->iflist_mtx); 830 mutex_lock(&local->iflist_mtx);
827 list_add_tail_rcu(&sdata->list, &local->interfaces); 831 list_add_tail_rcu(&sdata->list, &local->interfaces);
828 mutex_unlock(&local->iflist_mtx); 832 mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8084b622e97e..dd8ec8d5e8b2 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -328,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
328 if (!wiphy) 328 if (!wiphy)
329 return NULL; 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 wiphy->privid = mac80211_wiphy_privid; 334 wiphy->privid = mac80211_wiphy_privid;
333 335
334 /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ 336 /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 775365f856c9..96f13ad05d3c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1192,10 +1192,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
1192 struct net_device *dev = sdata->dev; 1192 struct net_device *dev = sdata->dev;
1193 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 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 && 1195 if (ieee80211_has_a4(hdr->frame_control) &&
1196 ieee80211_has_a4(hdr->frame_control)) 1196 sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
1197 return -1; 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 return -1; 1202 return -1;
1200 1203
1201 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); 1204 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
@@ -1245,7 +1248,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
1245 if ((sdata->vif.type == NL80211_IFTYPE_AP || 1248 if ((sdata->vif.type == NL80211_IFTYPE_AP ||
1246 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && 1249 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
1247 !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && 1250 !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
1248 (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) { 1251 (rx->flags & IEEE80211_RX_RA_MATCH) &&
1252 (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
1249 if (is_multicast_ether_addr(ehdr->h_dest)) { 1253 if (is_multicast_ether_addr(ehdr->h_dest)) {
1250 /* 1254 /*
1251 * send multicast frames both to higher layers in 1255 * send multicast frames both to higher layers in
@@ -2007,7 +2011,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
2007 2011
2008 switch (sdata->vif.type) { 2012 switch (sdata->vif.type) {
2009 case NL80211_IFTYPE_STATION: 2013 case NL80211_IFTYPE_STATION:
2010 if (!bssid && !sdata->use_4addr) 2014 if (!bssid && !sdata->u.mgd.use_4addr)
2011 return 0; 2015 return 0;
2012 if (!multicast && 2016 if (!multicast &&
2013 compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { 2017 compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index b3c1faeb5927..5af2f40ea4db 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
1051 1051
1052 hdr = (struct ieee80211_hdr *) skb->data; 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 tx->sta = rcu_dereference(sdata->u.vlan.sta); 1055 tx->sta = rcu_dereference(sdata->u.vlan.sta);
1056 if (!tx->sta) 1056 if (!tx->sta)
1057 tx->sta = sta_info_get(local, hdr->addr1); 1057 tx->sta = sta_info_get(local, hdr->addr1);
@@ -1632,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1632 switch (sdata->vif.type) { 1632 switch (sdata->vif.type) {
1633 case NL80211_IFTYPE_AP_VLAN: 1633 case NL80211_IFTYPE_AP_VLAN:
1634 rcu_read_lock(); 1634 rcu_read_lock();
1635 if (sdata->use_4addr) 1635 sta = rcu_dereference(sdata->u.vlan.sta);
1636 sta = rcu_dereference(sdata->u.vlan.sta);
1637 if (sta) { 1636 if (sta) {
1638 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); 1637 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
1639 /* RA TA DA SA */ 1638 /* RA TA DA SA */
@@ -1727,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1727#endif 1726#endif
1728 case NL80211_IFTYPE_STATION: 1727 case NL80211_IFTYPE_STATION:
1729 memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); 1728 memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
1730 if (sdata->use_4addr && ethertype != ETH_P_PAE) { 1729 if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
1731 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); 1730 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
1732 /* RA TA DA SA */ 1731 /* RA TA DA SA */
1733 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); 1732 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
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}