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

📄 addrconf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct in6_addr addr;	struct inet6_dev    * idev;	ASSERT_RTNL();	if ((dev->type != ARPHRD_ETHER) &&	    (dev->type != ARPHRD_FDDI) &&	    (dev->type != ARPHRD_IEEE802_TR) &&	    (dev->type != ARPHRD_ARCNET) &&	    (dev->type != ARPHRD_INFINIBAND)) {		/* Alas, we support only Ethernet autoconfiguration. */		return;	}	idev = addrconf_add_dev(dev);	if (idev == NULL)		return;	memset(&addr, 0, sizeof(struct in6_addr));	addr.s6_addr32[0] = htonl(0xFE800000);	if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0)		addrconf_add_linklocal(idev, &addr);}#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)static void addrconf_sit_config(struct net_device *dev){	struct inet6_dev *idev;	ASSERT_RTNL();	/*	 * Configure the tunnel with one of our IPv4	 * addresses... we should configure all of	 * our v4 addrs in the tunnel	 */	if ((idev = ipv6_find_idev(dev)) == NULL) {		printk(KERN_DEBUG "init sit: add_dev failed\n");		return;	}	sit_add_v4_addrs(idev);	if (dev->flags&IFF_POINTOPOINT) {		addrconf_add_mroute(dev);		addrconf_add_lroute(dev);	} else		sit_route_add(dev);}#endifstatic inline intipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev){	struct in6_addr lladdr;	if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) {		addrconf_add_linklocal(idev, &lladdr);		return 0;	}	return -1;}static void ip6_tnl_add_linklocal(struct inet6_dev *idev){	struct net_device *link_dev;	/* first try to inherit the link-local address from the link device */	if (idev->dev->iflink &&	    (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) {		if (!ipv6_inherit_linklocal(idev, link_dev))			return;	}	/* then try to inherit it from any device */	for_each_netdev(&init_net, link_dev) {		if (!ipv6_inherit_linklocal(idev, link_dev))			return;	}	printk(KERN_DEBUG "init ip6-ip6: add_linklocal failed\n");}/* * Autoconfigure tunnel with a link-local address so routing protocols, * DHCPv6, MLD etc. can be run over the virtual link */static void addrconf_ip6_tnl_config(struct net_device *dev){	struct inet6_dev *idev;	ASSERT_RTNL();	if ((idev = addrconf_add_dev(dev)) == NULL) {		printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");		return;	}	ip6_tnl_add_linklocal(idev);}static int addrconf_notify(struct notifier_block *this, unsigned long event,			   void * data){	struct net_device *dev = (struct net_device *) data;	struct inet6_dev *idev = __in6_dev_get(dev);	int run_pending = 0;	int err;	if (dev->nd_net != &init_net)		return NOTIFY_DONE;	switch(event) {	case NETDEV_REGISTER:		if (!idev && dev->mtu >= IPV6_MIN_MTU) {			idev = ipv6_add_dev(dev);			if (!idev)				return notifier_from_errno(-ENOMEM);		}		break;	case NETDEV_UP:	case NETDEV_CHANGE:		if (dev->flags & IFF_SLAVE)			break;		if (event == NETDEV_UP) {			if (!addrconf_qdisc_ok(dev)) {				/* device is not ready yet. */				printk(KERN_INFO					"ADDRCONF(NETDEV_UP): %s: "					"link is not ready\n",					dev->name);				break;			}			if (!idev && dev->mtu >= IPV6_MIN_MTU)				idev = ipv6_add_dev(dev);			if (idev)				idev->if_flags |= IF_READY;		} else {			if (!addrconf_qdisc_ok(dev)) {				/* device is still not ready. */				break;			}			if (idev) {				if (idev->if_flags & IF_READY) {					/* device is already configured. */					break;				}				idev->if_flags |= IF_READY;			}			printk(KERN_INFO					"ADDRCONF(NETDEV_CHANGE): %s: "					"link becomes ready\n",					dev->name);			run_pending = 1;		}		switch(dev->type) {#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)		case ARPHRD_SIT:			addrconf_sit_config(dev);			break;#endif		case ARPHRD_TUNNEL6:			addrconf_ip6_tnl_config(dev);			break;		case ARPHRD_LOOPBACK:			init_loopback(dev);			break;		default:			addrconf_dev_config(dev);			break;		}		if (idev) {			if (run_pending)				addrconf_dad_run(idev);			/* If the MTU changed during the interface down, when the			   interface up, the changed MTU must be reflected in the			   idev as well as routers.			 */			if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) {				rt6_mtu_change(dev, dev->mtu);				idev->cnf.mtu6 = dev->mtu;			}			idev->tstamp = jiffies;			inet6_ifinfo_notify(RTM_NEWLINK, idev);			/* If the changed mtu during down is lower than IPV6_MIN_MTU			   stop IPv6 on this interface.			 */			if (dev->mtu < IPV6_MIN_MTU)				addrconf_ifdown(dev, event != NETDEV_DOWN);		}		break;	case NETDEV_CHANGEMTU:		if (idev && dev->mtu >= IPV6_MIN_MTU) {			rt6_mtu_change(dev, dev->mtu);			idev->cnf.mtu6 = dev->mtu;			break;		}		if (!idev && dev->mtu >= IPV6_MIN_MTU) {			idev = ipv6_add_dev(dev);			if (idev)				break;		}		/* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */	case NETDEV_DOWN:	case NETDEV_UNREGISTER:		/*		 *	Remove all addresses from this interface.		 */		addrconf_ifdown(dev, event != NETDEV_DOWN);		break;	case NETDEV_CHANGENAME:		if (idev) {			snmp6_unregister_dev(idev);#ifdef CONFIG_SYSCTL			addrconf_sysctl_unregister(&idev->cnf);			neigh_sysctl_unregister(idev->nd_parms);			neigh_sysctl_register(dev, idev->nd_parms,					      NET_IPV6, NET_IPV6_NEIGH, "ipv6",					      &ndisc_ifinfo_sysctl_change,					      NULL);			addrconf_sysctl_register(idev, &idev->cnf);#endif			err = snmp6_register_dev(idev);			if (err)				return notifier_from_errno(err);		}		break;	}	return NOTIFY_OK;}/* *	addrconf module should be notified of a device going up */static struct notifier_block ipv6_dev_notf = {	.notifier_call = addrconf_notify,	.priority = 0};static int addrconf_ifdown(struct net_device *dev, int how){	struct inet6_dev *idev;	struct inet6_ifaddr *ifa, **bifa;	int i;	ASSERT_RTNL();	if (dev == init_net.loopback_dev && how == 1)		how = 0;	rt6_ifdown(dev);	neigh_ifdown(&nd_tbl, dev);	idev = __in6_dev_get(dev);	if (idev == NULL)		return -ENODEV;	/* Step 1: remove reference to ipv6 device from parent device.		   Do not dev_put!	 */	if (how == 1) {		idev->dead = 1;		/* protected by rtnl_lock */		rcu_assign_pointer(dev->ip6_ptr, NULL);		/* Step 1.5: remove snmp6 entry */		snmp6_unregister_dev(idev);	}	/* Step 2: clear hash table */	for (i=0; i<IN6_ADDR_HSIZE; i++) {		bifa = &inet6_addr_lst[i];		write_lock_bh(&addrconf_hash_lock);		while ((ifa = *bifa) != NULL) {			if (ifa->idev == idev) {				*bifa = ifa->lst_next;				ifa->lst_next = NULL;				addrconf_del_timer(ifa);				in6_ifa_put(ifa);				continue;			}			bifa = &ifa->lst_next;		}		write_unlock_bh(&addrconf_hash_lock);	}	write_lock_bh(&idev->lock);	/* Step 3: clear flags for stateless addrconf */	if (how != 1)		idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);	/* Step 4: clear address list */#ifdef CONFIG_IPV6_PRIVACY	if (how == 1 && del_timer(&idev->regen_timer))		in6_dev_put(idev);	/* clear tempaddr list */	while ((ifa = idev->tempaddr_list) != NULL) {		idev->tempaddr_list = ifa->tmp_next;		ifa->tmp_next = NULL;		ifa->dead = 1;		write_unlock_bh(&idev->lock);		spin_lock_bh(&ifa->lock);		if (ifa->ifpub) {			in6_ifa_put(ifa->ifpub);			ifa->ifpub = NULL;		}		spin_unlock_bh(&ifa->lock);		in6_ifa_put(ifa);		write_lock_bh(&idev->lock);	}#endif	while ((ifa = idev->addr_list) != NULL) {		idev->addr_list = ifa->if_next;		ifa->if_next = NULL;		ifa->dead = 1;		addrconf_del_timer(ifa);		write_unlock_bh(&idev->lock);		__ipv6_ifa_notify(RTM_DELADDR, ifa);		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);		in6_ifa_put(ifa);		write_lock_bh(&idev->lock);	}	write_unlock_bh(&idev->lock);	/* Step 5: Discard multicast list */	if (how == 1)		ipv6_mc_destroy_dev(idev);	else		ipv6_mc_down(idev);	idev->tstamp = jiffies;	/* Shot the device (if unregistered) */	if (how == 1) {#ifdef CONFIG_SYSCTL		addrconf_sysctl_unregister(&idev->cnf);		neigh_sysctl_unregister(idev->nd_parms);#endif		neigh_parms_release(&nd_tbl, idev->nd_parms);		neigh_ifdown(&nd_tbl, dev);		in6_dev_put(idev);	}	return 0;}static void addrconf_rs_timer(unsigned long data){	struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;	if (ifp->idev->cnf.forwarding)		goto out;	if (ifp->idev->if_flags & IF_RA_RCVD) {		/*		 *	Announcement received after solicitation		 *	was sent		 */		goto out;	}	spin_lock(&ifp->lock);	if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) {		struct in6_addr all_routers;		/* The wait after the last probe can be shorter */		addrconf_mod_timer(ifp, AC_RS,				   (ifp->probes == ifp->idev->cnf.rtr_solicits) ?				   ifp->idev->cnf.rtr_solicit_delay :				   ifp->idev->cnf.rtr_solicit_interval);		spin_unlock(&ifp->lock);		ipv6_addr_all_routers(&all_routers);		ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers);	} else {		spin_unlock(&ifp->lock);		/*		 * Note: we do not support deprecated "all on-link"		 * assumption any longer.		 */		printk(KERN_DEBUG "%s: no IPv6 routers present\n",		       ifp->idev->dev->name);	}out:	in6_ifa_put(ifp);}/* *	Duplicate Address Detection */static void addrconf_dad_kick(struct inet6_ifaddr *ifp){	unsigned long rand_num;	struct inet6_dev *idev = ifp->idev;	if (ifp->flags & IFA_F_OPTIMISTIC)		rand_num = 0;	else		rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);	ifp->probes = idev->cnf.dad_transmits;	addrconf_mod_timer(ifp, AC_DAD, rand_num);}static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags){	struct inet6_dev *idev = ifp->idev;	struct net_device *dev = idev->dev;	addrconf_join_solict(dev, &ifp->addr);	net_srandom(ifp->addr.s6_addr32[3]);	read_lock_bh(&idev->lock);	if (ifp->dead)		goto out;	spin_lock_bh(&ifp->lock);	if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||	    !(ifp->flags&IFA_F_TENTATIVE) ||	    ifp->flags & IFA_F_NODAD) {		ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);		spin_unlock_bh(&ifp->lock);		read_unlock_bh(&idev->lock);		addrconf_dad_completed(ifp);		return;	}	if (!(idev->if_flags & IF_READY)) {		spin_unlock_bh(&ifp->lock);		read_unlock_bh(&idev->lock);		/*		 * If the defice is not ready:		 * - keep it tentative if it is a permanent address.		 * - otherwise, kill it.		 */		in6_ifa_hold(ifp);		addrconf_dad_stop(ifp);		return;	}	/*	 * Optimistic nodes can start receiving	 * Frames right away	 */	if(ifp->flags & IFA_F_OPTIMISTIC)		ip6_ins_rt(ifp->rt);	addrconf_dad_kick(ifp);	spin_unlock_bh(&ifp->lock);out:	read_unlock_bh(&idev->lock);}static void addrconf_dad_timer(unsigned long data){	struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;	struct inet6_dev *idev = ifp->idev;	struct in6_addr unspec;	struct in6_addr mcaddr;	read_lock_bh(&idev->lock);	if (idev->dead) {		read_unlock_bh(&idev->lock);		goto out;	}	spin_lock_bh(&ifp->lock);	if (ifp->probes == 0) {		/*		 * DAD was successful		 */		ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);		spin_unlock_bh(&ifp->lock);		read_unlock_bh(&idev->lock);		addrconf_dad_completed(ifp);		goto out;	}	ifp->probes--;	addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);	spin_unlock_bh(&ifp->lock);	read_unlock_bh(&idev->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);out:	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 &&	    (

⌨️ 快捷键说明

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