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

📄 addrconf.c

📁 ipv6地址转换器
💻 C
📖 第 1 页 / 共 3 页
字号:
}static void addrconf_add_lroute(struct device *dev){	struct in6_addr addr;	ipv6_addr_set(&addr,  __constant_htonl(0xFE800000), 0, 0, 0);	addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);}static struct inet6_dev *addrconf_add_dev(struct device *dev){	struct inet6_dev *idev;	if ((idev = ipv6_find_idev(dev)) == NULL)		return NULL;	/* Add default multicast route */	addrconf_add_mroute(dev);	/* Add link local route */	addrconf_add_lroute(dev);	return idev;}void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len){	struct prefix_info *pinfo;	struct rt6_info *rt;	__u32 valid_lft;	__u32 prefered_lft;	int addr_type;	unsigned long rt_expires;	struct inet6_dev *in6_dev = ipv6_get_idev(dev);	if (in6_dev == NULL) {		printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name);		return;	}	pinfo = (struct prefix_info *) opt;		if (len < sizeof(struct prefix_info)) {		ADBG(("addrconf: prefix option too short\n"));		return;	}		/*	 *	Validation checks ([ADDRCONF], page 19)	 */	addr_type = ipv6_addr_type(&pinfo->prefix);	if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL))		return;	valid_lft = ntohl(pinfo->valid);	prefered_lft = ntohl(pinfo->prefered);	if (prefered_lft > valid_lft) {		printk(KERN_WARNING "addrconf: prefix option has invalid lifetime\n");		return;	}	/*	 *	Two things going on here:	 *	1) Add routes for on-link prefixes	 *	2) Configure prefixes with the auto flag set	 */	/* Avoid arithemtic overflow. Really, we could	   save rt_expires in seconds, likely valid_lft,	   but it would require division in fib gc, that it	   not good.	 */	if (valid_lft >= 0x7FFFFFFF/HZ)		rt_expires = 0;	else		rt_expires = jiffies + valid_lft * HZ;	rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1);	if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {		if (rt->rt6i_flags&RTF_EXPIRES) {			if (pinfo->onlink == 0 || valid_lft == 0) {				ip6_del_rt(rt);			} else {				rt->rt6i_expires = rt_expires;			}		}	} else if (pinfo->onlink && valid_lft) {		addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,				      dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES);	}	if (rt)		dst_release(&rt->u.dst);	/* Try to figure out our local address for this prefix */	if (pinfo->autoconf && in6_dev->cnf.autoconf) {		struct inet6_ifaddr * ifp;		struct in6_addr addr;		int plen;		plen = pinfo->prefix_len >> 3;#ifdef CONFIG_IPV6_EUI64		if (pinfo->prefix_len == 64) {			memcpy(&addr, &pinfo->prefix, 8);			if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&			    ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev))				return;			goto ok;		}#endif#ifndef CONFIG_IPV6_NO_PB		if (pinfo->prefix_len == ((sizeof(struct in6_addr) - dev->addr_len)<<3)) {			memcpy(&addr, &pinfo->prefix, plen);			memcpy(addr.s6_addr + plen, dev->dev_addr,			       dev->addr_len);			goto ok;		}#endif		printk(KERN_DEBUG "IPv6 addrconf: prefix with wrong length %d\n", pinfo->prefix_len);		return;ok:		ifp = ipv6_chk_addr(&addr, dev, 1);		if ((ifp == NULL || (ifp->flags&ADDR_INVALID)) && valid_lft) {			if (ifp == NULL)				ifp = ipv6_add_addr(in6_dev, &addr, addr_type & IPV6_ADDR_SCOPE_MASK);			if (ifp == NULL)				return;			ifp->prefix_len = pinfo->prefix_len;			addrconf_dad_start(ifp);		}		if (ifp && valid_lft == 0) {			ipv6_del_addr(ifp);			ifp = NULL;		}		if (ifp) {			int event = 0;			ifp->valid_lft = valid_lft;			ifp->prefered_lft = prefered_lft;			ifp->tstamp = jiffies;			if (ifp->flags & ADDR_INVALID)				event = RTM_NEWADDR;			ifp->flags &= ~(ADDR_DEPRECATED|ADDR_INVALID);			ipv6_ifa_notify(event, ifp);		}	}}/* *	Set destination address. *	Special case for SIT interfaces where we create a new "virtual" *	device. */int addrconf_set_dstaddr(void *arg){	struct in6_ifreq ireq;	struct device *dev;	int err = -EINVAL;	rtnl_lock();	err = -EFAULT;	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))		goto err_exit;	dev = dev_get_by_index(ireq.ifr6_ifindex);	err = -ENODEV;	if (dev == NULL)		goto err_exit;	if (dev->type == ARPHRD_SIT) {		struct ifreq ifr;		mm_segment_t	oldfs;		struct ip_tunnel_parm p;		err = -EADDRNOTAVAIL;		if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))			goto err_exit;		memset(&p, 0, sizeof(p));		p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];		p.iph.saddr = 0;		p.iph.version = 4;		p.iph.ihl = 5;		p.iph.protocol = IPPROTO_IPV6;		p.iph.ttl = 64;		ifr.ifr_ifru.ifru_data = (void*)&p;		oldfs = get_fs(); set_fs(KERNEL_DS);		err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);		set_fs(oldfs);		if (err == 0) {			err = -ENOBUFS;			if ((dev = dev_get(p.name)) == NULL)				goto err_exit;			err = dev_open(dev);		}	}err_exit:	rtnl_unlock();	return err;}/* *	Manual configuration of address on an interface */static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen){	struct inet6_ifaddr *ifp;	struct inet6_dev *idev;	struct device *dev;	int scope;		if ((dev = dev_get_by_index(ifindex)) == NULL)		return -ENODEV;		if (!(dev->flags&IFF_UP))		return -ENETDOWN;	if ((idev = addrconf_add_dev(dev)) == NULL)		return -ENOBUFS;	scope = ipv6_addr_scope(pfx);	addrconf_lock();	if ((ifp = ipv6_add_addr(idev, pfx, scope)) != NULL) {		ifp->prefix_len = plen;		ifp->flags |= ADDR_PERMANENT;		addrconf_dad_start(ifp);		addrconf_unlock();		return 0;	}	addrconf_unlock();	return -ENOBUFS;}static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen){	struct inet6_ifaddr *ifp;	struct inet6_dev *idev;	struct device *dev;		if ((dev = dev_get_by_index(ifindex)) == NULL)		return -ENODEV;	if ((idev = ipv6_get_idev(dev)) == NULL)		return -ENXIO;	start_bh_atomic();	for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {		if (ifp->prefix_len == plen &&		    (!memcmp(pfx, &ifp->addr, sizeof(struct in6_addr)))) {			ipv6_del_addr(ifp);			end_bh_atomic();			/* If the last address is deleted administratively,			   disable IPv6 on this interface.			 */			if (idev->addr_list == NULL)				addrconf_ifdown(idev->dev, 1);			return 0;		}	}	end_bh_atomic();	return -EADDRNOTAVAIL;}int addrconf_add_ifaddr(void *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 *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 device *dev;	int scope;	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] = __constant_htonl(0xfe800000);		scope = IFA_LINK;	} else {		scope = IPV6_ADDR_COMPATv4;	}	if (addr.s6_addr32[3]) {		addrconf_lock();		ifp = ipv6_add_addr(idev, &addr, scope);		if (ifp) {			ifp->flags |= ADDR_PERMANENT;			ifp->prefix_len = 128;			ipv6_ifa_notify(RTM_NEWADDR, ifp);		}		addrconf_unlock();		return;	}        for (dev = dev_base; dev != NULL; dev = dev->next) {		if (dev->ip_ptr && (dev->flags & IFF_UP)) {			struct in_device * in_dev = dev->ip_ptr;			struct in_ifaddr * ifa;			int flag = scope;			for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {				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;				}				addrconf_lock();				ifp = ipv6_add_addr(idev, &addr, flag);				if (ifp) {					if (idev->dev->flags&IFF_POINTOPOINT)						ifp->prefix_len = 10;					else						ifp->prefix_len = 96;					ifp->flags |= ADDR_PERMANENT;					ipv6_ifa_notify(RTM_NEWADDR, ifp);				}				addrconf_unlock();			}		}        }}static void init_loopback(struct device *dev){	struct in6_addr addr;	struct inet6_dev  *idev;	struct inet6_ifaddr * ifp;	/* ::1 */	memset(&addr, 0, sizeof(struct in6_addr));	addr.s6_addr[15] = 1;	if ((idev = ipv6_find_idev(dev)) == NULL) {		printk(KERN_DEBUG "init loopback: add_dev failed\n");		return;	}	addrconf_lock();	ifp = ipv6_add_addr(idev, &addr, IFA_HOST);	if (ifp) {		ifp->flags |= ADDR_PERMANENT;		ifp->prefix_len = 128;		ipv6_ifa_notify(RTM_NEWADDR, ifp);	}	addrconf_unlock();}static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr){	struct inet6_ifaddr * ifp;	addrconf_lock();	ifp = ipv6_add_addr(idev, addr, IFA_LINK);	if (ifp) {		ifp->flags = ADDR_PERMANENT;		ifp->prefix_len = 10;		addrconf_dad_start(ifp);	}	addrconf_unlock();}static void addrconf_dev_config(struct device *dev){	struct in6_addr addr;	struct inet6_dev    * idev;	if (dev->type != ARPHRD_ETHER) {		/* Alas, we support only Ethernet autoconfiguration. */		return;	}	idev = addrconf_add_dev(dev);	if (idev == NULL)		return;#ifdef CONFIG_IPV6_EUI64	memset(&addr, 0, sizeof(struct in6_addr));	addr.s6_addr[0] = 0xFE;	addr.s6_addr[1] = 0x80;	if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0)		addrconf_add_linklocal(idev, &addr);#endif#ifndef CONFIG_IPV6_NO_PB	memset(&addr, 0, sizeof(struct in6_addr));	addr.s6_addr[0] = 0xFE;	addr.s6_addr[1] = 0x80;	memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len), 	       dev->dev_addr, dev->addr_len);	addrconf_add_linklocal(idev, &addr);#endif}static void addrconf_sit_config(struct device *dev){	struct inet6_dev *idev;	/* 	 * 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);}int addrconf_notify(struct notifier_block *this, unsigned long event, 		    void * data){	struct device *dev;	dev = (struct device *) data;	switch(event) {	case NETDEV_UP:		switch(dev->type) {		case ARPHRD_SIT:			addrconf_sit_config(dev);			break;		case ARPHRD_LOOPBACK:			init_loopback(dev);			break;		default:			addrconf_dev_config(dev);			break;		};#ifdef CONFIG_IPV6_NETLINK		rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);#endif		break;	case NETDEV_CHANGEMTU:		if (dev->mtu >= IPV6_MIN_MTU) {			struct inet6_dev *idev;			if ((idev = ipv6_get_idev(dev)) == NULL)				break;			idev->cnf.mtu6 = dev->mtu;			rt6_mtu_change(dev, 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.		 */		if (addrconf_ifdown(dev, event != NETDEV_DOWN) == 0) {#ifdef CONFIG_IPV6_NETLINK			rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);#endif		}		break;	case NETDEV_CHANGE:		break;	};	return NOTIFY_OK;}static int addrconf_ifdown(struct device *dev, int how){	struct inet6_dev *idev, **bidev;	struct inet6_ifaddr *ifa, **bifa;	int i, hash;	rt6_ifdown(dev);	neigh_ifdown(&nd_tbl, dev);	idev = ipv6_get_idev(dev);	if (idev == NULL)		return -ENODEV;	start_bh_atomic();	/* Discard address list */	idev->addr_list = NULL;	/*	 * Clean addresses hash table	 */	for (i=0; i<16; i++) {		bifa = &inet6_addr_lst[i];		while ((ifa = *bifa) != NULL) {			if (ifa->idev == idev) {				*bifa = ifa->lst_next;				del_timer(&ifa->timer);				ipv6_ifa_notify(RTM_DELADDR, ifa);				kfree(ifa);				continue;			}			bifa = &ifa->lst_next;		}	}	/* Discard multicast list */	if (how == 1)		ipv6_mc_destroy_dev(idev);	else		ipv6_mc_down(idev);	/* Delete device from device hash table (if unregistered) */	if (how == 1) {		hash = ipv6_devindex_hash(dev->ifindex);		for (bidev = &inet6_dev_lst[hash]; (idev=*bidev) != NULL; bidev = &idev->next) {			if (idev->dev == dev) {				*bidev = idev->next;				neigh_parms_release(&nd_tbl, idev->nd_parms);#ifdef CONFIG_SYSCTL				addrconf_sysctl_unregister(&idev->cnf);#endif				kfree(idev);				break;			}		}	}	end_bh_atomic();	return 0;}static void addrconf_rs_timer(unsigned long data){	struct inet6_ifaddr *ifp;	ifp = (struct inet6_ifaddr *) data;	if (ifp->idev->cnf.forwarding)		return;	if (ifp->idev->if_flags & IF_RA_RCVD) {		/*		 *	Announcement received after solicitation		 *	was sent		 */		return;	}	if (ifp->probes++ <= ifp->idev->cnf.rtr_solicits) {		struct in6_addr all_routers;		ipv6_addr_all_routers(&all_routers);		ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers);				ifp->timer.function = addrconf_rs_timer;		ifp->timer.expires = (jiffies + 				      ifp->idev->cnf.rtr_solicit_interval);		add_timer(&ifp->timer);	} else {		struct in6_rtmsg rtmsg;		printk(KERN_DEBUG "%s: no IPv6 routers present\n",		       ifp->idev->dev->name);		memset(&rtmsg, 0, sizeof(struct in6_rtmsg));		rtmsg.rtmsg_type = RTMSG_NEWROUTE;		rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;		rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF | 				     RTF_DEFAULT | RTF_UP);

⌨️ 快捷键说明

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