Skip to content

Commit 9bc383d

Browse files
jmberglinvjw
authored andcommitted
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>
1 parent 5be83de commit 9bc383d

File tree

9 files changed

+82
-30
lines changed

9 files changed

+82
-30
lines changed

include/net/cfg80211.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,13 +1134,18 @@ struct cfg80211_ops {
11341134
* by default -- this flag will be set depending on the kernel's default
11351135
* on wiphy_new(), but can be changed by the driver if it has a good
11361136
* 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
11371140
*/
11381141
enum wiphy_flags {
11391142
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
11401143
WIPHY_FLAG_STRICT_REGULATORY = BIT(1),
11411144
WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
11421145
WIPHY_FLAG_NETNS_OK = BIT(3),
11431146
WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
1147+
WIPHY_FLAG_4ADDR_AP = BIT(5),
1148+
WIPHY_FLAG_4ADDR_STATION = BIT(6),
11441149
};
11451150

11461151
/**
@@ -1366,6 +1371,10 @@ struct cfg80211_cached_keys;
13661371
* @ssid_len: (private) Used by the internal configuration code
13671372
* @wext: (private) Used by the internal wireless extensions compat code
13681373
* @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
13691378
*/
13701379
struct wireless_dev {
13711380
struct wiphy *wiphy;
@@ -1379,6 +1388,8 @@ struct wireless_dev {
13791388

13801389
struct work_struct cleanup_work;
13811390

1391+
bool use_4addr;
1392+
13821393
/* currently used for IBSS and SME - might be rearranged later */
13831394
u8 ssid[IEEE80211_MAX_SSID_LEN];
13841395
u8 ssid_len;

net/mac80211/cfg.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl80211_iftype type,
4242
if (!nl80211_type_check(type))
4343
return false;
4444

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-
}
5445
return true;
5546
}
5647

@@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
10798
params->mesh_id_len,
10899
params->mesh_id);
109100

110-
if (params->use_4addr >= 0)
111-
sdata->use_4addr = !!params->use_4addr;
112-
113101
if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
114102
return 0;
115103

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+
116111
sdata->u.mntr_flags = *flags;
117112
return 0;
118113
}
@@ -827,7 +822,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
827822
return -EINVAL;
828823
}
829824

830-
if (vlansdata->use_4addr) {
825+
if (params->vlan->ieee80211_ptr->use_4addr) {
831826
if (vlansdata->u.vlan.sta)
832827
return -EBUSY;
833828

net/mac80211/ieee80211_i.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ struct ieee80211_if_managed {
312312
} mfp; /* management frame protection */
313313

314314
int wmm_last_param_set;
315+
316+
u8 use_4addr;
315317
};
316318

317319
enum ieee80211_ibss_request {
@@ -459,8 +461,6 @@ struct ieee80211_sub_if_data {
459461
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
460462
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
461463

462-
bool use_4addr; /* use 4-address frames */
463-
464464
union {
465465
struct ieee80211_if_ap ap;
466466
struct ieee80211_if_wds wds;

net/mac80211/iface.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
752752
ieee80211_mandatory_rates(sdata->local,
753753
sdata->local->hw.conf.channel->band);
754754
sdata->drop_unencrypted = 0;
755-
sdata->use_4addr = 0;
755+
if (type == NL80211_IFTYPE_STATION)
756+
sdata->u.mgd.use_4addr = false;
756757

757758
return 0;
758759
}
@@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
810811
/* setup type-dependent data */
811812
ieee80211_setup_sdata(sdata, type);
812813

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+
813820
ret = register_netdevice(ndev);
814821
if (ret)
815822
goto fail;
@@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
820827
params->mesh_id_len,
821828
params->mesh_id);
822829

823-
if (params && params->use_4addr >= 0)
824-
sdata->use_4addr = !!params->use_4addr;
825-
826830
mutex_lock(&local->iflist_mtx);
827831
list_add_tail_rcu(&sdata->list, &local->interfaces);
828832
mutex_unlock(&local->iflist_mtx);

net/mac80211/main.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
328328
if (!wiphy)
329329
return NULL;
330330

331-
wiphy->flags |= WIPHY_FLAG_NETNS_OK;
331+
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
332+
WIPHY_FLAG_4ADDR_AP |
333+
WIPHY_FLAG_4ADDR_STATION;
332334
wiphy->privid = mac80211_wiphy_privid;
333335

334336
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */

net/mac80211/rx.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,10 +1192,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
11921192
struct net_device *dev = sdata->dev;
11931193
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
11941194

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)
11971197
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)))
11991202
return -1;
12001203

