📄 dev.c
字号:
* Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface * to create /proc/net/dev */ static int dev_get_info(char *buffer, char **start, off_t offset, int length){ int len = 0; off_t begin = 0; off_t pos = 0; int size; struct net_device *dev; size = sprintf(buffer, "Inter-| Receive | Transmit\n" " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"); pos += size; len += size; read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_stats(buffer+len, dev); len += size; pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) break; } read_unlock(&dev_base_lock); *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ if (len > length) len = length; /* Ending slop */ if (len < 0) len = 0; return len;}static int dev_proc_stats(char *buffer, char **start, off_t offset, int length, int *eof, void *data){ int i, lcpu; int len=0; for (lcpu=0; lcpu<smp_num_cpus; lcpu++) { i = cpu_logical_map(lcpu); len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", netdev_rx_stat[i].total, netdev_rx_stat[i].dropped, netdev_rx_stat[i].time_squeeze, netdev_rx_stat[i].throttled, netdev_rx_stat[i].fastroute_hit, netdev_rx_stat[i].fastroute_success, netdev_rx_stat[i].fastroute_defer, netdev_rx_stat[i].fastroute_deferred_out,#if 0 netdev_rx_stat[i].fastroute_latency_reduction#else netdev_rx_stat[i].cpu_collision#endif ); } len -= offset; if (len > length) len = length; if (len < 0) len = 0; *start = buffer + offset; *eof = 1; return len;}#endif /* CONFIG_PROC_FS */#ifdef WIRELESS_EXT#ifdef CONFIG_PROC_FS/* * Print one entry of /proc/net/wireless * This is a clone of /proc/net/dev (just above) */static int sprintf_wireless_stats(char *buffer, struct net_device *dev){ /* Get stats from the driver */ struct iw_statistics *stats = (dev->get_wireless_stats ? dev->get_wireless_stats(dev) : (struct iw_statistics *) NULL); int size; if (stats != (struct iw_statistics *) NULL) { size = sprintf(buffer, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d\n", dev->name, stats->status, stats->qual.qual, stats->qual.updated & 1 ? '.' : ' ', stats->qual.level, stats->qual.updated & 2 ? '.' : ' ', stats->qual.noise, stats->qual.updated & 4 ? '.' : ' ', stats->discard.nwid, stats->discard.code, stats->discard.misc); stats->qual.updated = 0; } else size = 0; return size;}/* * Print info for /proc/net/wireless (print all entries) * This is a clone of /proc/net/dev (just above) */static int dev_get_wireless_info(char * buffer, char **start, off_t offset, int length){ int len = 0; off_t begin = 0; off_t pos = 0; int size; struct net_device * dev; size = sprintf(buffer, "Inter-| sta-| Quality | Discarded packets\n" " face | tus | link level noise | nwid crypt misc\n" ); pos += size; len += size; read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_wireless_stats(buffer + len, dev); len += size; pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) break; } read_unlock(&dev_base_lock); *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ if (len > length) len = length; /* Ending slop */ if (len < 0) len = 0; return len;}#endif /* CONFIG_PROC_FS */#endif /* WIRELESS_EXT *//** * 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); } br_write_lock_bh(BR_NETPROTO_LOCK); slave->master = master; br_write_unlock_bh(BR_NETPROTO_LOCK); 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) {#ifdef CONFIG_NET_FASTROUTE if (dev->flags&IFF_PROMISC) { netdev_fastroute_obstacles++; dev_clear_fastroute(dev); } else netdev_fastroute_obstacles--;#endif 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);}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 == 0) 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;}/* * Perform the SIOCxIFxxx calls. */ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd){ struct net_device *dev; int err; if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) return -ENODEV; switch(cmd) { case SIOCGIFFLAGS: /* Get interface flags */ ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI|IFF_RUNNING)) |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); if (netif_running(dev) && netif_carrier_ok(dev)) ifr->ifr_flags |= IFF_RUNNING; 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 */ if (ifr->ifr_mtu == dev->mtu) return 0; /* * MTU must be positive. */ if (ifr->ifr_mtu<0) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; if (dev->change_mtu) err = dev->change_mtu(dev, ifr->ifr_mtu); else { dev->mtu = ifr->ifr_mtu; err = 0; } if (!err && dev->flags&IFF_UP) notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev); return err; case SIOCGIFHWADDR: memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr->ifr_hwaddr.sa_family=dev->type; return 0; case SIOCSIFHWADDR: if (dev->set_mac_address == NULL) 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, MAX_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 == NULL || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1); return 0; case SIOCDELMULTI: if (dev->set_multicast_list == NULL || ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; 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: if (dev->flags&IFF_UP) return -EBUSY; if (__dev_get_by_name(ifr->ifr_newname)) return -EEXIST; memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); dev->name[IFNAMSIZ-1] = 0; notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); return 0; /* * Unknown or private ioctl */ default: if ((cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) || cmd == SIOCETHTOOL) { if (dev->do_ioctl) { if (!netif_device_present(dev)) return -ENODEV; return dev->do_ioctl(dev, ifr, cmd); } return -EOPNOTSUPP; }#ifdef WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { if (dev->do_ioctl) { if (!netif_device_present(dev)) return -ENODEV; return dev->do_ioctl(dev, ifr, cmd); } return -EOPNOTSUPP; }#endif /* WIRELESS_EXT */ } return -EINVAL;}/* * 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 *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 *) arg); rtnl_shunlock(); return ret; } if (cmd == SIOCGIFNAME) { return dev_ifname((struct ifreq *)arg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -