📄 dev.c
字号:
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_FS
static 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\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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -