net_init.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:19k
- /* net_init.c: Initialization for network devices. */
- /*
- Written 1993,1994,1995 by Donald Becker.
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
- This file contains the initialization for the "pl14+" style ethernet
- drivers. It should eventually replace most of drivers/net/Space.c.
- It's primary advantage is that it's able to allocate low-memory buffers.
- A secondary advantage is that the dangerous NE*000 netcards can reserve
- their I/O port region before the SCSI probes start.
- Modifications/additions by Bjorn Ekwall <bj0rn@blox.se>:
- ethdev_index[MAX_ETH_CARDS]
- register_netdev() / unregister_netdev()
-
- Modifications by Wolfgang Walter
- Use dev_close cleanly so we always shut things down tidily.
-
- Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses.
-
- 14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function.
- 24/09/96 - Paul Norton: Add token-ring variants of the netdev functions.
-
- 08/11/99 - Alan Cox: Got fed up of the mess in this file and cleaned it
- up. We now share common code and have regularised name
- allocation setups. Abolished the 16 card limits.
- 03/19/2000 - jgarzik and Urban Widmark: init_etherdev 32-byte align
- 03/21/2001 - jgarzik: alloc_etherdev and friends
- */
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/slab.h>
- #include <linux/if_ether.h>
- #include <linux/string.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/fddidevice.h>
- #include <linux/hippidevice.h>
- #include <linux/trdevice.h>
- #include <linux/fcdevice.h>
- #include <linux/if_arp.h>
- #include <linux/if_ltalk.h>
- #include <linux/rtnetlink.h>
- #include <net/neighbour.h>
- /* The network devices currently exist only in the socket namespace, so these
- entries are unused. The only ones that make sense are
- open start the ethercard
- close stop the ethercard
- ioctl To get statistics, perhaps set the interface port (AUI, BNC, etc.)
- One can also imagine getting raw packets using
- read & write
- but this is probably better handled by a raw packet socket.
- Given that almost all of these functions are handled in the current
- socket-based scheme, putting ethercard devices in /dev/ seems pointless.
-
- [Removed all support for /dev network devices. When someone adds
- streams then by magic we get them, but otherwise they are un-needed
- and a space waste]
- */
- static struct net_device *alloc_netdev(int sizeof_priv, const char *mask,
- void (*setup)(struct net_device *))
- {
- struct net_device *dev;
- int alloc_size;
- /* ensure 32-byte alignment of the private area */
- alloc_size = sizeof (*dev) + sizeof_priv + 31;
- dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL);
- if (dev == NULL)
- {
- printk(KERN_ERR "alloc_dev: Unable to allocate device memory.n");
- return NULL;
- }
- memset(dev, 0, alloc_size);
- if (sizeof_priv)
- dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
- setup(dev);
- strcpy(dev->name, mask);
- return dev;
- }
- static struct net_device *init_alloc_dev(int sizeof_priv)
- {
- struct net_device *dev;
- int alloc_size;
- /* ensure 32-byte alignment of the private area */
- alloc_size = sizeof (*dev) + sizeof_priv + 31;
- dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL);
- if (dev == NULL)
- {
- printk(KERN_ERR "alloc_dev: Unable to allocate device memory.n");
- return NULL;
- }
- memset(dev, 0, alloc_size);
- if (sizeof_priv)
- dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
- return dev;
- }
- /*
- * Create and name a device from a prototype, then perform any needed
- * setup.
- */
- static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv,
- char *mask, void (*setup)(struct net_device *))
- {
- int new_device = 0;
- /*
- * Allocate a device if one is not provided.
- */
-
- if (dev == NULL) {
- dev=init_alloc_dev(sizeof_priv);
- if(dev==NULL)
- return NULL;
- new_device = 1;
- }
- /*
- * Allocate a name
- */
-
- if (dev->name[0] == ' ' || dev->name[0] == ' ') {
- strcpy(dev->name, mask);
- if (dev_alloc_name(dev, mask)<0) {
- if (new_device)
- kfree(dev);
- return NULL;
- }
- }
- netdev_boot_setup_check(dev);
-
- /*
- * Configure via the caller provided setup function then
- * register if needed.
- */
-
- setup(dev);
-
- if (new_device) {
- int err;
- rtnl_lock();
- err = register_netdevice(dev);
- rtnl_unlock();
- if (err < 0) {
- kfree(dev);
- dev = NULL;
- }
- }
- return dev;
- }
- #if defined(CONFIG_HIPPI) || defined(CONFIG_TR) || defined(CONFIG_NET_FC)
- static int __register_netdev(struct net_device *dev)
- {
- if (dev->init && dev->init(dev) != 0) {
- unregister_netdev(dev);
- return -EIO;
- }
- return 0;
- }
- #endif
- /**
- * init_etherdev - Register ethernet device
- * @dev: An ethernet device structure to be filled in, or %NULL if a new
- * struct should be allocated.
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this ethernet device
- *
- * Fill in the fields of the device structure with ethernet-generic values.
- *
- * If no device structure is passed, a new one is constructed, complete with
- * a private data area of size @sizeof_priv. A 32-byte (not bit)
- * alignment is enforced for this private data area.
- *
- * If an empty string area is passed as dev->name, or a new structure is made,
- * a new name string is constructed.
- */
- struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv)
- {
- return init_netdev(dev, sizeof_priv, "eth%d", ether_setup);
- }
- /**
- * alloc_etherdev - Allocates and sets up an ethernet device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this ethernet device
- *
- * Fill in the fields of the device structure with ethernet-generic
- * values. Basically does everything except registering the device.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
- struct net_device *alloc_etherdev(int sizeof_priv)
- {
- return alloc_netdev(sizeof_priv, "eth%d", ether_setup);
- }
- EXPORT_SYMBOL(init_etherdev);
- EXPORT_SYMBOL(alloc_etherdev);
- static int eth_mac_addr(struct net_device *dev, void *p)
- {
- struct sockaddr *addr=p;
- if (netif_running(dev))
- return -EBUSY;
- memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
- return 0;
- }
- static int eth_change_mtu(struct net_device *dev, int new_mtu)
- {
- if ((new_mtu < 68) || (new_mtu > 1500))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
- }
- #ifdef CONFIG_FDDI
- /**
- * init_fddidev - Register FDDI device
- * @dev: A FDDI device structure to be filled in, or %NULL if a new
- * struct should be allocated.
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this ethernet device
- *
- * Fill in the fields of the device structure with FDDI-generic values.
- *
- * If no device structure is passed, a new one is constructed, complete with
- * a private data area of size @sizeof_priv. A 32-byte (not bit)
- * alignment is enforced for this private data area.
- *
- * If an empty string area is passed as dev->name, or a new structure is made,
- * a new name string is constructed.
- */
- struct net_device *init_fddidev(struct net_device *dev, int sizeof_priv)
- {
- return init_netdev(dev, sizeof_priv, "fddi%d", fddi_setup);
- }
- /**
- * alloc_fddidev - Register FDDI device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this FDDI device
- *
- * Fill in the fields of the device structure with FDDI-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
- struct net_device *alloc_fddidev(int sizeof_priv)
- {
- return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup);
- }
- EXPORT_SYMBOL(init_fddidev);
- EXPORT_SYMBOL(alloc_fddidev);
- static int fddi_change_mtu(struct net_device *dev, int new_mtu)
- {
- if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN))
- return(-EINVAL);
- dev->mtu = new_mtu;
- return(0);
- }
- #endif /* CONFIG_FDDI */
- #ifdef CONFIG_HIPPI
- static int hippi_change_mtu(struct net_device *dev, int new_mtu)
- {
- /*
- * HIPPI's got these nice large MTUs.
- */
- if ((new_mtu < 68) || (new_mtu > 65280))
- return -EINVAL;
- dev->mtu = new_mtu;
- return(0);
- }
- /*
- * For HIPPI we will actually use the lower 4 bytes of the hardware
- * address as the I-FIELD rather than the actual hardware address.
- */
- static int hippi_mac_addr(struct net_device *dev, void *p)
- {
- struct sockaddr *addr = p;
- if (netif_running(dev))
- return -EBUSY;
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- return 0;
- }
- /**
- * init_hippi_dev - Register HIPPI device
- * @dev: A HIPPI device structure to be filled in, or %NULL if a new
- * struct should be allocated.
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this ethernet device
- *
- * Fill in the fields of the device structure with HIPPI-generic values.
- *
- * If no device structure is passed, a new one is constructed, complete with
- * a private data area of size @sizeof_priv. A 32-byte (not bit)
- * alignment is enforced for this private data area.
- *
- * If an empty string area is passed as dev->name, or a new structure is made,
- * a new name string is constructed.
- */
- struct net_device *init_hippi_dev(struct net_device *dev, int sizeof_priv)
- {
- return init_netdev(dev, sizeof_priv, "hip%d", hippi_setup);
- }
- /**
- * alloc_hippi_dev - Register HIPPI device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this HIPPI device
- *
- * Fill in the fields of the device structure with HIPPI-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
- struct net_device *alloc_hippi_dev(int sizeof_priv)
- {
- return alloc_netdev(sizeof_priv, "hip%d", hippi_setup);
- }
- int register_hipdev(struct net_device *dev)
- {
- return __register_netdev(dev);
- }
- void unregister_hipdev(struct net_device *dev)
- {
- unregister_netdev(dev);
- }
- EXPORT_SYMBOL(init_hippi_dev);
- EXPORT_SYMBOL(alloc_hippi_dev);
- EXPORT_SYMBOL(register_hipdev);
- EXPORT_SYMBOL(unregister_hipdev);
- static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
- {
- /* Never send broadcast/multicast ARP messages */
- p->mcast_probes = 0;
-
- /* In IPv6 unicast probes are valid even on NBMA,
- * because they are encapsulated in normal IPv6 protocol.
- * Should be a generic flag.
- */
- if (p->tbl->family != AF_INET6)
- p->ucast_probes = 0;
- return 0;
- }
- #endif /* CONFIG_HIPPI */
- void ether_setup(struct net_device *dev)
- {
- /* Fill in the fields of the device structure with ethernet-generic values.
- This should be in a common file instead of per-driver. */
-
- dev->change_mtu = eth_change_mtu;
- dev->hard_header = eth_header;
- dev->rebuild_header = eth_rebuild_header;
- dev->set_mac_address = eth_mac_addr;
- dev->hard_header_cache = eth_header_cache;
- dev->header_cache_update= eth_header_cache_update;
- dev->hard_header_parse = eth_header_parse;
- dev->type = ARPHRD_ETHER;
- dev->hard_header_len = ETH_HLEN;
- dev->mtu = 1500; /* eth_mtu */
- dev->addr_len = ETH_ALEN;
- dev->tx_queue_len = 100; /* Ethernet wants good queues */
-
- memset(dev->broadcast,0xFF, ETH_ALEN);
- /* New-style flags. */
- dev->flags = IFF_BROADCAST|IFF_MULTICAST;
- }
- EXPORT_SYMBOL(ether_setup);
- #ifdef CONFIG_FDDI
- void fddi_setup(struct net_device *dev)
- {
- /*
- * Fill in the fields of the device structure with FDDI-generic values.
- * This should be in a common file instead of per-driver.
- */
-
- dev->change_mtu = fddi_change_mtu;
- dev->hard_header = fddi_header;
- dev->rebuild_header = fddi_rebuild_header;
- dev->type = ARPHRD_FDDI;
- dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */
- dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */
- dev->addr_len = FDDI_K_ALEN;
- dev->tx_queue_len = 100; /* Long queues on FDDI */
-
- memset(dev->broadcast, 0xFF, FDDI_K_ALEN);
- /* New-style flags */
- dev->flags = IFF_BROADCAST | IFF_MULTICAST;
- }
- EXPORT_SYMBOL(fddi_setup);
- #endif /* CONFIG_FDDI */
- #ifdef CONFIG_HIPPI
- void hippi_setup(struct net_device *dev)
- {
- dev->set_multicast_list = NULL;
- dev->change_mtu = hippi_change_mtu;
- dev->hard_header = hippi_header;
- dev->rebuild_header = hippi_rebuild_header;
- dev->set_mac_address = hippi_mac_addr;
- dev->hard_header_parse = NULL;
- dev->hard_header_cache = NULL;
- dev->header_cache_update = NULL;
- dev->neigh_setup = hippi_neigh_setup_dev;
- /*
- * We don't support HIPPI `ARP' for the time being, and probably
- * never will unless someone else implements it. However we
- * still need a fake ARPHRD to make ifconfig and friends play ball.
- */
- dev->type = ARPHRD_HIPPI;
- dev->hard_header_len = HIPPI_HLEN;
- dev->mtu = 65280;
- dev->addr_len = HIPPI_ALEN;
- dev->tx_queue_len = 25 /* 5 */;
- memset(dev->broadcast, 0xFF, HIPPI_ALEN);
- /*
- * HIPPI doesn't support broadcast+multicast and we only use
- * static ARP tables. ARP is disabled by hippi_neigh_setup_dev.
- */
- dev->flags = 0;
- }
- EXPORT_SYMBOL(hippi_setup);
- #endif /* CONFIG_HIPPI */
- #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
- static int ltalk_change_mtu(struct net_device *dev, int mtu)
- {
- return -EINVAL;
- }
- static int ltalk_mac_addr(struct net_device *dev, void *addr)
- {
- return -EINVAL;
- }
- void ltalk_setup(struct net_device *dev)
- {
- /* Fill in the fields of the device structure with localtalk-generic values. */
-
- dev->change_mtu = ltalk_change_mtu;
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->set_mac_address = ltalk_mac_addr;
- dev->hard_header_cache = NULL;
- dev->header_cache_update= NULL;
- dev->type = ARPHRD_LOCALTLK;
- dev->hard_header_len = LTALK_HLEN;
- dev->mtu = LTALK_MTU;
- dev->addr_len = LTALK_ALEN;
- dev->tx_queue_len = 10;
-
- dev->broadcast[0] = 0xFF;
- dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
- }
- EXPORT_SYMBOL(ltalk_setup);
- #endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
- int register_netdev(struct net_device *dev)
- {
- int err;
- rtnl_lock();
- /*
- * If the name is a format string the caller wants us to
- * do a name allocation
- */
-
- if (strchr(dev->name, '%'))
- {
- err = dev_alloc_name(dev, dev->name);
- if (err < 0)
- goto out;
- }
-
- /*
- * Back compatibility hook. Kill this one in 2.5
- */
-
- if (dev->name[0]==0 || dev->name[0]==' ')
- {
- err = dev_alloc_name(dev, "eth%d");
- if (err < 0)
- goto out;
- }
- err = register_netdevice(dev);
- out:
- rtnl_unlock();
- return err;
- }
- void unregister_netdev(struct net_device *dev)
- {
- rtnl_lock();
- unregister_netdevice(dev);
- rtnl_unlock();
- }
- EXPORT_SYMBOL(register_netdev);
- EXPORT_SYMBOL(unregister_netdev);
- #ifdef CONFIG_TR
- void tr_setup(struct net_device *dev)
- {
- /*
- * Configure and register
- */
-
- dev->hard_header = tr_header;
- dev->rebuild_header = tr_rebuild_header;
- dev->type = ARPHRD_IEEE802_TR;
- dev->hard_header_len = TR_HLEN;
- dev->mtu = 2000;
- dev->addr_len = TR_ALEN;
- dev->tx_queue_len = 100; /* Long queues on tr */
-
- memset(dev->broadcast,0xFF, TR_ALEN);
- /* New-style flags. */
- dev->flags = IFF_BROADCAST | IFF_MULTICAST ;
- }
- /**
- * init_trdev - Register token ring device
- * @dev: A token ring device structure to be filled in, or %NULL if a new
- * struct should be allocated.
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this ethernet device
- *
- * Fill in the fields of the device structure with token ring-generic values.
- *
- * If no device structure is passed, a new one is constructed, complete with
- * a private data area of size @sizeof_priv. A 32-byte (not bit)
- * alignment is enforced for this private data area.
- *
- * If an empty string area is passed as dev->name, or a new structure is made,
- * a new name string is constructed.
- */
- struct net_device *init_trdev(struct net_device *dev, int sizeof_priv)
- {
- return init_netdev(dev, sizeof_priv, "tr%d", tr_setup);
- }
- /**
- * alloc_trdev - Register token ring device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this token ring device
- *
- * Fill in the fields of the device structure with token ring-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
- struct net_device *alloc_trdev(int sizeof_priv)
- {
- return alloc_netdev(sizeof_priv, "tr%d", tr_setup);
- }
- int register_trdev(struct net_device *dev)
- {
- return __register_netdev(dev);
- }
- void unregister_trdev(struct net_device *dev)
- {
- unregister_netdev(dev);
- }
- EXPORT_SYMBOL(tr_setup);
- EXPORT_SYMBOL(init_trdev);
- EXPORT_SYMBOL(alloc_trdev);
- EXPORT_SYMBOL(register_trdev);
- EXPORT_SYMBOL(unregister_trdev);
- #endif /* CONFIG_TR */
- #ifdef CONFIG_NET_FC
- void fc_setup(struct net_device *dev)
- {
- dev->hard_header = fc_header;
- dev->rebuild_header = fc_rebuild_header;
-
- dev->type = ARPHRD_IEEE802;
- dev->hard_header_len = FC_HLEN;
- dev->mtu = 2024;
- dev->addr_len = FC_ALEN;
- dev->tx_queue_len = 100; /* Long queues on fc */
- memset(dev->broadcast,0xFF, FC_ALEN);
- /* New-style flags. */
- dev->flags = IFF_BROADCAST;
- }
- /**
- * init_fcdev - Register fibre channel device
- * @dev: A fibre channel device structure to be filled in, or %NULL if a new
- * struct should be allocated.
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this ethernet device
- *
- * Fill in the fields of the device structure with fibre channel-generic values.
- *
- * If no device structure is passed, a new one is constructed, complete with
- * a private data area of size @sizeof_priv. A 32-byte (not bit)
- * alignment is enforced for this private data area.
- *
- * If an empty string area is passed as dev->name, or a new structure is made,
- * a new name string is constructed.
- */
- struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv)
- {
- return init_netdev(dev, sizeof_priv, "fc%d", fc_setup);
- }
- /**
- * alloc_fcdev - Register fibre channel device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this fibre channel device
- *
- * Fill in the fields of the device structure with fibre channel-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
- struct net_device *alloc_fcdev(int sizeof_priv)
- {
- return alloc_netdev(sizeof_priv, "fc%d", fc_setup);
- }
- int register_fcdev(struct net_device *dev)
- {
- return __register_netdev(dev);
- }
-
- void unregister_fcdev(struct net_device *dev)
- {
- unregister_netdev(dev);
- }
- EXPORT_SYMBOL(fc_setup);
- EXPORT_SYMBOL(init_fcdev);
- EXPORT_SYMBOL(alloc_fcdev);
- EXPORT_SYMBOL(register_fcdev);
- EXPORT_SYMBOL(unregister_fcdev);
- #endif /* CONFIG_NET_FC */