7649 lines · 189.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* *	IPv6 Address [auto]configuration *	Linux INET6 implementation * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt> *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru> */ /* *	Changes: * *	Janos Farkas			:	delete timer on ifdown *	<chexum@bankinf.banki.hu> *	Andi Kleen			:	kill double kfree on module *						unload. *	Maciej W. Rozycki		:	FDDI support *	sekiya@USAGI			:	Don't send too many RS *						packets. *	yoshfuji@USAGI			:       Fixed interval between DAD *						packets. *	YOSHIFUJI Hideaki @USAGI	:	improved accuracy of *						address validation timer. *	YOSHIFUJI Hideaki @USAGI	:	Privacy Extensions (RFC3041) *						support. *	Yuji SEKIYA @USAGI		:	Don't assign a same IPv6 *						address on a same interface. *	YOSHIFUJI Hideaki @USAGI	:	ARCnet support *	YOSHIFUJI Hideaki @USAGI	:	convert /proc/net/if_inet6 to *						seq_file. *	YOSHIFUJI Hideaki @USAGI	:	improved source address *						selection; consider scope, *						status etc. */ #define pr_fmt(fmt) "IPv6: " fmt #include <crypto/sha1.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched/signal.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/inet.h>#include <linux/in6.h>#include <linux/netdevice.h>#include <linux/if_addr.h>#include <linux/if_arp.h>#include <linux/if_arcnet.h>#include <linux/if_infiniband.h>#include <linux/route.h>#include <linux/inetdevice.h>#include <linux/init.h>#include <linux/slab.h>#ifdef CONFIG_SYSCTL#include <linux/sysctl.h>#endif#include <linux/capability.h>#include <linux/delay.h>#include <linux/notifier.h>#include <linux/string.h>#include <linux/hash.h> #include <net/ip_tunnels.h>#include <net/net_namespace.h>#include <net/sock.h>#include <net/snmp.h> #include <net/6lowpan.h>#include <net/firewire.h>#include <net/ipv6.h>#include <net/protocol.h>#include <net/ndisc.h>#include <net/ip6_route.h>#include <net/addrconf.h>#include <net/tcp.h>#include <net/ip.h>#include <net/netlink.h>#include <net/pkt_sched.h>#include <net/l3mdev.h>#include <net/netdev_lock.h>#include <linux/if_tunnel.h>#include <linux/rtnetlink.h>#include <linux/netconf.h>#include <linux/random.h>#include <linux/uaccess.h>#include <linux/unaligned.h> #include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/export.h>#include <linux/ioam6.h> #define IPV6_MAX_STRLEN \	sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") static inline u32 cstamp_delta(unsigned long cstamp){	return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;} static inline s32 rfc3315_s14_backoff_init(s32 irt){	/* multiply 'initial retransmission time' by 0.9 .. 1.1 */	u64 tmp = get_random_u32_inclusive(900000, 1100000) * (u64)irt;	do_div(tmp, 1000000);	return (s32)tmp;} static inline s32 rfc3315_s14_backoff_update(s32 rt, s32 mrt){	/* multiply 'retransmission timeout' by 1.9 .. 2.1 */	u64 tmp = get_random_u32_inclusive(1900000, 2100000) * (u64)rt;	do_div(tmp, 1000000);	if ((s32)tmp > mrt) {		/* multiply 'maximum retransmission time' by 0.9 .. 1.1 */		tmp = get_random_u32_inclusive(900000, 1100000) * (u64)mrt;		do_div(tmp, 1000000);	}	return (s32)tmp;} #ifdef CONFIG_SYSCTLstatic int addrconf_sysctl_register(struct inet6_dev *idev);static void addrconf_sysctl_unregister(struct inet6_dev *idev);#elsestatic inline int addrconf_sysctl_register(struct inet6_dev *idev){	return 0;} static inline void addrconf_sysctl_unregister(struct inet6_dev *idev){}#endif static void ipv6_gen_rnd_iid(struct in6_addr *addr); static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);static int ipv6_count_addresses(const struct inet6_dev *idev);static int ipv6_generate_stable_address(struct in6_addr *addr,					u8 dad_count,					const struct inet6_dev *idev); #define IN6_ADDR_HSIZE_SHIFT	8#define IN6_ADDR_HSIZE		(1 << IN6_ADDR_HSIZE_SHIFT) static void addrconf_verify(struct net *net);static void addrconf_verify_rtnl(struct net *net); static struct workqueue_struct *addrconf_wq; static void addrconf_join_anycast(struct inet6_ifaddr *ifp);static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); static void addrconf_type_change(struct net_device *dev,				 unsigned long event);static int addrconf_ifdown(struct net_device *dev, bool unregister); static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,						  int plen,						  const struct net_device *dev,						  u32 flags, u32 noflags,						  bool no_gw); static void addrconf_dad_start(struct inet6_ifaddr *ifp);static void addrconf_dad_work(struct work_struct *w);static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id,				   bool send_na);static void addrconf_dad_run(struct inet6_dev *idev, bool restart);static void addrconf_rs_timer(struct timer_list *t);static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); static void inet6_prefix_notify(int event, struct inet6_dev *idev,				struct prefix_info *pinfo); static struct ipv6_devconf ipv6_devconf __read_mostly = {	.forwarding		= 0,	.hop_limit		= IPV6_DEFAULT_HOPLIMIT,	.mtu6			= IPV6_MIN_MTU,	.accept_ra		= 1,	.accept_redirects	= 1,	.autoconf		= 1,	.force_mld_version	= 0,	.mldv1_unsolicited_report_interval = 10 * HZ,	.mldv2_unsolicited_report_interval = HZ,	.dad_transmits		= 1,	.rtr_solicits		= MAX_RTR_SOLICITATIONS,	.rtr_solicit_interval	= RTR_SOLICITATION_INTERVAL,	.rtr_solicit_max_interval = RTR_SOLICITATION_MAX_INTERVAL,	.rtr_solicit_delay	= MAX_RTR_SOLICITATION_DELAY,	.use_tempaddr		= 0,	.temp_valid_lft		= TEMP_VALID_LIFETIME,	.temp_prefered_lft	= TEMP_PREFERRED_LIFETIME,	.regen_min_advance	= REGEN_MIN_ADVANCE,	.regen_max_retry	= REGEN_MAX_RETRY,	.max_desync_factor	= MAX_DESYNC_FACTOR,	.max_addresses		= IPV6_MAX_ADDRESSES,	.accept_ra_defrtr	= 1,	.ra_defrtr_metric	= IP6_RT_PRIO_USER,	.accept_ra_from_local	= 0,	.accept_ra_min_hop_limit= 1,	.accept_ra_min_lft	= 0,	.accept_ra_pinfo	= 1,#ifdef CONFIG_IPV6_ROUTER_PREF	.accept_ra_rtr_pref	= 1,	.rtr_probe_interval	= 60 * HZ,#ifdef CONFIG_IPV6_ROUTE_INFO	.accept_ra_rt_info_min_plen = 0,	.accept_ra_rt_info_max_plen = 0,#endif#endif	.proxy_ndp		= 0,	.accept_source_route	= 0,	/* we do not accept RH0 by default. */	.disable_ipv6		= 0,	.accept_dad		= 0,	.suppress_frag_ndisc	= 1,	.accept_ra_mtu		= 1,	.stable_secret		= {		.initialized = false,	},	.use_oif_addrs_only	= 0,	.ignore_routes_with_linkdown = 0,	.keep_addr_on_down	= 0,	.seg6_enabled		= 0,#ifdef CONFIG_IPV6_SEG6_HMAC	.seg6_require_hmac	= 0,#endif	.enhanced_dad           = 1,	.addr_gen_mode		= IN6_ADDR_GEN_MODE_EUI64,	.disable_policy		= 0,	.rpl_seg_enabled	= 0,	.ioam6_enabled		= 0,	.ioam6_id               = IOAM6_DEFAULT_IF_ID,	.ioam6_id_wide		= IOAM6_DEFAULT_IF_ID_WIDE,	.ndisc_evict_nocarrier	= 1,	.ra_honor_pio_life	= 0,	.ra_honor_pio_pflag	= 0,	.force_forwarding	= 0,}; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {	.forwarding		= 0,	.hop_limit		= IPV6_DEFAULT_HOPLIMIT,	.mtu6			= IPV6_MIN_MTU,	.accept_ra		= 1,	.accept_redirects	= 1,	.autoconf		= 1,	.force_mld_version	= 0,	.mldv1_unsolicited_report_interval = 10 * HZ,	.mldv2_unsolicited_report_interval = HZ,	.dad_transmits		= 1,	.rtr_solicits		= MAX_RTR_SOLICITATIONS,	.rtr_solicit_interval	= RTR_SOLICITATION_INTERVAL,	.rtr_solicit_max_interval = RTR_SOLICITATION_MAX_INTERVAL,	.rtr_solicit_delay	= MAX_RTR_SOLICITATION_DELAY,	.use_tempaddr		= 0,	.temp_valid_lft		= TEMP_VALID_LIFETIME,	.temp_prefered_lft	= TEMP_PREFERRED_LIFETIME,	.regen_min_advance	= REGEN_MIN_ADVANCE,	.regen_max_retry	= REGEN_MAX_RETRY,	.max_desync_factor	= MAX_DESYNC_FACTOR,	.max_addresses		= IPV6_MAX_ADDRESSES,	.accept_ra_defrtr	= 1,	.ra_defrtr_metric	= IP6_RT_PRIO_USER,	.accept_ra_from_local	= 0,	.accept_ra_min_hop_limit= 1,	.accept_ra_min_lft	= 0,	.accept_ra_pinfo	= 1,#ifdef CONFIG_IPV6_ROUTER_PREF	.accept_ra_rtr_pref	= 1,	.rtr_probe_interval	= 60 * HZ,#ifdef CONFIG_IPV6_ROUTE_INFO	.accept_ra_rt_info_min_plen = 0,	.accept_ra_rt_info_max_plen = 0,#endif#endif	.proxy_ndp		= 0,	.accept_source_route	= 0,	/* we do not accept RH0 by default. */	.disable_ipv6		= 0,	.accept_dad		= 1,	.suppress_frag_ndisc	= 1,	.accept_ra_mtu		= 1,	.stable_secret		= {		.initialized = false,	},	.use_oif_addrs_only	= 0,	.ignore_routes_with_linkdown = 0,	.keep_addr_on_down	= 0,	.seg6_enabled		= 0,#ifdef CONFIG_IPV6_SEG6_HMAC	.seg6_require_hmac	= 0,#endif	.enhanced_dad           = 1,	.addr_gen_mode		= IN6_ADDR_GEN_MODE_EUI64,	.disable_policy		= 0,	.rpl_seg_enabled	= 0,	.ioam6_enabled		= 0,	.ioam6_id               = IOAM6_DEFAULT_IF_ID,	.ioam6_id_wide		= IOAM6_DEFAULT_IF_ID_WIDE,	.ndisc_evict_nocarrier	= 1,	.ra_honor_pio_life	= 0,	.ra_honor_pio_pflag	= 0,	.force_forwarding	= 0,}; /* Check if link is ready: is it up and is a valid qdisc available */static inline bool addrconf_link_ready(const struct net_device *dev){	return netif_oper_up(dev) && !qdisc_tx_is_noop(dev);} static void addrconf_del_rs_timer(struct inet6_dev *idev){	if (timer_delete(&idev->rs_timer))		__in6_dev_put(idev);} static void addrconf_del_dad_work(struct inet6_ifaddr *ifp){	if (cancel_delayed_work(&ifp->dad_work))		__in6_ifa_put(ifp);} static void addrconf_mod_rs_timer(struct inet6_dev *idev,				  unsigned long when){	if (!mod_timer(&idev->rs_timer, jiffies + when))		in6_dev_hold(idev);} static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp,				   unsigned long delay){	in6_ifa_hold(ifp);	if (mod_delayed_work(addrconf_wq, &ifp->dad_work, delay))		in6_ifa_put(ifp);} static int snmp6_alloc_dev(struct inet6_dev *idev){	int i; 	idev->stats.ipv6 = alloc_percpu_gfp(struct ipstats_mib, GFP_KERNEL_ACCOUNT);	if (!idev->stats.ipv6)		goto err_ip; 	for_each_possible_cpu(i) {		struct ipstats_mib *addrconf_stats;		addrconf_stats = per_cpu_ptr(idev->stats.ipv6, i);		u64_stats_init(&addrconf_stats->syncp);	}  	idev->stats.icmpv6dev = kzalloc_obj(struct icmpv6_mib_device);	if (!idev->stats.icmpv6dev)		goto err_icmp;	idev->stats.icmpv6msgdev = kzalloc_obj(struct icmpv6msg_mib_device,					       GFP_KERNEL_ACCOUNT);	if (!idev->stats.icmpv6msgdev)		goto err_icmpmsg; 	return 0; err_icmpmsg:	kfree(idev->stats.icmpv6dev);err_icmp:	free_percpu(idev->stats.ipv6);err_ip:	return -ENOMEM;} static struct inet6_dev *ipv6_add_dev(struct net_device *dev){	struct inet6_dev *ndev;	int err = -ENOMEM; 	ASSERT_RTNL();	netdev_assert_locked_ops_compat(dev); 	if (dev->mtu < IPV6_MIN_MTU && dev != blackhole_netdev)		return ERR_PTR(-EINVAL); 	ndev = kzalloc_obj(*ndev, GFP_KERNEL_ACCOUNT);	if (!ndev)		return ERR_PTR(err); 	rwlock_init(&ndev->lock);	ndev->dev = dev;	INIT_LIST_HEAD(&ndev->addr_list);	timer_setup(&ndev->rs_timer, addrconf_rs_timer, 0);	memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); 	if (ndev->cnf.stable_secret.initialized)		ndev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; 	ndev->cnf.mtu6 = dev->mtu;	ndev->ra_mtu = 0;	ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);	if (!ndev->nd_parms) {		kfree(ndev);		return ERR_PTR(err);	}	if (ndev->cnf.forwarding)		netif_disable_lro(dev);	/* We refer to the device */	netdev_hold(dev, &ndev->dev_tracker, GFP_KERNEL); 	if (snmp6_alloc_dev(ndev) < 0) {		netdev_dbg(dev, "%s: cannot allocate memory for statistics\n",			   __func__);		neigh_parms_release(&nd_tbl, ndev->nd_parms);		netdev_put(dev, &ndev->dev_tracker);		kfree(ndev);		return ERR_PTR(err);	} 	if (dev != blackhole_netdev) {		if (snmp6_register_dev(ndev) < 0) {			netdev_dbg(dev, "%s: cannot create /proc/net/dev_snmp6/%s\n",				   __func__, dev->name);			goto err_release;		}	}	/* One reference from device. */	refcount_set(&ndev->refcnt, 1); 	if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))		ndev->cnf.accept_dad = -1; #if IS_ENABLED(CONFIG_IPV6_SIT)	if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {		pr_info("%s: Disabled Multicast RS\n", dev->name);		ndev->cnf.rtr_solicits = 0;	}#endif 	INIT_LIST_HEAD(&ndev->tempaddr_list);	ndev->desync_factor = U32_MAX;	if ((dev->flags&IFF_LOOPBACK) ||	    dev->type == ARPHRD_TUNNEL ||	    dev->type == ARPHRD_TUNNEL6 ||	    dev->type == ARPHRD_SIT ||	    dev->type == ARPHRD_NONE) {		ndev->cnf.use_tempaddr = -1;	} 	ndev->token = in6addr_any; 	if (netif_running(dev) && addrconf_link_ready(dev))		ndev->if_flags |= IF_READY; 	ipv6_mc_init_dev(ndev);	ndev->tstamp = jiffies;	if (dev != blackhole_netdev) {		err = addrconf_sysctl_register(ndev);		if (err) {			ipv6_mc_destroy_dev(ndev);			snmp6_unregister_dev(ndev);			goto err_release;		}	}	/* protected by rtnl_lock */	rcu_assign_pointer(dev->ip6_ptr, ndev); 	if (dev != blackhole_netdev) {		/* Join interface-local all-node multicast group */		ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes); 		/* Join all-node multicast group */		ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); 		/* Join all-router multicast group if forwarding is set */		if (ndev->cnf.forwarding && (dev->flags & IFF_MULTICAST))			ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);	}	return ndev; err_release:	neigh_parms_release(&nd_tbl, ndev->nd_parms);	ndev->dead = 1;	in6_dev_finish_destroy(ndev);	return ERR_PTR(err);} static struct inet6_dev *ipv6_find_idev(struct net_device *dev){	struct inet6_dev *idev; 	ASSERT_RTNL(); 	idev = __in6_dev_get(dev);	if (!idev) {		idev = ipv6_add_dev(dev);		if (IS_ERR(idev))			return idev;

Lines 1–500 of 7649.