📄 dev.c
字号:
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);
}
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)))
return -EFAULT;
}
return ret;
/*
* These ioctl calls:
* - require superuser power.
* - require strict serialization.
* - do not return a value
*/
case SIOCSIFFLAGS:
case SIOCSIFMETRIC:
case SIOCSIFMTU:
case SIOCSIFMAP:
case SIOCSIFHWADDR:
case SIOCSIFSLAVE:
case SIOCADDMULTI:
case SIOCDELMULTI:
case SIOCSIFHWBROADCAST:
case SIOCSIFTXQLEN:
case SIOCSIFNAME:
case SIOCETHTOOL:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
dev_probe_unlock();
return ret;
case SIOCGIFMEM:
/* Get the per device memory space. We can add this but currently
do not support it */
case SIOCSIFMEM:
/* Set the per device memory buffer space. Not applicable in our case */
case SIOCSIFLINK:
return -EINVAL;
/*
* Unknown or private ioctl.
*/
default:
if (cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) {
dev_load(ifr.ifr_name);
dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
dev_probe_unlock();
if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return ret;
}
#ifdef WIRELESS_EXT
/* Take care of Wireless Extensions */
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
/* If command is `set a parameter', or
* `get the encoding parameters', check if
* the user has the right to do it */
if (IW_IS_SET(cmd) || (cmd == SIOCGIWENCODE)) {
if(!capable(CAP_NET_ADMIN))
return -EPERM;
}
dev_load(ifr.ifr_name);
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
if (!ret && IW_IS_GET(cmd) &&
copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return ret;
}
#endif /* WIRELESS_EXT */
return -EINVAL;
}
}
/**
* dev_new_index - allocate an ifindex
*
* Returns a suitable unique value for a new device interface
* number. The caller must hold the rtnl semaphore or the
* dev_base_lock to be sure it remains unique.
*/
int dev_new_index(void)
{
static int ifindex;
for (;;) {
if (++ifindex <= 0)
ifindex=1;
if (__dev_get_by_index(ifindex) == NULL)
return ifindex;
}
}
static int dev_boot_phase = 1;
/**
* register_netdevice - register a network device
* @dev: device to register
*
* Take a completed network device structure and add it to the kernel
* interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier
* chain. 0 is returned on success. A negative errno code is returned
* on a failure to set up the device, or if the name is a duplicate.
*
* Callers must hold the rtnl semaphore. See the comment at the
* end of Space.c for details about the locking. You may want
* register_netdev() instead of this.
*
* BUGS:
* The locking appears insufficient to guarantee two parallel registers
* will not get the same name.
*/
int register_netdevice(struct net_device *dev)
{
struct net_device *d, **dp;
#ifdef CONFIG_NET_DIVERT
int ret;
#endif
spin_lock_init(&dev->queue_lock);
spin_lock_init(&dev->xmit_lock);
dev->xmit_lock_owner = -1;
#ifdef CONFIG_NET_FASTROUTE
dev->fastpath_lock=RW_LOCK_UNLOCKED;
#endif
if (dev_boot_phase) {
#ifdef CONFIG_NET_DIVERT
ret = alloc_divert_blk(dev);
if (ret)
return ret;
#endif /* CONFIG_NET_DIVERT */
/* This is NOT bug, but I am not sure, that all the
devices, initialized before netdev module is started
are sane.
Now they are chained to device boot list
and probed later. If a module is initialized
before netdev, but assumes that dev->init
is really called by register_netdev(), it will fail.
So that this message should be printed for a while.
*/
printk(KERN_INFO "early initialization of device %s is deferred\n", dev->name);
/* Check for existence, and append to tail of chain */
for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
if (d == dev || strcmp(d->name, dev->name) == 0) {
return -EEXIST;
}
}
dev->next = NULL;
write_lock_bh(&dev_base_lock);
*dp = dev;
dev_hold(dev);
write_unlock_bh(&dev_base_lock);
/*
* Default initial state at registry is that the
* device is present.
*/
set_bit(__LINK_STATE_PRESENT, &dev->state);
return 0;
}
#ifdef CONFIG_NET_DIVERT
ret = alloc_divert_blk(dev);
if (ret)
return ret;
#endif /* CONFIG_NET_DIVERT */
dev->iflink = -1;
/* Init, if this function is available */
if (dev->init && dev->init(dev) != 0)
return -EIO;
dev->ifindex = dev_new_index();
if (dev->iflink == -1)
dev->iflink = dev->ifindex;
/* Check for existence, and append to tail of chain */
for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
if (d == dev || strcmp(d->name, dev->name) == 0) {
return -EEXIST;
}
}
/*
* nil rebuild_header routine,
* that should be never called and used as just bug trap.
*/
if (dev->rebuild_header == NULL)
dev->rebuild_header = default_rebuild_header;
/*
* Default initial state at registry is that the
* device is present.
*/
set_bit(__LINK_STATE_PRESENT, &dev->state);
dev->next = NULL;
dev_init_scheduler(dev);
write_lock_bh(&dev_base_lock);
*dp = dev;
dev_hold(dev);
dev->deadbeaf = 0;
write_unlock_bh(&dev_base_lock);
/* Notify protocols, that a new device appeared. */
notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
net_run_sbin_hotplug(dev, "register");
return 0;
}
/**
* netdev_finish_unregister - complete unregistration
* @dev: device
*
* Destroy and free a dead device. A value of zero is returned on
* success.
*/
int netdev_finish_unregister(struct net_device *dev)
{
BUG_TRAP(dev->ip_ptr==NULL);
BUG_TRAP(dev->ip6_ptr==NULL);
BUG_TRAP(dev->dn_ptr==NULL);
if (!dev->deadbeaf) {
printk(KERN_ERR "Freeing alive device %p, %s\n", dev, dev->name);
return 0;
}
#ifdef NET_REFCNT_DEBUG
printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name,
(dev->features & NETIF_F_DYNALLOC)?"":", old style");
#endif
if (dev->destructor)
dev->destructor(dev);
if (dev->features & NETIF_F_DYNALLOC)
kfree(dev);
return 0;
}
/**
* unregister_netdevice - remove device from the kernel
* @dev: device
*
* This function shuts down a device interface and removes it
* from the kernel tables. On success 0 is returned, on a failure
* a negative errno code is returned.
*
* Callers must hold the rtnl semaphore. See the comment at the
* end of Space.c for details about the locking. You may want
* unregister_netdev() instead of this.
*/
int unregister_netdevice(struct net_device *dev)
{
unsigned long now, warning_time;
struct net_device *d, **dp;
/* If device is running, close it first. */
if (dev->flags & IFF_UP)
dev_close(dev);
BUG_TRAP(dev->deadbeaf==0);
dev->deadbeaf = 1;
/* And unlink it from device chain. */
for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {
if (d == dev) {
write_lock_bh(&dev_base_lock);
*dp = d->next;
write_unlock_bh(&dev_base_lock);
break;
}
}
if (d == NULL) {
printk(KERN_DEBUG "unregister_netdevice: device %s/%p never was registered\n", dev->name, dev);
return -ENODEV;
}
/* Synchronize to net_rx_action. */
br_write_lock_bh(BR_NETPROTO_LOCK);
br_write_unlock_bh(BR_NETPROTO_LOCK);
if (dev_boot_phase == 0) {
#ifdef CONFIG_NET_FASTROUTE
dev_clear_fastroute(dev);
#endif
/* Shutdown queueing discipline. */
dev_shutdown(dev);
net_run_sbin_hotplug(dev, "unregister");
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
*/
notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
/*
* Flush the multicast chain
*/
dev_mc_discard(dev);
}
if (dev->uninit)
dev->uninit(dev);
/* Notifier chain MUST detach us from master device. */
BUG_TRAP(dev->master==NULL);
#ifdef CONFIG_NET_DIVERT
free_divert_blk(dev);
#endif
if (dev->features & NETIF_F_DYNALLOC) {
#ifdef NET_REFCNT_DEBUG
if (atomic_read(&dev->refcnt) != 1)
printk(KERN_DEBUG "unregister_netdevice: holding %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)-1);
#endif
dev_put(dev);
return 0;
}
/* Last reference is our one */
if (atomic_read(&dev->refcnt) == 1) {
dev_put(dev);
return 0;
}
#ifdef NET_REFCNT_DEBUG
printk("unregister_netdevice: waiting %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt));
#endif
/* EXPLANATION. If dev->refcnt is not now 1 (our own reference)
it means that someone in the kernel still has a reference
to this device and we cannot release it.
"New style" devices have destructors, hence we can return from this
function and destructor will do all the work later. As of kernel 2.4.0
there are very few "New Style" devices.
"Old style" devices expect that the device is free of any references
upon exit from this function.
We cannot return from this function until all such references have
fallen away. This is because the caller of this function will probably
immediately kfree(*dev) and then be unloaded via sys_delete_module.
So, we linger until all references fall away. The duration of the
linger is basically unbounded! It is driven by, for example, the
current setting of sysctl_ipfrag_time.
After 1 second, we start to rebroadcast unregister notifications
in hope that careless clients will release the device.
*/
now = warning_time = jiffies;
while (atomic_read(&dev->refcnt) != 1) {
if ((jiffies - now) > 1*HZ) {
/* Rebroadcast unregister notification */
notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
}
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/4)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -