Skip to content
Snippets Groups Projects
dev.c 108 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
    /*
     * 	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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *				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 <linux/bitops.h>
    
    #include <linux/capability.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/cpu.h>
    #include <linux/types.h>
    #include <linux/kernel.h>
    #include <linux/sched.h>
    
    Arjan van de Ven's avatar
    Arjan van de Ven committed
    #include <linux/mutex.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #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/net_namespace.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #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/if_macvlan.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #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>
    #include <linux/delay.h>
    
    #include <net/wext.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <net/iw_handler.h>
    #include <asm/current.h>
    
    Steve Grubb's avatar
    Steve Grubb committed
    #include <linux/audit.h>
    
    #include <linux/dmaengine.h>
    
    #include <linux/err.h>
    
    #include <linux/ctype.h>
    
    #include <linux/if_arp.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /*
     *	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 adversely affected.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *             --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 DEFINE_SPINLOCK(ptype_lock);
    
    static struct list_head ptype_base[16] __read_mostly;	/* 16 way hashed list */
    static struct list_head ptype_all __read_mostly;	/* Taps */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    struct net_dma {
    	struct dma_client client;
    	spinlock_t lock;
    	cpumask_t channel_mask;
    	struct dma_chan *channels[NR_CPUS];
    };
    
    static enum dma_state_client
    netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
    	enum dma_state state);
    
    static struct net_dma net_dma = {
    	.client = {
    		.event_callback = netdev_dma_event,
    	},
    };
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /*
    
     * The @dev_base_head list is protected by @dev_base_lock and the rtnl
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     * semaphore.
     *
     * Pure readers hold dev_base_lock for reading.
     *
     * Writers must hold the rtnl semaphore while they loop through the
    
     * dev_base_head list, and hold dev_base_lock for writing when they do the
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     * 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.
     */
    DEFINE_RWLOCK(dev_base_lock);
    
    EXPORT_SYMBOL(dev_base_lock);
    
    #define NETDEV_HASHBITS	8
    
    #define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
    
    	return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)];
    
    static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)];
    
    /* Device list insertion */
    static int list_netdevice(struct net_device *dev)
    {
    	struct net *net = dev->nd_net;
    
    	ASSERT_RTNL();
    
    	write_lock_bh(&dev_base_lock);
    	list_add_tail(&dev->dev_list, &net->dev_base_head);
    	hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name));
    	hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
    	write_unlock_bh(&dev_base_lock);
    	return 0;
    }
    
    /* Device list removal */
    static void unlist_netdevice(struct net_device *dev)
    {
    	ASSERT_RTNL();
    
    	/* Unlink dev from the device chain */
    	write_lock_bh(&dev_base_lock);
    	list_del(&dev->dev_list);
    	hlist_del(&dev->name_hlist);
    	hlist_del(&dev->index_hlist);
    	write_unlock_bh(&dev_base_lock);
    }
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /*
     *	Our notifier list
     */
    
    
    static RAW_NOTIFIER_HEAD(netdev_chain);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /*
     *	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);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    extern int netdev_kobject_init(void);
    extern int netdev_register_kobject(struct net_device *);
    extern void netdev_unregister_kobject(struct net_device *);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    /*
     * register_netdevice() inits dev->_xmit_lock and sets lockdep class
     * according to dev->type
     */
    static const unsigned short netdev_lock_type[] =
    	{ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25,
    	 ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET,
    	 ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM,
    	 ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP,
    	 ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD,
    	 ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25,
    	 ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP,
    	 ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD,
    	 ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI,
    	 ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE,
    	 ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET,
    	 ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
    	 ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211,
    	 ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_VOID,
    	 ARPHRD_NONE};
    
    static const char *netdev_lock_name[] =
    	{"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
    	 "_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET",
    	 "_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM",
    	 "_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP",
    	 "_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD",
    	 "_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25",
    	 "_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP",
    	 "_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD",
    	 "_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI",
    	 "_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE",
    	 "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET",
    	 "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
    	 "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211",
    	 "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_VOID",
    	 "_xmit_NONE"};
    
    static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
    
    static inline unsigned short netdev_lock_pos(unsigned short dev_type)
    {
    	int i;
    
    	for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++)
    		if (netdev_lock_type[i] == dev_type)
    			return i;
    	/* the last key is used by default */
    	return ARRAY_SIZE(netdev_lock_type) - 1;
    }
    
    static inline void netdev_set_lockdep_class(spinlock_t *lock,
    					    unsigned short dev_type)
    {
    	int i;
    
    	i = netdev_lock_pos(dev_type);
    	lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i],
    				   netdev_lock_name[i]);
    }
    #else
    static inline void netdev_set_lockdep_class(spinlock_t *lock,
    					    unsigned short dev_type)
    {
    }
    #endif
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /*******************************************************************************
    
    		Protocol management and registration routines
    
    *******************************************************************************/
    
    /*
     *	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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	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))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		list_add_rcu(&pt->list, &ptype_all);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		hash = ntohs(pt->type) & 15;
    		list_add_rcu(&pt->list, &ptype_base[hash]);
    	}
    	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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *
     *      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))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		head = &ptype_all;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	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.
     */
    static 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(&init_net, name))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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
    
     *	@net: the applicable net namespace
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct hlist_node *p;
    
    
    	hlist_for_each(p, dev_name_hash(net, name)) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct net_device *dev;
    
    	read_lock(&dev_base_lock);
    
    	dev = __dev_get_by_name(net, name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct hlist_node *p;
    
    
    	hlist_for_each(p, dev_index_hash(net, ifindex)) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct net_device *dev;
    
    	read_lock(&dev_base_lock);
    
    	dev = __dev_get_by_index(net, ifindex);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct net_device *dev;
    
    	ASSERT_RTNL();
    
    
    	for_each_netdev(&init_net, dev)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct net_device *dev;
    
    
    	ASSERT_RTNL();
    
    		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);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	rtnl_unlock();
    	return dev;
    }
    
    EXPORT_SYMBOL(dev_getfirstbyhwtype);
    
    /**
     *	dev_get_by_flags - find any device with given flags
    
     *	@net: the applicable net namespace
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	struct net_device *dev, *ret;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	read_lock(&dev_base_lock);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (((dev->flags ^ if_flags) & mask) == 0) {
    			dev_hold(dev);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			break;
    		}
    	}
    	read_unlock(&dev_base_lock);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /**
     *	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.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    int dev_valid_name(const char *name)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	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
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@name: name format string
    
     *	@buf:  scratch buffer and result name string
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *
     *	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.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    
    static int __dev_alloc_name(struct net *net, const char *name, char *buf)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	int i = 0;
    	const char *p;
    	const int max_netdevices = 8*PAGE_SIZE;
    
    	unsigned long *inuse;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	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);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (!inuse)
    			return -ENOMEM;
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			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);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			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))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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;
    }
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /**
     *	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];
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int err = 0;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	ASSERT_RTNL();
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (dev->flags & IFF_UP)
    		return -EBUSY;
    
    	if (!dev_valid_name(newname))
    		return -EINVAL;
    
    
    	memcpy(oldname, dev->name, IFNAMSIZ);
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	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))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		return -EEXIST;
    	else
    		strlcpy(dev->name, newname, IFNAMSIZ);
    
    
    	device_rename(&dev->dev, dev->name);
    
    	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;
    		}
    	}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	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);
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /**
     *	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);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
    	}
    }
    
    /**
     *	dev_load 	- load a network module
    
     *	@net: the applicable net namespace
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *	@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)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	struct net_device *dev;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	read_lock(&dev_base_lock);
    
    	dev = __dev_get_by_name(net, name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	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;
    
    	/*