aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/cfg.c32
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/rx.c18
-rw-r--r--net/mac80211/sta_info.c3
-rw-r--r--net/mac80211/tx.c45
-rw-r--r--net/wireless/util.c4
7 files changed, 99 insertions, 12 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 56319b51d170..576b86f81d1b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80211_iftype type)
36 } 36 }
37} 37}
38 38
39static bool nl80211_params_check(enum nl80211_iftype type,
40 struct vif_params *params)
41{
42 if (!nl80211_type_check(type))
43 return false;
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;
55}
56
39static int ieee80211_add_iface(struct wiphy *wiphy, char *name, 57static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
40 enum nl80211_iftype type, u32 *flags, 58 enum nl80211_iftype type, u32 *flags,
41 struct vif_params *params) 59 struct vif_params *params)
@@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
45 struct ieee80211_sub_if_data *sdata; 63 struct ieee80211_sub_if_data *sdata;
46 int err; 64 int err;
47 65
48 if (!nl80211_type_check(type)) 66 if (!nl80211_params_check(type, params))
49 return -EINVAL; 67 return -EINVAL;
50 68
51 err = ieee80211_if_add(local, name, &dev, type, params); 69 err = ieee80211_if_add(local, name, &dev, type, params);
@@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
75 if (netif_running(dev)) 93 if (netif_running(dev))
76 return -EBUSY; 94 return -EBUSY;
77 95
78 if (!nl80211_type_check(type)) 96 if (!nl80211_params_check(type, params))
79 return -EINVAL; 97 return -EINVAL;
80 98
81 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 99 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
89 params->mesh_id_len, 107 params->mesh_id_len,
90 params->mesh_id); 108 params->mesh_id);
91 109
110 if (params->use_4addr >= 0)
111 sdata->use_4addr = !!params->use_4addr;
112
92 if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) 113 if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
93 return 0; 114 return 0;
94 115
@@ -806,6 +827,13 @@ static int ieee80211_change_station(struct wiphy *wiphy,
806 return -EINVAL; 827 return -EINVAL;
807 } 828 }
808 829
830 if (vlansdata->use_4addr) {
831 if (vlansdata->u.vlan.sta)
832 return -EBUSY;
833
834 rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
835 }
836
809 sta->sdata = vlansdata; 837 sta->sdata = vlansdata;
810 ieee80211_send_layer2_update(sta); 838 ieee80211_send_layer2_update(sta);
811 } 839 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1f4f88a8f80c..19b0c128d940 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -208,6 +208,9 @@ struct ieee80211_if_wds {
208 208
209struct ieee80211_if_vlan { 209struct ieee80211_if_vlan {
210 struct list_head list; 210 struct list_head list;
211
212 /* used for all tx if the VLAN is configured to 4-addr mode */
213 struct sta_info *sta;
211}; 214};
212 215
213struct mesh_stats { 216struct mesh_stats {
@@ -457,6 +460,8 @@ struct ieee80211_sub_if_data {
457 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ 460 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
458 int max_ratectrl_rateidx; /* max TX rateidx for rate control */ 461 int max_ratectrl_rateidx; /* max TX rateidx for rate control */
459 462
463 bool use_4addr; /* use 4-address frames */
464
460 union { 465 union {
461 struct ieee80211_if_ap ap; 466 struct ieee80211_if_ap ap;
462 struct ieee80211_if_wds wds; 467 struct ieee80211_if_wds wds;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8495161b99b8..1f02b0610e82 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -752,6 +752,7 @@ 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 756
756 return 0; 757 return 0;
757} 758}
@@ -819,6 +820,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
819 params->mesh_id_len, 820 params->mesh_id_len,
820 params->mesh_id); 821 params->mesh_id);
821 822
823 if (params && params->use_4addr >= 0)
824 sdata->use_4addr = !!params->use_4addr;
825
822 mutex_lock(&local->iflist_mtx); 826 mutex_lock(&local->iflist_mtx);
823 list_add_tail_rcu(&sdata->list, &local->interfaces); 827 list_add_tail_rcu(&sdata->list, &local->interfaces);
824 mutex_unlock(&local->iflist_mtx); 828 mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4066570dd414..76478362a538 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1181,6 +1181,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
1181{ 1181{
1182 struct net_device *dev = rx->dev; 1182 struct net_device *dev = rx->dev;
1183 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1183 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1184 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
1185
1186 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
1187 ieee80211_has_a4(hdr->frame_control))
1188 return -1;
1189 if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
1190 return -1;
1184 1191
1185 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); 1192 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
1186} 1193}
@@ -1534,6 +1541,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
1534{ 1541{
1535 struct net_device *dev = rx->dev; 1542 struct net_device *dev = rx->dev;
1536 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 1543 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
1544 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1537 __le16 fc = hdr->frame_control; 1545 __le16 fc = hdr->frame_control;
1538 int err; 1546 int err;
1539 1547
@@ -1543,6 +1551,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
1543 if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 1551 if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
1544 return RX_DROP_MONITOR; 1552 return RX_DROP_MONITOR;
1545 1553
1554 /*
1555 * Allow the cooked monitor interface of an AP to see 4-addr frames so
1556 * that a 4-addr station can be detected and moved into a separate VLAN
1557 */
1558 if (ieee80211_has_a4(hdr->frame_control) &&
1559 sdata->vif.type == NL80211_IFTYPE_AP)
1560 return RX_DROP_MONITOR;
1561
1546 err = __ieee80211_data_to_8023(rx); 1562 err = __ieee80211_data_to_8023(rx);
1547 if (unlikely(err)) 1563 if (unlikely(err))
1548 return RX_DROP_UNUSABLE; 1564 return RX_DROP_UNUSABLE;
@@ -1983,7 +1999,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
1983 1999
1984 switch (sdata->vif.type) { 2000 switch (sdata->vif.type) {
1985 case NL80211_IFTYPE_STATION: 2001 case NL80211_IFTYPE_STATION:
1986 if (!bssid) 2002 if (!bssid && !sdata->use_4addr)
1987 return 0; 2003 return 0;
1988 if (!multicast && 2004 if (!multicast &&
1989 compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { 2005 compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index be59456e8a42..396a94806de9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -509,6 +509,9 @@ static void __sta_info_unlink(struct sta_info **sta)
509 local->num_sta--; 509 local->num_sta--;
510 local->sta_generation++; 510 local->sta_generation++;
511 511
512 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
513 rcu_assign_pointer(sdata->u.vlan.sta, NULL);
514
512 if (local->ops->sta_notify) { 515 if (local->ops->sta_notify) {
513 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 516 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
514 sdata = container_of(sdata->bss, 517 sdata = container_of(sdata->bss,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index bfaa43e096d2..2f3345c5f7cf 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1051,7 +1051,10 @@ 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 tx->sta = sta_info_get(local, hdr->addr1); 1054 if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
1055 tx->sta = rcu_dereference(sdata->u.vlan.sta);
1056 if (!tx->sta)
1057 tx->sta = sta_info_get(local, hdr->addr1);
1055 1058
1056 if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && 1059 if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
1057 (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { 1060 (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
@@ -1613,7 +1616,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1613 const u8 *encaps_data; 1616 const u8 *encaps_data;
1614 int encaps_len, skip_header_bytes; 1617 int encaps_len, skip_header_bytes;
1615 int nh_pos, h_pos; 1618 int nh_pos, h_pos;
1616 struct sta_info *sta; 1619 struct sta_info *sta = NULL;
1617 u32 sta_flags = 0; 1620 u32 sta_flags = 0;
1618 1621
1619 if (unlikely(skb->len < ETH_HLEN)) { 1622 if (unlikely(skb->len < ETH_HLEN)) {
@@ -1630,8 +1633,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1630 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); 1633 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
1631 1634
1632 switch (sdata->vif.type) { 1635 switch (sdata->vif.type) {
1633 case NL80211_IFTYPE_AP:
1634 case NL80211_IFTYPE_AP_VLAN: 1636 case NL80211_IFTYPE_AP_VLAN:
1637 rcu_read_lock();
1638 if (sdata->use_4addr)
1639 sta = rcu_dereference(sdata->u.vlan.sta);
1640 if (sta) {
1641 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
1642 /* RA TA DA SA */
1643 memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
1644 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
1645 memcpy(hdr.addr3, skb->data, ETH_ALEN);
1646 memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
1647 hdrlen = 30;
1648 sta_flags = get_sta_flags(sta);
1649 }
1650 rcu_read_unlock();
1651 if (sta)
1652 break;
1653 /* fall through */
1654 case NL80211_IFTYPE_AP:
1635 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); 1655 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
1636 /* DA BSSID SA */ 1656 /* DA BSSID SA */
1637 memcpy(hdr.addr1, skb->data, ETH_ALEN); 1657 memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -1705,12 +1725,21 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1705 break; 1725 break;
1706#endif 1726#endif
1707 case NL80211_IFTYPE_STATION: 1727 case NL80211_IFTYPE_STATION:
1708 fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
1709 /* BSSID SA DA */
1710 memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); 1728 memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
1711 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); 1729 if (sdata->use_4addr && ethertype != ETH_P_PAE) {
1712 memcpy(hdr.addr3, skb->data, ETH_ALEN); 1730 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
1713 hdrlen = 24; 1731 /* RA TA DA SA */
1732 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
1733 memcpy(hdr.addr3, skb->data, ETH_ALEN);
1734 memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
1735 hdrlen = 30;
1736 } else {
1737 fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
1738 /* BSSID SA DA */
1739 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
1740 memcpy(hdr.addr3, skb->data, ETH_ALEN);
1741 hdrlen = 24;
1742 }
1714 break; 1743 break;
1715 case NL80211_IFTYPE_ADHOC: 1744 case NL80211_IFTYPE_ADHOC:
1716 /* DA SA BSSID */ 1745 /* DA SA BSSID */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3fc2df86278f..5aa39f7cf9b9 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
320 break; 320 break;
321 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): 321 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
322 if (unlikely(iftype != NL80211_IFTYPE_WDS && 322 if (unlikely(iftype != NL80211_IFTYPE_WDS &&
323 iftype != NL80211_IFTYPE_MESH_POINT)) 323 iftype != NL80211_IFTYPE_MESH_POINT &&
324 iftype != NL80211_IFTYPE_AP_VLAN &&
325 iftype != NL80211_IFTYPE_STATION))
324 return -1; 326 return -1;
325 if (iftype == NL80211_IFTYPE_MESH_POINT) { 327 if (iftype == NL80211_IFTYPE_MESH_POINT) {
326 struct ieee80211s_hdr *meshdr = 328 struct ieee80211s_hdr *meshdr =