⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 addrconf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len){	struct prefix_info *pinfo;	__u32 valid_lft;	__u32 prefered_lft;	int addr_type;	unsigned long rt_expires;	struct inet6_dev *in6_dev;	pinfo = (struct prefix_info *) opt;	if (len < sizeof(struct prefix_info)) {		ADBG(("addrconf: prefix option too short\n"));		return;	}	/*	 *	Validation checks ([ADDRCONF], page 19)	 */	addr_type = ipv6_addr_type(&pinfo->prefix);	if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL))		return;	valid_lft = ntohl(pinfo->valid);	prefered_lft = ntohl(pinfo->prefered);	if (prefered_lft > valid_lft) {		if (net_ratelimit())			printk(KERN_WARNING "addrconf: prefix option has invalid lifetime\n");		return;	}	in6_dev = in6_dev_get(dev);	if (in6_dev == NULL) {		if (net_ratelimit())			printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name);		return;	}	/*	 *	Two things going on here:	 *	1) Add routes for on-link prefixes	 *	2) Configure prefixes with the auto flag set	 */	/* Avoid arithmetic overflow. Really, we could	   save rt_expires in seconds, likely valid_lft,	   but it would require division in fib gc, that it	   not good.	 */	if (valid_lft >= 0x7FFFFFFF/HZ)		rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ);	else		rt_expires = valid_lft * HZ;	/*	 * We convert this (in jiffies) to clock_t later.	 * Avoid arithmetic overflow there as well.	 * Overflow can happen only if HZ < USER_HZ.	 */	if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ)		rt_expires = 0x7FFFFFFF / USER_HZ;	if (pinfo->onlink) {		struct rt6_info *rt;		rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1);		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {			if (rt->rt6i_flags&RTF_EXPIRES) {				if (valid_lft == 0) {					ip6_del_rt(rt);					rt = NULL;				} else {					rt->rt6i_expires = jiffies + rt_expires;				}			}		} else if (valid_lft) {			addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,					      dev, jiffies_to_clock_t(rt_expires), RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT);		}		if (rt)			dst_release(&rt->u.dst);	}	/* Try to figure out our local address for this prefix */	if (pinfo->autoconf && in6_dev->cnf.autoconf) {		struct inet6_ifaddr * ifp;		struct in6_addr addr;		int create = 0, update_lft = 0;		if (pinfo->prefix_len == 64) {			memcpy(&addr, &pinfo->prefix, 8);			if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&			    ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) {				in6_dev_put(in6_dev);				return;			}			goto ok;		}		if (net_ratelimit())			printk(KERN_DEBUG "IPv6 addrconf: prefix with wrong length %d\n",			       pinfo->prefix_len);		in6_dev_put(in6_dev);		return;ok:		ifp = ipv6_get_ifaddr(&addr, dev, 1);		if (ifp == NULL && valid_lft) {			int max_addresses = in6_dev->cnf.max_addresses;			u32 addr_flags = 0;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD			if (in6_dev->cnf.optimistic_dad &&			    !ipv6_devconf.forwarding)				addr_flags = IFA_F_OPTIMISTIC;#endif			/* Do not allow to create too much of autoconfigured			 * addresses; this would be too easy way to crash kernel.			 */			if (!max_addresses ||			    ipv6_count_addresses(in6_dev) < max_addresses)				ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,						    addr_type&IPV6_ADDR_SCOPE_MASK,						    addr_flags);			if (!ifp || IS_ERR(ifp)) {				in6_dev_put(in6_dev);				return;			}			update_lft = create = 1;			ifp->cstamp = jiffies;			addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT);		}		if (ifp) {			int flags;			unsigned long now;#ifdef CONFIG_IPV6_PRIVACY			struct inet6_ifaddr *ift;#endif			u32 stored_lft;			/* update lifetime (RFC2462 5.5.3 e) */			spin_lock(&ifp->lock);			now = jiffies;			if (ifp->valid_lft > (now - ifp->tstamp) / HZ)				stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;			else				stored_lft = 0;			if (!update_lft && stored_lft) {				if (valid_lft > MIN_VALID_LIFETIME ||				    valid_lft > stored_lft)					update_lft = 1;				else if (stored_lft <= MIN_VALID_LIFETIME) {					/* valid_lft <= stored_lft is always true */					/* XXX: IPsec */					update_lft = 0;				} else {					valid_lft = MIN_VALID_LIFETIME;					if (valid_lft < prefered_lft)						prefered_lft = valid_lft;					update_lft = 1;				}			}			if (update_lft) {				ifp->valid_lft = valid_lft;				ifp->prefered_lft = prefered_lft;				ifp->tstamp = now;				flags = ifp->flags;				ifp->flags &= ~IFA_F_DEPRECATED;				spin_unlock(&ifp->lock);				if (!(flags&IFA_F_TENTATIVE))					ipv6_ifa_notify(0, ifp);			} else				spin_unlock(&ifp->lock);#ifdef CONFIG_IPV6_PRIVACY			read_lock_bh(&in6_dev->lock);			/* update all temporary addresses in the list */			for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) {				/*				 * When adjusting the lifetimes of an existing				 * temporary address, only lower the lifetimes.				 * Implementations must not increase the				 * lifetimes of an existing temporary address				 * when processing a Prefix Information Option.				 */				spin_lock(&ift->lock);				flags = ift->flags;				if (ift->valid_lft > valid_lft &&				    ift->valid_lft - valid_lft > (jiffies - ift->tstamp) / HZ)					ift->valid_lft = valid_lft + (jiffies - ift->tstamp) / HZ;				if (ift->prefered_lft > prefered_lft &&				    ift->prefered_lft - prefered_lft > (jiffies - ift->tstamp) / HZ)					ift->prefered_lft = prefered_lft + (jiffies - ift->tstamp) / HZ;				spin_unlock(&ift->lock);				if (!(flags&IFA_F_TENTATIVE))					ipv6_ifa_notify(0, ift);			}			if (create && in6_dev->cnf.use_tempaddr > 0) {				/*				 * When a new public address is created as described in [ADDRCONF],				 * also create a new temporary address.				 */				read_unlock_bh(&in6_dev->lock);				ipv6_create_tempaddr(ifp, NULL);			} else {				read_unlock_bh(&in6_dev->lock);			}#endif			in6_ifa_put(ifp);			addrconf_verify(0);		}	}	inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo);	in6_dev_put(in6_dev);}/* *	Set destination address. *	Special case for SIT interfaces where we create a new "virtual" *	device. */int addrconf_set_dstaddr(void __user *arg){	struct in6_ifreq ireq;	struct net_device *dev;	int err = -EINVAL;	rtnl_lock();	err = -EFAULT;	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))		goto err_exit;	dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex);	err = -ENODEV;	if (dev == NULL)		goto err_exit;#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)	if (dev->type == ARPHRD_SIT) {		struct ifreq ifr;		mm_segment_t	oldfs;		struct ip_tunnel_parm p;		err = -EADDRNOTAVAIL;		if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))			goto err_exit;		memset(&p, 0, sizeof(p));		p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];		p.iph.saddr = 0;		p.iph.version = 4;		p.iph.ihl = 5;		p.iph.protocol = IPPROTO_IPV6;		p.iph.ttl = 64;		ifr.ifr_ifru.ifru_data = (void __user *)&p;		oldfs = get_fs(); set_fs(KERNEL_DS);		err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);		set_fs(oldfs);		if (err == 0) {			err = -ENOBUFS;			if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL)				goto err_exit;			err = dev_open(dev);		}	}#endiferr_exit:	rtnl_unlock();	return err;}/* *	Manual configuration of address on an interface */static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,			  __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft){	struct inet6_ifaddr *ifp;	struct inet6_dev *idev;	struct net_device *dev;	int scope;	u32 flags = RTF_EXPIRES;	ASSERT_RTNL();	/* check the lifetime */	if (!valid_lft || prefered_lft > valid_lft)		return -EINVAL;	if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)		return -ENODEV;	if ((idev = addrconf_add_dev(dev)) == NULL)		return -ENOBUFS;	scope = ipv6_addr_scope(pfx);	if (valid_lft == INFINITY_LIFE_TIME) {		ifa_flags |= IFA_F_PERMANENT;		flags = 0;	} else if (valid_lft >= 0x7FFFFFFF/HZ)		valid_lft = 0x7FFFFFFF/HZ;	if (prefered_lft == 0)		ifa_flags |= IFA_F_DEPRECATED;	else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&		 (prefered_lft != INFINITY_LIFE_TIME))		prefered_lft = 0x7FFFFFFF/HZ;	ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);	if (!IS_ERR(ifp)) {		spin_lock_bh(&ifp->lock);		ifp->valid_lft = valid_lft;		ifp->prefered_lft = prefered_lft;		ifp->tstamp = jiffies;		spin_unlock_bh(&ifp->lock);		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,				      jiffies_to_clock_t(valid_lft * HZ), flags);		/*		 * Note that section 3.1 of RFC 4429 indicates		 * that the Optimistic flag should not be set for		 * manually configured addresses		 */		addrconf_dad_start(ifp, 0);		in6_ifa_put(ifp);		addrconf_verify(0);		return 0;	}	return PTR_ERR(ifp);}static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen){	struct inet6_ifaddr *ifp;	struct inet6_dev *idev;	struct net_device *dev;	if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)		return -ENODEV;	if ((idev = __in6_dev_get(dev)) == NULL)		return -ENXIO;	read_lock_bh(&idev->lock);	for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {		if (ifp->prefix_len == plen &&		    ipv6_addr_equal(pfx, &ifp->addr)) {			in6_ifa_hold(ifp);			read_unlock_bh(&idev->lock);			ipv6_del_addr(ifp);			/* If the last address is deleted administratively,			   disable IPv6 on this interface.			 */			if (idev->addr_list == NULL)				addrconf_ifdown(idev->dev, 1);			return 0;		}	}	read_unlock_bh(&idev->lock);	return -EADDRNOTAVAIL;}int addrconf_add_ifaddr(void __user *arg){	struct in6_ifreq ireq;	int err;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))		return -EFAULT;	rtnl_lock();	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,			     IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);	rtnl_unlock();	return err;}int addrconf_del_ifaddr(void __user *arg){	struct in6_ifreq ireq;	int err;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))		return -EFAULT;	rtnl_lock();	err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);	rtnl_unlock();	return err;}#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)static void sit_add_v4_addrs(struct inet6_dev *idev){	struct inet6_ifaddr * ifp;	struct in6_addr addr;	struct net_device *dev;	int scope;	ASSERT_RTNL();	memset(&addr, 0, sizeof(struct in6_addr));	memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4);	if (idev->dev->flags&IFF_POINTOPOINT) {		addr.s6_addr32[0] = htonl(0xfe800000);		scope = IFA_LINK;	} else {		scope = IPV6_ADDR_COMPATv4;	}	if (addr.s6_addr32[3]) {		ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT);		if (!IS_ERR(ifp)) {			spin_lock_bh(&ifp->lock);			ifp->flags &= ~IFA_F_TENTATIVE;			spin_unlock_bh(&ifp->lock);			ipv6_ifa_notify(RTM_NEWADDR, ifp);			in6_ifa_put(ifp);		}		return;	}	for_each_netdev(&init_net, dev) {		struct in_device * in_dev = __in_dev_get_rtnl(dev);		if (in_dev && (dev->flags & IFF_UP)) {			struct in_ifaddr * ifa;			int flag = scope;			for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {				int plen;				addr.s6_addr32[3] = ifa->ifa_local;				if (ifa->ifa_scope == RT_SCOPE_LINK)					continue;				if (ifa->ifa_scope >= RT_SCOPE_HOST) {					if (idev->dev->flags&IFF_POINTOPOINT)						continue;					flag |= IFA_HOST;				}				if (idev->dev->flags&IFF_POINTOPOINT)					plen = 64;				else					plen = 96;				ifp = ipv6_add_addr(idev, &addr, plen, flag,						    IFA_F_PERMANENT);				if (!IS_ERR(ifp)) {					spin_lock_bh(&ifp->lock);					ifp->flags &= ~IFA_F_TENTATIVE;					spin_unlock_bh(&ifp->lock);					ipv6_ifa_notify(RTM_NEWADDR, ifp);					in6_ifa_put(ifp);				}			}		}	}}#endifstatic void init_loopback(struct net_device *dev){	struct inet6_dev  *idev;	struct inet6_ifaddr * ifp;	/* ::1 */	ASSERT_RTNL();	if ((idev = ipv6_find_idev(dev)) == NULL) {		printk(KERN_DEBUG "init loopback: add_dev failed\n");		return;	}	ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT);	if (!IS_ERR(ifp)) {		spin_lock_bh(&ifp->lock);		ifp->flags &= ~IFA_F_TENTATIVE;		spin_unlock_bh(&ifp->lock);		ipv6_ifa_notify(RTM_NEWADDR, ifp);		in6_ifa_put(ifp);	}}static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr){	struct inet6_ifaddr * ifp;	u32 addr_flags = IFA_F_PERMANENT;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD	if (idev->cnf.optimistic_dad &&	    !ipv6_devconf.forwarding)		addr_flags |= IFA_F_OPTIMISTIC;#endif	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);	if (!IS_ERR(ifp)) {		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);		addrconf_dad_start(ifp, 0);		in6_ifa_put(ifp);	}}static void addrconf_dev_config(struct net_device *dev){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -