📄 dev.c
字号:
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;}/* * Perform a SIOCGIFCONF call. This structure will change * size eventually, and there is nothing I can do about it. * Thus we will need a 'compatibility mode'. */static int dev_ifconf(char *arg){ struct ifconf ifc; struct net_device *dev; char *pos; int len; int total; int i; /* * Fetch the caller's info block. */ if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) return -EFAULT; pos = ifc.ifc_buf; len = ifc.ifc_len; /* * Loop over the interfaces, and write an info block for each. */ total = 0; for (dev = dev_base; dev != NULL; dev = dev->next) { for (i=0; i<NPROTO; i++) { if (gifconf_list[i]) { int done; if (pos==NULL) { done = gifconf_list[i](dev, NULL, 0); } else { done = gifconf_list[i](dev, pos+total, len-total); } if (done<0) { return -EFAULT; } total += done; } } } /* * All done. Write the updated control block back to the caller. */ ifc.ifc_len = total; if (copy_to_user(arg, &ifc, sizeof(struct ifconf))) return -EFAULT; /* * Both BSD and Solaris return 0 here, so we do too. */ return 0;}/* * This is invoked by the /proc filesystem handler to display a device * in detail. */#ifdef CONFIG_PROC_FSstatic int sprintf_stats(char *buffer, struct net_device *dev){ struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL); int size; if (stats) size = sprintf(buffer, "%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 size = sprintf(buffer, "%6s: No statistics available.\n", dev->name); return size;}/* * 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 %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.fragment, stats->discard.retries, stats->discard.misc, stats->miss.beacon); 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 | Missed\n" " face | tus | link level noise | nwid crypt frag retry misc | beacon\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 *//* * Allow programatic access to /proc/net/wireless even if /proc * doesn't exist... Also more efficient... */static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr){ /* Get stats from the driver */ struct iw_statistics *stats = (dev->get_wireless_stats ? dev->get_wireless_stats(dev) : (struct iw_statistics *) NULL); if (stats != (struct iw_statistics *) NULL) { struct iwreq * wrq = (struct iwreq *)ifr; /* Copy statistics to the user buffer */ if(copy_to_user(wrq->u.data.pointer, stats, sizeof(struct iw_statistics))) return -EFAULT; /* Check if we need to clear the update flag */ if(wrq->u.data.flags != 0) stats->qual.updated = 0; return(0); } else return -EOPNOTSUPP;}#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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -