📄 dev.c
字号:
/* * NET3 Protocol independent device support routines. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Derived from the non IP parts of dev.c 1.0.19 * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> * * Additional Authors: * Florian la Roche <rzsfl@rz.uni-sb.de> * Alan Cox <gw4pts@gw4pts.ampr.org> * David Hinds <dahinds@users.sourceforge.net> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * Adam Sulmicki <adam@cfar.umd.edu> * Pekka Riikonen <priikone@poesidon.pspt.fi> * * Changes: * D.J. Barrow : Fixed bug where dev->refcnt gets set * to 2 if register_netdev gets called * before net_dev_init & also removed a * few lines of code in the process. * Alan Cox : device private ioctl copies fields back. * Alan Cox : Transmit queue code does relevant * stunts to keep the queue safe. * Alan Cox : Fixed double lock. * Alan Cox : Fixed promisc NULL pointer trap * ???????? : Support the full private ioctl range * Alan Cox : Moved ioctl permission check into * drivers * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI * Alan Cox : 100 backlog just doesn't cut it when * you start doing multicast video 8) * Alan Cox : Rewrote net_bh and list manager. * Alan Cox : Fix ETH_P_ALL echoback lengths. * Alan Cox : Took out transmit every packet pass * Saved a few bytes in the ioctl handler * Alan Cox : Network driver sets packet type before * calling netif_rx. Saves a function * call a packet. * Alan Cox : Hashed net_bh() * Richard Kooijman: Timestamp fixes. * Alan Cox : Wrong field in SIOCGIFDSTADDR * Alan Cox : Device lock protection. * Alan Cox : Fixed nasty side effect of device close * changes. * Rudi Cilibrasi : Pass the right thing to * set_mac_address() * Dave Miller : 32bit quantity for the device lock to * make it work out on a Sparc. * Bjorn Ekwall : Added KERNELD hack. * Alan Cox : Cleaned up the backlog initialise. * Craig Metz : SIOCGIFCONF fix if space for under * 1 device. * Thomas Bogendoerfer : Return ENODEV for dev_open, if there * is no device open function. * Andi Kleen : Fix error reporting for SIOCGIFCONF * Michael Chastain : Fix signed/unsigned for SIOCGIFCONF * Cyrus Durgin : Cleaned for KMOD * Adam Sulmicki : Bug Fix : Network Device Unload * A network device unload needs to purge * the backlog queue. * Paul Rusty Russell : SIOCSIFNAME * Pekka Riikonen : Netdev boot-time settings code * Andrew Morton : Make unregister_netdevice wait * indefinitely on dev->refcnt * J Hadi Salim : - Backlog queue sampling * - netif_rx() feedback */#include <asm/uaccess.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/config.h>#include <linux/cpu.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/notifier.h>#include <linux/skbuff.h>#include <net/sock.h>#include <linux/rtnetlink.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/stat.h>#include <linux/if_bridge.h>#include <linux/divert.h>#include <net/dst.h>#include <net/pkt_sched.h>#include <net/checksum.h>#include <linux/highmem.h>#include <linux/init.h>#include <linux/kmod.h>#include <linux/module.h>#include <linux/kallsyms.h>#include <linux/netpoll.h>#include <linux/rcupdate.h>#ifdef CONFIG_NET_RADIO#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */#include <net/iw_handler.h>#endif /* CONFIG_NET_RADIO */#include <asm/current.h>/* This define, if set, will randomly drop a packet when congestion * is more than moderate. It helps fairness in the multi-interface * case when one of them is a hog, but it kills performance for the * single interface case so it is off now by default. */#undef RAND_LIE/* Setting this will sample the queue lengths and thus congestion * via a timer instead of as each packet is received. */#undef OFFLINE_SAMPLE/* * The list of packet types we will receive (as opposed to discard) * and the routines to invoke. * * Why 16. Because with 16 the only overlap we get on a hash of the * low nibble of the protocol value is RARP/SNAP/X.25. * * NOTE: That is no longer true with the addition of VLAN tags. Not * sure which should go first, but I bet it won't make much * difference if we are running VLANs. The good news is that * this protocol won't be in the list unless compiled in, so * the average user (w/out VLANs) will not be adversly affected. * --BLG * * 0800 IP * 8100 802.1Q VLAN * 0001 802.3 * 0002 AX.25 * 0004 802.2 * 8035 RARP * 0005 SNAP * 0805 X.25 * 0806 ARP * 8137 IPX * 0009 Localtalk * 86DD IPv6 */static spinlock_t ptype_lock = SPIN_LOCK_UNLOCKED;static struct list_head ptype_base[16]; /* 16 way hashed list */static struct list_head ptype_all; /* Taps */#ifdef OFFLINE_SAMPLEstatic void sample_queue(unsigned long dummy);static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);#endif/* * The @dev_base list is protected by @dev_base_lock and the rtln * semaphore. * * Pure readers hold dev_base_lock for reading. * * Writers must hold the rtnl semaphore while they loop through the * dev_base list, and hold dev_base_lock for writing when they do the * actual updates. This allows pure readers to access the list even * while a writer is preparing to update it. * * To put it another way, dev_base_lock is held for writing only to * protect against pure readers; the rtnl semaphore provides the * protection against other writers. * * See, for example usages, register_netdevice() and * unregister_netdevice(), which must be called with the rtnl * semaphore held. */struct net_device *dev_base;struct net_device **dev_tail = &dev_base;rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;EXPORT_SYMBOL(dev_base);EXPORT_SYMBOL(dev_base_lock);#define NETDEV_HASHBITS 8static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];static struct hlist_head dev_index_head[1<<NETDEV_HASHBITS];static inline struct hlist_head *dev_name_hash(const char *name){ unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); return &dev_name_head[hash & ((1<<NETDEV_HASHBITS)-1)];}static inline struct hlist_head *dev_index_hash(int ifindex){ return &dev_index_head[ifindex & ((1<<NETDEV_HASHBITS)-1)];}/* * Our notifier list */static struct notifier_block *netdev_chain;/* * Device drivers call our routines to queue packets here. We empty the * queue in the local softnet handler. */DEFINE_PER_CPU(struct softnet_data, softnet_data) = { 0, };#ifdef CONFIG_SYSFSextern int netdev_sysfs_init(void);extern int netdev_register_sysfs(struct net_device *);extern void netdev_unregister_sysfs(struct net_device *);#else#define netdev_sysfs_init() (0)#define netdev_register_sysfs(dev) (0)#define netdev_unregister_sysfs(dev) do { } while(0)#endif/******************************************************************************* Protocol management and registration routines*******************************************************************************//* * For efficiency */int netdev_nit;/* * Add a protocol ID to the list. Now that the input handler is * smarter we can dispense with all the messy stuff that used to be * here. * * BEWARE!!! Protocol handlers, mangling input packets, * MUST BE last in hash buckets and checking protocol handlers * MUST start from promiscuous ptype_all chain in net_bh. * It is true now, do not change it. * Explanation follows: if protocol handler, mangling packet, will * be the first on list, it is not able to sense, that packet * is cloned and should be copied-on-write, so that it will * change it and subsequent readers will get broken packet. * --ANK (980803) *//** * dev_add_pack - add packet handler * @pt: packet type declaration * * Add a protocol handler to the networking stack. The passed &packet_type * is linked into kernel lists and may not be freed until it has been * removed from the kernel lists. * * This call does not sleep therefore it can not * guarantee all CPU's that are in middle of receiving packets * will see the new packet type (until the next received packet). */void dev_add_pack(struct packet_type *pt){ int hash; spin_lock_bh(&ptype_lock); if (pt->type == htons(ETH_P_ALL)) { netdev_nit++; list_add_rcu(&pt->list, &ptype_all); } else { hash = ntohs(pt->type) & 15; list_add_rcu(&pt->list, &ptype_base[hash]); } spin_unlock_bh(&ptype_lock);}extern void linkwatch_run_queue(void);/** * __dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function * returns. * * The packet type might still be in use by receivers * and must not be freed until after all the CPU's have gone * through a quiescent state. */void __dev_remove_pack(struct packet_type *pt){ struct list_head *head; struct packet_type *pt1; spin_lock_bh(&ptype_lock); if (pt->type == htons(ETH_P_ALL)) { netdev_nit--; head = &ptype_all; } else head = &ptype_base[ntohs(pt->type) & 15]; list_for_each_entry(pt1, head, list) { if (pt == pt1) { list_del_rcu(&pt->list); goto out; } } printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);out: spin_unlock_bh(&ptype_lock);}/** * dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function * returns. * * This call sleeps to guarantee that no CPU is looking at the packet * type after return. */void dev_remove_pack(struct packet_type *pt){ __dev_remove_pack(pt); synchronize_net();}/****************************************************************************** Device Boot-time Settings Routines*******************************************************************************//* Boot time configuration table */static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX];/** * netdev_boot_setup_add - add new setup entry * @name: name of the device * @map: configured settings for the device * * Adds new setup entry to the dev_boot_setup list. The function * returns 0 on error and 1 on success. This is a generic routine to * all netdevices. */int netdev_boot_setup_add(char *name, struct ifmap *map){ struct netdev_boot_setup *s; int i; s = dev_boot_setup; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { if (s[i].name[0] == '\0' || s[i].name[0] == ' ') { memset(s[i].name, 0, sizeof(s[i].name)); strcpy(s[i].name, name); memcpy(&s[i].map, map, sizeof(s[i].map)); break; } } return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1;}/** * netdev_boot_setup_check - check boot time settings * @dev: the netdevice * * Check boot time settings for the device. * The found settings are set for the device to be used * later in the device probing. * Returns 0 if no settings found, 1 if they are. */int netdev_boot_setup_check(struct net_device *dev){ struct netdev_boot_setup *s = dev_boot_setup; int i; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { if (s[i].name[0] != '\0' && s[i].name[0] != ' ' && !strncmp(dev->name, s[i].name, strlen(s[i].name))) { dev->irq = s[i].map.irq; dev->base_addr = s[i].map.base_addr; dev->mem_start = s[i].map.mem_start; dev->mem_end = s[i].map.mem_end; return 1; } } return 0;}/** * netdev_boot_base - get address from boot time settings * @prefix: prefix for network device * @unit: id for network device * * Check boot time settings for the base address of device. * The found settings are set for the device to be used * later in the device probing. * Returns 0 if no settings found. */unsigned long netdev_boot_base(const char *prefix, int unit){ const struct netdev_boot_setup *s = dev_boot_setup; char name[IFNAMSIZ]; int i; sprintf(name, "%s%d", prefix, unit); /* * If device already registered then return base of 1 * to indicate not to probe for this interface */ if (__dev_get_by_name(name)) return 1; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) if (!strcmp(name, s[i].name)) return s[i].map.base_addr; return 0;}/* * Saves at boot time configured settings for any netdevice. */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 * @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(const char *name){ struct hlist_node *p; hlist_for_each(p, dev_name_hash(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 * @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(const char *name){ struct net_device *dev; read_lock(&dev_base_lock); dev = __dev_get_by_name(name); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); return dev;}/* Return value is changed to int to prevent illegal usage in future. It is still legal to use to check for device existence. User should understand, that the result returned by this function is meaningless, if it was not issued under rtnl semaphore. *//**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -