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

📄 addrconf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		ADBG(("ipv6_add_addr: already assigned\n"));		err = -EEXIST;		goto out;	}	ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);	if (ifa == NULL) {		ADBG(("ipv6_add_addr: malloc failed\n"));		err = -ENOBUFS;		goto out;	}	rt = addrconf_dst_alloc(idev, addr, 0);	if (IS_ERR(rt)) {		err = PTR_ERR(rt);		goto out;	}	ipv6_addr_copy(&ifa->addr, addr);	spin_lock_init(&ifa->lock);	init_timer(&ifa->timer);	ifa->timer.data = (unsigned long) ifa;	ifa->scope = scope;	ifa->prefix_len = pfxlen;	ifa->flags = flags | IFA_F_TENTATIVE;	ifa->cstamp = ifa->tstamp = jiffies;	ifa->rt = rt;	/*	 * part one of RFC 4429, section 3.3	 * We should not configure an address as	 * optimistic if we do not yet know the link	 * layer address of our nexhop router	 */	if (rt->rt6i_nexthop == NULL)		ifa->flags &= ~IFA_F_OPTIMISTIC;	ifa->idev = idev;	in6_dev_hold(idev);	/* For caller */	in6_ifa_hold(ifa);	/* Add to big hash table */	hash = ipv6_addr_hash(addr);	ifa->lst_next = inet6_addr_lst[hash];	inet6_addr_lst[hash] = ifa;	in6_ifa_hold(ifa);	write_unlock(&addrconf_hash_lock);	write_lock(&idev->lock);	/* Add to inet6_dev unicast addr list. */	ipv6_link_dev_addr(idev, ifa);#ifdef CONFIG_IPV6_PRIVACY	if (ifa->flags&IFA_F_TEMPORARY) {		ifa->tmp_next = idev->tempaddr_list;		idev->tempaddr_list = ifa;		in6_ifa_hold(ifa);	}#endif	in6_ifa_hold(ifa);	write_unlock(&idev->lock);out2:	rcu_read_unlock_bh();	if (likely(err == 0))		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);	else {		kfree(ifa);		ifa = ERR_PTR(err);	}	return ifa;out:	write_unlock(&addrconf_hash_lock);	goto out2;}/* This function wants to get referenced ifp and releases it before return */static void ipv6_del_addr(struct inet6_ifaddr *ifp){	struct inet6_ifaddr *ifa, **ifap;	struct inet6_dev *idev = ifp->idev;	int hash;	int deleted = 0, onlink = 0;	unsigned long expires = jiffies;	hash = ipv6_addr_hash(&ifp->addr);	ifp->dead = 1;	write_lock_bh(&addrconf_hash_lock);	for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL;	     ifap = &ifa->lst_next) {		if (ifa == ifp) {			*ifap = ifa->lst_next;			__in6_ifa_put(ifp);			ifa->lst_next = NULL;			break;		}	}	write_unlock_bh(&addrconf_hash_lock);	write_lock_bh(&idev->lock);#ifdef CONFIG_IPV6_PRIVACY	if (ifp->flags&IFA_F_TEMPORARY) {		for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL;		     ifap = &ifa->tmp_next) {			if (ifa == ifp) {				*ifap = ifa->tmp_next;				if (ifp->ifpub) {					in6_ifa_put(ifp->ifpub);					ifp->ifpub = NULL;				}				__in6_ifa_put(ifp);				ifa->tmp_next = NULL;				break;			}		}	}#endif	for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) {		if (ifa == ifp) {			*ifap = ifa->if_next;			__in6_ifa_put(ifp);			ifa->if_next = NULL;			if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)				break;			deleted = 1;			continue;		} else if (ifp->flags & IFA_F_PERMANENT) {			if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,					      ifp->prefix_len)) {				if (ifa->flags & IFA_F_PERMANENT) {					onlink = 1;					if (deleted)						break;				} else {					unsigned long lifetime;					if (!onlink)						onlink = -1;					spin_lock(&ifa->lock);					lifetime = min_t(unsigned long,							 ifa->valid_lft, 0x7fffffffUL/HZ);					if (time_before(expires,							ifa->tstamp + lifetime * HZ))						expires = ifa->tstamp + lifetime * HZ;					spin_unlock(&ifa->lock);				}			}		}		ifap = &ifa->if_next;	}	write_unlock_bh(&idev->lock);	ipv6_ifa_notify(RTM_DELADDR, ifp);	atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);	addrconf_del_timer(ifp);	/*	 * Purge or update corresponding prefix	 *	 * 1) we don't purge prefix here if address was not permanent.	 *    prefix is managed by its own lifetime.	 * 2) if there're no addresses, delete prefix.	 * 3) if there're still other permanent address(es),	 *    corresponding prefix is still permanent.	 * 4) otherwise, update prefix lifetime to the	 *    longest valid lifetime among the corresponding	 *    addresses on the device.	 *    Note: subsequent RA will update lifetime.	 *	 * --yoshfuji	 */	if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {		struct in6_addr prefix;		struct rt6_info *rt;		ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);		rt = rt6_lookup(&prefix, NULL, ifp->idev->dev->ifindex, 1);		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {			if (onlink == 0) {				ip6_del_rt(rt);				rt = NULL;			} else if (!(rt->rt6i_flags & RTF_EXPIRES)) {				rt->rt6i_expires = expires;				rt->rt6i_flags |= RTF_EXPIRES;			}		}		dst_release(&rt->u.dst);	}	in6_ifa_put(ifp);}#ifdef CONFIG_IPV6_PRIVACYstatic int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift){	struct inet6_dev *idev = ifp->idev;	struct in6_addr addr, *tmpaddr;	unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp;	int tmp_plen;	int ret = 0;	int max_addresses;	u32 addr_flags;	write_lock(&idev->lock);	if (ift) {		spin_lock_bh(&ift->lock);		memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);		spin_unlock_bh(&ift->lock);		tmpaddr = &addr;	} else {		tmpaddr = NULL;	}retry:	in6_dev_hold(idev);	if (idev->cnf.use_tempaddr <= 0) {		write_unlock(&idev->lock);		printk(KERN_INFO			"ipv6_create_tempaddr(): use_tempaddr is disabled.\n");		in6_dev_put(idev);		ret = -1;		goto out;	}	spin_lock_bh(&ifp->lock);	if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {		idev->cnf.use_tempaddr = -1;	/*XXX*/		spin_unlock_bh(&ifp->lock);		write_unlock(&idev->lock);		printk(KERN_WARNING			"ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n");		in6_dev_put(idev);		ret = -1;		goto out;	}	in6_ifa_hold(ifp);	memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);	if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) {		spin_unlock_bh(&ifp->lock);		write_unlock(&idev->lock);		printk(KERN_WARNING			"ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n");		in6_ifa_put(ifp);		in6_dev_put(idev);		ret = -1;		goto out;	}	memcpy(&addr.s6_addr[8], idev->rndid, 8);	tmp_valid_lft = min_t(__u32,			      ifp->valid_lft,			      idev->cnf.temp_valid_lft);	tmp_prefered_lft = min_t(__u32,				 ifp->prefered_lft,				 idev->cnf.temp_prefered_lft - desync_factor / HZ);	tmp_plen = ifp->prefix_len;	max_addresses = idev->cnf.max_addresses;	tmp_cstamp = ifp->cstamp;	tmp_tstamp = ifp->tstamp;	spin_unlock_bh(&ifp->lock);	write_unlock(&idev->lock);	addr_flags = IFA_F_TEMPORARY;	/* set in addrconf_prefix_rcv() */	if (ifp->flags & IFA_F_OPTIMISTIC)		addr_flags |= IFA_F_OPTIMISTIC;	ift = !max_addresses ||	      ipv6_count_addresses(idev) < max_addresses ?		ipv6_add_addr(idev, &addr, tmp_plen,			      ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,			      addr_flags) : NULL;	if (!ift || IS_ERR(ift)) {		in6_ifa_put(ifp);		in6_dev_put(idev);		printk(KERN_INFO			"ipv6_create_tempaddr(): retry temporary address regeneration.\n");		tmpaddr = &addr;		write_lock(&idev->lock);		goto retry;	}	spin_lock_bh(&ift->lock);	ift->ifpub = ifp;	ift->valid_lft = tmp_valid_lft;	ift->prefered_lft = tmp_prefered_lft;	ift->cstamp = tmp_cstamp;	ift->tstamp = tmp_tstamp;	spin_unlock_bh(&ift->lock);	addrconf_dad_start(ift, 0);	in6_ifa_put(ift);	in6_dev_put(idev);out:	return ret;}#endif/* *	Choose an appropriate source address (RFC3484) */struct ipv6_saddr_score {	int		addr_type;	unsigned int	attrs;	int		matchlen;	int		scope;	unsigned int	rule;};#define IPV6_SADDR_SCORE_LOCAL		0x0001#define IPV6_SADDR_SCORE_PREFERRED	0x0004#define IPV6_SADDR_SCORE_HOA		0x0008#define IPV6_SADDR_SCORE_OIF		0x0010#define IPV6_SADDR_SCORE_LABEL		0x0020#define IPV6_SADDR_SCORE_PRIVACY	0x0040static inline int ipv6_saddr_preferred(int type){	if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|		    IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))		return 1;	return 0;}/* static matching label */static inline int ipv6_saddr_label(const struct in6_addr *addr, int type){ /*  * 	prefix (longest match)	label  * 	-----------------------------  * 	::1/128			0  * 	::/0			1  * 	2002::/16		2  * 	::/96			3  * 	::ffff:0:0/96		4  *	fc00::/7		5  * 	2001::/32		6  */	if (type & IPV6_ADDR_LOOPBACK)		return 0;	else if (type & IPV6_ADDR_COMPATv4)		return 3;	else if (type & IPV6_ADDR_MAPPED)		return 4;	else if (addr->s6_addr32[0] == htonl(0x20010000))		return 6;	else if (addr->s6_addr16[0] == htons(0x2002))		return 2;	else if ((addr->s6_addr[0] & 0xfe) == 0xfc)		return 5;	return 1;}int ipv6_dev_get_saddr(struct net_device *daddr_dev,		       struct in6_addr *daddr, struct in6_addr *saddr){	struct ipv6_saddr_score hiscore;	struct inet6_ifaddr *ifa_result = NULL;	int daddr_type = __ipv6_addr_type(daddr);	int daddr_scope = __ipv6_addr_src_scope(daddr_type);	u32 daddr_label = ipv6_saddr_label(daddr, daddr_type);	struct net_device *dev;	memset(&hiscore, 0, sizeof(hiscore));	read_lock(&dev_base_lock);	rcu_read_lock();	for_each_netdev(&init_net, dev) {		struct inet6_dev *idev;		struct inet6_ifaddr *ifa;		/* Rule 0: Candidate Source Address (section 4)		 *  - multicast and link-local destination address,		 *    the set of candidate source address MUST only		 *    include addresses assigned to interfaces		 *    belonging to the same link as the outgoing		 *    interface.		 * (- For site-local destination addresses, the		 *    set of candidate source addresses MUST only		 *    include addresses assigned to interfaces		 *    belonging to the same site as the outgoing		 *    interface.)		 */		if ((daddr_type & IPV6_ADDR_MULTICAST ||		     daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&		    daddr_dev && dev != daddr_dev)			continue;		idev = __in6_dev_get(dev);		if (!idev)			continue;		read_lock_bh(&idev->lock);		for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {			struct ipv6_saddr_score score;			score.addr_type = __ipv6_addr_type(&ifa->addr);			/* Rule 0:			 * - Tentative Address (RFC2462 section 5.4)			 *  - A tentative address is not considered			 *    "assigned to an interface" in the traditional			 *    sense, unless it is also flagged as optimistic.			 * - Candidate Source Address (section 4)			 *  - In any case, anycast addresses, multicast			 *    addresses, and the unspecified address MUST			 *    NOT be included in a candidate set.			 */			if ((ifa->flags & IFA_F_TENTATIVE) &&			    (!(ifa->flags & IFA_F_OPTIMISTIC)))				continue;			if (unlikely(score.addr_type == IPV6_ADDR_ANY ||				     score.addr_type & IPV6_ADDR_MULTICAST)) {				LIMIT_NETDEBUG(KERN_DEBUG					       "ADDRCONF: unspecified / multicast address "					       "assigned as unicast address on %s",					       dev->name);				continue;			}			score.attrs = 0;			score.matchlen = 0;			score.scope = 0;			score.rule = 0;			if (ifa_result == NULL) {				/* record it if the first available entry */				goto record_it;			}			/* Rule 1: Prefer same address */			if (hiscore.rule < 1) {				if (ipv6_addr_equal(&ifa_result->addr, daddr))					hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL;				hiscore.rule++;			}			if (ipv6_addr_equal(&ifa->addr, daddr)) {				score.attrs |= IPV6_SADDR_SCORE_LOCAL;				if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) {					score.rule = 1;					goto record_it;				}			} else {				if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)					continue;			}			/* Rule 2: Prefer appropriate scope */			if (hiscore.rule < 2) {				hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);				hiscore.rule++;			}			score.scope = __ipv6_addr_src_scope(score.addr_type);			if (hiscore.scope < score.scope) {				if (hiscore.scope < daddr_scope) {					score.rule = 2;					goto record_it;				} else					continue;			} else if (score.scope < hiscore.scope) {				if (score.scope < daddr_scope)					break; /* addresses sorted by scope */				else {					score.rule = 2;					goto record_it;				}			}			/* Rule 3: Avoid deprecated and optimistic addresses */			if (hiscore.rule < 3) {				if (ipv6_saddr_preferred(hiscore.addr_type) ||				   (((ifa_result->flags &				    (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))					hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;				hiscore.rule++;			}			if (ipv6_saddr_preferred(score.addr_type) ||			   (((ifa->flags &			    (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {				score.attrs |= IPV6_SADDR_SCORE_PREFERRED;				if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {					score.rule = 3;					goto record_it;				}			} else {				if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)					continue;			}			/* Rule 4: Prefer home address */#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)			if (hiscore.rule < 4) {				if (ifa_result->flags & IFA_F_HOMEADDRESS)					hiscore.attrs |= IPV6_SADDR_SCORE_HOA;				hiscore.rule++;			}			if (ifa->flags & IFA_F_HOMEADDRESS) {				score.attrs |= IPV6_SADDR_SCORE_HOA;				if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {					score.rule = 4;					goto record_it;				}			} else {				if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)					continue;			}#else			if (hiscore.rule < 4)				hiscore.rule++;#endif			/* Rule 5: Prefer outgoing interface */			if (hiscore.rule < 5) {				if (daddr_dev == NULL ||				    daddr_dev == ifa_result->idev->dev)					hiscore.attrs |= IPV6_SADDR_SCORE_OIF;				hiscore.rule++;			}			if (daddr_dev == NULL ||			    daddr_dev == ifa->idev->dev) {				score.attrs |= IPV6_SADDR_SCORE_OIF;				if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) {					score.rule = 5;					goto record_it;				}

⌨️ 快捷键说明

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