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

📄 addrconf.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 4 页
字号:
			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 *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 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] = __constant_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 (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 = 10;				else					plen = 96;				ifp = ipv6_add_addr(idev, &addr, plen, flag,						    IFA_F_PERMANENT);				if (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 in6_addr addr;	struct inet6_dev  *idev;	struct inet6_ifaddr * ifp;	/* ::1 */	ASSERT_RTNL();	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;	}	ifp = ipv6_add_addr(idev, &addr, 128, IFA_HOST, IFA_F_PERMANENT);	if (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, 10, IFA_LINK, IFA_F_PERMANENT);	if (ifp) {		addrconf_dad_start(ifp);		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)) {		/* 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_addr[0] = 0xFE;	addr.s6_addr[1] = 0x80;	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);}int addrconf_notify(struct notifier_block *this, unsigned long event, 		    void * data){	struct net_device *dev;	dev = (struct net_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;		};		break;	case NETDEV_CHANGEMTU:		if (dev->mtu >= IPV6_MIN_MTU) {			struct inet6_dev *idev;			if ((idev = __in6_dev_get(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.		 */		addrconf_ifdown(dev, event != NETDEV_DOWN);		break;	case NETDEV_CHANGE:		break;	};	return NOTIFY_OK;}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);	}	/* Step 3: clear address list */	write_lock_bh(&idev->lock);	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 4: Discard multicast list */	if (how == 1)		ipv6_mc_destroy_dev(idev);	else		ipv6_mc_down(idev);	/* Shot the device (if unregistered) */	if (how == 1) {		neigh_parms_release(&nd_tbl, idev->nd_parms);#ifdef CONFIG_SYSCTL		addrconf_sysctl_unregister(&idev->cnf);#endif		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 {		struct in6_rtmsg rtmsg;		spin_unlock(&ifp->lock);		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);		rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;		ip6_route_add(&rtmsg);	}out:	in6_ifa_put(ifp);}/* *	Duplicate Address Detection */static void addrconf_dad_start(struct inet6_ifaddr *ifp){	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, RTF_ADDRCONF);	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){	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 &&	    (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_FSstatic int iface_proc_info(char *buffer, char **start, off_t offset,			   int length){	struct inet6_ifaddr *ifp;	int i;	int len = 0;	off_t pos=0;	off_t begin=0;	for (i=0; i < IN6_ADDR_HSIZE; i++) {		read_lock_bh(&addrconf_hash_lock);		for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {			int j;			for (j=0; j<16; j++) {				sprintf(buffer + len, "%02x",					ifp->addr.s6_addr[j]);				len += 2;			}			len += sprintf(buffer + len,				       " %02x %02x %02x %02x %8s\n",				       ifp->idev->dev->ifindex,

⌨️ 快捷键说明

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