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

📄 addrconf.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;	struct in6_addr unspec;	struct in6_addr mcaddr;	spin_lock_bh(&ifp->lock);	if (ifp->probes == 0) {		/*		 * DAD was successful		 */		ifp->flags &= ~IFA_F_TENTATIVE;		spin_unlock_bh(&ifp->lock);		addrconf_dad_completed(ifp);		in6_ifa_put(ifp);		return;	}	ifp->probes--;	addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);	spin_unlock_bh(&ifp->lock);	/* send a neighbour solicitation for our addr */	memset(&unspec, 0, sizeof(unspec));	addrconf_addr_solict_mult(&ifp->addr, &mcaddr);	ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);	in6_ifa_put(ifp);}static void addrconf_dad_completed(struct inet6_ifaddr *ifp){	struct net_device *	dev = ifp->idev->dev;	/*	 *	Configure the address for reception. Now it is valid.	 */	ipv6_ifa_notify(RTM_NEWADDR, ifp);	/* If added prefix is link local and forwarding is off,	   start sending router solicitations.	 */	if (ifp->idev->cnf.forwarding == 0 &&	    ifp->idev->cnf.rtr_solicits > 0 &&	    (dev->flags&IFF_LOOPBACK) == 0 &&	    (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {		struct in6_addr all_routers;		ipv6_addr_all_routers(&all_routers);		/*		 *	If a host as already performed a random delay		 *	[...] as part of DAD [...] there is no need		 *	to delay again before sending the first RS		 */		ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers);		spin_lock_bh(&ifp->lock);		ifp->probes = 1;		ifp->idev->if_flags |= IF_RS_SENT;		addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval);		spin_unlock_bh(&ifp->lock);	}}#ifdef CONFIG_PROC_FSstruct if6_iter_state {	int bucket;};static struct inet6_ifaddr *if6_get_first(struct seq_file *seq){	struct inet6_ifaddr *ifa = NULL;	struct if6_iter_state *state = seq->private;	for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {		ifa = inet6_addr_lst[state->bucket];		if (ifa)			break;	}	return ifa;}static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa){	struct if6_iter_state *state = seq->private;	ifa = ifa->lst_next;try_again:	if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) {		ifa = inet6_addr_lst[state->bucket];		goto try_again;	}	return ifa;}static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos){	struct inet6_ifaddr *ifa = if6_get_first(seq);	if (ifa)		while(pos && (ifa = if6_get_next(seq, ifa)) != NULL)			--pos;	return pos ? NULL : ifa;}static void *if6_seq_start(struct seq_file *seq, loff_t *pos){	read_lock_bh(&addrconf_hash_lock);	return if6_get_idx(seq, *pos);}static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct inet6_ifaddr *ifa;	ifa = if6_get_next(seq, v);	++*pos;	return ifa;}static void if6_seq_stop(struct seq_file *seq, void *v){	read_unlock_bh(&addrconf_hash_lock);}static int if6_seq_show(struct seq_file *seq, void *v){	struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;	seq_printf(seq,		   "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x %02x %8s\n",		   NIP6(ifp->addr),		   ifp->idev->dev->ifindex,		   ifp->prefix_len,		   ifp->scope,		   ifp->flags,		   ifp->idev->dev->name);	return 0;}static struct seq_operations if6_seq_ops = {	.start	= if6_seq_start,	.next	= if6_seq_next,	.show	= if6_seq_show,	.stop	= if6_seq_stop,};static int if6_seq_open(struct inode *inode, struct file *file){	struct seq_file *seq;	int rc = -ENOMEM;	struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);	if (!s)		goto out;	memset(s, 0, sizeof(*s));	rc = seq_open(file, &if6_seq_ops);	if (rc)		goto out_kfree;	seq = file->private_data;	seq->private = s;out:	return rc;out_kfree:	kfree(s);	goto out;}static struct file_operations if6_fops = {	.owner		= THIS_MODULE,	.open		= if6_seq_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release_private,};int __init if6_proc_init(void){	if (!proc_net_fops_create("if_inet6", S_IRUGO, &if6_fops))		return -ENOMEM;	return 0;}void if6_proc_exit(void){	proc_net_remove("if_inet6");}#endif	/* CONFIG_PROC_FS *//* *	Periodic address status verification */static void addrconf_verify(unsigned long foo){	struct inet6_ifaddr *ifp;	unsigned long now, next;	int i;	spin_lock_bh(&addrconf_verify_lock);	now = jiffies;	next = now + ADDR_CHECK_FREQUENCY;	del_timer(&addr_chk_timer);	for (i=0; i < IN6_ADDR_HSIZE; i++) {restart:		write_lock(&addrconf_hash_lock);		for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {			unsigned long age;#ifdef CONFIG_IPV6_PRIVACY			unsigned long regen_advance;#endif			if (ifp->flags & IFA_F_PERMANENT)				continue;			spin_lock(&ifp->lock);			age = (now - ifp->tstamp) / HZ;#ifdef CONFIG_IPV6_PRIVACY			regen_advance = ifp->idev->cnf.regen_max_retry * 					ifp->idev->cnf.dad_transmits * 					ifp->idev->nd_parms->retrans_time / HZ;#endif			if (age >= ifp->valid_lft) {				spin_unlock(&ifp->lock);				in6_ifa_hold(ifp);				write_unlock(&addrconf_hash_lock);				ipv6_del_addr(ifp);				goto restart;			} else if (age >= ifp->prefered_lft) {				/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */				int deprecate = 0;				if (!(ifp->flags&IFA_F_DEPRECATED)) {					deprecate = 1;					ifp->flags |= IFA_F_DEPRECATED;				}				if (time_before(ifp->tstamp + ifp->valid_lft * HZ, next))					next = ifp->tstamp + ifp->valid_lft * HZ;				spin_unlock(&ifp->lock);				if (deprecate) {					in6_ifa_hold(ifp);					write_unlock(&addrconf_hash_lock);					ipv6_ifa_notify(0, ifp);					in6_ifa_put(ifp);					goto restart;				}#ifdef CONFIG_IPV6_PRIVACY			} else if ((ifp->flags&IFA_F_TEMPORARY) &&				   !(ifp->flags&IFA_F_TENTATIVE)) {				if (age >= ifp->prefered_lft - regen_advance) {					struct inet6_ifaddr *ifpub = ifp->ifpub;					if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))						next = ifp->tstamp + ifp->prefered_lft * HZ;					if (!ifp->regen_count && ifpub) {						ifp->regen_count++;						in6_ifa_hold(ifp);						in6_ifa_hold(ifpub);						spin_unlock(&ifp->lock);						write_unlock(&addrconf_hash_lock);						ipv6_create_tempaddr(ifpub, ifp);						in6_ifa_put(ifpub);						in6_ifa_put(ifp);						goto restart;					}				} else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))					next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;				spin_unlock(&ifp->lock);#endif			} else {				/* ifp->prefered_lft <= ifp->valid_lft */				if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))					next = ifp->tstamp + ifp->prefered_lft * HZ;				spin_unlock(&ifp->lock);			}		}		write_unlock(&addrconf_hash_lock);	}	addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;	add_timer(&addr_chk_timer);	spin_unlock_bh(&addrconf_verify_lock);}static intinet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct in6_addr *pfx;	pfx = NULL;	if (rta[IFA_ADDRESS-1]) {		if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx))			return -EINVAL;		pfx = RTA_DATA(rta[IFA_ADDRESS-1]);	}	if (rta[IFA_LOCAL-1]) {		if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))			return -EINVAL;		pfx = RTA_DATA(rta[IFA_LOCAL-1]);	}	if (pfx == NULL)		return -EINVAL;	return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);}static intinet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr  **rta = arg;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct in6_addr *pfx;	pfx = NULL;	if (rta[IFA_ADDRESS-1]) {		if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx))			return -EINVAL;		pfx = RTA_DATA(rta[IFA_ADDRESS-1]);	}	if (rta[IFA_LOCAL-1]) {		if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))			return -EINVAL;		pfx = RTA_DATA(rta[IFA_LOCAL-1]);	}	if (pfx == NULL)		return -EINVAL;	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);}static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,			     u32 pid, u32 seq, int event){	struct ifaddrmsg *ifm;	struct nlmsghdr  *nlh;	struct ifa_cacheinfo ci;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;	ifm = NLMSG_DATA(nlh);	ifm->ifa_family = AF_INET6;	ifm->ifa_prefixlen = ifa->prefix_len;	ifm->ifa_flags = ifa->flags;	ifm->ifa_scope = RT_SCOPE_UNIVERSE;	if (ifa->scope&IFA_HOST)		ifm->ifa_scope = RT_SCOPE_HOST;	else if (ifa->scope&IFA_LINK)		ifm->ifa_scope = RT_SCOPE_LINK;	else if (ifa->scope&IFA_SITE)		ifm->ifa_scope = RT_SCOPE_SITE;	ifm->ifa_index = ifa->idev->dev->ifindex;	RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr);	if (!(ifa->flags&IFA_F_PERMANENT)) {		ci.ifa_prefered = ifa->prefered_lft;		ci.ifa_valid = ifa->valid_lft;		if (ci.ifa_prefered != INFINITY_LIFE_TIME) {			long tval = (jiffies - ifa->tstamp)/HZ;			ci.ifa_prefered -= tval;			if (ci.ifa_valid != INFINITY_LIFE_TIME)				ci.ifa_valid -= tval;		}	} else {		ci.ifa_prefered = INFINITY_LIFE_TIME;		ci.ifa_valid = INFINITY_LIFE_TIME;	}	ci.cstamp = (__u32)(TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) / HZ * 100		    + TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);	ci.tstamp = (__u32)(TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) / HZ * 100		    + TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);	RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,				u32 pid, u32 seq, int event){	struct ifaddrmsg *ifm;	struct nlmsghdr  *nlh;	struct ifa_cacheinfo ci;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;	ifm = NLMSG_DATA(nlh);	ifm->ifa_family = AF_INET6;		ifm->ifa_prefixlen = 128;	ifm->ifa_flags = IFA_F_PERMANENT;	ifm->ifa_scope = RT_SCOPE_UNIVERSE;	if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE)		ifm->ifa_scope = RT_SCOPE_SITE;	ifm->ifa_index = ifmca->idev->dev->ifindex;	RTA_PUT(skb, IFA_MULTICAST, 16, &ifmca->mca_addr);	ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ		    * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ		    * 100 / HZ);	ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ		    * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ		    * 100 / HZ);	ci.ifa_prefered = INFINITY_LIFE_TIME;	ci.ifa_valid = INFINITY_LIFE_TIME;	RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,				u32 pid, u32 seq, int event){	struct ifaddrmsg *ifm;	struct nlmsghdr  *nlh;	struct ifa_cacheinfo ci;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;	ifm = NLMSG_DATA(nlh);	ifm->ifa_family = AF_INET6;		ifm->ifa_prefixlen = 128;	ifm->ifa_flags = IFA_F_PERMANENT;	ifm->ifa_scope = RT_SCOPE_UNIVERSE;	if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE)		ifm->ifa_scope = RT_SCOPE_SITE;	ifm->ifa_index = ifaca->aca_idev->dev->ifindex;	RTA_PUT(skb, IFA_ANYCAST, 16, &ifaca->aca_addr);	ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ		    * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ		    * 100 / HZ);	ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ		    * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ		    * 100 / HZ);	ci.ifa_prefered = INFINITY_LIFE_TIME;	ci.ifa_valid = INFINITY_LIFE_TIME;	RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}enum addr_type_t{	UNICAST_ADDR,	MULTICAST_ADDR,	ANYCAST_ADDR,};static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,			   enum addr_type_t type){	int idx, ip_idx;	int s_idx, s_ip_idx;	int err = 1;	struct net_device *dev;	struct inet6_dev *idev = NULL;	struct inet6_ifaddr *ifa;	struct ifmcaddr6 *ifmca;	struct ifacaddr6 *ifaca;	s_idx = cb->args[0];	s_ip_idx = ip_idx = cb->args[1];	read_lock(&dev_base_lock);		for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {		if (idx < s_idx)			continue;		if (idx > s_idx)			s_ip_idx = 0;		ip_idx = 0;		if ((idev = in6_dev_get(dev)) == NULL)			continue;		read_lock_bh(&idev->lock);		switch (type) {		case UNICAST_ADDR:			/* unicast address */			for (ifa = idev->addr_list; ifa;			     ifa = ifa->if_next, ip_idx++) {				if (ip_idx < s_ip_idx)					continue;				if ((err = inet6_fill_ifaddr(skb, ifa, 				    NETLINK_CB(cb->skb).pid, 				    cb->nlh->nlmsg_seq, RTM_NEWADDR)) <= 0)					goto done;			}			/* temp addr */#ifdef CONFIG_IPV6_PRIVACY			for (ifa = idev->tempaddr_list; ifa; 			     ifa = ifa->tmp_next, ip_idx++) {				if (ip_idx < s_ip_idx)					continue;				if ((err = inet6_fill_ifaddr(skb, ifa, 				    NETLINK_CB(cb->skb).pid, 				    cb->nlh->nlmsg_seq, RTM_NEWADDR)) <= 0) 					goto done;			}#endif			break;		case MULTICAST_ADDR:			/* multicast address */			for (ifmca = idev->mc_list; ifmca; 			     ifmca = ifmca->next, ip_idx++) {				if (ip_idx < s_ip_idx)					continue;				if ((err = inet6_fill_ifmcaddr(skb, ifmca, 				    NETLINK_CB(cb->skb).pid, 				    cb->nlh->nlmsg_seq, RTM_GETMULTICAST)) <= 0)					goto done;			}			break;		case ANYCAST_ADDR:			/* anycast address */			for (ifaca = idev->ac_list; ifaca;			 

⌨️ 快捷键说明

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