12011204
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)
12451248
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
12461249
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
12471250
!(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)) {
12491253
if (is_multicast_ether_addr(ehdr->h_dest)) {
12501254
/*
12511255
* send multicast frames both to higher layers in
@@ -2007,7 +2011,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
20072011

20082012
switch (sdata->vif.type) {
20092013
case NL80211_IFTYPE_STATION:
2010-
if (!bssid && !sdata->use_4addr)
2014+
if (!bssid && !sdata->u.mgd.use_4addr)
20112015
return 0;
20122016
if (!multicast &&
20132017
compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {

net/mac80211/tx.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
10511051

10521052
hdr = (struct ieee80211_hdr *) skb->data;
10531053

1054-
if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
1054+
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
10551055
tx->sta = rcu_dereference(sdata->u.vlan.sta);
10561056
if (!tx->sta)
10571057
tx->sta = sta_info_get(local, hdr->addr1);
@@ -1632,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
16321632
switch (sdata->vif.type) {
16331633
case NL80211_IFTYPE_AP_VLAN:
16341634
rcu_read_lock();
1635-
if (sdata->use_4addr)
1636-
sta = rcu_dereference(sdata->u.vlan.sta);
1635+
sta = rcu_dereference(sdata->u.vlan.sta);
16371636
if (sta) {
16381637
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
16391638
/* RA TA DA SA */
@@ -1727,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
17271726
#endif
17281727
case NL80211_IFTYPE_STATION:
17291728
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) {
17311730
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
17321731
/* RA TA DA SA */
17331732
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);

net/wireless/nl80211.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,28 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
968968
return 0;
969969
}
970970

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+
971993
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
972994
{
973995
struct cfg80211_registered_device *rdev;
@@ -1011,6 +1033,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
10111033
if (info->attrs[NL80211_ATTR_4ADDR]) {
10121034
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
10131035
change = true;
1036+
err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
1037+
if (err)
1038+
goto unlock;
10141039
} else {
10151040
params.use_4addr = -1;
10161041
}
@@ -1034,6 +1059,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
10341059
else
10351060
err = 0;
10361061

1062+
if (!err && params.use_4addr != -1)
1063+
dev->ieee80211_ptr->use_4addr = params.use_4addr;
1064+
10371065
unlock:
10381066
dev_put(dev);
10391067
cfg80211_unlock_rdev(rdev);
@@ -1081,8 +1109,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
10811109
params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
10821110
}
10831111

1084-
if (info->attrs[NL80211_ATTR_4ADDR])
1112+
if (info->attrs[NL80211_ATTR_4ADDR]) {
10851113
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+
}
10861118

10871119
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
10881120
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,

net/wireless/util.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
659659
return -EOPNOTSUPP;
660660

661661
if (ntype != otype) {
662+
dev->ieee80211_ptr->use_4addr = false;
663+
662664
switch (otype) {
663665
case NL80211_IFTYPE_ADHOC:
664666
cfg80211_leave_ibss(rdev, dev, false);
@@ -682,5 +684,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
682684

683685
WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
684686

687+
if (!err && params && params->use_4addr != -1)
688+
dev->ieee80211_ptr->use_4addr = params->use_4addr;
689+
685690
return err;
686691
}

0 commit comments

Comments
 (0)