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

ipv4: fix wildcard search with inet_confirm_addr()

Help of this function says: "in_dev: only on this interface, 0=any interface",
but since commit 39a6d0630012 ("[NETNS]: Process inet_confirm_addr in the
correct namespace."), the code supposes that it will never be NULL. This
function is never called with in_dev == NULL, but it's exported and may be used
by an external module.

Because this patch restore the ability to call inet_confirm_addr() with in_dev
== NULL, I partially revert the above commit, as suggested by Julian.

CC: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Nicolas Dichtel and committed by
David S. Miller
b601fa19 95ab0991

+11 -11
+2 -2
drivers/net/bonding/bonding.h
··· 394 394 in_dev = __in_dev_get_rcu(dev); 395 395 396 396 if (in_dev) 397 - addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST); 398 - 397 + addr = inet_confirm_addr(dev_net(dev), in_dev, dst, local, 398 + RT_SCOPE_HOST); 399 399 rcu_read_unlock(); 400 400 return addr; 401 401 }
+2 -3
include/linux/inetdevice.h
··· 164 164 void devinet_init(void); 165 165 struct in_device *inetdev_by_index(struct net *, int); 166 166 __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); 167 - __be32 inet_confirm_addr(struct in_device *in_dev, __be32 dst, __be32 local, 168 - int scope); 167 + __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, 168 + __be32 local, int scope); 169 169 struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, 170 170 __be32 mask); 171 - 172 171 static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) 173 172 { 174 173 return !((addr^ifa->ifa_address)&ifa->ifa_mask);
+3 -1
net/ipv4/arp.c
··· 381 381 382 382 static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) 383 383 { 384 + struct net *net = dev_net(in_dev->dev); 384 385 int scope; 385 386 386 387 switch (IN_DEV_ARP_IGNORE(in_dev)) { ··· 400 399 case 3: /* Do not reply for scope host addresses */ 401 400 sip = 0; 402 401 scope = RT_SCOPE_LINK; 402 + in_dev = NULL; 403 403 break; 404 404 case 4: /* Reserved */ 405 405 case 5: ··· 412 410 default: 413 411 return 0; 414 412 } 415 - return !inet_confirm_addr(in_dev, sip, tip, scope); 413 + return !inet_confirm_addr(net, in_dev, sip, tip, scope); 416 414 } 417 415 418 416 static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
+4 -5
net/ipv4/devinet.c
··· 1240 1240 1241 1241 /* 1242 1242 * Confirm that local IP address exists using wildcards: 1243 - * - in_dev: only on this interface, 0=any interface 1243 + * - net: netns to check, cannot be NULL 1244 + * - in_dev: only on this interface, NULL=any interface 1244 1245 * - dst: only in the same subnet as dst, 0=any dst 1245 1246 * - local: address, 0=autoselect the local address 1246 1247 * - scope: maximum allowed scope value for the local address 1247 1248 */ 1248 - __be32 inet_confirm_addr(struct in_device *in_dev, 1249 + __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, 1249 1250 __be32 dst, __be32 local, int scope) 1250 1251 { 1251 1252 __be32 addr = 0; 1252 1253 struct net_device *dev; 1253 - struct net *net; 1254 1254 1255 - if (scope != RT_SCOPE_LINK) 1255 + if (in_dev != NULL) 1256 1256 return confirm_addr_indev(in_dev, dst, local, scope); 1257 1257 1258 - net = dev_net(in_dev->dev); 1259 1258 rcu_read_lock(); 1260 1259 for_each_netdev_rcu(net, dev) { 1261 1260 in_dev = __in_dev_get_rcu(dev);