Skip to content
Snippets Groups Projects
dev.c 79.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
     
    /* Synchronize with packet receive processing. */
    void synchronize_net(void) 
    {
    	might_sleep();
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /**
     *	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.  You may want
     *	unregister_netdev() instead of this.
     */
    
    int unregister_netdevice(struct net_device *dev)
    {
    	struct net_device *d, **dp;
    
    	BUG_ON(dev_boot_phase);
    	ASSERT_RTNL();
    
    	/* Some devices call without registering for initialization unwind. */
    	if (dev->reg_state == NETREG_UNINITIALIZED) {
    		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "
    				  "was registered\n", dev->name, dev);
    		return -ENODEV;
    	}
    
    	BUG_ON(dev->reg_state != NETREG_REGISTERED);
    
    	/* If device is running, close it first. */
    	if (dev->flags & IFF_UP)
    		dev_close(dev);
    
    	/* 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);
    			hlist_del(&dev->name_hlist);
    			hlist_del(&dev->index_hlist);
    			if (dev_tail == &dev->next)
    				dev_tail = dp;
    			*dp = d->next;
    			write_unlock_bh(&dev_base_lock);
    			break;
    		}
    	}
    	if (!d) {
    		printk(KERN_ERR "unregister net_device: '%s' not found\n",
    		       dev->name);
    		return -ENODEV;
    	}
    
    	dev->reg_state = NETREG_UNREGISTERING;
    
    	synchronize_net();
    
    	/* Shutdown queueing discipline. */
    	dev_shutdown(dev);
    
    	
    	/* 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);
    
    	free_divert_blk(dev);
    
    	/* Finish processing unregister after unlock */
    	net_set_todo(dev);
    
    	synchronize_net();
    
    	dev_put(dev);
    	return 0;
    }
    
    /**
     *	unregister_netdev - 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.
     *
     *	This is just a wrapper for unregister_netdevice that takes
     *	the rtnl semaphore.  In general you want to use this and not
     *	unregister_netdevice.
     */
    void unregister_netdev(struct net_device *dev)
    {
    	rtnl_lock();
    	unregister_netdevice(dev);
    	rtnl_unlock();
    }
    
    EXPORT_SYMBOL(unregister_netdev);
    
    #ifdef CONFIG_HOTPLUG_CPU
    static int dev_cpu_callback(struct notifier_block *nfb,
    			    unsigned long action,
    			    void *ocpu)
    {
    	struct sk_buff **list_skb;
    	struct net_device **list_net;
    	struct sk_buff *skb;
    	unsigned int cpu, oldcpu = (unsigned long)ocpu;
    	struct softnet_data *sd, *oldsd;
    
    	if (action != CPU_DEAD)
    		return NOTIFY_OK;
    
    	local_irq_disable();
    	cpu = smp_processor_id();
    	sd = &per_cpu(softnet_data, cpu);
    	oldsd = &per_cpu(softnet_data, oldcpu);
    
    	/* Find end of our completion_queue. */
    	list_skb = &sd->completion_queue;
    	while (*list_skb)
    		list_skb = &(*list_skb)->next;
    	/* Append completion queue from offline CPU. */
    	*list_skb = oldsd->completion_queue;
    	oldsd->completion_queue = NULL;
    
    	/* Find end of our output_queue. */
    	list_net = &sd->output_queue;
    	while (*list_net)
    		list_net = &(*list_net)->next_sched;
    	/* Append output queue from offline CPU. */
    	*list_net = oldsd->output_queue;
    	oldsd->output_queue = NULL;
    
    	raise_softirq_irqoff(NET_TX_SOFTIRQ);
    	local_irq_enable();
    
    	/* Process offline CPU's input_pkt_queue */
    	while ((skb = __skb_dequeue(&oldsd->input_pkt_queue)))
    		netif_rx(skb);
    
    	return NOTIFY_OK;
    }
    #endif /* CONFIG_HOTPLUG_CPU */
    
    
    /*
     *	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.
     *
     */
    
    /*
     *       This is called single threaded during boot, so no need
     *       to take the rtnl semaphore.
     */
    static int __init net_dev_init(void)
    {
    	int i, rc = -ENOMEM;
    
    	BUG_ON(!dev_boot_phase);
    
    	net_random_init();
    
    	if (dev_proc_init())
    		goto out;
    
    	if (netdev_sysfs_init())
    		goto out;
    
    	INIT_LIST_HEAD(&ptype_all);
    	for (i = 0; i < 16; i++) 
    		INIT_LIST_HEAD(&ptype_base[i]);
    
    	for (i = 0; i < ARRAY_SIZE(dev_name_head); i++)
    		INIT_HLIST_HEAD(&dev_name_head[i]);
    
    	for (i = 0; i < ARRAY_SIZE(dev_index_head); i++)
    		INIT_HLIST_HEAD(&dev_index_head[i]);
    
    	/*
    	 *	Initialise the packet receive queues.
    	 */
    
    	for (i = 0; i < NR_CPUS; i++) {
    		struct softnet_data *queue;
    
    		queue = &per_cpu(softnet_data, i);
    		skb_queue_head_init(&queue->input_pkt_queue);
    		queue->completion_queue = NULL;
    		INIT_LIST_HEAD(&queue->poll_list);
    		set_bit(__LINK_STATE_START, &queue->backlog_dev.state);
    		queue->backlog_dev.weight = weight_p;
    		queue->backlog_dev.poll = process_backlog;
    		atomic_set(&queue->backlog_dev.refcnt, 1);
    	}
    
    	dev_boot_phase = 0;
    
    	open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
    	open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
    
    	hotcpu_notifier(dev_cpu_callback, 0);
    	dst_init();
    	dev_mcast_init();
    	rc = 0;
    out:
    	return rc;
    }
    
    subsys_initcall(net_dev_init);
    
    EXPORT_SYMBOL(__dev_get_by_index);
    EXPORT_SYMBOL(__dev_get_by_name);
    EXPORT_SYMBOL(__dev_remove_pack);
    EXPORT_SYMBOL(__skb_linearize);
    EXPORT_SYMBOL(dev_add_pack);
    EXPORT_SYMBOL(dev_alloc_name);
    EXPORT_SYMBOL(dev_close);
    EXPORT_SYMBOL(dev_get_by_flags);
    EXPORT_SYMBOL(dev_get_by_index);
    EXPORT_SYMBOL(dev_get_by_name);
    EXPORT_SYMBOL(dev_ioctl);
    EXPORT_SYMBOL(dev_open);
    EXPORT_SYMBOL(dev_queue_xmit);
    EXPORT_SYMBOL(dev_remove_pack);
    EXPORT_SYMBOL(dev_set_allmulti);
    EXPORT_SYMBOL(dev_set_promiscuity);
    EXPORT_SYMBOL(dev_change_flags);
    EXPORT_SYMBOL(dev_set_mtu);
    EXPORT_SYMBOL(dev_set_mac_address);
    EXPORT_SYMBOL(free_netdev);
    EXPORT_SYMBOL(netdev_boot_setup_check);
    EXPORT_SYMBOL(netdev_set_master);
    EXPORT_SYMBOL(netdev_state_change);
    EXPORT_SYMBOL(netif_receive_skb);
    EXPORT_SYMBOL(netif_rx);
    EXPORT_SYMBOL(register_gifconf);
    EXPORT_SYMBOL(register_netdevice);
    EXPORT_SYMBOL(register_netdevice_notifier);
    EXPORT_SYMBOL(skb_checksum_help);
    EXPORT_SYMBOL(synchronize_net);
    EXPORT_SYMBOL(unregister_netdevice);
    EXPORT_SYMBOL(unregister_netdevice_notifier);
    EXPORT_SYMBOL(net_enable_timestamp);
    EXPORT_SYMBOL(net_disable_timestamp);
    EXPORT_SYMBOL(dev_get_flags);
    
    #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
    EXPORT_SYMBOL(br_handle_frame_hook);
    EXPORT_SYMBOL(br_fdb_get_hook);
    EXPORT_SYMBOL(br_fdb_put_hook);
    #endif
    
    #ifdef CONFIG_KMOD
    EXPORT_SYMBOL(dev_load);
    #endif
    
    EXPORT_PER_CPU_SYMBOL(softnet_data);