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

📄 addrconf.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 4 页
字号:
	for (dev = dev_base; dev; dev=dev->next) {		idev = __in6_dev_get(dev);		if (idev) {			read_lock_bh(&idev->lock);			for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {				if (ifp->scope == scope) {					if (!(ifp->flags&(IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {						in6_ifa_hold(ifp);						read_unlock_bh(&idev->lock);						goto out_unlock_base;					}					if (!match && !(ifp->flags&IFA_F_TENTATIVE)) {						match = ifp;						in6_ifa_hold(ifp);					}				}			}			read_unlock_bh(&idev->lock);		}	}out_unlock_base:	read_unlock(&addrconf_lock);	read_unlock(&dev_base_lock);out:	if (ifp == NULL) {		ifp = match;		match = NULL;	}	err = -EADDRNOTAVAIL;	if (ifp) {		ipv6_addr_copy(saddr, &ifp->addr);		err = 0;		in6_ifa_put(ifp);	}	if (match)		in6_ifa_put(match);	return err;}int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr){	struct inet6_dev *idev;	int err = -EADDRNOTAVAIL;	read_lock(&addrconf_lock);	if ((idev = __in6_dev_get(dev)) != NULL) {		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)) {				ipv6_addr_copy(addr, &ifp->addr);				err = 0;				break;			}		}		read_unlock_bh(&idev->lock);	}	read_unlock(&addrconf_lock);	return err;}int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev){	struct inet6_ifaddr * ifp;	u8 hash = ipv6_addr_hash(addr);	read_lock_bh(&addrconf_hash_lock);	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {		if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&		    !(ifp->flags&IFA_F_TENTATIVE)) {			if (dev == NULL || ifp->idev->dev == dev ||			    !(ifp->scope&(IFA_LINK|IFA_HOST)))				break;		}	}	read_unlock_bh(&addrconf_hash_lock);	return ifp != NULL;}struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev){	struct inet6_ifaddr * ifp;	u8 hash = ipv6_addr_hash(addr);	read_lock_bh(&addrconf_hash_lock);	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {		if (ipv6_addr_cmp(&ifp->addr, addr) == 0) {			if (dev == NULL || ifp->idev->dev == dev ||			    !(ifp->scope&(IFA_LINK|IFA_HOST))) {				in6_ifa_hold(ifp);				break;			}		}	}	read_unlock_bh(&addrconf_hash_lock);	return ifp;}/* Gets referenced address, destroys ifaddr */void addrconf_dad_failure(struct inet6_ifaddr *ifp){	if (net_ratelimit())		printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);	if (ifp->flags&IFA_F_PERMANENT) {		spin_lock_bh(&ifp->lock);		addrconf_del_timer(ifp);		ifp->flags |= IFA_F_TENTATIVE;		spin_unlock_bh(&ifp->lock);		in6_ifa_put(ifp);	} else		ipv6_del_addr(ifp);}/* Join to solicited addr multicast group. */static void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr){	struct in6_addr maddr;	if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))		return;	addrconf_addr_solict_mult(addr, &maddr);	ipv6_dev_mc_inc(dev, &maddr);}static void addrconf_leave_solict(struct net_device *dev, struct in6_addr *addr){	struct in6_addr maddr;	if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))		return;	addrconf_addr_solict_mult(addr, &maddr);	ipv6_dev_mc_dec(dev, &maddr);}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;	}	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;}/* *	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));	memcpy(&rtmsg.rtmsg_dst, pfx, sizeof(struct in6_addr));	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);}/* 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,		      __constant_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|RTF_ADDRCONF;	rtmsg.rtmsg_type = RTMSG_NEWROUTE;	ip6_route_add(&rtmsg);}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 bytes "::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);}static void addrconf_add_lroute(struct net_device *dev){	struct in6_addr addr;	ipv6_addr_set(&addr,  __constant_htonl(0xFE800000), 0, 0, 0);	addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);}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;	struct rt6_info *rt;	__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 arithemtic 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;	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 (pinfo->onlink == 0 || valid_lft == 0) {				ip6_del_rt(rt);				rt = NULL;			} else {				rt->rt6i_expires = rt_expires;			}		}	} else if (pinfo->onlink && valid_lft) {		addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,				      dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES);	}	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 plen;		plen = pinfo->prefix_len >> 3;		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);		if (ifp == NULL && valid_lft) {			ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,					    addr_type&IPV6_ADDR_SCOPE_MASK, 0);			if (ifp == NULL) {				in6_dev_put(in6_dev);				return;			}			addrconf_dad_start(ifp);		}		if (ifp && valid_lft == 0) {			ipv6_del_addr(ifp);			ifp = NULL;		}		if (ifp) {			int flags;			spin_lock(&ifp->lock);			ifp->valid_lft = valid_lft;			ifp->prefered_lft = prefered_lft;			ifp->tstamp = jiffies;			flags = ifp->flags;			ifp->flags &= ~IFA_F_DEPRECATED;			spin_unlock(&ifp->lock);			if (!(flags&IFA_F_TENTATIVE))				ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ?						0 : RTM_NEWADDR, ifp);			in6_ifa_put(ifp);		}	}	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 *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*)&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);	if ((ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT)) != NULL) {		addrconf_dad_start(ifp);		in6_ifa_put(ifp);		return 0;	}	return -ENOBUFS;}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(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 &&		    (!memcmp(pfx, &ifp->addr, sizeof(struct in6_addr)))) {			in6_ifa_hold(ifp);			read_unlock_bh(&idev->lock);			

⌨️ 快捷键说明

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