📄 dev.c
字号:
return softnet_get_online(pos);}static void softnet_seq_stop(struct seq_file *seq, void *v){}static int softnet_seq_show(struct seq_file *seq, void *v){ struct netif_rx_stats *s = v; seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", s->total, s->dropped, s->time_squeeze, s->throttled, s->fastroute_hit, s->fastroute_success, s->fastroute_defer, s->fastroute_deferred_out,#if 0 s->fastroute_latency_reduction#else s->cpu_collision#endif ); return 0;}static struct seq_operations dev_seq_ops = { .start = dev_seq_start, .next = dev_seq_next, .stop = dev_seq_stop, .show = dev_seq_show,};static int dev_seq_open(struct inode *inode, struct file *file){ return seq_open(file, &dev_seq_ops);}static struct file_operations dev_seq_fops = { .owner = THIS_MODULE, .open = dev_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};static struct seq_operations softnet_seq_ops = { .start = softnet_seq_start, .next = softnet_seq_next, .stop = softnet_seq_stop, .show = softnet_seq_show,};static int softnet_seq_open(struct inode *inode, struct file *file){ return seq_open(file, &softnet_seq_ops);}static struct file_operations softnet_seq_fops = { .owner = THIS_MODULE, .open = softnet_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};#ifdef WIRELESS_EXTextern int wireless_proc_init(void);#else#define wireless_proc_init() 0#endifstatic int __init dev_proc_init(void){ int rc = -ENOMEM; if (!proc_net_fops_create("dev", S_IRUGO, &dev_seq_fops)) goto out; if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops)) goto out_dev; if (wireless_proc_init()) goto out_softnet; rc = 0;out: return rc;out_softnet: proc_net_remove("softnet_stat");out_dev: proc_net_remove("dev"); goto out;}#else#define dev_proc_init() 0#endif /* CONFIG_PROC_FS *//** * netdev_set_master - set up master/slave pair * @slave: slave device * @master: new master device * * Changes the master device of the slave. Pass %NULL to break the * bonding. The caller must hold the RTNL semaphore. On a failure * a negative errno code is returned. On success the reference counts * are adjusted, %RTM_NEWLINK is sent to the routing socket and the * function returns zero. */int netdev_set_master(struct net_device *slave, struct net_device *master){ struct net_device *old = slave->master; ASSERT_RTNL(); if (master) { if (old) return -EBUSY; dev_hold(master); } slave->master = master; synchronize_net(); if (old) dev_put(old); if (master) slave->flags |= IFF_SLAVE; else slave->flags &= ~IFF_SLAVE; rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE); return 0;}/** * dev_set_promiscuity - update promiscuity count on a device * @dev: device * @inc: modifier * * Add or remove promsicuity from a device. While the count in the device * remains above zero the interface remains promiscuous. Once it hits zero * the device reverts back to normal filtering operation. A negative inc * value is used to drop promiscuity on the device. */void dev_set_promiscuity(struct net_device *dev, int inc){ unsigned short old_flags = dev->flags; dev->flags |= IFF_PROMISC; if ((dev->promiscuity += inc) == 0) dev->flags &= ~IFF_PROMISC; if (dev->flags ^ old_flags) { dev_mc_upload(dev); printk(KERN_INFO "device %s %s promiscuous mode\n", dev->name, (dev->flags & IFF_PROMISC) ? "entered" : "left"); }}/** * dev_set_allmulti - update allmulti count on a device * @dev: device * @inc: modifier * * Add or remove reception of all multicast frames to a device. While the * count in the device remains above zero the interface remains listening * to all interfaces. Once it hits zero the device reverts back to normal * filtering operation. A negative @inc value is used to drop the counter * when releasing a resource needing all multicasts. */void dev_set_allmulti(struct net_device *dev, int inc){ unsigned short old_flags = dev->flags; dev->flags |= IFF_ALLMULTI; if ((dev->allmulti += inc) == 0) dev->flags &= ~IFF_ALLMULTI; if (dev->flags ^ old_flags) dev_mc_upload(dev);}unsigned dev_get_flags(const struct net_device *dev){ unsigned flags; flags = (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI | IFF_RUNNING)) | (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); if (netif_running(dev) && netif_carrier_ok(dev)) flags |= IFF_RUNNING; return flags;}int dev_change_flags(struct net_device *dev, unsigned flags){ int ret; int old_flags = dev->flags; /* * Set the flags on our device. */ dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | IFF_AUTOMEDIA)) | (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | IFF_ALLMULTI)); /* * Load in the correct multicast list now the flags have changed. */ dev_mc_upload(dev); /* * Have we downed the interface. We handle IFF_UP ourselves * according to user attempts to set it, rather than blindly * setting it. */ ret = 0; if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */ ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); if (!ret) dev_mc_upload(dev); } if (dev->flags & IFF_UP && ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? +1 : -1; dev->gflags ^= IFF_PROMISC; dev_set_promiscuity(dev, inc); } /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI is important. Some (broken) drivers set IFF_PROMISC, when IFF_ALLMULTI is requested not asking us and not reporting. */ if ((flags ^ dev->gflags) & IFF_ALLMULTI) { int inc = (flags & IFF_ALLMULTI) ? +1 : -1; dev->gflags ^= IFF_ALLMULTI; dev_set_allmulti(dev, inc); } if (old_flags ^ dev->flags) rtmsg_ifinfo(RTM_NEWLINK, dev, old_flags ^ dev->flags); return ret;}int dev_set_mtu(struct net_device *dev, int new_mtu){ int err; if (new_mtu == dev->mtu) return 0; /* MTU must be positive. */ 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(&netdev_chain, NETDEV_CHANGEMTU, dev); return err;}/* * Perform the SIOCxIFxxx calls. */static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd){ int err; struct net_device *dev = __dev_get_by_name(ifr->ifr_name); if (!dev) return -ENODEV; switch (cmd) { case SIOCGIFFLAGS: /* Get interface flags */ ifr->ifr_flags = dev_get_flags(dev); return 0; case SIOCSIFFLAGS: /* Set interface flags */ return dev_change_flags(dev, ifr->ifr_flags); case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr->ifr_metric = 0; return 0; case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ return -EOPNOTSUPP; case SIOCGIFMTU: /* Get the MTU of a device */ ifr->ifr_mtu = dev->mtu; return 0; case SIOCSIFMTU: /* Set the MTU of a device */ return dev_set_mtu(dev, ifr->ifr_mtu); case SIOCGIFHWADDR: 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 SIOCSIFHWADDR: if (!dev->set_mac_address) return -EOPNOTSUPP; if (ifr->ifr_hwaddr.sa_family != dev->type) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; err = dev->set_mac_address(dev, &ifr->ifr_hwaddr); if (!err) notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; 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(&netdev_chain, NETDEV_CHANGEADDR, dev); 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 SIOCADDMULTI: if (!dev->set_multicast_list || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; return dev_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 dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data, dev->addr_len, 1); case SIOCGIFINDEX: ifr->ifr_ifindex = dev->ifindex; return 0; 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 SIOCSIFNAME: ifr->ifr_newname[IFNAMSIZ-1] = '\0'; return dev_change_name(dev, ifr->ifr_newname); /* * Unknown or private ioctl */ 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;}/* * This function handles all "interface"-type I/O control requests. The actual * 'doing' part of this is dev_ifsioc above. *//** * dev_ioctl - network device ioctl * @cmd: command to issue * @arg: pointer to a struct ifreq in user space * * Issue ioctl functions to devices. This is normally called by the * user space syscall interfaces but can sometimes be useful for * other purposes. The return value is the return from the syscall if * positive or a negative errno code on error. */int dev_ioctl(unsigned int cmd, void __user *arg){ struct ifreq ifr; int ret; char *colon; /* One special case: SIOCGIFCONF takes ifconf argument and requires shared lock, because it sleeps writing to user space. */ if (cmd == SIOCGIFCONF) { rtnl_shlock(); ret = dev_ifconf((char __user *) arg); rtnl_shunlock(); return ret; } if (cmd == SIOCGIFNAME) return dev_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; /* * See which interface the caller is talking about. */ switch (cmd) { /* * These ioctl calls: * - can be done by all. * - atomic and do not require locking. * - return a value */ case SIOCGIFFLAGS: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFHWADDR: case SIOCGIFSLAVE: case SIOCGIFMAP: case SIOCGIFINDEX: case SIOCGIFTXQLEN: dev_load(ifr.ifr_name); read_lock(&dev_base_lock); ret = dev_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; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -