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

📄 devinet.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	if( !in_dev ){		if( event == NETDEV_REGISTER && dev == &loopback_dev ){			in_dev = myinetdev_init( dev );			if (!in_dev)				panic("devinet: Failed to create loopback\n");			in_dev->cnf.no_xfrm = 1;			in_dev->cnf.no_policy = 1;		}		goto out;	}	switch (event) {		case NETDEV_REGISTER:			PR_DEBUG( "inetdev_event: bug\n");			dev->ip_ptr = NULL;			break;		case NETDEV_UP:			if(	dev->mtu < 68 )				break;			if(	dev == &loopback_dev ){				struct in_ifaddr *ifa;				if( (ifa = myinet_alloc_ifa()) != NULL ){					ifa->ifa_local = ifa->ifa_address = htonl(INADDR_LOOPBACK);					ifa->ifa_prefixlen = 8;					ifa->ifa_mask = inet_make_mask(8);					in_dev_hold(in_dev);					ifa->ifa_dev = in_dev;					ifa->ifa_scope = RT_SCOPE_HOST;					memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);					myinet_insert_ifa(ifa);				}			}			//ip_mc_up(in_dev);			break;		case NETDEV_DOWN:			//ip_mc_down(in_dev);			break;		case NETDEV_CHANGEMTU:			if (dev->mtu >= 68)				break;		case NETDEV_UNREGISTER:			//myinetdev_destroy(in_dev);		//the kernel's code has done this!!!			break;		case NETDEV_CHANGENAME:			myinetdev_changename(dev, in_dev);/*#ifdef CONFIG_SYSCTL			devinet_sysctl_unregister(&in_dev->cnf);			neigh_sysctl_unregister(in_dev->arp_parms);			neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,							NET_IPV4_NEIGH, "ipv4", NULL, NULL);			devinet_sysctl_register(in_dev, &in_dev->cnf);#endif*/			break;	}		out:	return 0;}static __inline__ int myinet_abc_len(u32 addr){	int rc = -1;  	if( ZERONET(addr) )  		rc = 0;	else{		addr = ntohl(addr);		if (IN_CLASSA(addr))			rc = 8;		else if (IN_CLASSB(addr))			rc = 16;		else if (IN_CLASSC(addr))			rc = 24;	}  	return rc;}static int myinet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa){	struct in_device *in_dev = __in_dev_get_rtnl(dev);	ASSERT_RTNL();	if (!in_dev) {		in_dev = myinetdev_init(dev);		if( !in_dev ){			myinet_free_ifa(ifa);			return -ENOBUFS;		}	}	if( ifa->ifa_dev != in_dev ){		BUG_TRAP( !ifa->ifa_dev );		in_dev_hold(in_dev);		ifa->ifa_dev = in_dev;	}	if( LOOPBACK(ifa->ifa_local) )		ifa->ifa_scope = RT_SCOPE_HOST;	return myinet_insert_ifa(ifa);}int mydevinet_ioctl(unsigned int cmd, void __user *arg){	struct ifreq ifr;	struct sockaddr_in sin_orig;	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;	char *colon;	struct in_device *in_dev;	struct in_ifaddr **ifap = NULL;	struct in_ifaddr *ifa = NULL;	struct net_device *dev;	int ret = -EFAULT;	int tryaddrmatch = 0;	if( copy_from_user(&ifr, arg, sizeof(struct ifreq)) )		goto out;	ifr.ifr_name[IFNAMSIZ - 1] = 0;	memcpy(&sin_orig, sin, sizeof(*sin));	colon = strchr(ifr.ifr_name, ':');	if( colon )		*colon = 0;#ifdef CONFIG_KMOD	dev_load(ifr.ifr_name);#endif	switch(cmd) {		case SIOCGIFADDR:		case SIOCGIFBRDADDR:		case SIOCGIFDSTADDR:		case SIOCGIFNETMASK:				tryaddrmatch = (sin_orig.sin_family == MY_AF_INET);				memset( sin, 0, sizeof(*sin) );				sin->sin_family = MY_AF_INET;				break;		case SIOCSIFFLAGS:				ret = -EACCES;				if( !capable(CAP_NET_ADMIN) )					goto out;				break;		case SIOCSIFADDR:		case SIOCSIFBRDADDR:		case SIOCSIFDSTADDR:		case SIOCSIFNETMASK:				ret = -EACCES;				if (!capable(CAP_NET_ADMIN))						goto out;				ret = -EINVAL;				if (sin->sin_family != MY_AF_INET)						goto out;				break;		default:				ret = -EINVAL;				goto out;	}	rtnl_lock();	ret = -ENODEV;	if( (dev = __dev_get_by_name(ifr.ifr_name)) == NULL )		goto done;	if( colon )		*colon = ':';	if( (in_dev = __in_dev_get_rtnl(dev)) != NULL ){		if( tryaddrmatch ){			for( ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next ){				if( !strcmp(ifr.ifr_name, ifa->ifa_label) &&				    sin_orig.sin_addr.s_addr == ifa->ifa_address) {					break;				}			}		}		if( !ifa ){			for( ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next )				if( !strcmp(ifr.ifr_name, ifa->ifa_label) )					break;		}	}	ret = -EADDRNOTAVAIL;	if( !ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS )		goto done;	switch(cmd) {		case SIOCGIFADDR:			sin->sin_addr.s_addr = ifa->ifa_local;			goto rarok;		case SIOCGIFBRDADDR:			sin->sin_addr.s_addr = ifa->ifa_broadcast;			goto rarok;		case SIOCGIFDSTADDR:			sin->sin_addr.s_addr = ifa->ifa_address;			goto rarok;		case SIOCGIFNETMASK:			sin->sin_addr.s_addr = ifa->ifa_mask;			goto rarok;		case SIOCSIFBRDADDR:			ret = 0;			if( ifa->ifa_broadcast != sin->sin_addr.s_addr ){				myinet_del_ifa(in_dev, ifap, 0);				ifa->ifa_broadcast = sin->sin_addr.s_addr;				myinet_insert_ifa(ifa);			}			break;		case SIOCSIFADDR:			ret = -EINVAL;			if( myinet_abc_len(sin->sin_addr.s_addr) < 0)				break;			if( !ifa ){				ret = -ENOBUFS;				if( (ifa = myinet_alloc_ifa()) == NULL )					break;				if( colon )					memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);				else					memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);			}else{				ret = 0;				if (ifa->ifa_local == sin->sin_addr.s_addr)					break;				myinet_del_ifa(in_dev, ifap, 0);				ifa->ifa_broadcast = 0;				ifa->ifa_anycast = 0;			}			ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;			if( !(dev->flags & IFF_POINTOPOINT) ){				ifa->ifa_prefixlen = myinet_abc_len(ifa->ifa_address);				ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);				if( (dev->flags & IFF_BROADCAST) && ifa->ifa_prefixlen < 31 )					ifa->ifa_broadcast = ifa->ifa_address | ~ifa->ifa_mask;			}else{				ifa->ifa_prefixlen = 32;				ifa->ifa_mask = inet_make_mask(32);			}			ret = myinet_set_ifa(dev, ifa);			break;		case SIOCSIFFLAGS:			if( colon ){				ret = -EADDRNOTAVAIL;				if( !ifa )					break;				ret = 0;				if( !(ifr.ifr_flags & IFF_UP) )					myinet_del_ifa( in_dev, ifap, 1 );				break;			}			ret = mydev_change_flags( dev, ifr.ifr_flags );			break;		case SIOCSIFNETMASK:			ret = -EINVAL;			if( bad_mask(sin->sin_addr.s_addr, 0) )				break;			ret = 0;			if (ifa->ifa_mask != sin->sin_addr.s_addr) {				u32 old_mask = ifa->ifa_mask;				myinet_del_ifa(in_dev, ifap, 0);				ifa->ifa_mask = sin->sin_addr.s_addr;				ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);				if( (dev->flags & IFF_BROADCAST) && (ifa->ifa_prefixlen < 31) &&								(ifa->ifa_broadcast == (ifa->ifa_local|~old_mask))) {					ifa->ifa_broadcast = (ifa->ifa_local | ~sin->sin_addr.s_addr);				}				myinet_insert_ifa(ifa);			}			break;		case SIOCSIFDSTADDR:			ret = 0;			if (ifa->ifa_address == sin->sin_addr.s_addr)				break;			ret = -EINVAL;			if( myinet_abc_len(sin->sin_addr.s_addr) < 0 )				break;			ret = 0;			myinet_del_ifa(in_dev, ifap, 0);			ifa->ifa_address = sin->sin_addr.s_addr;			myinet_insert_ifa(ifa);			break;	}done:	rtnl_unlock();out:	return ret;rarok:	rtnl_unlock();	ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;	goto out;}static struct notifier_block myip_netdev_notifier = {	.notifier_call = myinetdev_event,};static int myinet_gifconf(struct net_device *dev, char __user *buf, int len){	struct in_device *in_dev = __in_dev_get_rtnl(dev);	struct in_ifaddr *ifa;	struct ifreq ifr;	int done = 0;	if( !in_dev || (ifa = in_dev->ifa_list) == NULL )		goto out;	for (; ifa; ifa = ifa->ifa_next) {		if( !buf ){			done += sizeof(ifr);			continue;		}		if( len < (int) sizeof(ifr) )			break;		memset(&ifr, 0, sizeof(struct ifreq));		if( ifa->ifa_label )			strcpy(ifr.ifr_name, ifa->ifa_label);		else			strcpy(ifr.ifr_name, dev->name);		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = MY_AF_INET;		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local;		if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {			done = -EFAULT;			break;		}		buf  += sizeof(struct ifreq);		len  -= sizeof(struct ifreq);		done += sizeof(struct ifreq);	}out:	return done;}void __init mydevinet_init(void){	myregister_gifconf( MY_PF_INET, myinet_gifconf );	myregister_netdevice_notifier( &myip_netdev_notifier );}void __exit mydevinet_exit(void){	myunregister_netdevice_notifier( &myip_netdev_notifier );	myunregister_gifconf( MY_PF_INET );}EXPORT_SYMBOL_GPL( mydevinet_ioctl );

⌨️ 快捷键说明

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