📄 dev.c
字号:
} 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); current->state = TASK_RUNNING; if ((jiffies - warning_time) > 10*HZ) { printk(KERN_EMERG "unregister_netdevice: waiting for %s to " "become free. Usage count = %d\n", dev->name, atomic_read(&dev->refcnt)); warning_time = jiffies; } } dev_put(dev); return 0;}/* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not * present) and leaves us with a valid list of present and active devices. * */extern void net_device_init(void);extern void ip_auto_config(void);#ifdef CONFIG_NET_DIVERTextern void dv_init(void);#endif /* CONFIG_NET_DIVERT *//* * Callers must hold the rtnl semaphore. See the comment at the * end of Space.c for details about the locking. */int __init net_dev_init(void){ struct net_device *dev, **dp; int i;#ifdef CONFIG_NET_SCHED pktsched_init();#endif#ifdef CONFIG_NET_DIVERT dv_init();#endif /* CONFIG_NET_DIVERT */ /* * Initialise the packet receive queues. */ for (i = 0; i < NR_CPUS; i++) { struct softnet_data *queue; queue = &softnet_data[i]; skb_queue_head_init(&queue->input_pkt_queue); queue->throttle = 0; queue->cng_level = 0; queue->avg_blog = 10; /* arbitrary non-zero */ queue->completion_queue = NULL; } #ifdef CONFIG_NET_PROFILE net_profile_init(); NET_PROFILE_REGISTER(dev_queue_xmit); NET_PROFILE_REGISTER(softnet_process);#endif#ifdef OFFLINE_SAMPLE samp_timer.expires = jiffies + (10 * HZ); add_timer(&samp_timer);#endif /* * Add the devices. * If the call to dev->init fails, the dev is removed * from the chain disconnecting the device until the * next reboot. * * NB At boot phase networking is dead. No locking is required. * But we still preserve dev_base_lock for sanity. */ dp = &dev_base; while ((dev = *dp) != NULL) { spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->xmit_lock);#ifdef CONFIG_NET_FASTROUTE dev->fastpath_lock = RW_LOCK_UNLOCKED;#endif dev->xmit_lock_owner = -1; dev->iflink = -1; dev_hold(dev); /* * Allocate name. If the init() fails * the name will be reissued correctly. */ if (strchr(dev->name, '%')) dev_alloc_name(dev, dev->name); /* * Check boot time settings for the device. */ netdev_boot_setup_check(dev); if (dev->init && dev->init(dev)) { /* * It failed to come up. It will be unhooked later. * dev_alloc_name can now advance to next suitable * name that is checked next. */ dev->deadbeaf = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -