| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | *  Handle bridge arp/nd proxy/suppress | 
|---|
| 3 | 4 | * | 
|---|
| .. | .. | 
|---|
| 6 | 7 | * | 
|---|
| 7 | 8 | *  Authors: | 
|---|
| 8 | 9 | *	Roopa Prabhu <roopa@cumulusnetworks.com> | 
|---|
| 9 |  | - * | 
|---|
| 10 |  | - *  This program is free software; you can redistribute it and/or | 
|---|
| 11 |  | - *  modify it under the terms of the GNU General Public License | 
|---|
| 12 |  | - *  as published by the Free Software Foundation; either version | 
|---|
| 13 |  | - *  2 of the License, or (at your option) any later version. | 
|---|
| 14 | 10 | */ | 
|---|
| 15 | 11 |  | 
|---|
| 16 | 12 | #include <linux/kernel.h> | 
|---|
| .. | .. | 
|---|
| 21 | 17 | #include <linux/if_vlan.h> | 
|---|
| 22 | 18 | #include <linux/inetdevice.h> | 
|---|
| 23 | 19 | #include <net/addrconf.h> | 
|---|
|  | 20 | +#include <net/ipv6_stubs.h> | 
|---|
| 24 | 21 | #if IS_ENABLED(CONFIG_IPV6) | 
|---|
| 25 | 22 | #include <net/ip6_checksum.h> | 
|---|
| 26 | 23 | #endif | 
|---|
| .. | .. | 
|---|
| 39 | 36 | } | 
|---|
| 40 | 37 | } | 
|---|
| 41 | 38 |  | 
|---|
| 42 |  | -	br->neigh_suppress_enabled = neigh_suppress; | 
|---|
|  | 39 | +	br_opt_toggle(br, BROPT_NEIGH_SUPPRESS_ENABLED, neigh_suppress); | 
|---|
| 43 | 40 | } | 
|---|
| 44 | 41 |  | 
|---|
| 45 | 42 | #if IS_ENABLED(CONFIG_INET) | 
|---|
| .. | .. | 
|---|
| 91 | 88 | } | 
|---|
| 92 | 89 | } | 
|---|
| 93 | 90 |  | 
|---|
| 94 |  | -static int br_chk_addr_ip(struct net_device *dev, void *data) | 
|---|
|  | 91 | +static int br_chk_addr_ip(struct net_device *dev, | 
|---|
|  | 92 | +			  struct netdev_nested_priv *priv) | 
|---|
| 95 | 93 | { | 
|---|
| 96 |  | -	__be32 ip = *(__be32 *)data; | 
|---|
|  | 94 | +	__be32 ip = *(__be32 *)priv->data; | 
|---|
| 97 | 95 | struct in_device *in_dev; | 
|---|
| 98 | 96 | __be32 addr = 0; | 
|---|
| 99 | 97 |  | 
|---|
| .. | .. | 
|---|
| 110 | 108 |  | 
|---|
| 111 | 109 | static bool br_is_local_ip(struct net_device *dev, __be32 ip) | 
|---|
| 112 | 110 | { | 
|---|
| 113 |  | -	if (br_chk_addr_ip(dev, &ip)) | 
|---|
|  | 111 | +	struct netdev_nested_priv priv = { | 
|---|
|  | 112 | +		.data = (void *)&ip, | 
|---|
|  | 113 | +	}; | 
|---|
|  | 114 | + | 
|---|
|  | 115 | +	if (br_chk_addr_ip(dev, &priv)) | 
|---|
| 114 | 116 | return true; | 
|---|
| 115 | 117 |  | 
|---|
| 116 | 118 | /* check if ip is configured on upper dev */ | 
|---|
| 117 |  | -	if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &ip)) | 
|---|
|  | 119 | +	if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &priv)) | 
|---|
| 118 | 120 | return true; | 
|---|
| 119 | 121 |  | 
|---|
| 120 | 122 | return false; | 
|---|
| .. | .. | 
|---|
| 130 | 132 | u8 *arpptr, *sha; | 
|---|
| 131 | 133 | __be32 sip, tip; | 
|---|
| 132 | 134 |  | 
|---|
| 133 |  | -	BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; | 
|---|
|  | 135 | +	BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0; | 
|---|
| 134 | 136 |  | 
|---|
| 135 | 137 | if ((dev->flags & IFF_NOARP) || | 
|---|
| 136 | 138 | !pskb_may_pull(skb, arp_hdr_len(dev))) | 
|---|
| .. | .. | 
|---|
| 155 | 157 | ipv4_is_multicast(tip)) | 
|---|
| 156 | 158 | return; | 
|---|
| 157 | 159 |  | 
|---|
| 158 |  | -	if (br->neigh_suppress_enabled) { | 
|---|
|  | 160 | +	if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { | 
|---|
| 159 | 161 | if (p && (p->flags & BR_NEIGH_SUPPRESS)) | 
|---|
| 160 | 162 | return; | 
|---|
| 161 | 163 | if (parp->ar_op != htons(ARPOP_RREQUEST) && | 
|---|
| 162 | 164 | parp->ar_op != htons(ARPOP_RREPLY) && | 
|---|
| 163 | 165 | (ipv4_is_zeronet(sip) || sip == tip)) { | 
|---|
| 164 | 166 | /* prevent flooding to neigh suppress ports */ | 
|---|
| 165 |  | -			BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 167 | +			BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 166 | 168 | return; | 
|---|
| 167 | 169 | } | 
|---|
| 168 | 170 | } | 
|---|
| .. | .. | 
|---|
| 177 | 179 | return; | 
|---|
| 178 | 180 | } | 
|---|
| 179 | 181 |  | 
|---|
| 180 |  | -	if (br->neigh_suppress_enabled && br_is_local_ip(vlandev, tip)) { | 
|---|
|  | 182 | +	if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && | 
|---|
|  | 183 | +	    br_is_local_ip(vlandev, tip)) { | 
|---|
| 181 | 184 | /* its our local ip, so don't proxy reply | 
|---|
| 182 | 185 | * and don't forward to neigh suppress ports | 
|---|
| 183 | 186 | */ | 
|---|
| 184 |  | -		BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 187 | +		BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 185 | 188 | return; | 
|---|
| 186 | 189 | } | 
|---|
| 187 | 190 |  | 
|---|
| .. | .. | 
|---|
| 215 | 218 | /* If we have replied or as long as we know the | 
|---|
| 216 | 219 | * mac, indicate to arp replied | 
|---|
| 217 | 220 | */ | 
|---|
| 218 |  | -			if (replied || br->neigh_suppress_enabled) | 
|---|
| 219 |  | -				BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 221 | +			if (replied || | 
|---|
|  | 222 | +			    br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) | 
|---|
|  | 223 | +				BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 220 | 224 | } | 
|---|
| 221 | 225 |  | 
|---|
| 222 | 226 | neigh_release(n); | 
|---|
| .. | .. | 
|---|
| 364 | 368 | } | 
|---|
| 365 | 369 | } | 
|---|
| 366 | 370 |  | 
|---|
| 367 |  | -static int br_chk_addr_ip6(struct net_device *dev, void *data) | 
|---|
|  | 371 | +static int br_chk_addr_ip6(struct net_device *dev, | 
|---|
|  | 372 | +			   struct netdev_nested_priv *priv) | 
|---|
| 368 | 373 | { | 
|---|
| 369 |  | -	struct in6_addr *addr = (struct in6_addr *)data; | 
|---|
|  | 374 | +	struct in6_addr *addr = (struct in6_addr *)priv->data; | 
|---|
| 370 | 375 |  | 
|---|
| 371 | 376 | if (ipv6_chk_addr(dev_net(dev), addr, dev, 0)) | 
|---|
| 372 | 377 | return 1; | 
|---|
| .. | .. | 
|---|
| 377 | 382 | static bool br_is_local_ip6(struct net_device *dev, struct in6_addr *addr) | 
|---|
| 378 | 383 |  | 
|---|
| 379 | 384 | { | 
|---|
| 380 |  | -	if (br_chk_addr_ip6(dev, addr)) | 
|---|
|  | 385 | +	struct netdev_nested_priv priv = { | 
|---|
|  | 386 | +		.data = (void *)addr, | 
|---|
|  | 387 | +	}; | 
|---|
|  | 388 | + | 
|---|
|  | 389 | +	if (br_chk_addr_ip6(dev, &priv)) | 
|---|
| 381 | 390 | return true; | 
|---|
| 382 | 391 |  | 
|---|
| 383 | 392 | /* check if ip is configured on upper dev */ | 
|---|
| 384 |  | -	if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, addr)) | 
|---|
|  | 393 | +	if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, &priv)) | 
|---|
| 385 | 394 | return true; | 
|---|
| 386 | 395 |  | 
|---|
| 387 | 396 | return false; | 
|---|
| .. | .. | 
|---|
| 396 | 405 | struct ipv6hdr *iphdr; | 
|---|
| 397 | 406 | struct neighbour *n; | 
|---|
| 398 | 407 |  | 
|---|
| 399 |  | -	BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; | 
|---|
|  | 408 | +	BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0; | 
|---|
| 400 | 409 |  | 
|---|
| 401 | 410 | if (p && (p->flags & BR_NEIGH_SUPPRESS)) | 
|---|
| 402 | 411 | return; | 
|---|
| .. | .. | 
|---|
| 404 | 413 | if (msg->icmph.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT && | 
|---|
| 405 | 414 | !msg->icmph.icmp6_solicited) { | 
|---|
| 406 | 415 | /* prevent flooding to neigh suppress ports */ | 
|---|
| 407 |  | -		BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 416 | +		BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 408 | 417 | return; | 
|---|
| 409 | 418 | } | 
|---|
| 410 | 419 |  | 
|---|
| .. | .. | 
|---|
| 417 | 426 |  | 
|---|
| 418 | 427 | if (ipv6_addr_any(saddr) || !ipv6_addr_cmp(saddr, daddr)) { | 
|---|
| 419 | 428 | /* prevent flooding to neigh suppress ports */ | 
|---|
| 420 |  | -		BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 429 | +		BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 421 | 430 | return; | 
|---|
| 422 | 431 | } | 
|---|
| 423 | 432 |  | 
|---|
| .. | .. | 
|---|
| 435 | 444 | /* its our own ip, so don't proxy reply | 
|---|
| 436 | 445 | * and don't forward to arp suppress ports | 
|---|
| 437 | 446 | */ | 
|---|
| 438 |  | -		BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 447 | +		BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 439 | 448 | return; | 
|---|
| 440 | 449 | } | 
|---|
| 441 | 450 |  | 
|---|
| .. | .. | 
|---|
| 466 | 475 | * mac, indicate to NEIGH_SUPPRESS ports that we | 
|---|
| 467 | 476 | * have replied | 
|---|
| 468 | 477 | */ | 
|---|
| 469 |  | -			if (replied || br->neigh_suppress_enabled) | 
|---|
| 470 |  | -				BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; | 
|---|
|  | 478 | +			if (replied || | 
|---|
|  | 479 | +			    br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) | 
|---|
|  | 480 | +				BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; | 
|---|
| 471 | 481 | } | 
|---|
| 472 | 482 | neigh_release(n); | 
|---|
| 473 | 483 | } | 
|---|