Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

This extends the design in commit 958501163ddd ("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: Jouni Malinen <jouni@codeaurora.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jouni Malinen and committed by
David S. Miller
842a9ae0 787fb2bd

+22 -8
+1
include/linux/if_bridge.h
··· 44 44 #define BR_PROMISC BIT(7) 45 45 #define BR_PROXYARP BIT(8) 46 46 #define BR_LEARNING_SYNC BIT(9) 47 + #define BR_PROXYARP_WIFI BIT(10) 47 48 48 49 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); 49 50
+1
include/uapi/linux/if_link.h
··· 247 247 IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */ 248 248 IFLA_BRPORT_PROXYARP, /* proxy ARP */ 249 249 IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */ 250 + IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */ 250 251 __IFLA_BRPORT_MAX 251 252 }; 252 253 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+3
net/bridge/br_forward.c
··· 188 188 /* Do not flood to ports that enable proxy ARP */ 189 189 if (p->flags & BR_PROXYARP) 190 190 continue; 191 + if ((p->flags & BR_PROXYARP_WIFI) && 192 + BR_INPUT_SKB_CB(skb)->proxyarp_replied) 193 + continue; 191 194 192 195 prev = maybe_deliver(prev, p, skb, __packet_hook); 193 196 if (IS_ERR(prev))
+10 -7
net/bridge/br_input.c
··· 60 60 } 61 61 62 62 static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, 63 - u16 vid) 63 + u16 vid, struct net_bridge_port *p) 64 64 { 65 65 struct net_device *dev = br->dev; 66 66 struct neighbour *n; 67 67 struct arphdr *parp; 68 68 u8 *arpptr, *sha; 69 69 __be32 sip, tip; 70 + 71 + BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; 70 72 71 73 if (dev->flags & IFF_NOARP) 72 74 return; ··· 107 105 } 108 106 109 107 f = __br_fdb_get(br, n->ha, vid); 110 - if (f) 108 + if (f && ((p->flags & BR_PROXYARP) || 109 + (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)))) { 111 110 arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip, 112 111 sha, n->ha, sha); 112 + BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; 113 + } 113 114 114 115 neigh_release(n); 115 116 } ··· 158 153 159 154 dst = NULL; 160 155 161 - if (is_broadcast_ether_addr(dest)) { 162 - if (IS_ENABLED(CONFIG_INET) && 163 - p->flags & BR_PROXYARP && 164 - skb->protocol == htons(ETH_P_ARP)) 165 - br_do_proxy_arp(skb, br, vid); 156 + if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP)) 157 + br_do_proxy_arp(skb, br, vid, p); 166 158 159 + if (is_broadcast_ether_addr(dest)) { 167 160 skb2 = skb; 168 161 unicast = false; 169 162 } else if (is_multicast_ether_addr(dest)) {
+4 -1
net/bridge/br_netlink.c
··· 143 143 nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) || 144 144 nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) || 145 145 nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)) || 146 - nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP))) 146 + nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) || 147 + nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI, 148 + !!(p->flags & BR_PROXYARP_WIFI))) 147 149 return -EMSGSIZE; 148 150 149 151 return 0; ··· 555 553 br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); 556 554 br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); 557 555 br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP); 556 + br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); 558 557 559 558 if (tb[IFLA_BRPORT_COST]) { 560 559 err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
+1
net/bridge/br_private.h
··· 305 305 #endif 306 306 307 307 u16 frag_max_size; 308 + bool proxyarp_replied; 308 309 309 310 #ifdef CONFIG_BRIDGE_VLAN_FILTERING 310 311 bool vlan_filtered;
+2
net/bridge/br_sysfs_if.c
··· 171 171 BRPORT_ATTR_FLAG(learning, BR_LEARNING); 172 172 BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); 173 173 BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP); 174 + BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI); 174 175 175 176 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 176 177 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) ··· 216 215 &brport_attr_multicast_fast_leave, 217 216 #endif 218 217 &brport_attr_proxyarp, 218 + &brport_attr_proxyarp_wifi, 219 219 NULL 220 220 }; 221 221