aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2009-11-10 14:10:05 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-11 17:02:10 -0500
commitf14543ee4d0681df1377b976cba704557ba220d3 (patch)
treef148485869f6638030207c069742c1918647be6a /net/mac80211/rx.c
parent8b787643ca0a5130c647109d77fe512f89cfa611 (diff)
mac80211: implement support for 4-address frames for AP and client mode
In some situations it might be useful to run a network with an Access Point and multiple clients, but with each client bridged to a network behind it. For this to work, both the client and the AP need to transmit 4-address frames, containing both source and destination MAC addresses. With this patch, you can configure a client to communicate using only 4-address frames for data traffic. On the AP side you can enable 4-address frames for individual clients by isolating them in separate AP VLANs which are configured in 4-address mode. Such an AP VLAN will be limited to one client only, and this client will be used as the destination for all traffic on its interface, regardless of the destination MAC address in the packet headers. The advantage of this mode compared to regular WDS mode is that it's easier to configure and does not require a static list of peer MAC addresses on any side. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c18
1 files changed, 17 insertions, 1 deletions
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) {