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

📄 addrconf.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	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);						ipv6_del_addr(ifp);			/* If the last address is deleted administratively,			   disable IPv6 on this interface.			 */			if (idev->addr_list == NULL)				addrconf_ifdown(idev->dev, 1);			return 0;		}	}	read_unlock_bh(&idev->lock);	return -EADDRNOTAVAIL;}int addrconf_add_ifaddr(void __user *arg){	struct in6_ifreq ireq;	int err;		if (!capable(CAP_NET_ADMIN))		return -EPERM;		if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))		return -EFAULT;	rtnl_lock();	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);	rtnl_unlock();	return err;}int addrconf_del_ifaddr(void __user *arg){	struct in6_ifreq ireq;	int err;		if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))		return -EFAULT;	rtnl_lock();	err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);	rtnl_unlock();	return err;}static void sit_add_v4_addrs(struct inet6_dev *idev){	struct inet6_ifaddr * ifp;	struct in6_addr addr;	struct net_device *dev;	int scope;	ASSERT_RTNL();	memset(&addr, 0, sizeof(struct in6_addr));	memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4);	if (idev->dev->flags&IFF_POINTOPOINT) {		addr.s6_addr32[0] = htonl(0xfe800000);		scope = IFA_LINK;	} else {		scope = IPV6_ADDR_COMPATv4;	}	if (addr.s6_addr32[3]) {		ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT);		if (!IS_ERR(ifp)) {			spin_lock_bh(&ifp->lock);			ifp->flags &= ~IFA_F_TENTATIVE;			spin_unlock_bh(&ifp->lock);			ipv6_ifa_notify(RTM_NEWADDR, ifp);			in6_ifa_put(ifp);		}		return;	}        for (dev = dev_base; dev != NULL; dev = dev->next) {		struct in_device * in_dev = __in_dev_get(dev);		if (in_dev && (dev->flags & IFF_UP)) {			struct in_ifaddr * ifa;			int flag = scope;			for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {				int plen;				addr.s6_addr32[3] = ifa->ifa_local;				if (ifa->ifa_scope == RT_SCOPE_LINK)					continue;				if (ifa->ifa_scope >= RT_SCOPE_HOST) {					if (idev->dev->flags&IFF_POINTOPOINT)						continue;					flag |= IFA_HOST;				}				if (idev->dev->flags&IFF_POINTOPOINT)					plen = 64;				else					plen = 96;				ifp = ipv6_add_addr(idev, &addr, plen, flag,						    IFA_F_PERMANENT);				if (!IS_ERR(ifp)) {					spin_lock_bh(&ifp->lock);					ifp->flags &= ~IFA_F_TENTATIVE;					spin_unlock_bh(&ifp->lock);					ipv6_ifa_notify(RTM_NEWADDR, ifp);					in6_ifa_put(ifp);				}			}		}        }}static void init_loopback(struct net_device *dev){	struct inet6_dev  *idev;	struct inet6_ifaddr * ifp;	/* ::1 */	ASSERT_RTNL();	if ((idev = ipv6_find_idev(dev)) == NULL) {		printk(KERN_DEBUG "init loopback: add_dev failed\n");		return;	}	ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT);	if (!IS_ERR(ifp)) {		spin_lock_bh(&ifp->lock);		ifp->flags &= ~IFA_F_TENTATIVE;		spin_unlock_bh(&ifp->lock);		ipv6_ifa_notify(RTM_NEWADDR, ifp);		in6_ifa_put(ifp);	}}static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr){	struct inet6_ifaddr * ifp;	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);	if (!IS_ERR(ifp)) {		addrconf_dad_start(ifp, 0);		in6_ifa_put(ifp);	}}static void addrconf_dev_config(struct net_device *dev){	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)) {		/* 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);}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);}static inline intipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev){	struct in6_addr lladdr;	if (!ipv6_get_lladdr(link_dev, &lladdr)) {		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(idev->dev->iflink))) {		if (!ipv6_inherit_linklocal(idev, link_dev))			return;	}	/* then try to inherit it from any device */	for (link_dev = dev_base; link_dev; link_dev = link_dev->next) {		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);	addrconf_add_mroute(dev);}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);	switch(event) {	case NETDEV_UP:		switch(dev->type) {		case ARPHRD_SIT:			addrconf_sit_config(dev);			break;		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 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;		}		/* 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_CHANGE:		break;	case NETDEV_CHANGENAME:#ifdef CONFIG_SYSCTL		if (idev) {			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);			addrconf_sysctl_register(idev, &idev->cnf);		}#endif		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();	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) {		write_lock_bh(&addrconf_lock);		dev->ip6_ptr = NULL;		idev->dead = 1;		write_unlock_bh(&addrconf_lock);	}	/* 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);	/* 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);		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);	/* Step 5: netlink notification of this interface */	idev->tstamp = jiffies;	inet6_ifinfo_notify(RTM_NEWLINK, idev);		/* 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_start(struct inet6_ifaddr *ifp, int flags){	struct net_device *dev;	unsigned long rand_num;	dev = ifp->idev->dev;	addrconf_join_solict(dev, &ifp->addr);	if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0,					flags);	net_srandom(ifp->addr.s6_addr32[3]);	rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1);	spin_lock_bh(&ifp->lock);	if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||	    !(ifp->flags&IFA_F_TENTATIVE)) {		ifp->flags &= ~IFA_F_TENTATIVE;		spin_unlock_bh(&ifp->lock);		addrconf_dad_completed(ifp);		return;	}	ifp->probes = ifp->idev->cnf.dad_transmits;	addrconf_mod_timer(ifp, AC_DAD, rand_num);	spin_unlock_bh(&ifp->lock);}static void addrconf_dad_timer(unsigned long data){

⌨️ 快捷键说明

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