📄 dev.c
字号:
*/int __init netdev_boot_setup(char *str){ int ints[5]; struct ifmap map; str = get_options(str, ARRAY_SIZE(ints), ints); if (!str || !*str) return 0; /* Save settings */ memset(&map, 0, sizeof(map)); if (ints[0] > 0) map.irq = ints[1]; if (ints[0] > 1) map.base_addr = ints[2]; if (ints[0] > 2) map.mem_start = ints[3]; if (ints[0] > 3) map.mem_end = ints[4]; /* Add new entry to the list */ return netdev_boot_setup_add(str, &map);}__setup("netdev=", netdev_boot_setup);/******************************************************************************* Device Interface Subroutines*******************************************************************************//** * __dev_get_by_name - find a device by its name * @net: the applicable net namespace * @name: name to find * * Find an interface by name. Must be called under RTNL semaphore * or @dev_base_lock. If the name is found a pointer to the device * is returned. If the name is not found then %NULL is returned. The * reference counters are not incremented so the caller must be * careful with locks. */struct net_device *__dev_get_by_name(struct net *net, const char *name){ struct hlist_node *p; hlist_for_each(p, dev_name_hash(net, name)) { struct net_device *dev = hlist_entry(p, struct net_device, name_hlist); if (!strncmp(dev->name, name, IFNAMSIZ)) return dev; } return NULL;}/** * dev_get_by_name - find a device by its name * @net: the applicable net namespace * @name: name to find * * Find an interface by name. This can be called from any * context and does its own locking. The returned handle has * the usage count incremented and the caller must use dev_put() to * release it when it is no longer needed. %NULL is returned if no * matching device is found. */struct net_device *dev_get_by_name(struct net *net, const char *name){ struct net_device *dev; read_lock(&dev_base_lock); dev = __dev_get_by_name(net, name); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); return dev;}/** * __dev_get_by_index - find a device by its ifindex * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns %NULL if the device * is not found or a pointer to the device. The device has not * had its reference counter increased so the caller must be careful * about locking. The caller must hold either the RTNL semaphore * or @dev_base_lock. */struct net_device *__dev_get_by_index(struct net *net, int ifindex){ struct hlist_node *p; hlist_for_each(p, dev_index_hash(net, ifindex)) { struct net_device *dev = hlist_entry(p, struct net_device, index_hlist); if (dev->ifindex == ifindex) return dev; } return NULL;}/** * dev_get_by_index - find a device by its ifindex * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns NULL if the device * is not found or a pointer to the device. The device returned has * had a reference added and the pointer is safe until the user calls * dev_put to indicate they have finished with it. */struct net_device *dev_get_by_index(struct net *net, int ifindex){ struct net_device *dev; read_lock(&dev_base_lock); dev = __dev_get_by_index(net, ifindex); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); return dev;}/** * dev_getbyhwaddr - find a device by its hardware address * @net: the applicable net namespace * @type: media type of device * @ha: hardware address * * Search for an interface by MAC address. Returns NULL if the device * is not found or a pointer to the device. The caller must hold the * rtnl semaphore. The returned device has not had its ref count increased * and the caller must therefore be careful about locking * * BUGS: * If the API was consistent this would be __dev_get_by_hwaddr */struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha){ struct net_device *dev; ASSERT_RTNL(); for_each_netdev(&init_net, dev) if (dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len)) return dev; return NULL;}EXPORT_SYMBOL(dev_getbyhwaddr);struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type){ struct net_device *dev; ASSERT_RTNL(); for_each_netdev(net, dev) if (dev->type == type) return dev; return NULL;}EXPORT_SYMBOL(__dev_getfirstbyhwtype);struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type){ struct net_device *dev; rtnl_lock(); dev = __dev_getfirstbyhwtype(net, type); if (dev) dev_hold(dev); rtnl_unlock(); return dev;}EXPORT_SYMBOL(dev_getfirstbyhwtype);/** * dev_get_by_flags - find any device with given flags * @net: the applicable net namespace * @if_flags: IFF_* values * @mask: bitmask of bits in if_flags to check * * Search for any interface with the given flags. Returns NULL if a device * is not found or a pointer to the device. The device returned has * had a reference added and the pointer is safe until the user calls * dev_put to indicate they have finished with it. */struct net_device * dev_get_by_flags(struct net *net, unsigned short if_flags, unsigned short mask){ struct net_device *dev, *ret; ret = NULL; read_lock(&dev_base_lock); for_each_netdev(net, dev) { if (((dev->flags ^ if_flags) & mask) == 0) { dev_hold(dev); ret = dev; break; } } read_unlock(&dev_base_lock); return ret;}/** * dev_valid_name - check if name is okay for network device * @name: name string * * Network device names need to be valid file names to * to allow sysfs to work. We also disallow any kind of * whitespace. */int dev_valid_name(const char *name){ if (*name == '\0') return 0; if (strlen(name) >= IFNAMSIZ) return 0; if (!strcmp(name, ".") || !strcmp(name, "..")) return 0; while (*name) { if (*name == '/' || isspace(*name)) return 0; name++; } return 1;}/** * __dev_alloc_name - allocate a name for a device * @net: network namespace to allocate the device name in * @name: name format string * @buf: scratch buffer and result name string * * Passed a format string - eg "lt%d" it will try and find a suitable * id. It scans list of devices to build up a free map, then chooses * the first empty slot. The caller must hold the dev_base or rtnl lock * while allocating the name and adding the device in order to avoid * duplicates. * Limited to bits_per_byte * page size devices (ie 32K on most platforms). * Returns the number of the unit assigned or a negative errno code. */static int __dev_alloc_name(struct net *net, const char *name, char *buf){ int i = 0; const char *p; const int max_netdevices = 8*PAGE_SIZE; unsigned long *inuse; struct net_device *d; p = strnchr(name, IFNAMSIZ-1, '%'); if (p) { /* * Verify the string as this thing may have come from * the user. There must be either one "%d" and no other "%" * characters. */ if (p[1] != 'd' || strchr(p + 2, '%')) return -EINVAL; /* Use one page as a bit array of possible slots */ inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC); if (!inuse) return -ENOMEM; for_each_netdev(net, d) { if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices) continue; /* avoid cases where sscanf is not exact inverse of printf */ snprintf(buf, IFNAMSIZ, name, i); if (!strncmp(buf, d->name, IFNAMSIZ)) set_bit(i, inuse); } i = find_first_zero_bit(inuse, max_netdevices); free_page((unsigned long) inuse); } snprintf(buf, IFNAMSIZ, name, i); if (!__dev_get_by_name(net, buf)) return i; /* It is possible to run out of possible slots * when the name is long and there isn't enough space left * for the digits, or if all bits are used. */ return -ENFILE;}/** * dev_alloc_name - allocate a name for a device * @dev: device * @name: name format string * * Passed a format string - eg "lt%d" it will try and find a suitable * id. It scans list of devices to build up a free map, then chooses * the first empty slot. The caller must hold the dev_base or rtnl lock * while allocating the name and adding the device in order to avoid * duplicates. * Limited to bits_per_byte * page size devices (ie 32K on most platforms). * Returns the number of the unit assigned or a negative errno code. */int dev_alloc_name(struct net_device *dev, const char *name){ char buf[IFNAMSIZ]; struct net *net; int ret; BUG_ON(!dev->nd_net); net = dev->nd_net; ret = __dev_alloc_name(net, name, buf); if (ret >= 0) strlcpy(dev->name, buf, IFNAMSIZ); return ret;}/** * dev_change_name - change name of a device * @dev: device * @newname: name (or format string) must be at least IFNAMSIZ * * Change name of a device, can pass format strings "eth%d". * for wildcarding. */int dev_change_name(struct net_device *dev, char *newname){ char oldname[IFNAMSIZ]; int err = 0; int ret; struct net *net; ASSERT_RTNL(); BUG_ON(!dev->nd_net); net = dev->nd_net; if (dev->flags & IFF_UP) return -EBUSY; if (!dev_valid_name(newname)) return -EINVAL; if (strncmp(newname, dev->name, IFNAMSIZ) == 0) return 0; memcpy(oldname, dev->name, IFNAMSIZ); if (strchr(newname, '%')) { err = dev_alloc_name(dev, newname); if (err < 0) return err; strcpy(newname, dev->name); } else if (__dev_get_by_name(net, newname)) return -EEXIST; else strlcpy(dev->name, newname, IFNAMSIZ);rollback: device_rename(&dev->dev, dev->name); write_lock_bh(&dev_base_lock); hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); write_unlock_bh(&dev_base_lock); ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); ret = notifier_to_errno(ret); if (ret) { if (err) { printk(KERN_ERR "%s: name change rollback failed: %d.\n", dev->name, ret); } else { err = ret; memcpy(dev->name, oldname, IFNAMSIZ); goto rollback; } } return err;}/** * netdev_features_change - device changes features * @dev: device to cause notification * * Called to indicate a device has changed features. */void netdev_features_change(struct net_device *dev){ call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev);}EXPORT_SYMBOL(netdev_features_change);/** * netdev_state_change - device changes state * @dev: device to cause notification * * Called to indicate a device has changed state. This function calls * the notifier chains for netdev_chain and sends a NEWLINK message * to the routing socket. */void netdev_state_change(struct net_device *dev){ if (dev->flags & IFF_UP) { call_netdevice_notifiers(NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); }}/** * dev_load - load a network module * @net: the applicable net namespace * @name: name of interface * * If a network interface is not present and the process has suitable * privileges this function loads the module. If module loading is not * available in this kernel then it becomes a nop. */void dev_load(struct net *net, const char *name){ struct net_device *dev; read_lock(&dev_base_lock); dev = __dev_get_by_name(net, name); read_unlock(&dev_base_lock); if (!dev && capable(CAP_SYS_MODULE)) request_module("%s", name);}/** * dev_open - prepare an interface for use. * @dev: device to open * * Takes a device from down to up state. The device's private open * function is invoked and then the multicast lists are loaded. Finally * the device is moved into the up state and a %NETDEV_UP message is * sent to the netdev notifier chain. * * Calling this function on an active interface is a nop. On a failure * a negative errno code is returned. */int dev_open(struct net_device *dev){ int ret = 0; /* * Is it already up? */ if (dev->flags & IFF_UP) return 0; /* * Is it even present? */ if (!netif_device_present(dev)) return -ENODEV; /* * Call device private open method */ set_bit(__LINK_STATE_START, &dev->state); if (dev->validate_addr) ret = dev->validate_addr(dev); if (!ret && dev->open) ret = dev->open(dev); /* * If it went open OK then: */ if (ret) clear_bit(__LINK_STATE_START, &dev->state); else { /* * Set the flags. */ dev->flags |= IFF_UP; /* * Initialize multicasting status */ dev_set_rx_mode(dev); /* * Wakeup transmit queue engine */ dev_activate(dev); /* * ... and announce new interface. */ call_netdevice_notifiers(NETDEV_UP, dev); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -