diff options
author | Thomas Bushnell <thomas@gnu.org> | 1999-04-26 05:35:47 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1999-04-26 05:35:47 +0000 |
commit | 3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0 (patch) | |
tree | 50b56b8570e175dbcff43b5f0d61103b6fea5906 /i386/i386at/gpl/linux/net/dev.c | |
parent | 002b9c7d51f7fdb0fe222d4a6023655687c6e501 (diff) | |
download | gnumach-3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0.tar.gz gnumach-3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0.tar.bz2 gnumach-3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0.zip |
1998-11-06 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* i386/i386at/gpl/linux: Moved to ...
* linuxdev: ... here.
* i386/Makefrag: Linux drivers specific code moved to ...
* linuxdev/Makefrag: ... here.
* i386/Files: Recreated.
* i386/Subdirs: Likewise.
* linuxdev/drivers: New directory.
* linuxdev/arch: Likewise.
* linuxdev/arch/i386: Likewise.
* linuxdev/{block,scsi,net,pci}: Moved to ...
* linuxdev/drivers/{block,scsi,net,pci}: ... here.
* i386/{Drivers.in,device-drivers.h.in,driverlist.in}: Moved to ...
* linuxdev/{Drivers.in,device-drivers.h.in,driverlist.in}: ... here.
* linuxdev/{linux_emul.h,linux_*.c}: Moved to ...
* linuxdev/arch/i386/{linux_emul.h,linux_*.c}: ... here.
* linuxdev/arch/i386/linux_block.c: Include <linux_emul.h>, instead
of <i386at/gpl/linux/linux_emul.h>.
* linuxdev/arch/i386/linux_init.c: Likewise.
* linuxdev/arch/i386/linux_kmem.c: Likewise.
* linuxdev/arch/i386/linux_misc.c: Likewise.
* linuxdev/arch/i386/linux_net.c: Likewise.
* linuxdev/arch/i386/linux_sched.c: Likewise.
* device/ds_routines.c: Include <linuxdev/device-drivers.h>, instead
of <i386/device-drivers.h>.
* linuxdev/arch/i386/linux_init.c: Likewise.
* linuxdev/include/linux/autoconf.h: Likewise.
* Makefile.in: Include $(srcdir)/linuxdev/Makefrag.
* linuxdev/Drivers.in (AC_INIT): Use include/linux/autoconf.h,
instead of i386/i386asm.sym.
Diffstat (limited to 'i386/i386at/gpl/linux/net/dev.c')
-rw-r--r-- | i386/i386at/gpl/linux/net/dev.c | 1413 |
1 files changed, 0 insertions, 1413 deletions
diff --git a/i386/i386at/gpl/linux/net/dev.c b/i386/i386at/gpl/linux/net/dev.c deleted file mode 100644 index 69d576ff..00000000 --- a/i386/i386at/gpl/linux/net/dev.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* - * 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, <bir7@leland.Stanford.Edu> - * 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 <dhinds@allegro.stanford.edu> - * - * Changes: - * 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. - * - */ - -#include <asm/segment.h> -#include <asm/system.h> -#include <asm/bitops.h> -#include <linux/config.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/socket.h> -#include <linux/sockios.h> -#include <linux/in.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/if_ether.h> -#include <linux/inet.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/notifier.h> -#include <net/ip.h> -#include <net/route.h> -#include <linux/skbuff.h> -#include <net/sock.h> -#include <net/arp.h> -#include <net/slhc.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#ifdef CONFIG_NET_ALIAS -#include <linux/net_alias.h> -#endif -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> -#endif - -#ifndef MACH -/* - * The list of packet types we will receive (as opposed to discard) - * and the routines to invoke. - */ - -struct packet_type *ptype_base[16]; -struct packet_type *ptype_all = NULL; /* Taps */ - -/* - * Device list lock - */ - -int dev_lockct=0; - -/* - * Our notifier list - */ - -struct notifier_block *netdev_chain=NULL; - -/* - * Device drivers call our routines to queue packets here. We empty the - * queue in the bottom half handler. - */ - -static struct sk_buff_head backlog; - -/* - * We don't overdo the queue or we will thrash memory badly. - */ - -static int backlog_size = 0; - -/* - * Return the lesser of the two values. - */ - -static __inline__ unsigned long min(unsigned long a, unsigned long b) -{ - return (a < b)? a : b; -} - - -/****************************************************************************************** - - Protocol management and registration routines - -*******************************************************************************************/ - -/* - * For efficiency - */ - -static int dev_nit=0; - -/* - * 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. - */ - -void dev_add_pack(struct packet_type *pt) -{ - int hash; - if(pt->type==htons(ETH_P_ALL)) - { - dev_nit++; - pt->next=ptype_all; - ptype_all=pt; - } - else - { - hash=ntohs(pt->type)&15; - pt->next = ptype_base[hash]; - ptype_base[hash] = pt; - } -} - - -/* - * Remove a protocol ID from the list. - */ - -void dev_remove_pack(struct packet_type *pt) -{ - struct packet_type **pt1; - if(pt->type==htons(ETH_P_ALL)) - { - dev_nit--; - pt1=&ptype_all; - } - else - pt1=&ptype_base[ntohs(pt->type)&15]; - for(; (*pt1)!=NULL; pt1=&((*pt1)->next)) - { - if(pt==(*pt1)) - { - *pt1=pt->next; - return; - } - } - printk("dev_remove_pack: %p not found.\n", pt); -} - -/***************************************************************************************** - - Device Interface Subroutines - -******************************************************************************************/ - -/* - * Find an interface by name. - */ - -struct device *dev_get(const char *name) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (strcmp(dev->name, name) == 0) - return(dev); - } - return NULL; -} - -/* - * Find and possibly load an interface. - */ - -#ifdef CONFIG_KERNELD - -extern __inline__ void dev_load(const char *name) -{ - char *sptr; - - if(!dev_get(name)) { -#ifdef CONFIG_NET_ALIAS - for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break; - if (!(*sptr && *(sptr+1))) -#endif - request_module(name); - } -} - -#endif - -/* - * Prepare an interface for use. - */ - -int dev_open(struct device *dev) -{ - int ret = 0; - - /* - * Call device private open method - */ - if (dev->open) - ret = dev->open(dev); - - /* - * If it went open OK then set the flags - */ - - if (ret == 0) - { - dev->flags |= (IFF_UP | IFF_RUNNING); - /* - * Initialise multicasting status - */ - dev_mc_upload(dev); - notifier_call_chain(&netdev_chain, NETDEV_UP, dev); - } - return(ret); -} - - -/* - * Completely shutdown an interface. - */ - -int dev_close(struct device *dev) -{ - int ct=0; - - /* - * Call the device specific close. This cannot fail. - * Only if device is UP - */ - - if ((dev->flags & IFF_UP) && dev->stop) - dev->stop(dev); - - /* - * Device is now down. - */ - - dev->flags&=~(IFF_UP|IFF_RUNNING); - - /* - * Tell people we are going down - */ - notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); - /* - * Flush the multicast chain - */ - dev_mc_discard(dev); - /* - * Blank the IP addresses - */ - dev->pa_addr = 0; - dev->pa_dstaddr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - /* - * Purge any queued packets when we down the link - */ - while(ct<DEV_NUMBUFFS) - { - struct sk_buff *skb; - while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL) - if(skb->free) - kfree_skb(skb,FREE_WRITE); - ct++; - } - return(0); -} - - -/* - * Device change register/unregister. These are not inline or static - * as we export them to the world. - */ - -int register_netdevice_notifier(struct notifier_block *nb) -{ - return notifier_chain_register(&netdev_chain, nb); -} - -int unregister_netdevice_notifier(struct notifier_block *nb) -{ - return notifier_chain_unregister(&netdev_chain,nb); -} - -/* - * Send (or queue for sending) a packet. - * - * IMPORTANT: When this is called to resend frames. The caller MUST - * already have locked the sk_buff. Apart from that we do the - * rest of the magic. - */ - -void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) -{ - unsigned long flags; - struct sk_buff_head *list; - int retransmission = 0; /* used to say if the packet should go */ - /* at the front or the back of the */ - /* queue - front is a retransmit try */ - - if(pri>=0 && !skb_device_locked(skb)) - skb_device_lock(skb); /* Shove a lock on the frame */ -#if CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - skb->dev = dev; - - /* - * Negative priority is used to flag a frame that is being pulled from the - * queue front as a retransmit attempt. It therefore goes back on the queue - * start on a failure. - */ - - if (pri < 0) - { - pri = -pri-1; - retransmission = 1; - } - -#ifdef CONFIG_NET_DEBUG - if (pri >= DEV_NUMBUFFS) - { - printk("bad priority in dev_queue_xmit.\n"); - pri = 1; - } -#endif - - /* - * If the address has not been resolved. Call the device header rebuilder. - * This can cover all protocols and technically not just ARP either. - */ - - if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { - return; - } - - /* - * - * If dev is an alias, switch to its main device. - * "arp" resolution has been made with alias device, so - * arp entries refer to alias, not main. - * - */ - -#ifdef CONFIG_NET_ALIAS - if (net_alias_is(dev)) - skb->dev = dev = net_alias_main_dev(dev); -#endif - list = dev->buffs + pri; - - save_flags(flags); - /* if this isn't a retransmission, use the first packet instead... */ - if (!retransmission) { - if (skb_queue_len(list)) { - /* avoid overrunning the device queue.. */ - if (skb_queue_len(list) > dev->tx_queue_len) { - dev_kfree_skb(skb, FREE_WRITE); - return; - } - cli(); - skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */ - __skb_queue_tail(list, skb); - skb = __skb_dequeue(list); - skb_device_lock(skb); /* New buffer needs locking down */ - restore_flags(flags); - } - - /* copy outgoing packets to any sniffer packet handlers */ - if (dev_nit) { - struct packet_type *ptype; - skb->stamp=xtime; - for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) - { - /* Never send packets back to the socket - * they originated from - MvS (miquels@drinkel.ow.org) - */ - if ((ptype->dev == dev || !ptype->dev) && - ((struct sock *)ptype->data != skb->sk)) - { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) - break; - skb2->h.raw = skb2->data + dev->hard_header_len; - skb2->mac.raw = skb2->data; - ptype->func(skb2, skb->dev, ptype); - } - } - } - } - start_bh_atomic(); - if (dev->hard_start_xmit(skb, dev) == 0) { - /* - * Packet is now solely the responsibility of the driver - */ - end_bh_atomic(); - return; - } - end_bh_atomic(); - - /* - * Transmission failed, put skb back into a list. Once on the list it's safe and - * no longer device locked (it can be freed safely from the device queue) - */ - cli(); - skb_device_unlock(skb); - __skb_queue_head(list,skb); - restore_flags(flags); -} - -/* - * Receive a packet from a device driver and queue it for the upper - * (protocol) levels. It always succeeds. This is the recommended - * interface to use. - */ - -void netif_rx(struct sk_buff *skb) -{ - static int dropping = 0; - - /* - * Any received buffers are un-owned and should be discarded - * when freed. These will be updated later as the frames get - * owners. - */ - - skb->sk = NULL; - skb->free = 1; - if(skb->stamp.tv_sec==0) - skb->stamp = xtime; - - /* - * Check that we aren't overdoing things. - */ - - if (!backlog_size) - dropping = 0; - else if (backlog_size > 300) - dropping = 1; - - if (dropping) - { - kfree_skb(skb, FREE_READ); - return; - } - - /* - * Add it to the "backlog" queue. - */ -#if CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - skb_queue_tail(&backlog,skb); - backlog_size++; - - /* - * If any packet arrived, mark it for processing after the - * hardware interrupt returns. - */ - -#ifdef CONFIG_NET_RUNONIRQ /* Dont enable yet, needs some driver mods */ - net_bh(); -#else - mark_bh(NET_BH); -#endif - return; -} - -/* - * This routine causes all interfaces to try to send some data. - */ - -void dev_transmit(void) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->flags != 0 && !dev->tbusy) { - /* - * Kick the device - */ - dev_tint(dev); - } - } -} - - -/********************************************************************************** - - Receive Queue Processor - -***********************************************************************************/ - -/* - * This is a single non-reentrant routine which takes the received packet - * queue and throws it at the networking layers in the hope that something - * useful will emerge. - */ - -volatile unsigned long in_bh = 0; /* Non-reentrant remember */ - -int in_net_bh() /* Used by timer.c */ -{ - return(in_bh==0?0:1); -} - -/* - * When we are called the queue is ready to grab, the interrupts are - * on and hardware can interrupt and queue to the receive queue a we - * run with no problems. - * This is run as a bottom half after an interrupt handler that does - * mark_bh(NET_BH); - */ - -void net_bh(void *tmp) -{ - struct sk_buff *skb; - struct packet_type *ptype; - struct packet_type *pt_prev; - unsigned short type; - - /* - * Atomically check and mark our BUSY state. - */ - - if (set_bit(1, (void*)&in_bh)) - return; - - /* - * Can we send anything now? We want to clear the - * decks for any more sends that get done as we - * process the input. This also minimises the - * latency on a transmit interrupt bh. - */ - - dev_transmit(); - - /* - * Any data left to process. This may occur because a - * mark_bh() is done after we empty the queue including - * that from the device which does a mark_bh() just after - */ - - cli(); - - /* - * While the queue is not empty - */ - - while((skb=__skb_dequeue(&backlog))!=NULL) - { - /* - * We have a packet. Therefore the queue has shrunk - */ - backlog_size--; - - sti(); - - /* - * Bump the pointer to the next structure. - * - * On entry to the protocol layer. skb->data and - * skb->h.raw point to the MAC and encapsulated data - */ - - skb->h.raw = skb->data; - - /* - * Fetch the packet protocol ID. - */ - - type = skb->protocol; - - /* - * We got a packet ID. Now loop over the "known protocols" - * list. There are two lists. The ptype_all list of taps (normally empty) - * and the main protocol list which is hashed perfectly for normal protocols. - */ - pt_prev = NULL; - for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next) - { - if(pt_prev) - { - struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC); - if(skb2) - pt_prev->func(skb2,skb->dev, pt_prev); - } - pt_prev=ptype; - } - - for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) - { - if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev)) - { - /* - * We already have a match queued. Deliver - * to it and then remember the new match - */ - if(pt_prev) - { - struct sk_buff *skb2; - - skb2=skb_clone(skb, GFP_ATOMIC); - - /* - * Kick the protocol handler. This should be fast - * and efficient code. - */ - - if(skb2) - pt_prev->func(skb2, skb->dev, pt_prev); - } - /* Remember the current last to do */ - pt_prev=ptype; - } - } /* End of protocol list loop */ - - /* - * Is there a last item to send to ? - */ - - if(pt_prev) - pt_prev->func(skb, skb->dev, pt_prev); - /* - * Has an unknown packet has been received ? - */ - - else - kfree_skb(skb, FREE_WRITE); - - /* - * Again, see if we can transmit anything now. - * [Ought to take this out judging by tests it slows - * us down not speeds us up] - */ -#ifdef XMIT_EVERY - dev_transmit(); -#endif - cli(); - } /* End of queue loop */ - - /* - * We have emptied the queue - */ - - in_bh = 0; - sti(); - - /* - * One last output flush. - */ - -#ifdef XMIT_AFTER - dev_transmit(); -#endif -} - - -/* - * This routine is called when an device driver (i.e. an - * interface) is ready to transmit a packet. - */ - -void dev_tint(struct device *dev) -{ - int i; - unsigned long flags; - struct sk_buff_head * head; - - /* - * aliases do not transmit (for now :) ) - */ - -#ifdef CONFIG_NET_ALIAS - if (net_alias_is(dev)) return; -#endif - head = dev->buffs; - save_flags(flags); - cli(); - - /* - * Work the queues in priority order - */ - for(i = 0;i < DEV_NUMBUFFS; i++,head++) - { - struct sk_buff *skb = skb_peek(head); - - if (skb) { - __skb_unlink(skb, head); - /* - * Stop anyone freeing the buffer while we retransmit it - */ - skb_device_lock(skb); - restore_flags(flags); - /* - * Feed them to the output stage and if it fails - * indicate they re-queue at the front. - */ - dev_queue_xmit(skb,dev,-i - 1); - /* - * If we can take no more then stop here. - */ - if (dev->tbusy) - return; - cli(); - } - } - restore_flags(flags); -} - - -/* - * Perform a SIOCGIFCONF call. This structure will change - * size shortly, and there is nothing I can do about it. - * Thus we will need a 'compatibility mode'. - */ - -static int dev_ifconf(char *arg) -{ - struct ifconf ifc; - struct ifreq ifr; - struct device *dev; - char *pos; - int len; - int err; - - /* - * Fetch the caller's info block. - */ - - err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); - if(err) - return err; - memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); - len = ifc.ifc_len; - pos = ifc.ifc_buf; - - /* - * We now walk the device list filling each active device - * into the array. - */ - - err=verify_area(VERIFY_WRITE,pos,len); - if(err) - return err; - - /* - * Loop over the interfaces, and write an info block for each. - */ - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if(!(dev->flags & IFF_UP)) /* Downed devices don't count */ - continue; - /* - * Have we run out of space here ? - */ - - if (len < sizeof(struct ifreq)) - break; - - memset(&ifr, 0, sizeof(struct ifreq)); - strcpy(ifr.ifr_name, dev->name); - (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - - - /* - * Write this block to the caller's space. - */ - - memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); - pos += sizeof(struct ifreq); - len -= sizeof(struct ifreq); - } - - /* - * All done. Write the updated control block back to the caller. - */ - - ifc.ifc_len = (pos - ifc.ifc_buf); - ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; - memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); - - /* - * Report how much was filled in - */ - - return(pos - arg); -} - - -/* - * This is invoked by the /proc filesystem handler to display a device - * in detail. - */ - -#ifdef CONFIG_PROC_FS -static int sprintf_stats(char *buffer, struct device *dev) -{ - struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); - int size; - - if (stats) - size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", - dev->name, - stats->rx_packets, stats->rx_errors, - stats->rx_dropped + stats->rx_missed_errors, - stats->rx_fifo_errors, - stats->rx_length_errors + stats->rx_over_errors - + stats->rx_crc_errors + stats->rx_frame_errors, - stats->tx_packets, stats->tx_errors, stats->tx_dropped, - stats->tx_fifo_errors, stats->collisions, - stats->tx_carrier_errors + stats->tx_aborted_errors - + stats->tx_window_errors + stats->tx_heartbeat_errors); - else - size = sprintf(buffer, "%6s: No statistics available.\n", dev->name); - - return size; -} - -/* - * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface - * to create /proc/net/dev - */ - -int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - int len=0; - off_t begin=0; - off_t pos=0; - int size; - - struct device *dev; - - - size = sprintf(buffer, "Inter-| Receive | Transmit\n" - " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); - - pos+=size; - len+=size; - - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - size = sprintf_stats(buffer+len, dev); - len+=size; - pos=begin+len; - - if(pos<offset) - { - len=0; - begin=pos; - } - if(pos>offset+length) - break; - } - - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len=length; /* Ending slop */ - return len; -} -#endif /* CONFIG_PROC_FS */ - - -/* - * This checks bitmasks for the ioctl calls for devices. - */ - -static inline int bad_mask(unsigned long mask, unsigned long addr) -{ - if (addr & (mask = ~mask)) - return 1; - mask = ntohl(mask); - if (mask & (mask+1)) - return 1; - return 0; -} - -/* - * Perform the SIOCxIFxxx calls. - * - * The socket layer has seen an ioctl the address family thinks is - * for the device. At this point we get invoked to make a decision - */ - -static int dev_ifsioc(void *arg, unsigned int getset) -{ - struct ifreq ifr; - struct device *dev; - int ret; - - /* - * Fetch the caller's info block into kernel space - */ - - int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); - if(err) - return err; - - memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); - - /* - * See which interface the caller is talking about. - */ - - /* - * - * net_alias_dev_get(): dev_get() with added alias naming magic. - * only allow alias creation/deletion if (getset==SIOCSIFADDR) - * - */ - -#ifdef CONFIG_KERNELD - dev_load(ifr.ifr_name); -#endif - -#ifdef CONFIG_NET_ALIAS - if ((dev = net_alias_dev_get(ifr.ifr_name, getset == SIOCSIFADDR, &err, NULL, NULL)) == NULL) - return(err); -#else - if ((dev = dev_get(ifr.ifr_name)) == NULL) - return(-ENODEV); -#endif - switch(getset) - { - case SIOCGIFFLAGS: /* Get interface flags */ - ifr.ifr_flags = dev->flags; - goto rarok; - - case SIOCSIFFLAGS: /* Set interface flags */ - { - int old_flags = dev->flags; - - /* - * We are not allowed to potentially close/unload - * a device until we get this lock. - */ - - dev_lock_wait(); - - /* - * Set the flags on our device. - */ - - dev->flags = (ifr.ifr_flags & ( - IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | - IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | - IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER - | IFF_MULTICAST)) | (dev->flags & IFF_UP); - /* - * Load in the correct multicast list now the flags have changed. - */ - - dev_mc_upload(dev); - - /* - * Have we downed the interface. We handle IFF_UP ourselves - * according to user attempts to set it, rather than blindly - * setting it. - */ - - if ((old_flags^ifr.ifr_flags)&IFF_UP) /* Bit is different ? */ - { - if(old_flags&IFF_UP) /* Gone down */ - ret=dev_close(dev); - else /* Come up */ - { - ret=dev_open(dev); - if(ret<0) - dev->flags&=~IFF_UP; /* Open failed */ - } - } - else - ret=0; - /* - * Load in the correct multicast list now the flags have changed. - */ - - dev_mc_upload(dev); - } - break; - - case SIOCGIFADDR: /* Get interface address (and family) */ - if(ifr.ifr_addr.sa_family==AF_UNSPEC) - { - memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); - ifr.ifr_hwaddr.sa_family=dev->type; - goto rarok; - } - else - { - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_port = 0; - } - goto rarok; - - case SIOCSIFADDR: /* Set interface address (and family) */ - - /* - * BSDism. SIOCSIFADDR family=AF_UNSPEC sets the - * physical address. We can cope with this now. - */ - - if(ifr.ifr_addr.sa_family==AF_UNSPEC) - { - if(dev->set_mac_address==NULL) - return -EOPNOTSUPP; - ret=dev->set_mac_address(dev,&ifr.ifr_addr); - } - else - { - - /* - * if dev is an alias, must rehash to update - * address change - */ - -#ifdef CONFIG_NET_ALIAS - if (net_alias_is(dev)) - net_alias_dev_rehash(dev ,&ifr.ifr_addr); -#endif - dev->pa_addr = (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr; - dev->family = ifr.ifr_addr.sa_family; - -#ifdef CONFIG_INET - /* This is naughty. When net-032e comes out It wants moving into the net032 - code not the kernel. Till then it can sit here (SIGH) */ - dev->pa_mask = ip_get_mask(dev->pa_addr); -#endif - dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; - ret = 0; - } - break; - - case SIOCGIFBRDADDR: /* Get the broadcast address */ - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_port = 0; - goto rarok; - - case SIOCSIFBRDADDR: /* Set the broadcast address */ - dev->pa_brdaddr = (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr; - ret = 0; - break; - - case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_port = 0; - goto rarok; - - case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ - dev->pa_dstaddr = (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr; - ret = 0; - break; - - case SIOCGIFNETMASK: /* Get the netmask for the interface */ - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_port = 0; - goto rarok; - - case SIOCSIFNETMASK: /* Set the netmask for the interface */ - { - unsigned long mask = (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr; - ret = -EINVAL; - /* - * The mask we set must be legal. - */ - if (bad_mask(mask,0)) - break; - dev->pa_mask = mask; - ret = 0; - } - break; - - case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ - - ifr.ifr_metric = dev->metric; - goto rarok; - - case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ - dev->metric = ifr.ifr_metric; - ret=0; - break; - - case SIOCGIFMTU: /* Get the MTU of a device */ - ifr.ifr_mtu = dev->mtu; - goto rarok; - - case SIOCSIFMTU: /* Set the MTU of a device */ - - /* - * MTU must be positive. - */ - - if(ifr.ifr_mtu<68) - return -EINVAL; - dev->mtu = ifr.ifr_mtu; - ret = 0; - break; - - case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently - do not support it */ - ret = -EINVAL; - break; - - case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ - ret = -EINVAL; - break; - - case SIOCGIFHWADDR: - memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); - ifr.ifr_hwaddr.sa_family=dev->type; - goto rarok; - - case SIOCSIFHWADDR: - if(dev->set_mac_address==NULL) - return -EOPNOTSUPP; - if(ifr.ifr_hwaddr.sa_family!=dev->type) - return -EINVAL; - ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr); - break; - - case SIOCGIFMAP: - ifr.ifr_map.mem_start=dev->mem_start; - ifr.ifr_map.mem_end=dev->mem_end; - ifr.ifr_map.base_addr=dev->base_addr; - ifr.ifr_map.irq=dev->irq; - ifr.ifr_map.dma=dev->dma; - ifr.ifr_map.port=dev->if_port; - goto rarok; - - case SIOCSIFMAP: - if(dev->set_config==NULL) - return -EOPNOTSUPP; - return dev->set_config(dev,&ifr.ifr_map); - - case SIOCADDMULTI: - if(dev->set_multicast_list==NULL) - return -EINVAL; - if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) - return -EINVAL; - dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1); - return 0; - - case SIOCDELMULTI: - if(dev->set_multicast_list==NULL) - return -EINVAL; - if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) - return -EINVAL; - dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); - return 0; - /* - * Unknown or private ioctl - */ - - default: - if((getset >= SIOCDEVPRIVATE) && - (getset <= (SIOCDEVPRIVATE + 15))) { - if(dev->do_ioctl==NULL) - return -EOPNOTSUPP; - ret=dev->do_ioctl(dev, &ifr, getset); - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - break; - } - - ret = -EINVAL; - } - return(ret); -/* - * The load of calls that return an ifreq and ok (saves memory). - */ -rarok: - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - return 0; -} - - -/* - * This function handles all "interface"-type I/O control requests. The actual - * 'doing' part of this is dev_ifsioc above. - */ - -int dev_ioctl(unsigned int cmd, void *arg) -{ - switch(cmd) - { - case SIOCGIFCONF: - (void) dev_ifconf((char *) arg); - return 0; - - /* - * Ioctl calls that can be done by all. - */ - - case SIOCGIFFLAGS: - case SIOCGIFADDR: - case SIOCGIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case SIOCGIFSLAVE: - case SIOCGIFMAP: - return dev_ifsioc(arg, cmd); - - /* - * Ioctl calls requiring the power of a superuser - */ - - case SIOCSIFFLAGS: - case SIOCSIFADDR: - case SIOCSIFDSTADDR: - case SIOCSIFBRDADDR: - case SIOCSIFNETMASK: - case SIOCSIFMETRIC: - case SIOCSIFMTU: - case SIOCSIFMEM: - case SIOCSIFMAP: - case SIOCSIFSLAVE: - case SIOCADDMULTI: - case SIOCDELMULTI: - if (!suser()) - return -EPERM; - return dev_ifsioc(arg, cmd); - - case SIOCSIFLINK: - return -EINVAL; - - /* - * Unknown or private ioctl. - */ - - default: - if((cmd >= SIOCDEVPRIVATE) && - (cmd <= (SIOCDEVPRIVATE + 15))) { - return dev_ifsioc(arg, cmd); - } - return -EINVAL; - } -} -#endif /* ! MACH */ - -/* - * 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. - * - */ -extern int lance_init(void); -extern int pi_init(void); -extern int dec21040_init(void); - -int net_dev_init(void) -{ - struct device *dev, **dp; - -#ifndef MACH - /* - * Initialise the packet receive queue. - */ - - skb_queue_head_init(&backlog); -#endif - - /* - * This is VeryUgly(tm). - * - * Some devices want to be initialized eary.. - */ -#if defined(CONFIG_LANCE) - lance_init(); -#endif -#if defined(CONFIG_PI) - pi_init(); -#endif -#if defined(CONFIG_PT) - pt_init(); -#endif -#if defined(CONFIG_DEC_ELCP) - dec21040_init(); -#endif - /* - * SLHC if present needs attaching so other people see it - * even if not opened. - */ -#if (defined(CONFIG_SLIP_COMPRESSED) || defined(CONFIG_PPP)) && defined(CONFIG_SLHC_BUILTIN) - slhc_install(); -#endif - - /* - * Add the devices. - * If the call to dev->init fails, the dev is removed - * from the chain disconnecting the device until the - * next reboot. - */ - - dp = &dev_base; - while ((dev = *dp) != NULL) - { - int i; - for (i = 0; i < DEV_NUMBUFFS; i++) { - skb_queue_head_init(dev->buffs + i); - } - - if (dev->init && dev->init(dev)) - { - /* - * It failed to come up. Unhook it. - */ - *dp = dev->next; - } - else - { - dp = &dev->next; - } - } - -#ifdef CONFIG_PROC_FS - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_DEV, 3, "dev", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - dev_get_info - }); -#endif - - /* - * Initialise net_alias engine - * - * - register net_alias device notifier - * - register proc entries: /proc/net/alias_types - * /proc/net/aliases - */ - -#ifdef CONFIG_NET_ALIAS - net_alias_init(); -#endif - - bh_base[NET_BH].routine = net_bh; - enable_bh(NET_BH); - return 0; -} |