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

📄 dev.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 2 页
字号:
		return 0;	if (new_mtu < 0)		return -EINVAL;	if( !netif_device_present(dev) )		return -ENODEV;	err = 0;	if (dev->change_mtu)		err = dev->change_mtu( dev, new_mtu );	else		dev->mtu = new_mtu;	if( !err && dev->flags & IFF_UP )		notifier_call_chain( &mynetdev_chain, NETDEV_CHANGEMTU, dev );	return err;}int mydev_set_mac_address(struct net_device *dev, struct sockaddr *sa){	int err;	if( !dev->set_mac_address )		return -EOPNOTSUPP;	if( sa->sa_family != dev->type )		return -EINVAL;	if( !netif_device_present(dev) )		return -ENODEV;	err = dev->set_mac_address(dev, sa);	if (!err)		notifier_call_chain( &mynetdev_chain, NETDEV_CHANGEADDR, dev );	return err;}static int mydev_ifsioc(struct ifreq *ifr, unsigned int cmd){	int err = 0;	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);	if (!dev)		return -ENODEV;	switch( cmd ){		case SIOCGIFFLAGS:			ifr->ifr_flags = mydev_get_flags(dev);			return 0;		case SIOCGIFMTU:			ifr->ifr_mtu = dev->mtu;			return 0;		case SIOCGIFMETRIC:			ifr->ifr_metric = 0;			return 0;		case SIOCSIFFLAGS:			return mydev_change_flags(dev, ifr->ifr_flags);		case SIOCSIFMTU:			return mydev_set_mtu( dev, ifr->ifr_mtu );		case SIOCSIFMETRIC:			return -EOPNOTSUPP;		case SIOCGIFHWADDR:			if( !dev->addr_len )				memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data);			else				memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr,								min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));			ifr->ifr_hwaddr.sa_family = dev->type;			return 0;		case SIOCGIFMAP:			ifr->ifr_map.mem_start = dev->mem_start;			ifr->ifr_map.mem_end   = dev->mem_end;			ifr->ifr_map.base_addr = dev->base_addr;			ifr->ifr_map.irq       = dev->irq;			ifr->ifr_map.dma       = dev->dma;			ifr->ifr_map.port      = dev->if_port;			return 0;		case SIOCSIFMAP:			if( dev->set_config ){				if( !netif_device_present(dev) )					return -ENODEV;				return dev->set_config(dev, &ifr->ifr_map);			}			return -EOPNOTSUPP;		case SIOCGIFTXQLEN:			ifr->ifr_qlen = dev->tx_queue_len;			return 0;		case SIOCSIFTXQLEN:			if( ifr->ifr_qlen < 0 )				return -EINVAL;			dev->tx_queue_len = ifr->ifr_qlen;			return 0;		case SIOCGIFINDEX:			ifr->ifr_ifindex = dev->ifindex;			return 0;		case SIOCSIFHWADDR:			return mydev_set_mac_address(dev, &ifr->ifr_hwaddr);		case SIOCSIFNAME:			return -ENOIOCTLCMD;		case SIOCADDMULTI:			if( !dev->set_multicast_list ||							ifr->ifr_hwaddr.sa_family != AF_UNSPEC )				return -EINVAL;			if( !netif_device_present(dev) )				return -ENODEV;			return mydev_mc_add(dev, ifr->ifr_hwaddr.sa_data,dev->addr_len, 1);		case SIOCDELMULTI:			if( !dev->set_multicast_list ||							ifr->ifr_hwaddr.sa_family != AF_UNSPEC )				return -EINVAL;			if( !netif_device_present(dev) )				return -ENODEV;			return mydev_mc_delete(dev, ifr->ifr_hwaddr.sa_data, dev->addr_len, 1);		case SIOCSIFHWBROADCAST:			if( ifr->ifr_hwaddr.sa_family != dev->type )				return -EINVAL;			memcpy( dev->broadcast, ifr->ifr_hwaddr.sa_data,							min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));			notifier_call_chain( &mynetdev_chain, NETDEV_CHANGEADDR, dev );			return 0;		default:			if ((cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) ||							cmd == SIOCBONDENSLAVE ||							cmd == SIOCBONDRELEASE ||							cmd == SIOCBONDSETHWADDR ||							cmd == SIOCBONDSLAVEINFOQUERY ||							cmd == SIOCBONDINFOQUERY ||							cmd == SIOCBONDCHANGEACTIVE ||							cmd == SIOCGMIIPHY ||							cmd == SIOCGMIIREG ||							cmd == SIOCSMIIREG ||							cmd == SIOCBRADDIF ||							cmd == SIOCBRDELIF ||							cmd == SIOCWANDEV) {				err = -EOPNOTSUPP;				if( dev->do_ioctl ){					if( netif_device_present(dev) )						err = dev->do_ioctl( dev, ifr, cmd );					else						err = -ENODEV;				}			}else				err = -EINVAL;	}	return err;}static int mydev_ifconf(char __user *arg){	struct ifconf ifc;	struct net_device *dev;	char __user *pos;	int len;	int total;	int i;	if( copy_from_user(&ifc, arg, sizeof(struct ifconf)) )		return -EFAULT;	pos = ifc.ifc_buf;	len = ifc.ifc_len;	total = 0;	for( dev = dev_base; dev; dev = dev->next) {		for (i = 0; i < NPROTO; i++) {			if (gifconf_list[i]) {				int done;				if( !pos )					done = gifconf_list[i](dev, NULL, 0);				else					done = gifconf_list[i](dev, pos + total,							       len - total);				if (done < 0)					return -EFAULT;				total += done;			}		}  	}	ifc.ifc_len = total;	return copy_to_user(arg, &ifc, sizeof(struct ifconf)) ? -EFAULT : 0;}static int mydev_ifname(struct ifreq __user *arg){	struct net_device *dev;	struct ifreq ifr;	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))		return -EFAULT;	read_lock(&dev_base_lock);	dev = __dev_get_by_index( ifr.ifr_ifindex );	if (!dev) {		read_unlock(&dev_base_lock);		return -ENODEV;	}	strcpy(ifr.ifr_name, dev->name);	read_unlock(&dev_base_lock);	if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))		return -EFAULT;	return 0;}int mydev_ioctl(unsigned int cmd, void __user *arg){	struct ifreq ifr;	int ret;	char *colon;	if (cmd == SIOCGIFCONF) {		rtnl_shlock();		ret = mydev_ifconf((char __user *) arg);		rtnl_shunlock();		return ret;	}	if (cmd == SIOCGIFNAME)		return mydev_ifname((struct ifreq __user *)arg);	if( copy_from_user(&ifr, arg, sizeof(struct ifreq)) )		return -EFAULT;	ifr.ifr_name[IFNAMSIZ-1] = 0;	colon = strchr(ifr.ifr_name, ':');	if( colon )		*colon = 0;	switch( cmd ){		case SIOCGIFFLAGS:		case SIOCGIFMETRIC:		case SIOCGIFMTU:		case SIOCGIFHWADDR:		case SIOCGIFSLAVE:		case SIOCGIFMAP:		case SIOCGIFINDEX:		case SIOCGIFTXQLEN:			mydev_load(ifr.ifr_name);			read_lock(&dev_base_lock);			ret = mydev_ifsioc(&ifr, cmd);			read_unlock(&dev_base_lock);			if( !ret ){				if( colon )					*colon = ':';				if( copy_to_user(arg, &ifr, sizeof(struct ifreq)) )					ret = -EFAULT;			}			return ret;		case SIOCETHTOOL:			dev_load(ifr.ifr_name);			rtnl_lock();			ret = dev_ethtool(&ifr);			rtnl_unlock();			if (!ret) {				if (colon)					*colon = ':';				if (copy_to_user(arg, &ifr,						 sizeof(struct ifreq)))					ret = -EFAULT;			}			return ret;		case SIOCGMIIPHY:		case SIOCGMIIREG:		case SIOCSIFNAME:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			dev_load(ifr.ifr_name);			rtnl_lock();			ret = mydev_ifsioc(&ifr, cmd);			rtnl_unlock();			if (!ret) {				if (colon)					*colon = ':';				if (copy_to_user(arg, &ifr,						 sizeof(struct ifreq)))					ret = -EFAULT;			}			return ret;		case SIOCSIFFLAGS:		case SIOCSIFMETRIC:		case SIOCSIFMTU:		case SIOCSIFMAP:		case SIOCSIFHWADDR:		case SIOCSIFSLAVE:		case SIOCADDMULTI:		case SIOCDELMULTI:		case SIOCSIFHWBROADCAST:		case SIOCSIFTXQLEN:		case SIOCSMIIREG:		case SIOCBONDENSLAVE:		case SIOCBONDRELEASE:		case SIOCBONDSETHWADDR:		case SIOCBONDCHANGEACTIVE:		case SIOCBRADDIF:		case SIOCBRDELIF:			if (!capable(CAP_NET_ADMIN))				return -EPERM;		case SIOCBONDSLAVEINFOQUERY:		case SIOCBONDINFOQUERY:			dev_load(ifr.ifr_name);			rtnl_lock();			ret = mydev_ifsioc(&ifr, cmd);			rtnl_unlock();			return ret;		case SIOCGIFMEM:		case SIOCSIFMEM:		case SIOCSIFLINK:			return -EINVAL;		default:			if (cmd == SIOCWANDEV ||			    (cmd >= SIOCDEVPRIVATE &&			     cmd <= SIOCDEVPRIVATE + 15)) {				dev_load(ifr.ifr_name);				rtnl_lock();				ret = mydev_ifsioc(&ifr, cmd);				rtnl_unlock();				if (!ret && copy_to_user(arg, &ifr,							 sizeof(struct ifreq)))					ret = -EFAULT;				return ret;			}			return -EINVAL;	}	return 0;}#ifdef CONFIG_PROC_FSstatic __inline__ struct net_device *mydev_get_idx( loff_t pos ){	struct net_device *dev;	loff_t i = -1;	for( dev = dev_base; dev; dev = dev->next ){		if( strlen( dev->name ) > 2 && strncmp( dev->name, "my", 2 ) == 0 ){			if( ++i >= pos )				break;		}	}	return i == pos ? dev : NULL;}void *mydev_seq_start( struct seq_file *seq, loff_t *pos ){	read_lock( &dev_base_lock );	return *pos ? mydev_get_idx(*pos - 1) : SEQ_START_TOKEN;}void *mydev_seq_next(struct seq_file *seq, void *v, loff_t *pos){	++*pos;	return mydev_get_idx( *pos -1 );}void mydev_seq_stop(struct seq_file *seq, void *v){	read_unlock(&dev_base_lock);}static void mydev_seq_printf_stats(struct seq_file *seq, struct net_device *dev){	if (dev->get_stats) {		struct net_device_stats *stats = dev->get_stats(dev);		seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "						"%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",						dev->name, stats->rx_bytes, stats->rx_packets,						stats->rx_errors,						stats->rx_dropped + stats->rx_missed_errors,						stats->rx_fifo_errors,						stats->rx_length_errors + stats->rx_over_errors +						stats->rx_crc_errors + stats->rx_frame_errors,						stats->rx_compressed, stats->multicast,						stats->tx_bytes, stats->tx_packets,						stats->tx_errors, stats->tx_dropped,						stats->tx_fifo_errors, stats->collisions,						stats->tx_carrier_errors +						stats->tx_aborted_errors +						stats->tx_window_errors +						stats->tx_heartbeat_errors,						stats->tx_compressed);	}else		seq_printf(seq, "%6s: No statistics available.\n", dev->name);}static int mydev_seq_show(struct seq_file *seq, void *v){	if( v == SEQ_START_TOKEN )		seq_puts(seq, "Inter-|   Receive                            "						"                    |  Transmit\n"						" face |bytes    packets errs drop fifo frame "						"compressed multicast|bytes    packets errs "						"drop fifo colls carrier compressed\n");	else		mydev_seq_printf_stats(seq, v);	return 0;}struct seq_operations mydev_seq_ops = {	.start = mydev_seq_start,	.next  = mydev_seq_next,	.stop  = mydev_seq_stop,	.show  = mydev_seq_show,};static int mydev_seq_open( struct inode *inode, struct file *file ){	return seq_open( file, &mydev_seq_ops );}static struct file_operations mydev_seq_fops = {	.owner	 = THIS_MODULE,	.open    = mydev_seq_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release,};static int __init mydev_proc_init(void){	int rc = -ENOMEM;	if( !proc_net_fops_create("mydev", S_IRUGO, &mydev_seq_fops) )		goto out;	//if( !proc_net_fops_create("mysoftnet_stat", S_IRUGO, &softnet_seq_fops) )	//	goto out_dev;	rc = 0;out:	return rc;//out_softnet://	proc_net_remove("mysoftnet_stat");	goto out;}#else#define dev_proc_init() 0#endif	/* CONFIG_PROC_FS */int __init mynet_dev_init(void){	int i;	if( mydev_proc_init() )		goto out;	INIT_LIST_HEAD( &myptype_all );	for (i = 0; i < 16; i++) 		INIT_LIST_HEAD( &myptype_base[i] );	PR_DEBUG( "init the softnet_data queue...\n");	for_each_cpu(i) {		struct softnet_data *queue;		queue = &per_cpu( mysoftnet_data, i );		skb_queue_head_init( &queue->input_pkt_queue );		queue->completion_queue = NULL;		INIT_LIST_HEAD( &queue->poll_list );		set_bit( __LINK_STATE_START, &queue->backlog_dev.state );		queue->backlog_dev.weight = myweight_p;		queue->backlog_dev.poll = myprocess_backlog;		atomic_set( &queue->backlog_dev.refcnt, 1 );	}	open_softirq( MYNET_TX_SOFTIRQ, mynet_tx_action, NULL );	open_softirq( MYNET_RX_SOFTIRQ, mynet_rx_action, NULL );out:	return 0;}void __exit mynet_dev_exit(void){#ifdef CONFIG_PROC_FS	//proc_net_remove("mysoftnet_stat");    proc_net_remove("mydev");#endif}EXPORT_SYMBOL_GPL( mynetif_rx );EXPORT_SYMBOL_GPL( mydev_add_pack );EXPORT_SYMBOL_GPL( mydev_remove_pack );EXPORT_SYMBOL_GPL( mydev_queue_xmit );EXPORT_SYMBOL_GPL( myregister_gifconf );EXPORT_SYMBOL_GPL( myregister_netdevice_notifier );EXPORT_SYMBOL_GPL( myunregister_netdevice_notifier );EXPORT_SYMBOL_GPL( myregister_netdev );EXPORT_SYMBOL_GPL( mydev_ioctl );EXPORT_SYMBOL_GPL( mydev_change_flags );EXPORT_SYMBOL_GPL( myunregister_netdev );

⌨️ 快捷键说明

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