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(¨_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 = ¨_netdev_ops;
dev->ethtool_ops = ¨_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);
}