aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyeyoon Park <kyeyoonp@codeaurora.org>2014-10-23 17:49:17 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-27 19:02:04 -0400
commit958501163ddd6ea22a98f94fa0e7ce6d4734e5c4 (patch)
tree5559ec9c425fc5e8092961a2b82b2cafd8239c75
parentb8901ac319768cdd3afa060787503e0c405f9607 (diff)
bridge: Add support for IEEE 802.11 Proxy ARP
This feature is defined in IEEE Std 802.11-2012, 10.23.13. It allows the AP devices to keep track of the hardware-address-to-IP-address mapping of the mobile devices within the WLAN network. The AP will learn this mapping via observing DHCP, ARP, and NS/NA frames. When a request for such information is made (i.e. ARP request, Neighbor Solicitation), the AP will respond on behalf of the associated mobile device. In the process of doing so, the AP will drop the multicast request frame that was intended to go out to the wireless medium. It was recommended at the LKS workshop to do this implementation in the bridge layer. vxlan.c is already doing something very similar. The DHCP snooping code will be added to the userspace application (hostapd) per the recommendation. This RFC commit is only for IPv4. A similar approach in the bridge layer will be taken for IPv6 as well. Signed-off-by: Kyeyoon Park <kyeyoonp@codeaurora.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--net/bridge/br_forward.c5
-rw-r--r--net/bridge/br_input.c60
-rw-r--r--net/bridge/br_netlink.c4
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/br_sysfs_if.c2
6 files changed, 72 insertions, 1 deletions
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 0bdb77e16875..7072d8325016 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -243,6 +243,7 @@ enum {
243 IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */ 243 IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */
244 IFLA_BRPORT_LEARNING, /* mac learning */ 244 IFLA_BRPORT_LEARNING, /* mac learning */
245 IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */ 245 IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
246 IFLA_BRPORT_PROXYARP, /* proxy ARP */
246 __IFLA_BRPORT_MAX 247 __IFLA_BRPORT_MAX
247}; 248};
248#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) 249#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 992ec49a96aa..1510b54e6a2e 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -183,6 +183,11 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
183 /* Do not flood unicast traffic to ports that turn it off */ 183 /* Do not flood unicast traffic to ports that turn it off */
184 if (unicast && !(p->flags & BR_FLOOD)) 184 if (unicast && !(p->flags & BR_FLOOD))
185 continue; 185 continue;
186
187 /* Do not flood to ports that enable proxy ARP */
188 if (p->flags & BR_PROXYARP)
189 continue;
190
186 prev = maybe_deliver(prev, p, skb, __packet_hook); 191 prev = maybe_deliver(prev, p, skb, __packet_hook);
187 if (IS_ERR(prev)) 192 if (IS_ERR(prev))
188 goto out; 193 goto out;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 6fd5522df696..1f1de715197c 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -16,6 +16,8 @@
16#include <linux/netdevice.h> 16#include <linux/netdevice.h>
17#include <linux/etherdevice.h> 17#include <linux/etherdevice.h>
18#include <linux/netfilter_bridge.h> 18#include <linux/netfilter_bridge.h>
19#include <linux/neighbour.h>
20#include <net/arp.h>
19#include <linux/export.h> 21#include <linux/export.h>
20#include <linux/rculist.h> 22#include <linux/rculist.h>
21#include "br_private.h" 23#include "br_private.h"
@@ -57,6 +59,60 @@ static int br_pass_frame_up(struct sk_buff *skb)
57 netif_receive_skb); 59 netif_receive_skb);
58} 60}
59 61
62static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
63 u16 vid)
64{
65 struct net_device *dev = br->dev;
66 struct neighbour *n;
67 struct arphdr *parp;
68 u8 *arpptr, *sha;
69 __be32 sip, tip;
70
71 if (dev->flags & IFF_NOARP)
72 return;
73
74 if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
75 dev->stats.tx_dropped++;
76 return;
77 }
78 parp = arp_hdr(skb);
79
80 if (parp->ar_pro != htons(ETH_P_IP) ||
81 parp->ar_op != htons(ARPOP_REQUEST) ||
82 parp->ar_hln != dev->addr_len ||
83 parp->ar_pln != 4)
84 return;
85
86 arpptr = (u8 *)parp + sizeof(struct arphdr);
87 sha = arpptr;
88 arpptr += dev->addr_len; /* sha */
89 memcpy(&sip, arpptr, sizeof(sip));
90 arpptr += sizeof(sip);
91 arpptr += dev->addr_len; /* tha */
92 memcpy(&tip, arpptr, sizeof(tip));
93
94 if (ipv4_is_loopback(tip) ||
95 ipv4_is_multicast(tip))
96 return;
97
98 n = neigh_lookup(&arp_tbl, &tip, dev);
99 if (n) {
100 struct net_bridge_fdb_entry *f;
101
102 if (!(n->nud_state & NUD_VALID)) {
103 neigh_release(n);
104 return;
105 }
106
107 f = __br_fdb_get(br, n->ha, vid);
108 if (f)
109 arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip,
110 sha, n->ha, sha);
111
112 neigh_release(n);
113 }
114}
115
60/* note: already called with rcu_read_lock */ 116/* note: already called with rcu_read_lock */
61int br_handle_frame_finish(struct sk_buff *skb) 117int br_handle_frame_finish(struct sk_buff *skb)
62{ 118{
@@ -98,6 +154,10 @@ int br_handle_frame_finish(struct sk_buff *skb)
98 dst = NULL; 154 dst = NULL;
99 155
100 if (is_broadcast_ether_addr(dest)) { 156 if (is_broadcast_ether_addr(dest)) {
157 if (p->flags & BR_PROXYARP &&
158 skb->protocol == htons(ETH_P_ARP))
159 br_do_proxy_arp(skb, br, vid);
160
101 skb2 = skb; 161 skb2 = skb;
102 unicast = false; 162 unicast = false;
103 } else if (is_multicast_ether_addr(dest)) { 163 } else if (is_multicast_ether_addr(dest)) {
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 2ff9706647f2..86c239b06f6e 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -60,7 +60,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
60 nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) || 60 nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) ||
61 nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) || 61 nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
62 nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) || 62 nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
63 nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD))) 63 nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)) ||
64 nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)))
64 return -EMSGSIZE; 65 return -EMSGSIZE;
65 66
66 return 0; 67 return 0;
@@ -332,6 +333,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
332 br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); 333 br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
333 br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); 334 br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
334 br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); 335 br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
336 br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
335 337
336 if (tb[IFLA_BRPORT_COST]) { 338 if (tb[IFLA_BRPORT_COST]) {
337 err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); 339 err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 4d783d071305..8f3f08140258 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -172,6 +172,7 @@ struct net_bridge_port
172#define BR_FLOOD 0x00000040 172#define BR_FLOOD 0x00000040
173#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) 173#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
174#define BR_PROMISC 0x00000080 174#define BR_PROMISC 0x00000080
175#define BR_PROXYARP 0x00000100
175 176
176#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 177#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
177 struct bridge_mcast_own_query ip4_own_query; 178 struct bridge_mcast_own_query ip4_own_query;
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index e561cd59b8a6..2de5d91199e8 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -170,6 +170,7 @@ BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
170BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK); 170BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
171BRPORT_ATTR_FLAG(learning, BR_LEARNING); 171BRPORT_ATTR_FLAG(learning, BR_LEARNING);
172BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); 172BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
173BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
173 174
174#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 175#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
175static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) 176static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
@@ -213,6 +214,7 @@ static const struct brport_attribute *brport_attrs[] = {
213 &brport_attr_multicast_router, 214 &brport_attr_multicast_router,
214 &brport_attr_multicast_fast_leave, 215 &brport_attr_multicast_fast_leave,
215#endif 216#endif
217 &brport_attr_proxyarp,
216 NULL 218 NULL
217}; 219};
218 220