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

ipv6: enable anycast addresses as source addresses for datagrams

This change allows to consider an anycast address valid as source address
when given via an IPV6_PKTINFO or IPV6_2292PKTINFO ancillary data item.
So, when sending a datagram with ancillary data, the unicast and anycast
addresses are handled in the same way.

- Adds ipv6_chk_acast_addr_src() to check if an anycast address is link-local
on given interface or is global.
- Uses it in ip6_datagram_send_ctl().

Signed-off-by: Francois-Xavier Le Bail <fx.lebail@yahoo.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

FX Le Bail and committed by
David S. Miller
7c90cc2d eb97768a

+17 -3
+3 -2
include/net/addrconf.h
··· 205 205 int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr); 206 206 int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr); 207 207 bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, 208 - const struct in6_addr *addr); 209 - 208 + const struct in6_addr *addr); 209 + bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, 210 + const struct in6_addr *addr); 210 211 211 212 /* Device notifier */ 212 213 int register_inet6addr_notifier(struct notifier_block *nb);
+11
net/ipv6/anycast.c
··· 383 383 return found; 384 384 } 385 385 386 + /* check if this anycast address is link-local on given interface or 387 + * is global 388 + */ 389 + bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, 390 + const struct in6_addr *addr) 391 + { 392 + return ipv6_chk_acast_addr(net, 393 + (ipv6_addr_type(addr) & IPV6_ADDR_LINKLOCAL ? 394 + dev : NULL), 395 + addr); 396 + } 386 397 387 398 #ifdef CONFIG_PROC_FS 388 399 struct ac6_iter_state {
+3 -1
net/ipv6/datagram.c
··· 699 699 int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; 700 700 if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) && 701 701 !ipv6_chk_addr(net, &src_info->ipi6_addr, 702 - strict ? dev : NULL, 0)) 702 + strict ? dev : NULL, 0) && 703 + !ipv6_chk_acast_addr_src(net, dev, 704 + &src_info->ipi6_addr)) 703 705 err = -EINVAL; 704 706 else 705 707 fl6->saddr = src_info->ipi6_addr;