static void eth_configure()

in drivers/net_kern.c [369:487]


static void eth_configure(int n, void *init, char *mac,
			  struct transport *transport, gfp_t gfp_mask)
{
	struct uml_net *device;
	struct net_device *dev;
	struct uml_net_private *lp;
	int err, size;

	size = transport->private_size + sizeof(struct uml_net_private);

	device = kzalloc(sizeof(*device), gfp_mask);
	if (device == NULL) {
		printk(KERN_ERR "eth_configure failed to allocate struct "
		       "uml_net\n");
		return;
	}

	dev = alloc_etherdev(size);
	if (dev == NULL) {
		printk(KERN_ERR "eth_configure: failed to allocate struct "
		       "net_device for eth%d\n", n);
		goto out_free_device;
	}

	INIT_LIST_HEAD(&device->list);
	device->index = n;

	/* If this name ends up conflicting with an existing registered
	 * netdevice, that is OK, register_netdev{,ice}() will notice this
	 * and fail.
	 */
	snprintf(dev->name, sizeof(dev->name), "eth%d", n);

	uml_net_setup_etheraddr(dev, mac);

	printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr);

	lp = netdev_priv(dev);
	/* This points to the transport private data. It's still clear, but we
	 * must memset it to 0 *now*. Let's help the drivers. */
	memset(lp, 0, size);
	INIT_WORK(&lp->work, uml_dev_close);

	/* sysfs register */
	if (!driver_registered) {
		platform_driver_register(&uml_net_driver);
		driver_registered = 1;
	}
	device->pdev.id = n;
	device->pdev.name = DRIVER_NAME;
	device->pdev.dev.release = net_device_release;
	dev_set_drvdata(&device->pdev.dev, device);
	if (platform_device_register(&device->pdev))
		goto out_free_netdev;
	SET_NETDEV_DEV(dev,&device->pdev.dev);

	device->dev = dev;

	/*
	 * These just fill in a data structure, so there's no failure
	 * to be worried about.
	 */
	(*transport->kern->init)(dev, init);

	*lp = ((struct uml_net_private)
		{ .list  		= LIST_HEAD_INIT(lp->list),
		  .dev 			= dev,
		  .fd 			= -1,
		  .mac 			= { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
		  .max_packet		= transport->user->max_packet,
		  .protocol 		= transport->kern->protocol,
		  .open 		= transport->user->open,
		  .close 		= transport->user->close,
		  .remove 		= transport->user->remove,
		  .read 		= transport->kern->read,
		  .write 		= transport->kern->write,
		  .add_address 		= transport->user->add_address,
		  .delete_address  	= transport->user->delete_address });

	spin_lock_init(&lp->lock);
	memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac));

	if ((transport->user->init != NULL) &&
	    ((*transport->user->init)(&lp->user, dev) != 0))
		goto out_unregister;

	dev->mtu = transport->user->mtu;
	dev->netdev_ops = &uml_netdev_ops;
	dev->ethtool_ops = &uml_net_ethtool_ops;
	dev->watchdog_timeo = (HZ >> 1);
	dev->irq = UM_ETH_IRQ;

	err = update_drop_skb(lp->max_packet);
	if (err)
		goto out_undo_user_init;

	rtnl_lock();
	err = register_netdevice(dev);
	rtnl_unlock();
	if (err)
		goto out_undo_user_init;

	spin_lock(&devices_lock);
	list_add(&device->list, &devices);
	spin_unlock(&devices_lock);

	return;

out_undo_user_init:
	if (transport->user->remove != NULL)
		(*transport->user->remove)(&lp->user);
out_unregister:
	platform_device_unregister(&device->pdev);
	return; /* platform_device_unregister frees dev and device */
out_free_netdev:
	free_netdev(dev);
out_free_device:
	kfree(device);
}