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

📄 addrconf.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	__ipv6_dev_ac_dec(ifp->idev, &addr);}static int ipv6_generate_eui64(u8 *eui, struct net_device *dev){	switch (dev->type) {	case ARPHRD_ETHER:	case ARPHRD_FDDI:	case ARPHRD_IEEE802_TR:		if (dev->addr_len != ETH_ALEN)			return -1;		memcpy(eui, dev->dev_addr, 3);		memcpy(eui + 5, dev->dev_addr+3, 3);		eui[3] = 0xFF;		eui[4] = 0xFE;		eui[0] ^= 2;		return 0;	case ARPHRD_ARCNET:		/* XXX: inherit EUI-64 from other interface -- yoshfuji */		if (dev->addr_len != ARCNET_ALEN)			return -1;		memset(eui, 0, 7);		eui[7] = *(u8*)dev->dev_addr;		return 0;	}	return -1;}static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev){	int err = -1;	struct inet6_ifaddr *ifp;	read_lock_bh(&idev->lock);	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {		if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {			memcpy(eui, ifp->addr.s6_addr+8, 8);			err = 0;			break;		}	}	read_unlock_bh(&idev->lock);	return err;}#ifdef CONFIG_IPV6_PRIVACY/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */static int __ipv6_regen_rndid(struct inet6_dev *idev){	struct net_device *dev;	struct scatterlist sg[2];	sg[0].page = virt_to_page(idev->entropy);	sg[0].offset = offset_in_page(idev->entropy);	sg[0].length = 8;	sg[1].page = virt_to_page(idev->work_eui64);	sg[1].offset = offset_in_page(idev->work_eui64);	sg[1].length = 8;	dev = idev->dev;	if (ipv6_generate_eui64(idev->work_eui64, dev)) {		printk(KERN_INFO			"__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",			idev);		get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64));	}regen:	spin_lock(&md5_tfm_lock);	if (unlikely(md5_tfm == NULL)) {		spin_unlock(&md5_tfm_lock);		return -1;	}	crypto_digest_init(md5_tfm);	crypto_digest_update(md5_tfm, sg, 2);	crypto_digest_final(md5_tfm, idev->work_digest);	spin_unlock(&md5_tfm_lock);	memcpy(idev->rndid, &idev->work_digest[0], 8);	idev->rndid[0] &= ~0x02;	memcpy(idev->entropy, &idev->work_digest[8], 8);	/*	 * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:	 * check if generated address is not inappropriate	 *	 *  - Reserved subnet anycast (RFC 2526)	 *	11111101 11....11 1xxxxxxx	 *  - ISATAP (draft-ietf-ngtrans-isatap-13.txt) 5.1	 *	00-00-5E-FE-xx-xx-xx-xx	 *  - value 0	 *  - XXX: already assigned to an address on the device	 */	if (idev->rndid[0] == 0xfd && 	    (idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff &&	    (idev->rndid[7]&0x80))		goto regen;	if ((idev->rndid[0]|idev->rndid[1]) == 0) {		if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe)			goto regen;		if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00)			goto regen;	}	return 0;}static void ipv6_regen_rndid(unsigned long data){	struct inet6_dev *idev = (struct inet6_dev *) data;	unsigned long expires;	read_lock_bh(&addrconf_lock);	write_lock_bh(&idev->lock);	if (idev->dead)		goto out;	if (__ipv6_regen_rndid(idev) < 0)		goto out;		expires = jiffies +		idev->cnf.temp_prefered_lft * HZ - 		idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;	if (time_before(expires, jiffies)) {		printk(KERN_WARNING			"ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n",			idev->dev->name);		goto out;	}	if (!mod_timer(&idev->regen_timer, expires))		in6_dev_hold(idev);out:	write_unlock_bh(&idev->lock);	read_unlock_bh(&addrconf_lock);	in6_dev_put(idev);}static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {	int ret = 0;	if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0)		ret = __ipv6_regen_rndid(idev);	return ret;}#endif/* *	Add prefix route. */static voidaddrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,		      unsigned long expires, unsigned flags){	struct in6_rtmsg rtmsg;	memset(&rtmsg, 0, sizeof(rtmsg));	ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx);	rtmsg.rtmsg_dst_len = plen;	rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;	rtmsg.rtmsg_ifindex = dev->ifindex;	rtmsg.rtmsg_info = expires;	rtmsg.rtmsg_flags = RTF_UP|flags;	rtmsg.rtmsg_type = RTMSG_NEWROUTE;	/* Prevent useless cloning on PtP SIT.	   This thing is done here expecting that the whole	   class of non-broadcast devices need not cloning.	 */	if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))		rtmsg.rtmsg_flags |= RTF_NONEXTHOP;	ip6_route_add(&rtmsg, NULL, NULL);}/* Create "default" multicast route to the interface */static void addrconf_add_mroute(struct net_device *dev){	struct in6_rtmsg rtmsg;	memset(&rtmsg, 0, sizeof(rtmsg));	ipv6_addr_set(&rtmsg.rtmsg_dst,		      htonl(0xFF000000), 0, 0, 0);	rtmsg.rtmsg_dst_len = 8;	rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;	rtmsg.rtmsg_ifindex = dev->ifindex;	rtmsg.rtmsg_flags = RTF_UP;	rtmsg.rtmsg_type = RTMSG_NEWROUTE;	ip6_route_add(&rtmsg, NULL, NULL);}static void sit_route_add(struct net_device *dev){	struct in6_rtmsg rtmsg;	memset(&rtmsg, 0, sizeof(rtmsg));	rtmsg.rtmsg_type	= RTMSG_NEWROUTE;	rtmsg.rtmsg_metric	= IP6_RT_PRIO_ADDRCONF;	/* prefix length - 96 bits "::d.d.d.d" */	rtmsg.rtmsg_dst_len	= 96;	rtmsg.rtmsg_flags	= RTF_UP|RTF_NONEXTHOP;	rtmsg.rtmsg_ifindex	= dev->ifindex;	ip6_route_add(&rtmsg, NULL, NULL);}static void addrconf_add_lroute(struct net_device *dev){	struct in6_addr addr;	ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);	addrconf_prefix_route(&addr, 64, dev, 0, 0);}static struct inet6_dev *addrconf_add_dev(struct net_device *dev){	struct inet6_dev *idev;	ASSERT_RTNL();	if ((idev = ipv6_find_idev(dev)) == NULL)		return NULL;	/* Add default multicast route */	addrconf_add_mroute(dev);	/* Add link local route */	addrconf_add_lroute(dev);	return idev;}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 = 0;	else		rt_expires = jiffies + valid_lft * 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, NULL, NULL);					rt = NULL;				} else {					rt->rt6i_expires = rt_expires;				}			}		} else if (valid_lft) {			addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,					      dev, 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;			/* 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, 0);			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(ireq.ifr6_ifindex);	err = -ENODEV;	if (dev == NULL)		goto err_exit;	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(p.name)) == NULL)				goto err_exit;			err = dev_open(dev);		}	}err_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){	struct inet6_ifaddr *ifp;	struct inet6_dev *idev;	struct net_device *dev;	int scope;	ASSERT_RTNL();		if ((dev = __dev_get_by_index(ifindex)) == NULL)		return -ENODEV;		if (!(dev->flags&IFF_UP))		return -ENETDOWN;	if ((idev = addrconf_add_dev(dev)) == NULL)		return -ENOBUFS;	scope = ipv6_addr_scope(pfx);	ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);	if (!IS_ERR(ifp)) {		addrconf_dad_start(ifp, 0);		in6_ifa_put(ifp);		return 0;	}	return PTR_ERR(ifp);}static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen){	struct inet6_ifaddr *ifp;

⌨️ 快捷键说明

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