diff options
-rw-r--r-- | net/mac80211/cfg.c | 32 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 5 | ||||
-rw-r--r-- | net/mac80211/iface.c | 4 | ||||
-rw-r--r-- | net/mac80211/rx.c | 18 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 3 | ||||
-rw-r--r-- | net/mac80211/tx.c | 45 | ||||
-rw-r--r-- | net/wireless/util.c | 4 |
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 | ||
39 | static 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 | |||
39 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 57 | static 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 | ||
209 | struct ieee80211_if_vlan { | 209 | struct 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 | ||
213 | struct mesh_stats { | 216 | struct 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 = |