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

📄 addrconf.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	write_unlock_bh(&addrconf_hash_lock);	write_lock_bh(&idev->lock);	/* Add to inet6_dev unicast addr list. */	ifa->if_next = idev->addr_list;	idev->addr_list = ifa;#ifdef CONFIG_IPV6_PRIVACY	ifa->regen_count = 0;	if (ifa->flags&IFA_F_TEMPORARY) {		ifa->tmp_next = idev->tempaddr_list;		idev->tempaddr_list = ifa;		in6_ifa_hold(ifa);	} else {		ifa->tmp_next = NULL;	}#endif	ifa->rt = rt;	in6_ifa_hold(ifa);	write_unlock_bh(&idev->lock);	read_unlock(&addrconf_lock);out:	spin_unlock_bh(&lock);	if (unlikely(err == 0))		notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);	else {		kfree(ifa);		ifa = ERR_PTR(err);	}	return ifa;}/* 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;	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;	     ifap = &ifa->if_next) {		if (ifa == ifp) {			*ifap = ifa->if_next;			__in6_ifa_put(ifp);			ifa->if_next = NULL;			break;		}	}	write_unlock_bh(&idev->lock);	ipv6_ifa_notify(RTM_DELADDR, ifp);	notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp);	addrconf_del_timer(ifp);	in6_ifa_put(ifp);}#ifdef CONFIG_IPV6_PRIVACYstatic int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift){	struct inet6_dev *idev;	struct in6_addr addr, *tmpaddr;	unsigned long tmp_prefered_lft, tmp_valid_lft;	int tmp_plen;	int ret = 0;	int max_addresses;	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:	spin_lock_bh(&ifp->lock);	in6_ifa_hold(ifp);	idev = ifp->idev;	in6_dev_hold(idev);	memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);	write_lock(&idev->lock);	if (idev->cnf.use_tempaddr <= 0) {		write_unlock(&idev->lock);		spin_unlock_bh(&ifp->lock);		printk(KERN_INFO			"ipv6_create_tempaddr(): use_tempaddr is disabled.\n");		in6_dev_put(idev);		in6_ifa_put(ifp);		ret = -1;		goto out;	}	if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {		idev->cnf.use_tempaddr = -1;	/*XXX*/		write_unlock(&idev->lock);		spin_unlock_bh(&ifp->lock);		printk(KERN_WARNING			"ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n");		in6_dev_put(idev);		in6_ifa_put(ifp);		ret = -1;		goto out;	}	if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) {		write_unlock(&idev->lock);		spin_unlock_bh(&ifp->lock);		printk(KERN_WARNING			"ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n");		in6_dev_put(idev);		in6_ifa_put(ifp);		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;	write_unlock(&idev->lock);	spin_unlock_bh(&ifp->lock);	ift = !max_addresses ||	      ipv6_count_addresses(idev) < max_addresses ? 		ipv6_add_addr(idev, &addr, tmp_plen,			      ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;	if (!ift || IS_ERR(ift)) {		in6_dev_put(idev);		in6_ifa_put(ifp);		printk(KERN_INFO			"ipv6_create_tempaddr(): retry temporary address regeneration.\n");		tmpaddr = &addr;		goto retry;	}	spin_lock_bh(&ift->lock);	ift->ifpub = ifp;	ift->valid_lft = tmp_valid_lft;	ift->prefered_lft = tmp_prefered_lft;	ift->cstamp = ifp->cstamp;	ift->tstamp = ifp->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 *	should do: *	i)	get an address with an appropriate scope *	ii)	see if there is a specific route for the destination and use *		an address of the attached interface  *	iii)	don't use deprecated addresses */static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref){	int pref;	pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;#ifdef CONFIG_IPV6_PRIVACY	pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;#endif	return pref;}#ifdef CONFIG_IPV6_PRIVACY#define IPV6_GET_SADDR_MAXSCORE(score)	((score) == 3)#else#define IPV6_GET_SADDR_MAXSCORE(score)	(score)#endifint ipv6_dev_get_saddr(struct net_device *dev,		   struct in6_addr *daddr, struct in6_addr *saddr, int onlink){	struct inet6_ifaddr *ifp = NULL;	struct inet6_ifaddr *match = NULL;	struct inet6_dev *idev;	int scope;	int err;	int hiscore = -1, score;	if (!onlink)		scope = ipv6_addr_scope(daddr);	else		scope = IFA_LINK;	/*	 *	known dev	 *	search dev and walk through dev addresses	 */	if (dev) {		if (dev->flags & IFF_LOOPBACK)			scope = IFA_HOST;		read_lock(&addrconf_lock);		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_TENTATIVE)						continue;#ifdef CONFIG_IPV6_PRIVACY					score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);#else					score = ipv6_saddr_pref(ifp, 0);#endif					if (score <= hiscore)						continue;					if (match)						in6_ifa_put(match);					match = ifp;					hiscore = score;					in6_ifa_hold(ifp);					if (IPV6_GET_SADDR_MAXSCORE(score)) {						read_unlock_bh(&idev->lock);						read_unlock(&addrconf_lock);						goto out;					}				}			}			read_unlock_bh(&idev->lock);		}		read_unlock(&addrconf_lock);	}	if (scope == IFA_LINK)		goto out;	/*	 *	dev == NULL or search failed for specified dev	 */	read_lock(&dev_base_lock);	read_lock(&addrconf_lock);	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_TENTATIVE)						continue;#ifdef CONFIG_IPV6_PRIVACY					score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);#else					score = ipv6_saddr_pref(ifp, 0);#endif					if (score <= hiscore)						continue;					if (match)						in6_ifa_put(match);					match = ifp;					hiscore = score;					in6_ifa_hold(ifp);					if (IPV6_GET_SADDR_MAXSCORE(score)) {						read_unlock_bh(&idev->lock);						goto out_unlock_base;					}				}			}			read_unlock_bh(&idev->lock);		}	}out_unlock_base:	read_unlock(&addrconf_lock);	read_unlock(&dev_base_lock);out:	err = -EADDRNOTAVAIL;	if (match) {		ipv6_addr_copy(saddr, &match->addr);		err = 0;		in6_ifa_put(match);	}	return err;}int ipv6_get_saddr(struct dst_entry *dst,		   struct in6_addr *daddr, struct in6_addr *saddr){	struct rt6_info *rt;	struct net_device *dev = NULL;	int onlink;	rt = (struct rt6_info *) dst;	if (rt)		dev = rt->rt6i_dev;	onlink = (rt && (rt->rt6i_flags & RTF_ALLONLINK));	return ipv6_dev_get_saddr(dev, daddr, saddr, onlink);}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;}static int ipv6_count_addresses(struct inet6_dev *idev){	int cnt = 0;	struct inet6_ifaddr *ifp;	read_lock_bh(&idev->lock);	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)		cnt++;	read_unlock_bh(&idev->lock);	return cnt;}int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict){	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) || strict))				break;		}	}	read_unlock_bh(&addrconf_hash_lock);	return ifp != NULL;}staticint ipv6_chk_same_addr(const 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)				break;		}	}	read_unlock_bh(&addrconf_hash_lock);	return ifp != NULL;}struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev, int strict){	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) || strict)) {				in6_ifa_hold(ifp);				break;			}		}	}	read_unlock_bh(&addrconf_hash_lock);	return ifp;}int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2){	const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;	const struct in6_addr *sk2_rcv_saddr6 = tcp_v6_rcv_saddr(sk2);	u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;	u32 sk2_rcv_saddr = tcp_v4_rcv_saddr(sk2);	int sk_ipv6only = ipv6_only_sock(sk);	int sk2_ipv6only = tcp_v6_ipv6only(sk2);	int addr_type = ipv6_addr_type(sk_rcv_saddr6);	int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;	if (!sk2_rcv_saddr && !sk_ipv6only)		return 1;	if (addr_type2 == IPV6_ADDR_ANY &&	    !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))		return 1;	if (addr_type == IPV6_ADDR_ANY &&	    !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))		return 1;	if (sk2_rcv_saddr6 &&	    !ipv6_addr_cmp(sk_rcv_saddr6, sk2_rcv_saddr6))		return 1;	if (addr_type == IPV6_ADDR_MAPPED &&	    !sk2_ipv6only &&	    (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr))		return 1;	return 0;}/* 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);#ifdef CONFIG_IPV6_PRIVACY	} else if (ifp->flags&IFA_F_TEMPORARY) {		struct inet6_ifaddr *ifpub;		spin_lock_bh(&ifp->lock);		ifpub = ifp->ifpub;		if (ifpub) {			in6_ifa_hold(ifpub);			spin_unlock_bh(&ifp->lock);			ipv6_create_tempaddr(ifpub, ifp);			in6_ifa_put(ifpub);		} else {			spin_unlock_bh(&ifp->lock);		}		ipv6_del_addr(ifp);#endif	} else		ipv6_del_addr(ifp);}/* Join to solicited addr multicast group. */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);}void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr){	struct in6_addr maddr;	if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP))		return;	addrconf_addr_solict_mult(addr, &maddr);	__ipv6_dev_mc_dec(idev, &maddr);}void addrconf_join_anycast(struct inet6_ifaddr *ifp){	struct in6_addr addr;	ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);	if (ipv6_addr_any(&addr))		return;	ipv6_dev_ac_inc(ifp->idev->dev, &addr);}void addrconf_leave_anycast(struct inet6_ifaddr *ifp){	struct in6_addr addr;	ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);	if (ipv6_addr_any(&addr))		return;

⌨️ 快捷键说明

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