Skip to content

Commit 9585011

Browse files
Kyeyoon Parkdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b8901ac commit 9585011

File tree

6 files changed

+72
-1
lines changed

6 files changed

+72
-1
lines changed

include/uapi/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ enum {
243243
IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */
244244
IFLA_BRPORT_LEARNING, /* mac learning */
245245
IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
246+
IFLA_BRPORT_PROXYARP, /* proxy ARP */
246247
__IFLA_BRPORT_MAX
247248
};
248249
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)

net/bridge/br_forward.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
183183
/* Do not flood unicast traffic to ports that turn it off */
184184
if (unicast && !(p->flags & BR_FLOOD))
185185
continue;
186+
187+
/* Do not flood to ports that enable proxy ARP */
188+
if (p->flags & BR_PROXYARP)
189+
continue;
190+
186191
prev = maybe_deliver(prev, p, skb, __packet_hook);
187192
if (IS_ERR(prev))
188193
goto out;

net/bridge/br_input.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <linux/netdevice.h>
1717
#include <linux/etherdevice.h>
1818
#include <linux/netfilter_bridge.h>
19+
#include <linux/neighbour.h>
20+
#include <net/arp.h>
1921
#include <linux/export.h>
2022
#include <linux/rculist.h>
2123
#include "br_private.h"
@@ -57,6 +59,60 @@ static int br_pass_frame_up(struct sk_buff *skb)
5759
netif_receive_skb);
5860
}
5961

62+
static 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+
60116
/* note: already called with rcu_read_lock */
61117
int br_handle_frame_finish(struct sk_buff *skb)
62118
{
@@ -98,6 +154,10 @@ int br_handle_frame_finish(struct sk_buff *skb)
98154
dst = NULL;
99155

100156
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+
101161
skb2 = skb;
102162
unicast = false;
103163
} else if (is_multicast_ether_addr(dest)) {

net/bridge/br_netlink.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
6060
nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) ||
6161
nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
6262
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)))
6465
return -EMSGSIZE;
6566

6667
return 0;
@@ -332,6 +333,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
332333
br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
333334
br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
334335
br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
336+
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
335337

336338
if (tb[IFLA_BRPORT_COST]) {
337339
err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));

net/bridge/br_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ struct net_bridge_port
172172
#define BR_FLOOD 0x00000040
173173
#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
174174
#define BR_PROMISC 0x00000080
175+
#define BR_PROXYARP 0x00000100
175176

176177
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
177178
struct bridge_mcast_own_query ip4_own_query;

net/bridge/br_sysfs_if.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
170170
BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
171171
BRPORT_ATTR_FLAG(learning, BR_LEARNING);
172172
BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
173+
BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
173174

174175
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
175176
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
@@ -213,6 +214,7 @@ static const struct brport_attribute *brport_attrs[] = {
213214
&brport_attr_multicast_router,
214215
&brport_attr_multicast_fast_leave,
215216
#endif
217+
&brport_attr_proxyarp,
216218
NULL
217219
};
218220

0 commit comments

Comments
 (0)