📄 dev.c
字号:
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 + -