Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 842a9ae0 authored by Jouni Malinen's avatar Jouni Malinen Committed by David S. Miller
Browse files

bridge: Extend Proxy ARP design to allow optional rules for Wi-Fi



This extends the design in commit 95850116 ("bridge: Add support for
IEEE 802.11 Proxy ARP") with optional set of rules that are needed to
meet the IEEE 802.11 and Hotspot 2.0 requirements for ProxyARP. The
previously added BR_PROXYARP behavior is left as-is and a new
BR_PROXYARP_WIFI alternative is added so that this behavior can be
configured from user space when required.

In addition, this enables proxyarp functionality for unicast ARP
requests for both BR_PROXYARP and BR_PROXYARP_WIFI since it is possible
to use unicast as well as broadcast for these frames.

The key differences in functionality:

BR_PROXYARP:
- uses the flag on the bridge port on which the request frame was
  received to determine whether to reply
- block bridge port flooding completely on ports that enable proxy ARP

BR_PROXYARP_WIFI:
- uses the flag on the bridge port to which the target device of the
  request belongs
- block bridge port flooding selectively based on whether the proxyarp
  functionality replied

Signed-off-by: default avatarJouni Malinen <jouni@codeaurora.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 787fb2bd
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@ struct br_ip_list {
#define BR_PROMISC		BIT(7)
#define BR_PROMISC		BIT(7)
#define BR_PROXYARP		BIT(8)
#define BR_PROXYARP		BIT(8)
#define BR_LEARNING_SYNC	BIT(9)
#define BR_LEARNING_SYNC	BIT(9)
#define BR_PROXYARP_WIFI	BIT(10)


extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));


+1 −0
Original line number Original line Diff line number Diff line
@@ -247,6 +247,7 @@ enum {
	IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
	IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
	IFLA_BRPORT_PROXYARP,	/* proxy ARP */
	IFLA_BRPORT_PROXYARP,	/* proxy ARP */
	IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
	IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
	IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
	__IFLA_BRPORT_MAX
	__IFLA_BRPORT_MAX
};
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+3 −0
Original line number Original line Diff line number Diff line
@@ -188,6 +188,9 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
		/* Do not flood to ports that enable proxy ARP */
		/* Do not flood to ports that enable proxy ARP */
		if (p->flags & BR_PROXYARP)
		if (p->flags & BR_PROXYARP)
			continue;
			continue;
		if ((p->flags & BR_PROXYARP_WIFI) &&
		    BR_INPUT_SKB_CB(skb)->proxyarp_replied)
			continue;


		prev = maybe_deliver(prev, p, skb, __packet_hook);
		prev = maybe_deliver(prev, p, skb, __packet_hook);
		if (IS_ERR(prev))
		if (IS_ERR(prev))
+10 −7
Original line number Original line Diff line number Diff line
@@ -60,7 +60,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
}
}


static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
			    u16 vid)
			    u16 vid, struct net_bridge_port *p)
{
{
	struct net_device *dev = br->dev;
	struct net_device *dev = br->dev;
	struct neighbour *n;
	struct neighbour *n;
@@ -68,6 +68,8 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
	u8 *arpptr, *sha;
	u8 *arpptr, *sha;
	__be32 sip, tip;
	__be32 sip, tip;


	BR_INPUT_SKB_CB(skb)->proxyarp_replied = false;

	if (dev->flags & IFF_NOARP)
	if (dev->flags & IFF_NOARP)
		return;
		return;


@@ -105,9 +107,12 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
		}
		}


		f = __br_fdb_get(br, n->ha, vid);
		f = __br_fdb_get(br, n->ha, vid);
		if (f)
		if (f && ((p->flags & BR_PROXYARP) ||
			  (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)))) {
			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip,
			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip,
				 sha, n->ha, sha);
				 sha, n->ha, sha);
			BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
		}


		neigh_release(n);
		neigh_release(n);
	}
	}
@@ -153,12 +158,10 @@ int br_handle_frame_finish(struct sk_buff *skb)


	dst = NULL;
	dst = NULL;


	if (is_broadcast_ether_addr(dest)) {
	if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
		if (IS_ENABLED(CONFIG_INET) &&
		br_do_proxy_arp(skb, br, vid, p);
		    p->flags & BR_PROXYARP &&
		    skb->protocol == htons(ETH_P_ARP))
			br_do_proxy_arp(skb, br, vid);


	if (is_broadcast_ether_addr(dest)) {
		skb2 = skb;
		skb2 = skb;
		unicast = false;
		unicast = false;
	} else if (is_multicast_ether_addr(dest)) {
	} else if (is_multicast_ether_addr(dest)) {
+4 −1
Original line number Original line Diff line number Diff line
@@ -143,7 +143,9 @@ static int br_port_fill_attrs(struct sk_buff *skb,
	    nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
	    nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
	    nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
	    nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
	    nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)) ||
	    nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)) ||
	    nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)))
	    nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) ||
	    nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI,
		       !!(p->flags & BR_PROXYARP_WIFI)))
		return -EMSGSIZE;
		return -EMSGSIZE;


	return 0;
	return 0;
@@ -553,6 +555,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
	br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
	br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
	br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
	br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);


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