appletalk: move to staging
authorArnd Bergmann <arnd@arndb.de>
Tue, 25 Jan 2011 22:17:27 +0000 (23:17 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 31 Jan 2011 21:38:16 +0000 (13:38 -0800)
For all I know, Appletalk is dead, the only reasonable
use right now would be nostalgia, and that can be served
well enough by old kernels. The code is largely not
in a bad shape, but it still uses the big kernel lock,
and nobody seems motivated to change that.

FWIW, the last release of MacOS that supported Appletalk
was MacOS X 10.5, made in 2007, and it has been abandoned
by Apple with 10.6. Using TCP/IP instead of Appletalk has
been supported since MacOS 7.6, which was released in
1997 and is able to run on most of the legacy hardware.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: netdev@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
42 files changed:
MAINTAINERS
drivers/net/Makefile
drivers/net/appletalk/Kconfig [deleted file]
drivers/net/appletalk/Makefile [deleted file]
drivers/net/appletalk/cops.c [deleted file]
drivers/net/appletalk/cops.h [deleted file]
drivers/net/appletalk/cops_ffdrv.h [deleted file]
drivers/net/appletalk/cops_ltdrv.h [deleted file]
drivers/net/appletalk/ipddp.c [deleted file]
drivers/net/appletalk/ipddp.h [deleted file]
drivers/net/appletalk/ltpc.c [deleted file]
drivers/net/appletalk/ltpc.h [deleted file]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/appletalk/Kconfig [new file with mode: 0644]
drivers/staging/appletalk/Makefile [new file with mode: 0644]
drivers/staging/appletalk/aarp.c [new file with mode: 0644]
drivers/staging/appletalk/atalk.h [new file with mode: 0644]
drivers/staging/appletalk/atalk_proc.c [new file with mode: 0644]
drivers/staging/appletalk/cops.c [new file with mode: 0644]
drivers/staging/appletalk/cops.h [new file with mode: 0644]
drivers/staging/appletalk/cops_ffdrv.h [new file with mode: 0644]
drivers/staging/appletalk/cops_ltdrv.h [new file with mode: 0644]
drivers/staging/appletalk/ddp.c [new file with mode: 0644]
drivers/staging/appletalk/dev.c [new file with mode: 0644]
drivers/staging/appletalk/ipddp.c [new file with mode: 0644]
drivers/staging/appletalk/ipddp.h [new file with mode: 0644]
drivers/staging/appletalk/ltpc.c [new file with mode: 0644]
drivers/staging/appletalk/ltpc.h [new file with mode: 0644]
drivers/staging/appletalk/sysctl_net_atalk.c [new file with mode: 0644]
fs/compat_ioctl.c
include/linux/Kbuild
include/linux/atalk.h [deleted file]
net/Kconfig
net/Makefile
net/appletalk/Makefile [deleted file]
net/appletalk/aarp.c [deleted file]
net/appletalk/atalk_proc.c [deleted file]
net/appletalk/ddp.c [deleted file]
net/appletalk/dev.c [deleted file]
net/appletalk/sysctl_net_atalk.c [deleted file]
net/socket.c

index dd6ca456cde3da2f87a0c47b6ca11b49488c77c7..3118d67d68fb5365839bdf74b27319a21ff267cb 100644 (file)
@@ -554,8 +554,7 @@ F:  drivers/hwmon/applesmc.c
 APPLETALK NETWORK LAYER
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 S:     Maintained
-F:     drivers/net/appletalk/
-F:     net/appletalk/
+F:     drivers/staging/appletalk/
 
 ARC FRAMEBUFFER DRIVER
 M:     Jaya Kumar <jayalk@intworks.biz>
index b90738d13994318dcf2a06442cd7eba52629b9a7..11a9c053f0c85f3def656c12a8faa18c376b784f 100644 (file)
@@ -265,7 +265,6 @@ obj-$(CONFIG_MACB) += macb.o
 obj-$(CONFIG_S6GMAC) += s6gmac.o
 
 obj-$(CONFIG_ARM) += arm/
-obj-$(CONFIG_DEV_APPLETALK) += appletalk/
 obj-$(CONFIG_TR) += tokenring/
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
deleted file mode 100644 (file)
index 0b376a9..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-#
-# Appletalk driver configuration
-#
-config ATALK
-       tristate "Appletalk protocol support"
-       depends on BKL # waiting to be removed from net/appletalk/ddp.c
-       select LLC
-       ---help---
-         AppleTalk is the protocol that Apple computers can use to communicate
-         on a network.  If your Linux box is connected to such a network and you
-         wish to connect to it, say Y.  You will need to use the netatalk package
-         so that your Linux box can act as a print and file server for Macs as
-         well as access AppleTalk printers.  Check out
-         <http://www.zettabyte.net/netatalk/> on the WWW for details.
-         EtherTalk is the name used for AppleTalk over Ethernet and the
-         cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
-         network using serial links.  EtherTalk and LocalTalk are fully
-         supported by Linux.
-
-         General information about how to connect Linux, Windows machines and
-         Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.  The
-         NET3-4-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information as well.
-
-         To compile this driver as a module, choose M here: the module will be
-         called appletalk. You almost certainly want to compile it as a
-         module so you can restart your AppleTalk stack without rebooting
-         your machine. I hear that the GNU boycott of Apple is over, so
-         even politically correct people are allowed to say Y here.
-
-config DEV_APPLETALK
-       tristate "Appletalk interfaces support"
-       depends on ATALK
-       help
-         AppleTalk is the protocol that Apple computers can use to communicate
-         on a network.  If your Linux box is connected to such a network, and wish
-         to do IP over it, or you have a LocalTalk card and wish to use it to
-         connect to the AppleTalk network, say Y.
-         
-
-config LTPC
-       tristate "Apple/Farallon LocalTalk PC support"
-       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
-       help
-         This allows you to use the AppleTalk PC card to connect to LocalTalk
-         networks. The card is also known as the Farallon PhoneNet PC card.
-         If you are in doubt, this card is the one with the 65C02 chip on it.
-         You also need version 1.3.3 or later of the netatalk package.
-         This driver is experimental, which means that it may not work.
-         See the file <file:Documentation/networking/ltpc.txt>.
-
-config COPS
-       tristate "COPS LocalTalk PC support"
-       depends on DEV_APPLETALK && (ISA || EISA)
-       help
-         This allows you to use COPS AppleTalk cards to connect to LocalTalk
-         networks. You also need version 1.3.3 or later of the netatalk
-         package. This driver is experimental, which means that it may not
-         work. This driver will only work if you choose "AppleTalk DDP"
-         networking support, above.
-         Please read the file <file:Documentation/networking/cops.txt>.
-
-config COPS_DAYNA
-       bool "Dayna firmware support"
-       depends on COPS
-       help
-         Support COPS compatible cards with Dayna style firmware (Dayna
-         DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC
-         III, Farallon PhoneNET PC II).
-
-config COPS_TANGENT
-       bool "Tangent firmware support"
-       depends on COPS
-       help
-         Support COPS compatible cards with Tangent style firmware (Tangent
-         ATB_II, Novell NL-1000, Daystar Digital LT-200.
-
-config IPDDP
-       tristate "Appletalk-IP driver support"
-       depends on DEV_APPLETALK && ATALK
-       ---help---
-         This allows IP networking for users who only have AppleTalk
-         networking available. This feature is experimental. With this
-         driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux
-         box is stuck on an AppleTalk only network) or decapsulate (e.g. if
-         you want your Linux box to act as an Internet gateway for a zoo of
-         AppleTalk connected Macs). Please see the file
-         <file:Documentation/networking/ipddp.txt> for more information.
-
-         If you say Y here, the AppleTalk-IP support will be compiled into
-         the kernel. In this case, you can either use encapsulation or
-         decapsulation, but not both. With the following two questions, you
-         decide which one you want.
-
-         To compile the AppleTalk-IP support as a module, choose M here: the
-         module will be called ipddp.
-         In this case, you will be able to use both encapsulation and
-         decapsulation simultaneously, by loading two copies of the module
-         and specifying different values for the module option ipddp_mode.
-
-config IPDDP_ENCAP
-       bool "IP to Appletalk-IP Encapsulation support"
-       depends on IPDDP
-       help
-         If you say Y here, the AppleTalk-IP code will be able to encapsulate
-         IP packets inside AppleTalk frames; this is useful if your Linux box
-         is stuck on an AppleTalk network (which hopefully contains a
-         decapsulator somewhere). Please see
-         <file:Documentation/networking/ipddp.txt> for more information. If
-         you said Y to "AppleTalk-IP driver support" above and you say Y
-         here, then you cannot say Y to "AppleTalk-IP to IP Decapsulation
-         support", below.
-
-config IPDDP_DECAP
-       bool "Appletalk-IP to IP Decapsulation support"
-       depends on IPDDP
-       help
-         If you say Y here, the AppleTalk-IP code will be able to decapsulate
-         AppleTalk-IP frames to IP packets; this is useful if you want your
-         Linux box to act as an Internet gateway for an AppleTalk network.
-         Please see <file:Documentation/networking/ipddp.txt> for more
-         information.  If you said Y to "AppleTalk-IP driver support" above
-         and you say Y here, then you cannot say Y to "IP to AppleTalk-IP
-         Encapsulation support", above.
-
diff --git a/drivers/net/appletalk/Makefile b/drivers/net/appletalk/Makefile
deleted file mode 100644 (file)
index 6cfc705..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for drivers/net/appletalk
-#
-
-obj-$(CONFIG_IPDDP) += ipddp.o
-obj-$(CONFIG_COPS) += cops.o
-obj-$(CONFIG_LTPC) += ltpc.o
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
deleted file mode 100644 (file)
index 748c9f5..0000000
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*      cops.c: LocalTalk driver for Linux.
- *
- *     Authors:
- *      - Jay Schulist <jschlst@samba.org>
- *
- *     With more than a little help from;
- *     - Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- *      Derived from:
- *      - skeleton.c: A network driver outline for linux.
- *        Written 1993-94 by Donald Becker.
- *     - ltpc.c: A driver for the LocalTalk PC card.
- *       Written by Bradford W. Johnson.
- *
- *      Copyright 1993 United States Government as represented by the
- *      Director, National Security Agency.
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU General Public License, incorporated herein by reference.
- *
- *     Changes:
- *     19970608        Alan Cox        Allowed dual card type support
- *                                     Can set board type in insmod
- *                                     Hooks for cops_setup routine
- *                                     (not yet implemented).
- *     19971101        Jay Schulist    Fixes for multiple lt* devices.
- *     19980607        Steven Hirsch   Fixed the badly broken support
- *                                     for Tangent type cards. Only
- *                                      tested on Daystar LT200. Some
- *                                      cleanup of formatting and program
- *                                      logic.  Added emacs 'local-vars'
- *                                      setup for Jay's brace style.
- *     20000211        Alan Cox        Cleaned up for softnet
- */
-
-static const char *version =
-"cops.c:v0.04 6/7/98 Jay Schulist <jschlst@samba.org>\n";
-/*
- *  Sources:
- *      COPS Localtalk SDK. This provides almost all of the information
- *      needed.
- */
-
-/*
- * insmod/modprobe configurable stuff.
- *     - IO Port, choose one your card supports or 0 if you dare.
- *     - IRQ, also choose one your card supports or nothing and let
- *       the driver figure it out.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>
-#include <linux/delay.h>       /* For udelay() */
-#include <linux/atalk.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "cops.h"              /* Our Stuff */
-#include "cops_ltdrv.h"                /* Firmware code for Tangent type cards. */
-#include "cops_ffdrv.h"                /* Firmware code for Dayna type cards. */
-
-/*
- *      The name of the card. Is used for messages and in the requests for
- *      io regions, irqs and dma channels
- */
-
-static const char *cardname = "cops";
-
-#ifdef CONFIG_COPS_DAYNA
-static int board_type = DAYNA; /* Module exported */
-#else
-static int board_type = TANGENT;
-#endif
-
-static int io = 0x240;         /* Default IO for Dayna */
-static int irq = 5;            /* Default IRQ */
-
-/*
- *     COPS Autoprobe information.
- *     Right now if port address is right but IRQ is not 5 this will
- *      return a 5 no matter what since we will still get a status response.
- *      Need one more additional check to narrow down after we have gotten
- *      the ioaddr. But since only other possible IRQs is 3 and 4 so no real
- *     hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with
- *     this driver.
- * 
- *     This driver has 2 modes and they are: Dayna mode and Tangent mode.
- *     Each mode corresponds with the type of card. It has been found
- *     that there are 2 main types of cards and all other cards are
- *     the same and just have different names or only have minor differences
- *     such as more IO ports. As this driver is tested it will
- *     become more clear on exactly what cards are supported. The driver
- *     defaults to using Dayna mode. To change the drivers mode, simply
- *     select Dayna or Tangent mode when configuring the kernel.
- *
- *      This driver should support:
- *      TANGENT driver mode:
- *              Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
- *             COPS LT-1
- *      DAYNA driver mode:
- *              Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 
- *             Farallon PhoneNET PC III, Farallon PhoneNET PC II
- *     Other cards possibly supported mode unknown though:
- *             Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
- *
- *     Cards NOT supported by this driver but supported by the ltpc.c
- *     driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *             Farallon PhoneNET PC
- *             Original Apple LocalTalk PC card
- * 
- *      N.B.
- *
- *      The Daystar Digital LT200 boards do not support interrupt-driven
- *      IO.  You must specify 'irq=0xff' as a module parameter to invoke
- *      polled mode.  I also believe that the port probing logic is quite
- *      dangerous at best and certainly hopeless for a polled card.  Best to 
- *      specify both. - Steve H.
- *
- */
-
-/*
- * Zero terminated list of IO ports to probe.
- */
-
-static unsigned int ports[] = { 
-       0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 
-       0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360,
-       0
-};
-
-/*
- * Zero terminated list of IRQ ports to probe.
- */
-
-static int cops_irqlist[] = {
-       5, 4, 3, 0 
-};
-
-static struct timer_list cops_timer;
-
-/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef COPS_DEBUG
-#define COPS_DEBUG 1 
-#endif
-static unsigned int cops_debug = COPS_DEBUG;
-
-/* The number of low I/O ports used by the card. */
-#define COPS_IO_EXTENT       8
-
-/* Information that needs to be kept for each board. */
-
-struct cops_local
-{
-        int board;                     /* Holds what board type is. */
-       int nodeid;                     /* Set to 1 once have nodeid. */
-        unsigned char node_acquire;    /* Node ID when acquired. */
-        struct atalk_addr node_addr;   /* Full node address */
-       spinlock_t lock;                /* RX/TX lock */
-};
-
-/* Index to functions, as function prototypes. */
-static int  cops_probe1 (struct net_device *dev, int ioaddr);
-static int  cops_irq (int ioaddr, int board);
-
-static int  cops_open (struct net_device *dev);
-static int  cops_jumpstart (struct net_device *dev);
-static void cops_reset (struct net_device *dev, int sleep);
-static void cops_load (struct net_device *dev);
-static int  cops_nodeid (struct net_device *dev, int nodeid);
-
-static irqreturn_t cops_interrupt (int irq, void *dev_id);
-static void cops_poll (unsigned long ltdev);
-static void cops_timeout(struct net_device *dev);
-static void cops_rx (struct net_device *dev);
-static netdev_tx_t  cops_send_packet (struct sk_buff *skb,
-                                           struct net_device *dev);
-static void set_multicast_list (struct net_device *dev);
-static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static int  cops_close (struct net_device *dev);
-
-static void cleanup_card(struct net_device *dev)
-{
-       if (dev->irq)
-               free_irq(dev->irq, dev);
-       release_region(dev->base_addr, COPS_IO_EXTENT);
-}
-
-/*
- *      Check for a network adaptor of this type, and return '0' iff one exists.
- *      If dev->base_addr == 0, probe all likely locations.
- *      If dev->base_addr in [1..0x1ff], always return failure.
- *        otherwise go with what we pass in.
- */
-struct net_device * __init cops_probe(int unit)
-{
-       struct net_device *dev;
-       unsigned *port;
-       int base_addr;
-       int err = 0;
-
-       dev = alloc_ltalkdev(sizeof(struct cops_local));
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "lt%d", unit);
-               netdev_boot_setup_check(dev);
-               irq = dev->irq;
-               base_addr = dev->base_addr;
-       } else {
-               base_addr = dev->base_addr = io;
-       }
-
-       if (base_addr > 0x1ff) {    /* Check a single specified location. */
-               err = cops_probe1(dev, base_addr);
-       } else if (base_addr != 0) { /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               /* FIXME  Does this really work for cards which generate irq?
-                * It's definitely N.G. for polled Tangent. sh
-                * Dayna cards don't autoprobe well at all, but if your card is
-                * at IRQ 5 & IO 0x240 we find it every time. ;) JS
-                */
-               for (port = ports; *port && cops_probe1(dev, *port) < 0; port++)
-                       ;
-               if (!*port)
-                       err = -ENODEV;
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       cleanup_card(dev);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops cops_netdev_ops = {
-       .ndo_open               = cops_open,
-        .ndo_stop               = cops_close,
-       .ndo_start_xmit         = cops_send_packet,
-       .ndo_tx_timeout         = cops_timeout,
-        .ndo_do_ioctl           = cops_ioctl,
-       .ndo_set_multicast_list = set_multicast_list,
-};
-
-/*
- *      This is the real probe routine. Linux has a history of friendly device
- *      probes on the ISA bus. A good device probes avoids doing writes, and
- *      verifies that the correct device exists and functions.
- */
-static int __init cops_probe1(struct net_device *dev, int ioaddr)
-{
-        struct cops_local *lp;
-       static unsigned version_printed;
-       int board = board_type;
-       int retval;
-       
-        if(cops_debug && version_printed++ == 0)
-               printk("%s", version);
-
-       /* Grab the region so no one else tries to probe our ioports. */
-       if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name))
-               return -EBUSY;
-
-        /*
-         * Since this board has jumpered interrupts, allocate the interrupt
-         * vector now. There is no point in waiting since no other device
-         * can use the interrupt, and this marks the irq as busy. Jumpered
-         * interrupts are typically not reported by the boards, and we must
-         * used AutoIRQ to find them.
-        */
-       dev->irq = irq;
-       switch (dev->irq)
-       {
-               case 0:
-                       /* COPS AutoIRQ routine */
-                       dev->irq = cops_irq(ioaddr, board);
-                       if (dev->irq)
-                               break;
-                       /* No IRQ found on this port, fallthrough */
-               case 1:
-                       retval = -EINVAL;
-                       goto err_out;
-
-               /* Fixup for users that don't know that IRQ 2 is really
-                * IRQ 9, or don't know which one to set.
-                */
-               case 2:
-                       dev->irq = 9;
-                       break;
-
-               /* Polled operation requested. Although irq of zero passed as
-                * a parameter tells the init routines to probe, we'll
-                * overload it to denote polled operation at runtime.
-                */
-               case 0xff:
-                       dev->irq = 0;
-                       break;
-
-               default:
-                       break;
-       }
-
-       /* Reserve any actual interrupt. */
-       if (dev->irq) {
-               retval = request_irq(dev->irq, cops_interrupt, 0, dev->name, dev);
-               if (retval)
-                       goto err_out;
-       }
-
-       dev->base_addr = ioaddr;
-
-        lp = netdev_priv(dev);
-        spin_lock_init(&lp->lock);
-
-       /* Copy local board variable to lp struct. */
-       lp->board               = board;
-
-       dev->netdev_ops         = &cops_netdev_ops;
-       dev->watchdog_timeo     = HZ * 2;
-
-
-       /* Tell the user where the card is and what mode we're in. */
-       if(board==DAYNA)
-               printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
-                       dev->name, cardname, ioaddr, dev->irq);
-       if(board==TANGENT) {
-               if(dev->irq)
-                       printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
-                               dev->name, cardname, ioaddr, dev->irq);
-               else
-                       printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
-                               dev->name, cardname, ioaddr);
-
-       }
-        return 0;
-
-err_out:
-       release_region(ioaddr, COPS_IO_EXTENT);
-       return retval;
-}
-
-static int __init cops_irq (int ioaddr, int board)
-{       /*
-         * This does not use the IRQ to determine where the IRQ is. We just
-         * assume that when we get a correct status response that it's the IRQ.
-         * This really just verifies the IO port but since we only have access
-         * to such a small number of IRQs (5, 4, 3) this is not bad.
-         * This will probably not work for more than one card.
-         */
-        int irqaddr=0;
-        int i, x, status;
-
-        if(board==DAYNA)
-        {
-                outb(0, ioaddr+DAYNA_RESET);
-                inb(ioaddr+DAYNA_RESET);
-                mdelay(333);
-        }
-        if(board==TANGENT)
-        {
-                inb(ioaddr);
-                outb(0, ioaddr);
-                outb(0, ioaddr+TANG_RESET);
-        }
-
-        for(i=0; cops_irqlist[i] !=0; i++)
-        {
-                irqaddr = cops_irqlist[i];
-                for(x = 0xFFFF; x>0; x --)    /* wait for response */
-                {
-                        if(board==DAYNA)
-                        {
-                                status = (inb(ioaddr+DAYNA_CARD_STATUS)&3);
-                                if(status == 1)
-                                        return irqaddr;
-                        }
-                        if(board==TANGENT)
-                        {
-                                if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0)
-                                        return irqaddr;
-                        }
-                }
-        }
-        return 0;       /* no IRQ found */
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- */
-static int cops_open(struct net_device *dev)
-{
-    struct cops_local *lp = netdev_priv(dev);
-
-       if(dev->irq==0)
-       {
-               /*
-                * I don't know if the Dayna-style boards support polled 
-                * operation.  For now, only allow it for Tangent.
-                */
-               if(lp->board==TANGENT)  /* Poll 20 times per second */
-               {
-                   init_timer(&cops_timer);
-                   cops_timer.function = cops_poll;
-                   cops_timer.data     = (unsigned long)dev;
-                   cops_timer.expires  = jiffies + HZ/20;
-                   add_timer(&cops_timer);
-               } 
-               else 
-               {
-                       printk(KERN_WARNING "%s: No irq line set\n", dev->name);
-                       return -EAGAIN;
-               }
-       }
-
-       cops_jumpstart(dev);    /* Start the card up. */
-
-       netif_start_queue(dev);
-        return 0;
-}
-
-/*
- *     This allows for a dynamic start/restart of the entire card.
- */
-static int cops_jumpstart(struct net_device *dev)
-{
-       struct cops_local *lp = netdev_priv(dev);
-
-       /*
-         *      Once the card has the firmware loaded and has acquired
-         *      the nodeid, if it is reset it will lose it all.
-         */
-        cops_reset(dev,1);     /* Need to reset card before load firmware. */
-        cops_load(dev);                /* Load the firmware. */
-
-       /*
-        *      If atalkd already gave us a nodeid we will use that
-        *      one again, else we wait for atalkd to give us a nodeid
-        *      in cops_ioctl. This may cause a problem if someone steals
-        *      our nodeid while we are resetting.
-        */     
-       if(lp->nodeid == 1)
-               cops_nodeid(dev,lp->node_acquire);
-
-       return 0;
-}
-
-static void tangent_wait_reset(int ioaddr)
-{
-       int timeout=0;
-
-       while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-               mdelay(1);   /* Wait 1 second */
-}
-
-/*
- *      Reset the LocalTalk board.
- */
-static void cops_reset(struct net_device *dev, int sleep)
-{
-        struct cops_local *lp = netdev_priv(dev);
-        int ioaddr=dev->base_addr;
-
-        if(lp->board==TANGENT)
-        {
-                inb(ioaddr);           /* Clear request latch. */
-                outb(0,ioaddr);                /* Clear the TANG_TX_READY flop. */
-                outb(0, ioaddr+TANG_RESET);    /* Reset the adapter. */
-
-               tangent_wait_reset(ioaddr);
-                outb(0, ioaddr+TANG_CLEAR_INT);
-        }
-        if(lp->board==DAYNA)
-        {
-                outb(0, ioaddr+DAYNA_RESET);   /* Assert the reset port */
-                inb(ioaddr+DAYNA_RESET);       /* Clear the reset */
-               if (sleep)
-                       msleep(333);
-               else
-                       mdelay(333);
-        }
-
-       netif_wake_queue(dev);
-}
-
-static void cops_load (struct net_device *dev)
-{
-        struct ifreq ifr;
-        struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru;
-        struct cops_local *lp = netdev_priv(dev);
-        int ioaddr=dev->base_addr;
-       int length, i = 0;
-
-        strcpy(ifr.ifr_name,"lt0");
-
-        /* Get card's firmware code and do some checks on it. */
-#ifdef CONFIG_COPS_DAYNA        
-        if(lp->board==DAYNA)
-        {
-                ltf->length=sizeof(ffdrv_code);
-                ltf->data=ffdrv_code;
-        }
-        else
-#endif        
-#ifdef CONFIG_COPS_TANGENT
-        if(lp->board==TANGENT)
-        {
-                ltf->length=sizeof(ltdrv_code);
-                ltf->data=ltdrv_code;
-        }
-        else
-#endif
-       {
-               printk(KERN_INFO "%s; unsupported board type.\n", dev->name);
-               return;
-       }
-       
-        /* Check to make sure firmware is correct length. */
-        if(lp->board==DAYNA && ltf->length!=5983)
-        {
-                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);
-                return;
-        }
-        if(lp->board==TANGENT && ltf->length!=2501)
-        {
-                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);
-                return;
-        }
-
-        if(lp->board==DAYNA)
-        {
-                /*
-                 *      We must wait for a status response
-                 *      with the DAYNA board.
-                 */
-                while(++i<65536)
-                {
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)
-                                break;
-                }
-
-                if(i==65536)
-                        return;
-        }
-
-        /*
-         *      Upload the firmware and kick. Byte-by-byte works nicely here.
-         */
-       i=0;
-        length = ltf->length;
-        while(length--)
-        {
-                outb(ltf->data[i], ioaddr);
-                i++;
-        }
-
-       if(cops_debug > 1)
-               printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
-                       dev->name, i, ltf->length);
-
-        if(lp->board==DAYNA)   /* Tell Dayna to run the firmware code. */
-                outb(1, ioaddr+DAYNA_INT_CARD);
-       else                    /* Tell Tang to run the firmware code. */
-               inb(ioaddr);
-
-        if(lp->board==TANGENT)
-        {
-                tangent_wait_reset(ioaddr);
-                inb(ioaddr);   /* Clear initial ready signal. */
-        }
-}
-
-/*
- *     Get the LocalTalk Nodeid from the card. We can suggest
- *     any nodeid 1-254. The card will try and get that exact
- *     address else we can specify 0 as the nodeid and the card
- *     will autoprobe for a nodeid.
- */
-static int cops_nodeid (struct net_device *dev, int nodeid)
-{
-       struct cops_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       if(lp->board == DAYNA)
-        {
-               /* Empty any pending adapter responses. */
-                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
-                {
-                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
-                               cops_rx(dev);   /* Kick any packets waiting. */
-                       schedule();
-                }
-
-                outb(2, ioaddr);               /* Output command packet length as 2. */
-                outb(0, ioaddr);
-                outb(LAP_INIT, ioaddr);        /* Send LAP_INIT command byte. */
-                outb(nodeid, ioaddr);          /* Suggest node address. */
-        }
-
-       if(lp->board == TANGENT)
-        {
-                /* Empty any pending adapter responses. */
-                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
-                {
-                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */
-                       cops_rx(dev);           /* Kick out packets waiting. */
-                       schedule();
-                }
-
-               /* Not sure what Tangent does if nodeid picked is used. */
-                if(nodeid == 0)                                /* Seed. */
-                       nodeid = jiffies&0xFF;          /* Get a random try */
-                outb(2, ioaddr);                       /* Command length LSB */
-                outb(0, ioaddr);                               /* Command length MSB */
-                outb(LAP_INIT, ioaddr);                /* Send LAP_INIT byte */
-                outb(nodeid, ioaddr);                  /* LAP address hint. */
-                outb(0xFF, ioaddr);                    /* Int. level to use */
-        }
-
-       lp->node_acquire=0;             /* Set nodeid holder to 0. */
-        while(lp->node_acquire==0)     /* Get *True* nodeid finally. */
-       {
-               outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */
-
-               if(lp->board == DAYNA)
-               {
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
-                               cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
-               }
-               if(lp->board == TANGENT)
-               {       
-                       if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
-                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
-               }
-               schedule();
-       }
-
-       if(cops_debug > 1)
-               printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
-                       dev->name, lp->node_acquire);
-
-       lp->nodeid=1;   /* Set got nodeid to 1. */
-
-        return 0;
-}
-
-/*
- *     Poll the Tangent type cards to see if we have work.
- */
-static void cops_poll(unsigned long ltdev)
-{
-       int ioaddr, status;
-       int boguscount = 0;
-
-       struct net_device *dev = (struct net_device *)ltdev;
-
-       del_timer(&cops_timer);
-
-       if(dev == NULL)
-               return; /* We've been downed */
-
-       ioaddr = dev->base_addr;
-       do {
-               status=inb(ioaddr+TANG_CARD_STATUS);
-               if(status & TANG_RX_READY)
-                       cops_rx(dev);
-               if(status & TANG_TX_READY)
-                       netif_wake_queue(dev);
-               status = inb(ioaddr+TANG_CARD_STATUS);
-       } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
-
-       /* poll 20 times per second */
-       cops_timer.expires = jiffies + HZ/20;
-       add_timer(&cops_timer);
-}
-
-/*
- *      The typical workload of the driver:
- *      Handle the network interface interrupts.
- */
-static irqreturn_t cops_interrupt(int irq, void *dev_id)
-{
-        struct net_device *dev = dev_id;
-        struct cops_local *lp;
-        int ioaddr, status;
-        int boguscount = 0;
-
-        ioaddr = dev->base_addr;
-        lp = netdev_priv(dev);
-
-       if(lp->board==DAYNA)
-       {
-               do {
-                       outb(0, ioaddr + COPS_CLEAR_INT);
-                               status=inb(ioaddr+DAYNA_CARD_STATUS);
-                               if((status&0x03)==DAYNA_RX_REQUEST)
-                                       cops_rx(dev);
-                       netif_wake_queue(dev);
-               } while(++boguscount < 20);
-       }
-       else
-       {
-               do {
-                               status=inb(ioaddr+TANG_CARD_STATUS);
-                       if(status & TANG_RX_READY)
-                               cops_rx(dev);
-                       if(status & TANG_TX_READY)
-                               netif_wake_queue(dev);
-                       status=inb(ioaddr+TANG_CARD_STATUS);
-               } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
-       }
-
-        return IRQ_HANDLED;
-}
-
-/*
- *      We have a good packet(s), get it/them out of the buffers.
- */
-static void cops_rx(struct net_device *dev)
-{
-        int pkt_len = 0;
-        int rsp_type = 0;
-        struct sk_buff *skb = NULL;
-        struct cops_local *lp = netdev_priv(dev);
-        int ioaddr = dev->base_addr;
-        int boguscount = 0;
-        unsigned long flags;
-
-
-       spin_lock_irqsave(&lp->lock, flags);
-       
-        if(lp->board==DAYNA)
-        {
-                outb(0, ioaddr);                /* Send out Zero length. */
-                outb(0, ioaddr);
-                outb(DATA_READ, ioaddr);        /* Send read command out. */
-
-                /* Wait for DMA to turn around. */
-                while(++boguscount<1000000)
-                {
-                       barrier();
-                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
-                                break;
-                }
-
-                if(boguscount==1000000)
-                {
-                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);
-                       spin_unlock_irqrestore(&lp->lock, flags);
-                        return;
-                }
-        }
-
-        /* Get response length. */
-       if(lp->board==DAYNA)
-               pkt_len = inb(ioaddr) & 0xFF;
-       else
-               pkt_len = inb(ioaddr) & 0x00FF;
-        pkt_len |= (inb(ioaddr) << 8);
-        /* Input IO code. */
-        rsp_type=inb(ioaddr);
-
-        /* Malloc up new buffer. */
-        skb = dev_alloc_skb(pkt_len);
-        if(skb == NULL)
-        {
-                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
-                       dev->name);
-                dev->stats.rx_dropped++;
-                while(pkt_len--)        /* Discard packet */
-                        inb(ioaddr);
-                spin_unlock_irqrestore(&lp->lock, flags);
-                return;
-        }
-        skb->dev = dev;
-        skb_put(skb, pkt_len);
-        skb->protocol = htons(ETH_P_LOCALTALK);
-
-        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
-
-        if(lp->board==DAYNA)
-                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
-
-        spin_unlock_irqrestore(&lp->lock, flags);  /* Restore interrupts. */
-
-        /* Check for bad response length */
-        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
-        {
-               printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
-                       dev->name, pkt_len);
-                dev->stats.tx_errors++;
-                dev_kfree_skb_any(skb);
-                return;
-        }
-
-        /* Set nodeid and then get out. */
-        if(rsp_type == LAP_INIT_RSP)
-        {      /* Nodeid taken from received packet. */
-                lp->node_acquire = skb->data[0];
-                dev_kfree_skb_any(skb);
-                return;
-        }
-
-        /* One last check to make sure we have a good packet. */
-        if(rsp_type != LAP_RESPONSE)
-        {
-                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
-                dev->stats.tx_errors++;
-                dev_kfree_skb_any(skb);
-                return;
-        }
-
-        skb_reset_mac_header(skb);    /* Point to entire packet. */
-        skb_pull(skb,3);
-        skb_reset_transport_header(skb);    /* Point to data (Skip header). */
-
-        /* Update the counters. */
-        dev->stats.rx_packets++;
-        dev->stats.rx_bytes += skb->len;
-
-        /* Send packet to a higher place. */
-        netif_rx(skb);
-}
-
-static void cops_timeout(struct net_device *dev)
-{
-        struct cops_local *lp = netdev_priv(dev);
-        int ioaddr = dev->base_addr;
-
-       dev->stats.tx_errors++;
-        if(lp->board==TANGENT)
-        {
-               if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-                               printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
-       }
-       printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
-       cops_jumpstart(dev);    /* Restart the card. */
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue(dev);
-}
-
-
-/*
- *     Make the card transmit a LocalTalk packet.
- */
-
-static netdev_tx_t cops_send_packet(struct sk_buff *skb,
-                                         struct net_device *dev)
-{
-        struct cops_local *lp = netdev_priv(dev);
-        int ioaddr = dev->base_addr;
-        unsigned long flags;
-
-        /*
-         * Block a timer-based transmit from overlapping. 
-        */
-        
-       netif_stop_queue(dev);
-
-       spin_lock_irqsave(&lp->lock, flags);
-       if(lp->board == DAYNA)   /* Wait for adapter transmit buffer. */
-               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
-                       cpu_relax();
-       if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
-               while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-                       cpu_relax();
-
-       /* Output IO length. */
-       outb(skb->len, ioaddr);
-       if(lp->board == DAYNA)
-                       outb(skb->len >> 8, ioaddr);
-       else
-               outb((skb->len >> 8)&0x0FF, ioaddr);
-
-       /* Output IO code. */
-       outb(LAP_WRITE, ioaddr);
-
-       if(lp->board == DAYNA)  /* Check the transmit buffer again. */
-               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
-
-       outsb(ioaddr, skb->data, skb->len);     /* Send out the data. */
-
-       if(lp->board==DAYNA)    /* Dayna requires you kick the card */
-               outb(1, ioaddr+DAYNA_INT_CARD);
-
-       spin_unlock_irqrestore(&lp->lock, flags);       /* Restore interrupts. */
-
-       /* Done sending packet, update counters and cleanup. */
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-       dev_kfree_skb (skb);
-       return NETDEV_TX_OK;
-}
-
-/*
- *     Dummy function to keep the Appletalk layer happy.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-        if(cops_debug >= 3)
-               printk("%s: set_multicast_list executed\n", dev->name);
-}
-
-/*
- *      System ioctls for the COPS LocalTalk card.
- */
-static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-        struct cops_local *lp = netdev_priv(dev);
-        struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;
-        struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr;
-
-        switch(cmd)
-        {
-                case SIOCSIFADDR:
-                       /* Get and set the nodeid and network # atalkd wants. */
-                       cops_nodeid(dev, sa->sat_addr.s_node);
-                       aa->s_net               = sa->sat_addr.s_net;
-                        aa->s_node              = lp->node_acquire;
-
-                       /* Set broardcast address. */
-                        dev->broadcast[0]       = 0xFF;
-                       
-                       /* Set hardware address. */
-                        dev->dev_addr[0]        = aa->s_node;
-                        dev->addr_len           = 1;
-                        return 0;
-
-                case SIOCGIFADDR:
-                        sa->sat_addr.s_net      = aa->s_net;
-                        sa->sat_addr.s_node     = aa->s_node;
-                        return 0;
-
-                default:
-                        return -EOPNOTSUPP;
-        }
-}
-
-/*
- *     The inverse routine to cops_open().
- */
-static int cops_close(struct net_device *dev)
-{
-       struct cops_local *lp = netdev_priv(dev);
-
-       /* If we were running polled, yank the timer.
-        */
-       if(lp->board==TANGENT && dev->irq==0)
-               del_timer(&cops_timer);
-
-       netif_stop_queue(dev);
-        return 0;
-}
-
-
-#ifdef MODULE
-static struct net_device *cops_dev;
-
-MODULE_LICENSE("GPL");
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(board_type, int, 0);
-
-static int __init cops_module_init(void)
-{
-       if (io == 0)
-               printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
-                       cardname);
-       cops_dev = cops_probe(-1);
-       if (IS_ERR(cops_dev))
-               return PTR_ERR(cops_dev);
-        return 0;
-}
-
-static void __exit cops_module_exit(void)
-{
-       unregister_netdev(cops_dev);
-       cleanup_card(cops_dev);
-       free_netdev(cops_dev);
-}
-module_init(cops_module_init);
-module_exit(cops_module_exit);
-#endif /* MODULE */
diff --git a/drivers/net/appletalk/cops.h b/drivers/net/appletalk/cops.h
deleted file mode 100644 (file)
index fd2750b..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*      cops.h: LocalTalk driver for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@samba.org>
- */
-
-#ifndef __LINUX_COPSLTALK_H
-#define __LINUX_COPSLTALK_H
-
-#ifdef __KERNEL__
-
-/* Max LLAP size we will accept. */
-#define MAX_LLAP_SIZE          603
-
-/* Tangent */
-#define TANG_CARD_STATUS        1
-#define TANG_CLEAR_INT          1
-#define TANG_RESET              3
-
-#define TANG_TX_READY           1
-#define TANG_RX_READY           2
-
-/* Dayna */
-#define DAYNA_CMD_DATA          0
-#define DAYNA_CLEAR_INT         1
-#define DAYNA_CARD_STATUS       2
-#define DAYNA_INT_CARD          3
-#define DAYNA_RESET             4
-
-#define DAYNA_RX_READY          0
-#define DAYNA_TX_READY          1
-#define DAYNA_RX_REQUEST        3
-
-/* Same on both card types */
-#define COPS_CLEAR_INT  1
-
-/* LAP response codes received from the cards. */
-#define LAP_INIT        1       /* Init cmd */
-#define LAP_INIT_RSP    2       /* Init response */
-#define LAP_WRITE       3       /* Write cmd */
-#define DATA_READ       4       /* Data read */
-#define LAP_RESPONSE    4       /* Received ALAP frame response */
-#define LAP_GETSTAT     5       /* Get LAP and HW status */
-#define LAP_RSPSTAT     6       /* Status response */
-
-#endif
-
-/*
- *     Structure to hold the firmware information.
- */
-struct ltfirmware
-{
-        unsigned int length;
-        const unsigned char *data;
-};
-
-#define DAYNA 1
-#define TANGENT 2
-
-#endif
diff --git a/drivers/net/appletalk/cops_ffdrv.h b/drivers/net/appletalk/cops_ffdrv.h
deleted file mode 100644 (file)
index b020050..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-
-/*
- *     The firmware this driver downloads into the Localtalk card is a
- *     separate program and is not GPL'd source code, even though the Linux
- *     side driver and the routine that loads this data into the card are.
- *     
- *     It is taken from the COPS SDK and is under the following license
- *
- *     This material is licensed to you strictly for use in conjunction with
- *     the use of COPS LocalTalk adapters.
- *     There is no charge for this SDK. And no waranty express or implied
- *     about its fitness for any purpose. However, we will cheerefully
- *     refund every penny you paid for this SDK...
- *     Regards,
- *
- *     Thomas F. Divine
- *     Chief Scientist
- */
-
-
-/*      cops_ffdrv.h: LocalTalk driver firmware dump for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@samba.org>
- */
-
-
-#ifdef CONFIG_COPS_DAYNA
-
-static const unsigned char ffdrv_code[] = {
-       58,3,0,50,228,149,33,255,255,34,226,149,
-       249,17,40,152,33,202,154,183,237,82,77,68,
-       11,107,98,19,54,0,237,176,175,50,80,0,
-       62,128,237,71,62,32,237,57,51,62,12,237,
-       57,50,237,57,54,62,6,237,57,52,62,12,
-       237,57,49,33,107,137,34,32,128,33,83,130,
-       34,40,128,33,86,130,34,42,128,33,112,130,
-       34,36,128,33,211,130,34,38,128,62,0,237,
-       57,16,33,63,148,34,34,128,237,94,205,15,
-       130,251,205,168,145,24,141,67,111,112,121,114,
-       105,103,104,116,32,40,67,41,32,49,57,56,
-       56,32,45,32,68,97,121,110,97,32,67,111,
-       109,109,117,110,105,99,97,116,105,111,110,115,
-       32,32,32,65,108,108,32,114,105,103,104,116,
-       115,32,114,101,115,101,114,118,101,100,46,32,
-       32,40,68,40,68,7,16,8,34,7,22,6,
-       16,5,12,4,8,3,6,140,0,16,39,128,
-       0,4,96,10,224,6,0,7,126,2,64,11,
-       118,12,6,13,0,14,193,15,0,5,96,3,
-       192,1,64,9,8,62,9,211,66,62,192,211,
-       66,62,100,61,32,253,6,28,33,205,129,14,
-       66,237,163,194,253,129,6,28,33,205,129,14,
-       64,237,163,194,9,130,201,62,47,50,71,152,
-       62,47,211,68,58,203,129,237,57,20,58,204,
-       129,237,57,21,33,77,152,54,132,205,233,129,
-       58,228,149,254,209,40,6,56,4,62,0,24,
-       2,219,96,33,233,149,119,230,62,33,232,149,
-       119,213,33,8,152,17,7,0,25,119,19,25,
-       119,209,201,251,237,77,245,197,213,229,221,229,
-       205,233,129,62,1,50,106,137,205,158,139,221,
-       225,225,209,193,241,251,237,77,245,197,213,219,
-       72,237,56,16,230,46,237,57,16,237,56,12,
-       58,72,152,183,32,26,6,20,17,128,2,237,
-       56,46,187,32,35,237,56,47,186,32,29,219,
-       72,230,1,32,3,5,32,232,175,50,72,152,
-       229,221,229,62,1,50,106,137,205,158,139,221,
-       225,225,24,25,62,1,50,72,152,58,201,129,
-       237,57,12,58,202,129,237,57,13,237,56,16,
-       246,17,237,57,16,209,193,241,251,237,77,245,
-       197,229,213,221,229,237,56,16,230,17,237,57,
-       16,237,56,20,58,34,152,246,16,246,8,211,
-       68,62,6,61,32,253,58,34,152,246,8,211,
-       68,58,203,129,237,57,20,58,204,129,237,57,
-       21,237,56,16,246,34,237,57,16,221,225,209,
-       225,193,241,251,237,77,33,2,0,57,126,230,
-       3,237,100,1,40,2,246,128,230,130,245,62,
-       5,211,64,241,211,64,201,229,213,243,237,56,
-       16,230,46,237,57,16,237,56,12,251,70,35,
-       35,126,254,175,202,77,133,254,129,202,15,133,
-       230,128,194,191,132,43,58,44,152,119,33,76,
-       152,119,35,62,132,119,120,254,255,40,4,58,
-       49,152,119,219,72,43,43,112,17,3,0,237,
-       56,52,230,248,237,57,52,219,72,230,1,194,
-       141,131,209,225,237,56,52,246,6,237,57,52,
-       62,1,55,251,201,62,3,211,66,62,192,211,
-       66,62,48,211,66,0,0,219,66,230,1,40,
-       4,219,67,24,240,205,203,135,58,75,152,254,
-       255,202,128,132,58,49,152,254,161,250,207,131,
-       58,34,152,211,68,62,10,211,66,62,128,211,
-       66,62,11,211,66,62,6,211,66,24,0,62,
-       14,211,66,62,33,211,66,62,1,211,66,62,
-       64,211,66,62,3,211,66,62,209,211,66,62,
-       100,71,219,66,230,1,32,6,5,32,247,195,
-       248,132,219,67,71,58,44,152,184,194,248,132,
-       62,100,71,219,66,230,1,32,6,5,32,247,
-       195,248,132,219,67,62,100,71,219,66,230,1,
-       32,6,5,32,247,195,248,132,219,67,254,133,
-       32,7,62,0,50,74,152,24,17,254,173,32,
-       7,62,1,50,74,152,24,6,254,141,194,248,
-       132,71,209,225,58,49,152,254,132,32,10,62,
-       50,205,2,134,205,144,135,24,27,254,140,32,
-       15,62,110,205,2,134,62,141,184,32,5,205,
-       144,135,24,8,62,10,205,2,134,205,8,134,
-       62,1,50,106,137,205,158,139,237,56,52,246,
-       6,237,57,52,175,183,251,201,62,20,135,237,
-       57,20,175,237,57,21,237,56,16,246,2,237,
-       57,16,237,56,20,95,237,56,21,123,254,10,
-       48,244,237,56,16,230,17,237,57,16,209,225,
-       205,144,135,62,1,50,106,137,205,158,139,237,
-       56,52,246,6,237,57,52,175,183,251,201,209,
-       225,243,219,72,230,1,40,13,62,10,211,66,
-       0,0,219,66,230,192,202,226,132,237,56,52,
-       246,6,237,57,52,62,1,55,251,201,205,203,
-       135,62,1,50,106,137,205,158,139,237,56,52,
-       246,6,237,57,52,183,251,201,209,225,62,1,
-       50,106,137,205,158,139,237,56,52,246,6,237,
-       57,52,62,2,55,251,201,209,225,243,219,72,
-       230,1,202,213,132,62,10,211,66,0,0,219,
-       66,230,192,194,213,132,229,62,1,50,106,137,
-       42,40,152,205,65,143,225,17,3,0,205,111,
-       136,62,6,211,66,58,44,152,211,66,237,56,
-       52,246,6,237,57,52,183,251,201,209,197,237,
-       56,52,230,248,237,57,52,219,72,230,1,32,
-       15,193,225,237,56,52,246,6,237,57,52,62,
-       1,55,251,201,14,23,58,37,152,254,0,40,
-       14,14,2,254,1,32,5,62,140,119,24,3,
-       62,132,119,43,43,197,205,203,135,193,62,1,
-       211,66,62,64,211,66,62,3,211,66,62,193,
-       211,66,62,100,203,39,71,219,66,230,1,32,
-       6,5,32,247,195,229,133,33,238,151,219,67,
-       71,58,44,152,184,194,229,133,119,62,100,71,
-       219,66,230,1,32,6,5,32,247,195,229,133,
-       219,67,35,119,13,32,234,193,225,62,1,50,
-       106,137,205,158,139,237,56,52,246,6,237,57,
-       52,175,183,251,201,33,234,151,35,35,62,255,
-       119,193,225,62,1,50,106,137,205,158,139,237,
-       56,52,246,6,237,57,52,175,251,201,243,61,
-       32,253,251,201,62,3,211,66,62,192,211,66,
-       58,49,152,254,140,32,19,197,229,213,17,181,
-       129,33,185,129,1,2,0,237,176,209,225,193,
-       24,27,229,213,33,187,129,58,49,152,230,15,
-       87,30,2,237,92,25,17,181,129,126,18,19,
-       35,126,18,209,225,58,34,152,246,8,211,68,
-       58,49,152,254,165,40,14,254,164,40,10,62,
-       10,211,66,62,224,211,66,24,25,58,74,152,
-       254,0,40,10,62,10,211,66,62,160,211,66,
-       24,8,62,10,211,66,62,128,211,66,62,11,
-       211,66,62,6,211,66,205,147,143,62,5,211,
-       66,62,224,211,66,62,5,211,66,62,96,211,
-       66,62,5,61,32,253,62,5,211,66,62,224,
-       211,66,62,14,61,32,253,62,5,211,66,62,
-       233,211,66,62,128,211,66,58,181,129,61,32,
-       253,62,1,211,66,62,192,211,66,1,254,19,
-       237,56,46,187,32,6,13,32,247,195,226,134,
-       62,192,211,66,0,0,219,66,203,119,40,250,
-       219,66,203,87,40,250,243,237,56,16,230,17,
-       237,57,16,237,56,20,251,62,5,211,66,62,
-       224,211,66,58,182,129,61,32,253,229,33,181,
-       129,58,183,129,203,63,119,35,58,184,129,119,
-       225,62,10,211,66,62,224,211,66,62,11,211,
-       66,62,118,211,66,62,47,211,68,62,5,211,
-       66,62,233,211,66,58,181,129,61,32,253,62,
-       5,211,66,62,224,211,66,58,182,129,61,32,
-       253,62,5,211,66,62,96,211,66,201,229,213,
-       58,50,152,230,15,87,30,2,237,92,33,187,
-       129,25,17,181,129,126,18,35,19,126,18,209,
-       225,58,71,152,246,8,211,68,58,50,152,254,
-       165,40,14,254,164,40,10,62,10,211,66,62,
-       224,211,66,24,8,62,10,211,66,62,128,211,
-       66,62,11,211,66,62,6,211,66,195,248,135,
-       62,3,211,66,62,192,211,66,197,229,213,17,
-       181,129,33,183,129,1,2,0,237,176,209,225,
-       193,62,47,211,68,62,10,211,66,62,224,211,
-       66,62,11,211,66,62,118,211,66,62,1,211,
-       66,62,0,211,66,205,147,143,195,16,136,62,
-       3,211,66,62,192,211,66,197,229,213,17,181,
-       129,33,183,129,1,2,0,237,176,209,225,193,
-       62,47,211,68,62,10,211,66,62,224,211,66,
-       62,11,211,66,62,118,211,66,205,147,143,62,
-       5,211,66,62,224,211,66,62,5,211,66,62,
-       96,211,66,62,5,61,32,253,62,5,211,66,
-       62,224,211,66,62,14,61,32,253,62,5,211,
-       66,62,233,211,66,62,128,211,66,58,181,129,
-       61,32,253,62,1,211,66,62,192,211,66,1,
-       254,19,237,56,46,187,32,6,13,32,247,195,
-       88,136,62,192,211,66,0,0,219,66,203,119,
-       40,250,219,66,203,87,40,250,62,5,211,66,
-       62,224,211,66,58,182,129,61,32,253,62,5,
-       211,66,62,96,211,66,201,197,14,67,6,0,
-       62,3,211,66,62,192,211,66,62,48,211,66,
-       0,0,219,66,230,1,40,4,219,67,24,240,
-       62,5,211,66,62,233,211,66,62,128,211,66,
-       58,181,129,61,32,253,237,163,29,62,192,211,
-       66,219,66,230,4,40,250,237,163,29,32,245,
-       219,66,230,4,40,250,62,255,71,219,66,230,
-       4,40,3,5,32,247,219,66,230,4,40,250,
-       62,5,211,66,62,224,211,66,58,182,129,61,
-       32,253,62,5,211,66,62,96,211,66,58,71,
-       152,254,1,202,18,137,62,16,211,66,62,56,
-       211,66,62,14,211,66,62,33,211,66,62,1,
-       211,66,62,248,211,66,237,56,48,246,153,230,
-       207,237,57,48,62,3,211,66,62,221,211,66,
-       193,201,58,71,152,211,68,62,10,211,66,62,
-       128,211,66,62,11,211,66,62,6,211,66,62,
-       6,211,66,58,44,152,211,66,62,16,211,66,
-       62,56,211,66,62,48,211,66,0,0,62,14,
-       211,66,62,33,211,66,62,1,211,66,62,248,
-       211,66,237,56,48,246,145,246,8,230,207,237,
-       57,48,62,3,211,66,62,221,211,66,193,201,
-       44,3,1,0,70,69,1,245,197,213,229,175,
-       50,72,152,237,56,16,230,46,237,57,16,237,
-       56,12,62,1,211,66,0,0,219,66,95,230,
-       160,32,3,195,20,139,123,230,96,194,72,139,
-       62,48,211,66,62,1,211,66,62,64,211,66,
-       237,91,40,152,205,207,143,25,43,55,237,82,
-       218,70,139,34,42,152,98,107,58,44,152,190,
-       194,210,138,35,35,62,130,190,194,200,137,62,
-       1,50,48,152,62,175,190,202,82,139,62,132,
-       190,32,44,50,50,152,62,47,50,71,152,229,
-       175,50,106,137,42,40,152,205,65,143,225,54,
-       133,43,70,58,44,152,119,43,112,17,3,0,
-       62,10,205,2,134,205,111,136,195,158,138,62,
-       140,190,32,19,50,50,152,58,233,149,230,4,
-       202,222,138,62,1,50,71,152,195,219,137,126,
-       254,160,250,185,138,254,166,242,185,138,50,50,
-       152,43,126,35,229,213,33,234,149,95,22,0,
-       25,126,254,132,40,18,254,140,40,14,58,50,
-       152,230,15,87,126,31,21,242,65,138,56,2,
-       175,119,58,50,152,230,15,87,58,233,149,230,
-       62,31,21,242,85,138,218,98,138,209,225,195,
-       20,139,58,50,152,33,100,137,230,15,95,22,
-       0,25,126,50,71,152,209,225,58,50,152,254,
-       164,250,135,138,58,73,152,254,0,40,4,54,
-       173,24,2,54,133,43,70,58,44,152,119,43,
-       112,17,3,0,205,70,135,175,50,106,137,205,
-       208,139,58,199,129,237,57,12,58,200,129,237,
-       57,13,237,56,16,246,17,237,57,16,225,209,
-       193,241,251,237,77,62,129,190,194,227,138,54,
-       130,43,70,58,44,152,119,43,112,17,3,0,
-       205,144,135,195,20,139,35,35,126,254,132,194,
-       227,138,175,50,106,137,205,158,139,24,42,58,
-       201,154,254,1,40,7,62,1,50,106,137,24,
-       237,58,106,137,254,1,202,222,138,62,128,166,
-       194,222,138,221,229,221,33,67,152,205,127,142,
-       205,109,144,221,225,225,209,193,241,251,237,77,
-       58,106,137,254,1,202,44,139,58,50,152,254,
-       164,250,44,139,58,73,152,238,1,50,73,152,
-       221,229,221,33,51,152,205,127,142,221,225,62,
-       1,50,106,137,205,158,139,195,13,139,24,208,
-       24,206,24,204,230,64,40,3,195,20,139,195,
-       20,139,43,126,33,8,152,119,35,58,44,152,
-       119,43,237,91,35,152,205,203,135,205,158,139,
-       195,13,139,175,50,78,152,62,3,211,66,62,
-       192,211,66,201,197,33,4,0,57,126,35,102,
-       111,62,1,50,106,137,219,72,205,141,139,193,
-       201,62,1,50,78,152,34,40,152,54,0,35,
-       35,54,0,195,163,139,58,78,152,183,200,229,
-       33,181,129,58,183,129,119,35,58,184,129,119,
-       225,62,47,211,68,62,14,211,66,62,193,211,
-       66,62,10,211,66,62,224,211,66,62,11,211,
-       66,62,118,211,66,195,3,140,58,78,152,183,
-       200,58,71,152,211,68,254,69,40,4,254,70,
-       32,17,58,73,152,254,0,40,10,62,10,211,
-       66,62,160,211,66,24,8,62,10,211,66,62,
-       128,211,66,62,11,211,66,62,6,211,66,62,
-       6,211,66,58,44,152,211,66,62,16,211,66,
-       62,56,211,66,62,48,211,66,0,0,219,66,
-       230,1,40,4,219,67,24,240,62,14,211,66,
-       62,33,211,66,42,40,152,205,65,143,62,1,
-       211,66,62,248,211,66,237,56,48,246,145,246,
-       8,230,207,237,57,48,62,3,211,66,62,221,
-       211,66,201,62,16,211,66,62,56,211,66,62,
-       48,211,66,0,0,219,66,230,1,40,4,219,
-       67,24,240,62,14,211,66,62,33,211,66,62,
-       1,211,66,62,248,211,66,237,56,48,246,153,
-       230,207,237,57,48,62,3,211,66,62,221,211,
-       66,201,229,213,33,234,149,95,22,0,25,126,
-       254,132,40,4,254,140,32,2,175,119,123,209,
-       225,201,6,8,14,0,31,48,1,12,16,250,
-       121,201,33,4,0,57,94,35,86,33,2,0,
-       57,126,35,102,111,221,229,34,89,152,237,83,
-       91,152,221,33,63,152,205,127,142,58,81,152,
-       50,82,152,58,80,152,135,50,80,152,205,162,
-       140,254,3,56,16,58,81,152,135,60,230,15,
-       50,81,152,175,50,80,152,24,23,58,79,152,
-       205,162,140,254,3,48,13,58,81,152,203,63,
-       50,81,152,62,255,50,79,152,58,81,152,50,
-       82,152,58,79,152,135,50,79,152,62,32,50,
-       83,152,50,84,152,237,56,16,230,17,237,57,
-       16,219,72,62,192,50,93,152,62,93,50,94,
-       152,58,93,152,61,50,93,152,32,9,58,94,
-       152,61,50,94,152,40,44,62,170,237,57,20,
-       175,237,57,21,237,56,16,246,2,237,57,16,
-       219,72,230,1,202,29,141,237,56,20,71,237,
-       56,21,120,254,10,48,237,237,56,16,230,17,
-       237,57,16,243,62,14,211,66,62,65,211,66,
-       251,58,39,152,23,23,60,50,39,152,71,58,
-       82,152,160,230,15,40,22,71,14,10,219,66,
-       230,16,202,186,141,219,72,230,1,202,186,141,
-       13,32,239,16,235,42,89,152,237,91,91,152,
-       205,47,131,48,7,61,202,186,141,195,227,141,
-       221,225,33,0,0,201,221,33,55,152,205,127,
-       142,58,84,152,61,50,84,152,40,19,58,82,
-       152,246,1,50,82,152,58,79,152,246,1,50,
-       79,152,195,29,141,221,225,33,1,0,201,221,
-       33,59,152,205,127,142,58,80,152,246,1,50,
-       80,152,58,82,152,135,246,1,50,82,152,58,
-       83,152,61,50,83,152,194,29,141,221,225,33,
-       2,0,201,221,229,33,0,0,57,17,4,0,
-       25,126,50,44,152,230,128,50,85,152,58,85,
-       152,183,40,6,221,33,88,2,24,4,221,33,
-       150,0,58,44,152,183,40,53,60,40,50,60,
-       40,47,61,61,33,86,152,119,35,119,35,54,
-       129,175,50,48,152,221,43,221,229,225,124,181,
-       40,42,33,86,152,17,3,0,205,189,140,17,
-       232,3,27,123,178,32,251,58,48,152,183,40,
-       224,58,44,152,71,62,7,128,230,127,71,58,
-       85,152,176,50,44,152,24,162,221,225,201,183,
-       221,52,0,192,221,52,1,192,221,52,2,192,
-       221,52,3,192,55,201,245,62,1,211,100,241,
-       201,245,62,1,211,96,241,201,33,2,0,57,
-       126,35,102,111,237,56,48,230,175,237,57,48,
-       62,48,237,57,49,125,237,57,32,124,237,57,
-       33,62,0,237,57,34,62,88,237,57,35,62,
-       0,237,57,36,237,57,37,33,128,2,125,237,
-       57,38,124,237,57,39,237,56,48,246,97,230,
-       207,237,57,48,62,0,237,57,0,62,0,211,
-       96,211,100,201,33,2,0,57,126,35,102,111,
-       237,56,48,230,175,237,57,48,62,12,237,57,
-       49,62,76,237,57,32,62,0,237,57,33,237,
-       57,34,125,237,57,35,124,237,57,36,62,0,
-       237,57,37,33,128,2,125,237,57,38,124,237,
-       57,39,237,56,48,246,97,230,207,237,57,48,
-       62,1,211,96,201,33,2,0,57,126,35,102,
-       111,229,237,56,48,230,87,237,57,48,125,237,
-       57,40,124,237,57,41,62,0,237,57,42,62,
-       67,237,57,43,62,0,237,57,44,58,106,137,
-       254,1,32,5,33,6,0,24,3,33,128,2,
-       125,237,57,46,124,237,57,47,237,56,50,230,
-       252,246,2,237,57,50,225,201,33,4,0,57,
-       94,35,86,33,2,0,57,126,35,102,111,237,
-       56,48,230,87,237,57,48,125,237,57,40,124,
-       237,57,41,62,0,237,57,42,62,67,237,57,
-       43,62,0,237,57,44,123,237,57,46,122,237,
-       57,47,237,56,50,230,244,246,0,237,57,50,
-       237,56,48,246,145,230,207,237,57,48,201,213,
-       237,56,46,95,237,56,47,87,237,56,46,111,
-       237,56,47,103,183,237,82,32,235,33,128,2,
-       183,237,82,209,201,213,237,56,38,95,237,56,
-       39,87,237,56,38,111,237,56,39,103,183,237,
-       82,32,235,33,128,2,183,237,82,209,201,245,
-       197,1,52,0,237,120,230,253,237,121,193,241,
-       201,245,197,1,52,0,237,120,246,2,237,121,
-       193,241,201,33,2,0,57,126,35,102,111,126,
-       35,110,103,201,33,0,0,34,102,152,34,96,
-       152,34,98,152,33,202,154,34,104,152,237,91,
-       104,152,42,226,149,183,237,82,17,0,255,25,
-       34,100,152,203,124,40,6,33,0,125,34,100,
-       152,42,104,152,35,35,35,229,205,120,139,193,
-       201,205,186,149,229,42,40,152,35,35,35,229,
-       205,39,144,193,124,230,3,103,221,117,254,221,
-       116,255,237,91,42,152,35,35,35,183,237,82,
-       32,12,17,5,0,42,42,152,205,171,149,242,
-       169,144,42,40,152,229,205,120,139,193,195,198,
-       149,237,91,42,152,42,98,152,25,34,98,152,
-       19,19,19,42,102,152,25,34,102,152,237,91,
-       100,152,33,158,253,25,237,91,102,152,205,171,
-       149,242,214,144,33,0,0,34,102,152,62,1,
-       50,95,152,205,225,144,195,198,149,58,95,152,
-       183,200,237,91,96,152,42,102,152,205,171,149,
-       242,5,145,237,91,102,152,33,98,2,25,237,
-       91,96,152,205,171,149,250,37,145,237,91,96,
-       152,42,102,152,183,237,82,32,7,42,98,152,
-       125,180,40,13,237,91,102,152,42,96,152,205,
-       171,149,242,58,145,237,91,104,152,42,102,152,
-       25,35,35,35,229,205,120,139,193,175,50,95,
-       152,201,195,107,139,205,206,149,250,255,243,205,
-       225,144,251,58,230,149,183,194,198,149,17,1,
-       0,42,98,152,205,171,149,250,198,149,62,1,
-       50,230,149,237,91,96,152,42,104,152,25,221,
-       117,252,221,116,253,237,91,104,152,42,96,152,
-       25,35,35,35,221,117,254,221,116,255,35,35,
-       35,229,205,39,144,124,230,3,103,35,35,35,
-       221,117,250,221,116,251,235,221,110,252,221,102,
-       253,115,35,114,35,54,4,62,1,211,100,211,
-       84,195,198,149,33,0,0,34,102,152,34,96,
-       152,34,98,152,33,202,154,34,104,152,237,91,
-       104,152,42,226,149,183,237,82,17,0,255,25,
-       34,100,152,33,109,152,54,0,33,107,152,229,
-       205,240,142,193,62,47,50,34,152,62,132,50,
-       49,152,205,241,145,205,61,145,58,39,152,60,
-       50,39,152,24,241,205,206,149,251,255,33,109,
-       152,126,183,202,198,149,110,221,117,251,33,109,
-       152,54,0,221,126,251,254,1,40,28,254,3,
-       40,101,254,4,202,190,147,254,5,202,147,147,
-       254,8,40,87,33,107,152,229,205,240,142,195,
-       198,149,58,201,154,183,32,21,33,111,152,126,
-       50,229,149,205,52,144,33,110,152,110,38,0,
-       229,205,11,142,193,237,91,96,152,42,104,152,
-       25,221,117,254,221,116,255,35,35,54,2,17,
-       2,0,43,43,115,35,114,58,44,152,35,35,
-       119,58,228,149,35,119,62,1,211,100,211,84,
-       62,1,50,201,154,24,169,205,153,142,58,231,
-       149,183,40,250,175,50,231,149,33,110,152,126,
-       254,255,40,91,58,233,149,230,63,183,40,83,
-       94,22,0,33,234,149,25,126,183,40,13,33,
-       110,152,94,33,234,150,25,126,254,3,32,36,
-       205,81,148,125,180,33,110,152,94,22,0,40,
-       17,33,234,149,25,54,0,33,107,152,229,205,
-       240,142,193,195,198,149,33,234,150,25,54,0,
-       33,110,152,94,22,0,33,234,149,25,126,50,
-       49,152,254,132,32,37,62,47,50,34,152,42,
-       107,152,229,33,110,152,229,205,174,140,193,193,
-       125,180,33,110,152,94,22,0,33,234,150,202,
-       117,147,25,52,195,120,147,58,49,152,254,140,
-       32,7,62,1,50,34,152,24,210,62,32,50,
-       106,152,24,19,58,49,152,95,58,106,152,163,
-       183,58,106,152,32,11,203,63,50,106,152,58,
-       106,152,183,32,231,254,2,40,51,254,4,40,
-       38,254,8,40,26,254,16,40,13,254,32,32,
-       158,62,165,50,49,152,62,69,24,190,62,164,
-       50,49,152,62,70,24,181,62,163,50,49,152,
-       175,24,173,62,162,50,49,152,62,1,24,164,
-       62,161,50,49,152,62,3,24,155,25,54,0,
-       221,126,251,254,8,40,7,58,230,149,183,202,
-       32,146,33,107,152,229,205,240,142,193,211,84,
-       195,198,149,237,91,96,152,42,104,152,25,221,
-       117,254,221,116,255,35,35,54,6,17,2,0,
-       43,43,115,35,114,58,228,149,35,35,119,58,
-       233,149,35,119,205,146,142,195,32,146,237,91,
-       96,152,42,104,152,25,229,205,160,142,193,58,
-       231,149,183,40,250,175,50,231,149,243,237,91,
-       96,152,42,104,152,25,221,117,254,221,116,255,
-       78,35,70,221,113,252,221,112,253,89,80,42,
-       98,152,183,237,82,34,98,152,203,124,40,19,
-       33,0,0,34,98,152,34,102,152,34,96,152,
-       62,1,50,95,152,24,40,221,94,252,221,86,
-       253,19,19,19,42,96,152,25,34,96,152,237,
-       91,100,152,33,158,253,25,237,91,96,152,205,
-       171,149,242,55,148,33,0,0,34,96,152,175,
-       50,230,149,251,195,32,146,245,62,1,50,231,
-       149,62,16,237,57,0,211,80,241,251,237,77,
-       201,205,186,149,229,229,33,0,0,34,37,152,
-       33,110,152,126,50,234,151,58,44,152,33,235,
-       151,119,221,54,253,0,221,54,254,0,195,230,
-       148,33,236,151,54,175,33,3,0,229,33,234,
-       151,229,205,174,140,193,193,33,236,151,126,254,
-       255,40,74,33,245,151,110,221,117,255,33,249,
-       151,126,221,166,255,221,119,255,33,253,151,126,
-       221,166,255,221,119,255,58,232,149,95,221,126,
-       255,163,221,119,255,183,40,15,230,191,33,110,
-       152,94,22,0,33,234,149,25,119,24,12,33,
-       110,152,94,22,0,33,234,149,25,54,132,33,
-       0,0,195,198,149,221,110,253,221,102,254,35,
-       221,117,253,221,116,254,17,32,0,221,110,253,
-       221,102,254,205,171,149,250,117,148,58,233,149,
-       203,87,40,84,33,1,0,34,37,152,221,54,
-       253,0,221,54,254,0,24,53,33,236,151,54,
-       175,33,3,0,229,33,234,151,229,205,174,140,
-       193,193,33,236,151,126,254,255,40,14,33,110,
-       152,94,22,0,33,234,149,25,54,140,24,159,
-       221,110,253,221,102,254,35,221,117,253,221,116,
-       254,17,32,0,221,110,253,221,102,254,205,171,
-       149,250,12,149,33,2,0,34,37,152,221,54,
-       253,0,221,54,254,0,24,54,33,236,151,54,
-       175,33,3,0,229,33,234,151,229,205,174,140,
-       193,193,33,236,151,126,254,255,40,15,33,110,
-       152,94,22,0,33,234,149,25,54,132,195,211,
-       148,221,110,253,221,102,254,35,221,117,253,221,
-       116,254,17,32,0,221,110,253,221,102,254,205,
-       171,149,250,96,149,33,1,0,195,198,149,124,
-       170,250,179,149,237,82,201,124,230,128,237,82,
-       60,201,225,253,229,221,229,221,33,0,0,221,
-       57,233,221,249,221,225,253,225,201,233,225,253,
-       229,221,229,221,33,0,0,221,57,94,35,86,
-       35,235,57,249,235,233,0,0,0,0,0,0,
-       62,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       175,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,133,1,0,0,0,63,
-       255,255,255,255,0,0,0,63,0,0,0,0,
-       0,0,0,0,0,0,0,24,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0
-       } ;
-
-#endif
diff --git a/drivers/net/appletalk/cops_ltdrv.h b/drivers/net/appletalk/cops_ltdrv.h
deleted file mode 100644 (file)
index c699b1a..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- *     The firmware this driver downloads into the Localtalk card is a
- *     separate program and is not GPL'd source code, even though the Linux
- *     side driver and the routine that loads this data into the card are.
- *     
- *     It is taken from the COPS SDK and is under the following license
- *
- *     This material is licensed to you strictly for use in conjunction with
- *     the use of COPS LocalTalk adapters.
- *     There is no charge for this SDK. And no waranty express or implied
- *     about its fitness for any purpose. However, we will cheerefully
- *     refund every penny you paid for this SDK...
- *     Regards,
- *
- *     Thomas F. Divine
- *     Chief Scientist
- */
-
-
-/*      cops_ltdrv.h: LocalTalk driver firmware dump for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@samba.org>
- */
-
-#ifdef CONFIG_COPS_TANGENT
-
-static const unsigned char ltdrv_code[] = {
-       58,3,0,50,148,10,33,143,15,62,85,119,
-       190,32,9,62,170,119,190,32,3,35,24,241,
-       34,146,10,249,17,150,10,33,143,15,183,237,
-       82,77,68,11,107,98,19,54,0,237,176,62,
-       16,237,57,51,62,0,237,57,50,237,57,54,
-       62,12,237,57,49,62,195,33,39,2,50,56,
-       0,34,57,0,237,86,205,30,2,251,205,60,
-       10,24,169,67,111,112,121,114,105,103,104,116,
-       32,40,99,41,32,49,57,56,56,45,49,57,
-       57,50,44,32,80,114,105,110,116,105,110,103,
-       32,67,111,109,109,117,110,105,99,97,116,105,
-       111,110,115,32,65,115,115,111,99,105,97,116,
-       101,115,44,32,73,110,99,46,65,108,108,32,
-       114,105,103,104,116,115,32,114,101,115,101,114,
-       118,101,100,46,32,32,4,4,22,40,255,60,
-       4,96,10,224,6,0,7,126,2,64,11,246,
-       12,6,13,0,14,193,15,0,5,96,3,192,
-       1,0,9,8,62,3,211,82,62,192,211,82,
-       201,62,3,211,82,62,213,211,82,201,62,5,
-       211,82,62,224,211,82,201,62,5,211,82,62,
-       224,211,82,201,62,5,211,82,62,96,211,82,
-       201,6,28,33,180,1,14,82,237,163,194,4,
-       2,33,39,2,34,64,0,58,3,0,230,1,
-       192,62,11,237,121,62,118,237,121,201,33,182,
-       10,54,132,205,253,1,201,245,197,213,229,42,
-       150,10,14,83,17,98,2,67,20,237,162,58,
-       179,1,95,219,82,230,1,32,6,29,32,247,
-       195,17,3,62,1,211,82,219,82,95,230,160,
-       32,10,237,162,32,225,21,32,222,195,15,3,
-       237,162,123,230,96,194,21,3,62,48,211,82,
-       62,1,211,82,175,211,82,237,91,150,10,43,
-       55,237,82,218,19,3,34,152,10,98,107,58,
-       154,10,190,32,81,62,1,50,158,10,35,35,
-       62,132,190,32,44,54,133,43,70,58,154,10,
-       119,43,112,17,3,0,205,137,3,62,16,211,
-       82,62,56,211,82,205,217,1,42,150,10,14,
-       83,17,98,2,67,20,58,178,1,95,195,59,
-       2,62,129,190,194,227,2,54,130,43,70,58,
-       154,10,119,43,112,17,3,0,205,137,3,195,
-       254,2,35,35,126,254,132,194,227,2,205,61,
-       3,24,20,62,128,166,194,222,2,221,229,221,
-       33,175,10,205,93,6,205,144,7,221,225,225,
-       209,193,241,251,237,77,221,229,221,33,159,10,
-       205,93,6,221,225,205,61,3,195,247,2,24,
-       237,24,235,24,233,230,64,40,2,24,227,24,
-       225,175,50,179,10,205,208,1,201,197,33,4,
-       0,57,126,35,102,111,205,51,3,193,201,62,
-       1,50,179,10,34,150,10,54,0,58,179,10,
-       183,200,62,14,211,82,62,193,211,82,62,10,
-       211,82,62,224,211,82,62,6,211,82,58,154,
-       10,211,82,62,16,211,82,62,56,211,82,62,
-       48,211,82,219,82,230,1,40,4,219,83,24,
-       242,62,14,211,82,62,33,211,82,62,1,211,
-       82,62,9,211,82,62,32,211,82,205,217,1,
-       201,14,83,205,208,1,24,23,14,83,205,208,
-       1,205,226,1,58,174,1,61,32,253,205,244,
-       1,58,174,1,61,32,253,205,226,1,58,175,
-       1,61,32,253,62,5,211,82,62,233,211,82,
-       62,128,211,82,58,176,1,61,32,253,237,163,
-       27,62,192,211,82,219,82,230,4,40,250,237,
-       163,27,122,179,32,243,219,82,230,4,40,250,
-       58,178,1,71,219,82,230,4,40,3,5,32,
-       247,219,82,230,4,40,250,205,235,1,58,177,
-       1,61,32,253,205,244,1,201,229,213,35,35,
-       126,230,128,194,145,4,43,58,154,10,119,43,
-       70,33,181,10,119,43,112,17,3,0,243,62,
-       10,211,82,219,82,230,128,202,41,4,209,225,
-       62,1,55,251,201,205,144,3,58,180,10,254,
-       255,202,127,4,205,217,1,58,178,1,71,219,
-       82,230,1,32,6,5,32,247,195,173,4,219,
-       83,71,58,154,10,184,194,173,4,58,178,1,
-       71,219,82,230,1,32,6,5,32,247,195,173,
-       4,219,83,58,178,1,71,219,82,230,1,32,
-       6,5,32,247,195,173,4,219,83,254,133,194,
-       173,4,58,179,1,24,4,58,179,1,135,61,
-       32,253,209,225,205,137,3,205,61,3,183,251,
-       201,209,225,243,62,10,211,82,219,82,230,128,
-       202,164,4,62,1,55,251,201,205,144,3,205,
-       61,3,183,251,201,209,225,62,2,55,251,201,
-       243,62,14,211,82,62,33,211,82,251,201,33,
-       4,0,57,94,35,86,33,2,0,57,126,35,
-       102,111,221,229,34,193,10,237,83,195,10,221,
-       33,171,10,205,93,6,58,185,10,50,186,10,
-       58,184,10,135,50,184,10,205,112,6,254,3,
-       56,16,58,185,10,135,60,230,15,50,185,10,
-       175,50,184,10,24,23,58,183,10,205,112,6,
-       254,3,48,13,58,185,10,203,63,50,185,10,
-       62,255,50,183,10,58,185,10,50,186,10,58,
-       183,10,135,50,183,10,62,32,50,187,10,50,
-       188,10,6,255,219,82,230,16,32,3,5,32,
-       247,205,180,4,6,40,219,82,230,16,40,3,
-       5,32,247,62,10,211,82,219,82,230,128,194,
-       46,5,219,82,230,16,40,214,237,95,71,58,
-       186,10,160,230,15,40,32,71,14,10,62,10,
-       211,82,219,82,230,128,202,119,5,205,180,4,
-       195,156,5,219,82,230,16,202,156,5,13,32,
-       229,16,225,42,193,10,237,91,195,10,205,252,
-       3,48,7,61,202,156,5,195,197,5,221,225,
-       33,0,0,201,221,33,163,10,205,93,6,58,
-       188,10,61,50,188,10,40,19,58,186,10,246,
-       1,50,186,10,58,183,10,246,1,50,183,10,
-       195,46,5,221,225,33,1,0,201,221,33,167,
-       10,205,93,6,58,184,10,246,1,50,184,10,
-       58,186,10,135,246,1,50,186,10,58,187,10,
-       61,50,187,10,194,46,5,221,225,33,2,0,
-       201,221,229,33,0,0,57,17,4,0,25,126,
-       50,154,10,230,128,50,189,10,58,189,10,183,
-       40,6,221,33,88,2,24,4,221,33,150,0,
-       58,154,10,183,40,49,60,40,46,61,33,190,
-       10,119,35,119,35,54,129,175,50,158,10,221,
-       43,221,229,225,124,181,40,42,33,190,10,17,
-       3,0,205,206,4,17,232,3,27,123,178,32,
-       251,58,158,10,183,40,224,58,154,10,71,62,
-       7,128,230,127,71,58,189,10,176,50,154,10,
-       24,166,221,225,201,183,221,52,0,192,221,52,
-       1,192,221,52,2,192,221,52,3,192,55,201,
-       6,8,14,0,31,48,1,12,16,250,121,201,
-       33,2,0,57,94,35,86,35,78,35,70,35,
-       126,35,102,105,79,120,68,103,237,176,201,33,
-       2,0,57,126,35,102,111,62,17,237,57,48,
-       125,237,57,40,124,237,57,41,62,0,237,57,
-       42,62,64,237,57,43,62,0,237,57,44,33,
-       128,2,125,237,57,46,124,237,57,47,62,145,
-       237,57,48,211,68,58,149,10,211,66,201,33,
-       2,0,57,126,35,102,111,62,33,237,57,48,
-       62,64,237,57,32,62,0,237,57,33,237,57,
-       34,125,237,57,35,124,237,57,36,62,0,237,
-       57,37,33,128,2,125,237,57,38,124,237,57,
-       39,62,97,237,57,48,211,67,58,149,10,211,
-       66,201,237,56,46,95,237,56,47,87,237,56,
-       46,111,237,56,47,103,183,237,82,32,235,33,
-       128,2,183,237,82,201,237,56,38,95,237,56,
-       39,87,237,56,38,111,237,56,39,103,183,237,
-       82,32,235,33,128,2,183,237,82,201,205,106,
-       10,221,110,6,221,102,7,126,35,110,103,195,
-       118,10,205,106,10,33,0,0,34,205,10,34,
-       198,10,34,200,10,33,143,15,34,207,10,237,
-       91,207,10,42,146,10,183,237,82,17,0,255,
-       25,34,203,10,203,124,40,6,33,0,125,34,
-       203,10,42,207,10,229,205,37,3,195,118,10,
-       205,106,10,229,42,150,10,35,35,35,229,205,
-       70,7,193,124,230,3,103,221,117,254,221,116,
-       255,237,91,152,10,35,35,35,183,237,82,32,
-       12,17,5,0,42,152,10,205,91,10,242,203,
-       7,42,150,10,229,205,37,3,195,118,10,237,
-       91,152,10,42,200,10,25,34,200,10,42,205,
-       10,25,34,205,10,237,91,203,10,33,158,253,
-       25,237,91,205,10,205,91,10,242,245,7,33,
-       0,0,34,205,10,62,1,50,197,10,205,5,
-       8,33,0,0,57,249,195,118,10,205,106,10,
-       58,197,10,183,202,118,10,237,91,198,10,42,
-       205,10,205,91,10,242,46,8,237,91,205,10,
-       33,98,2,25,237,91,198,10,205,91,10,250,
-       78,8,237,91,198,10,42,205,10,183,237,82,
-       32,7,42,200,10,125,180,40,13,237,91,205,
-       10,42,198,10,205,91,10,242,97,8,237,91,
-       207,10,42,205,10,25,229,205,37,3,175,50,
-       197,10,195,118,10,205,29,3,33,0,0,57,
-       249,195,118,10,205,106,10,58,202,10,183,40,
-       22,205,14,7,237,91,209,10,19,19,19,205,
-       91,10,242,139,8,33,1,0,195,118,10,33,
-       0,0,195,118,10,205,126,10,252,255,205,108,
-       8,125,180,194,118,10,237,91,200,10,33,0,
-       0,205,91,10,242,118,10,237,91,207,10,42,
-       198,10,25,221,117,254,221,116,255,35,35,35,
-       229,205,70,7,193,124,230,3,103,35,35,35,
-       221,117,252,221,116,253,229,221,110,254,221,102,
-       255,229,33,212,10,229,205,124,6,193,193,221,
-       110,252,221,102,253,34,209,10,33,211,10,54,
-       4,33,209,10,227,205,147,6,193,62,1,50,
-       202,10,243,221,94,252,221,86,253,42,200,10,
-       183,237,82,34,200,10,203,124,40,17,33,0,
-       0,34,200,10,34,205,10,34,198,10,50,197,
-       10,24,37,221,94,252,221,86,253,42,198,10,
-       25,34,198,10,237,91,203,10,33,158,253,25,
-       237,91,198,10,205,91,10,242,68,9,33,0,
-       0,34,198,10,205,5,8,33,0,0,57,249,
-       251,195,118,10,205,106,10,33,49,13,126,183,
-       40,16,205,42,7,237,91,47,13,19,19,19,
-       205,91,10,242,117,9,58,142,15,198,1,50,
-       142,15,195,118,10,33,49,13,126,254,1,40,
-       25,254,3,202,7,10,254,5,202,21,10,33,
-       49,13,54,0,33,47,13,229,205,207,6,195,
-       118,10,58,141,15,183,32,72,33,51,13,126,
-       50,149,10,205,86,7,33,50,13,126,230,127,
-       183,32,40,58,142,15,230,127,50,142,15,183,
-       32,5,198,1,50,142,15,33,50,13,126,111,
-       23,159,103,203,125,58,142,15,40,5,198,128,
-       50,142,15,33,50,13,119,33,50,13,126,111,
-       23,159,103,229,205,237,5,193,33,211,10,54,
-       2,33,2,0,34,209,10,58,154,10,33,212,
-       10,119,58,148,10,33,213,10,119,33,209,10,
-       229,205,147,6,193,24,128,42,47,13,229,33,
-       50,13,229,205,191,4,193,24,239,33,211,10,
-       54,6,33,3,0,34,209,10,58,154,10,33,
-       212,10,119,58,148,10,33,213,10,119,33,214,
-       10,54,5,33,209,10,229,205,147,6,24,200,
-       205,106,10,33,49,13,54,0,33,47,13,229,
-       205,207,6,33,209,10,227,205,147,6,193,205,
-       80,9,205,145,8,24,248,124,170,250,99,10,
-       237,82,201,124,230,128,237,82,60,201,225,253,
-       229,221,229,221,33,0,0,221,57,233,221,249,
-       221,225,253,225,201,233,225,253,229,221,229,221,
-       33,0,0,221,57,94,35,86,35,235,57,249,
-       235,233,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0
-       } ;
-
-#endif
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
deleted file mode 100644 (file)
index 10d0dba..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- *     ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
- *              Appletalk-IP to IP Decapsulation driver for Linux
- *
- *     Authors:
- *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *     - DDP-IP Decap by: Jay Schulist <jschlst@samba.org>
- *
- *     Derived from:
- *     - Almost all code already existed in net/appletalk/ddp.c I just
- *       moved/reorginized it into a driver file. Original IP-over-DDP code
- *       was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *      - skeleton.c: A network driver outline for linux.
- *        Written 1993-94 by Donald Becker.
- *     - dummy.c: A dummy net driver. By Nick Holloway.
- *     - MacGate: A user space Daemon for Appletalk-IP Decap for
- *       Linux by Jay Schulist <jschlst@samba.org>
- *
- *      Copyright 1993 United States Government as represented by the
- *      Director, National Security Agency.
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ip.h>
-#include <linux/atalk.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <net/route.h>
-#include <asm/uaccess.h>
-
-#include "ipddp.h"             /* Our stuff */
-
-static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
-
-static struct ipddp_route *ipddp_route_list;
-static DEFINE_SPINLOCK(ipddp_route_lock);
-
-#ifdef CONFIG_IPDDP_ENCAP
-static int ipddp_mode = IPDDP_ENCAP;
-#else
-static int ipddp_mode = IPDDP_DECAP;
-#endif
-
-/* Index to functions, as function prototypes. */
-static netdev_tx_t ipddp_xmit(struct sk_buff *skb,
-                                   struct net_device *dev);
-static int ipddp_create(struct ipddp_route *new_rt);
-static int ipddp_delete(struct ipddp_route *rt);
-static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
-static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-
-static const struct net_device_ops ipddp_netdev_ops = {
-       .ndo_start_xmit         = ipddp_xmit,
-       .ndo_do_ioctl           = ipddp_ioctl,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static struct net_device * __init ipddp_init(void)
-{
-       static unsigned version_printed;
-       struct net_device *dev;
-       int err;
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
-       strcpy(dev->name, "ipddp%d");
-
-       if (version_printed++ == 0)
-                printk(version);
-
-       /* Initialize the device structure. */
-       dev->netdev_ops = &ipddp_netdev_ops;
-
-        dev->type = ARPHRD_IPDDP;              /* IP over DDP tunnel */
-        dev->mtu = 585;
-        dev->flags |= IFF_NOARP;
-
-        /*
-         *      The worst case header we will need is currently a
-         *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
-         *      We send over SNAP so that takes another 8 bytes.
-         */
-        dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
-
-       err = register_netdev(dev);
-       if (err) {
-               free_netdev(dev);
-               return ERR_PTR(err);
-       }
-
-       /* Let the user now what mode we are in */
-       if(ipddp_mode == IPDDP_ENCAP)
-               printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
-                       dev->name);
-       if(ipddp_mode == IPDDP_DECAP)
-               printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>\n", 
-                       dev->name);
-
-        return dev;
-}
-
-
-/*
- * Transmit LLAP/ELAP frame using aarp_send_ddp.
- */
-static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       __be32 paddr = skb_rtable(skb)->rt_gateway;
-        struct ddpehdr *ddp;
-        struct ipddp_route *rt;
-        struct atalk_addr *our_addr;
-
-       spin_lock(&ipddp_route_lock);
-
-       /*
-         * Find appropriate route to use, based only on IP number.
-         */
-        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
-        {
-                if(rt->ip == paddr)
-                        break;
-        }
-        if(rt == NULL) {
-               spin_unlock(&ipddp_route_lock);
-                return NETDEV_TX_OK;
-       }
-
-        our_addr = atalk_find_dev_addr(rt->dev);
-
-       if(ipddp_mode == IPDDP_DECAP)
-               /* 
-                * Pull off the excess room that should not be there.
-                * This is due to a hard-header problem. This is the
-                * quick fix for now though, till it breaks.
-                */
-               skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
-
-       /* Create the Extended DDP header */
-       ddp = (struct ddpehdr *)skb->data;
-        ddp->deh_len_hops = htons(skb->len + (1<<10));
-        ddp->deh_sum = 0;
-
-       /*
-         * For Localtalk we need aarp_send_ddp to strip the
-         * long DDP header and place a shot DDP header on it.
-         */
-        if(rt->dev->type == ARPHRD_LOCALTLK)
-        {
-                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
-                ddp->deh_snet  = 0;
-        }
-        else
-        {
-                ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
-                ddp->deh_snet  = our_addr->s_net;
-        }
-        ddp->deh_dnode = rt->at.s_node;
-        ddp->deh_snode = our_addr->s_node;
-        ddp->deh_dport = 72;
-        ddp->deh_sport = 72;
-
-        *((__u8 *)(ddp+1)) = 22;               /* ddp type = IP */
-
-        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
-
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       aarp_send_ddp(rt->dev, skb, &rt->at, NULL);
-
-       spin_unlock(&ipddp_route_lock);
-
-        return NETDEV_TX_OK;
-}
-
-/*
- * Create a routing entry. We first verify that the
- * record does not already exist. If it does we return -EEXIST
- */
-static int ipddp_create(struct ipddp_route *new_rt)
-{
-        struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL);
-
-        if (rt == NULL)
-                return -ENOMEM;
-
-        rt->ip = new_rt->ip;
-        rt->at = new_rt->at;
-        rt->next = NULL;
-        if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
-               kfree(rt);
-                return -ENETUNREACH;
-        }
-
-       spin_lock_bh(&ipddp_route_lock);
-       if (__ipddp_find_route(rt)) {
-               spin_unlock_bh(&ipddp_route_lock);
-               kfree(rt);
-               return -EEXIST;
-       }
-
-        rt->next = ipddp_route_list;
-        ipddp_route_list = rt;
-
-       spin_unlock_bh(&ipddp_route_lock);
-
-        return 0;
-}
-
-/*
- * Delete a route, we only delete a FULL match.
- * If route does not exist we return -ENOENT.
- */
-static int ipddp_delete(struct ipddp_route *rt)
-{
-        struct ipddp_route **r = &ipddp_route_list;
-        struct ipddp_route *tmp;
-
-       spin_lock_bh(&ipddp_route_lock);
-        while((tmp = *r) != NULL)
-        {
-                if(tmp->ip == rt->ip &&
-                  tmp->at.s_net == rt->at.s_net &&
-                  tmp->at.s_node == rt->at.s_node)
-                {
-                        *r = tmp->next;
-                       spin_unlock_bh(&ipddp_route_lock);
-                        kfree(tmp);
-                        return 0;
-                }
-                r = &tmp->next;
-        }
-
-       spin_unlock_bh(&ipddp_route_lock);
-        return -ENOENT;
-}
-
-/*
- * Find a routing entry, we only return a FULL match
- */
-static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
-{
-        struct ipddp_route *f;
-
-        for(f = ipddp_route_list; f != NULL; f = f->next)
-        {
-                if(f->ip == rt->ip &&
-                  f->at.s_net == rt->at.s_net &&
-                  f->at.s_node == rt->at.s_node)
-                        return f;
-        }
-
-        return NULL;
-}
-
-static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-        struct ipddp_route __user *rt = ifr->ifr_data;
-        struct ipddp_route rcp, rcp2, *rp;
-
-        if(!capable(CAP_NET_ADMIN))
-                return -EPERM;
-
-       if(copy_from_user(&rcp, rt, sizeof(rcp)))
-               return -EFAULT;
-
-        switch(cmd)
-        {
-               case SIOCADDIPDDPRT:
-                        return ipddp_create(&rcp);
-
-                case SIOCFINDIPDDPRT:
-                       spin_lock_bh(&ipddp_route_lock);
-                       rp = __ipddp_find_route(&rcp);
-                       if (rp)
-                               memcpy(&rcp2, rp, sizeof(rcp2));
-                       spin_unlock_bh(&ipddp_route_lock);
-
-                       if (rp) {
-                               if (copy_to_user(rt, &rcp2,
-                                                sizeof(struct ipddp_route)))
-                                       return -EFAULT;
-                               return 0;
-                       } else
-                               return -ENOENT;
-
-                case SIOCDELIPDDPRT:
-                        return ipddp_delete(&rcp);
-
-                default:
-                        return -EINVAL;
-        }
-}
-
-static struct net_device *dev_ipddp;
-
-MODULE_LICENSE("GPL");
-module_param(ipddp_mode, int, 0);
-
-static int __init ipddp_init_module(void)
-{
-       dev_ipddp = ipddp_init();
-        if (IS_ERR(dev_ipddp))
-                return PTR_ERR(dev_ipddp);
-       return 0;
-}
-
-static void __exit ipddp_cleanup_module(void)
-{
-        struct ipddp_route *p;
-
-       unregister_netdev(dev_ipddp);
-        free_netdev(dev_ipddp);
-
-        while (ipddp_route_list) {
-                p = ipddp_route_list->next;
-                kfree(ipddp_route_list);
-                ipddp_route_list = p;
-        }
-}
-
-module_init(ipddp_init_module);
-module_exit(ipddp_cleanup_module);
diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h
deleted file mode 100644 (file)
index 531519d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *     ipddp.h: Header for IP-over-DDP driver for Linux.
- */
-
-#ifndef __LINUX_IPDDP_H
-#define __LINUX_IPDDP_H
-
-#ifdef __KERNEL__
-
-#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
-#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
-#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
-
-struct ipddp_route
-{
-        struct net_device *dev;             /* Carrier device */
-        __be32 ip;                       /* IP address */
-        struct atalk_addr at;              /* Gateway appletalk address */
-        int flags;
-        struct ipddp_route *next;
-};
-
-#define IPDDP_ENCAP    1
-#define IPDDP_DECAP    2
-
-#endif /* __KERNEL__ */
-#endif /* __LINUX_IPDDP_H */
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
deleted file mode 100644 (file)
index e69eead..0000000
+++ /dev/null
@@ -1,1288 +0,0 @@
-/***    ltpc.c -- a driver for the LocalTalk PC card.
- *
- *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU General Public License, incorporated herein by reference.
- *
- *      This is ALPHA code at best.  It may not work for you.  It may
- *      damage your equipment.  It may damage your relations with other
- *      users of your network.  Use it at your own risk!
- *
- *      Based in part on:
- *      skeleton.c      by Donald Becker
- *      dummy.c         by Nick Holloway and Alan Cox
- *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
- *      the netatalk source code (UMICH)
- *      lots of work on the card...
- *
- *      I do not have access to the (proprietary) SDK that goes with the card.
- *      If you do, I don't want to know about it, and you can probably write
- *      a better driver yourself anyway.  This does mean that the pieces that
- *      talk to the card are guesswork on my part, so use at your own risk!
- *
- *      This is my first try at writing Linux networking code, and is also
- *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
- *      welcome suggestions)
- *
- *      This is a loadable kernel module which seems to work at my site
- *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
- *      the kernel support from 1.3.3b2 including patches routing.patch
- *      and ddp.disappears.from.chooser.  In order to run it, you will need
- *      to patch ddp.c and aarp.c in the kernel, but only a little...
- *
- *      I'm fairly confident that while this is arguably badly written, the
- *      problems that people experience will be "higher level", that is, with
- *      complications in the netatalk code.  The driver itself doesn't do
- *      anything terribly complicated -- it pretends to be an ether device
- *      as far as netatalk is concerned, strips the DDP data out of the ether
- *      frame and builds a LLAP packet to send out the card.  In the other
- *      direction, it receives LLAP frames from the card and builds a fake
- *      ether packet that it then tosses up to the networking code.  You can
- *      argue (correctly) that this is an ugly way to do things, but it
- *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
- *
- *      The card will do a lot more than is used here -- I *think* it has the
- *      layers up through ATP.  Even if you knew how that part works (which I
- *      don't) it would be a big job to carve up the kernel ddp code to insert
- *      things at a higher level, and probably a bad idea...
- *
- *      There are a number of other cards that do LocalTalk on the PC.  If
- *      nobody finds any insurmountable (at the netatalk level) problems
- *      here, this driver should encourage people to put some work into the
- *      other cards (some of which I gather are still commercially available)
- *      and also to put hooks for LocalTalk into the official ddp code.
- *
- *      I welcome comments and suggestions.  This is my first try at Linux
- *      networking stuff, and there are probably lots of things that I did
- *      suboptimally.  
- *
- ***/
-
-/***
- *
- * $Log: ltpc.c,v $
- * Revision 1.1.2.1  2000/03/01 05:35:07  jgarzik
- * at and tr cleanup
- *
- * Revision 1.8  1997/01/28 05:44:54  bradford
- * Clean up for non-module a little.
- * Hacked about a bit to clean things up - Alan Cox 
- * Probably broken it from the origina 1.8
- *
-
- * 1998/11/09: David Huggins-Daines <dhd@debian.org>
- * Cleaned up the initialization code to use the standard autoirq methods,
-   and to probe for things in the standard order of i/o, irq, dma.  This
-   removes the "reset the reset" hack, because I couldn't figure out an
-   easy way to get the card to trigger an interrupt after it.
- * Added support for passing configuration parameters on the kernel command
-   line and through insmod
- * Changed the device name from "ltalk0" to "lt0", both to conform with the
-   other localtalk driver, and to clear up the inconsistency between the
-   module and the non-module versions of the driver :-)
- * Added a bunch of comments (I was going to make some enums for the state
-   codes and the register offsets, but I'm still not sure exactly what their
-   semantics are)
- * Don't poll anymore in interrupt-driven mode
- * It seems to work as a module now (as of 2.1.127), but I don't think
-   I'm responsible for that...
-
- *
- * Revision 1.7  1996/12/12 03:42:33  bradford
- * DMA alloc cribbed from 3c505.c.
- *
- * Revision 1.6  1996/12/12 03:18:58  bradford
- * Added virt_to_bus; works in 2.1.13.
- *
- * Revision 1.5  1996/12/12 03:13:22  root
- * xmitQel initialization -- think through better though.
- *
- * Revision 1.4  1996/06/18 14:55:55  root
- * Change names to ltpc. Tabs. Took a shot at dma alloc,
- * although more needs to be done eventually.
- *
- * Revision 1.3  1996/05/22 14:59:39  root
- * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
- *
- * Revision 1.2  1996/05/22 14:58:24  root
- * Change tabs mostly.
- *
- * Revision 1.1  1996/04/23 04:45:09  root
- * Initial revision
- *
- * Revision 0.16  1996/03/05 15:59:56  root
- * Change ARPHRD_LOCALTLK definition to the "real" one.
- *
- * Revision 0.15  1996/03/05 06:28:30  root
- * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
- * it's getting closer.
- *
- * Revision 0.14  1996/02/25 17:38:32  root
- * More cleanups.  Removed query to card on get_stats.
- *
- * Revision 0.13  1996/02/21  16:27:40  root
- * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
- * Clean up receive code a little.
- *
- * Revision 0.12  1996/02/19  16:34:53  root
- * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
- * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
- * including packet printing, 4 for lower level (card i/o) stuff.
- *
- * Revision 0.11  1996/02/12  15:53:38  root
- * Added router sends (requires new aarp.c patch)
- *
- * Revision 0.10  1996/02/11  00:19:35  root
- * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
- *
- * Revision 0.9  1996/02/10  23:59:35  root
- * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
- * has a *different* definition of struct sockaddr_at than the Linux kernel
- * does.  This is an "insidious and invidious" bug...
- * (Actually the preceding comment is false -- it's the atalk.h in the
- * ancient atalk-0.06 that's the problem)
- *
- * Revision 0.8  1996/02/10 19:09:00  root
- * Merge 1.3 changes.  Tested OK under 1.3.60.
- *
- * Revision 0.7  1996/02/10 17:56:56  root
- * Added debug=1 parameter on insmod for debugging prints.  Tried
- * to fix timer unload on rmmod, but I don't think that's the problem.
- *
- * Revision 0.6  1995/12/31  19:01:09  root
- * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
- * Clean up initial probing -- sometimes the card wakes up latched in reset.
- *
- * Revision 0.5  1995/12/22  06:03:44  root
- * Added comments in front and cleaned up a bit.
- * This version sent out to people.
- *
- * Revision 0.4  1995/12/18  03:46:44  root
- * Return shortDDP to longDDP fake to 0/0.  Added command structs.
- *
- ***/
-
-/* ltpc jumpers are:
-*
-*      Interrupts -- set at most one.  If none are set, the driver uses
-*      polled mode.  Because the card was developed in the XT era, the
-*      original documentation refers to IRQ2.  Since you'll be running
-*      this on an AT (or later) class machine, that really means IRQ9.
-*
-*      SW1     IRQ 4
-*      SW2     IRQ 3
-*      SW3     IRQ 9 (2 in original card documentation only applies to XT)
-*
-*
-*      DMA -- choose DMA 1 or 3, and set both corresponding switches.
-*
-*      SW4     DMA 3
-*      SW5     DMA 1
-*      SW6     DMA 3
-*      SW7     DMA 1
-*
-*
-*      I/O address -- choose one.  
-*
-*      SW8     220 / 240
-*/
-
-/*     To have some stuff logged, do 
-*      insmod ltpc.o debug=1
-*
-*      For a whole bunch of stuff, use higher numbers.
-*
-*      The default is 0, i.e. no messages except for the probe results.
-*/
-
-/* insmod-tweakable variables */
-static int debug;
-#define DEBUG_VERBOSE 1
-#define DEBUG_UPPER 2
-#define DEBUG_LOWER 4
-
-static int io;
-static int irq;
-static int dma;
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/atalk.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/system.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-
-/* our stuff */
-#include "ltpc.h"
-
-static DEFINE_SPINLOCK(txqueue_lock);
-static DEFINE_SPINLOCK(mbox_lock);
-
-/* function prototypes */
-static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
-       void *dbuf, int dbuflen);
-static int sendup_buffer (struct net_device *dev);
-
-/* Dma Memory related stuff, cribbed directly from 3c505.c */
-
-static unsigned long dma_mem_alloc(int size)
-{
-        int order = get_order(size);
-
-        return __get_dma_pages(GFP_KERNEL, order);
-}
-
-/* DMA data buffer, DMA command buffer */
-static unsigned char *ltdmabuf;
-static unsigned char *ltdmacbuf;
-
-/* private struct, holds our appletalk address */
-
-struct ltpc_private
-{
-       struct atalk_addr my_addr;
-};
-
-/* transmit queue element struct */
-
-struct xmitQel {
-       struct xmitQel *next;
-       /* command buffer */
-       unsigned char *cbuf;
-       short cbuflen;
-       /* data buffer */
-       unsigned char *dbuf;
-       short dbuflen;
-       unsigned char QWrite;   /* read or write data */
-       unsigned char mailbox;
-};
-
-/* the transmit queue itself */
-
-static struct xmitQel *xmQhd, *xmQtl;
-
-static void enQ(struct xmitQel *qel)
-{
-       unsigned long flags;
-       qel->next = NULL;
-       
-       spin_lock_irqsave(&txqueue_lock, flags);
-       if (xmQtl) {
-               xmQtl->next = qel;
-       } else {
-               xmQhd = qel;
-       }
-       xmQtl = qel;
-       spin_unlock_irqrestore(&txqueue_lock, flags);
-
-       if (debug & DEBUG_LOWER)
-               printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
-}
-
-static struct xmitQel *deQ(void)
-{
-       unsigned long flags;
-       int i;
-       struct xmitQel *qel=NULL;
-       
-       spin_lock_irqsave(&txqueue_lock, flags);
-       if (xmQhd) {
-               qel = xmQhd;
-               xmQhd = qel->next;
-               if(!xmQhd) xmQtl = NULL;
-       }
-       spin_unlock_irqrestore(&txqueue_lock, flags);
-
-       if ((debug & DEBUG_LOWER) && qel) {
-               int n;
-               printk(KERN_DEBUG "ltpc: dequeued command ");
-               n = qel->cbuflen;
-               if (n>100) n=100;
-               for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
-               printk("\n");
-       }
-
-       return qel;
-}
-
-/* and... the queue elements we'll be using */
-static struct xmitQel qels[16];
-
-/* and their corresponding mailboxes */
-static unsigned char mailbox[16];
-static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-static int wait_timeout(struct net_device *dev, int c)
-{
-       /* returns true if it stayed c */
-       /* this uses base+6, but it's ok */
-       int i;
-
-       /* twenty second or so total */
-
-       for(i=0;i<200000;i++) {
-               if ( c != inb_p(dev->base_addr+6) ) return 0;
-               udelay(100);
-       }
-       return 1; /* timed out */
-}
-
-/* get the first free mailbox */
-
-static int getmbox(void)
-{
-       unsigned long flags;
-       int i;
-
-       spin_lock_irqsave(&mbox_lock, flags);
-       for(i=1;i<16;i++) if(!mboxinuse[i]) {
-               mboxinuse[i]=1;
-               spin_unlock_irqrestore(&mbox_lock, flags);
-               return i;
-       }
-       spin_unlock_irqrestore(&mbox_lock, flags);
-       return 0;
-}
-
-/* read a command from the card */
-static void handlefc(struct net_device *dev)
-{
-       /* called *only* from idle, non-reentrant */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-
-       flags=claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma,DMA_MODE_READ);
-       set_dma_addr(dma,virt_to_bus(ltdmacbuf));
-       set_dma_count(dma,50);
-       enable_dma(dma);
-       release_dma_lock(flags);
-
-       inb_p(base+3);
-       inb_p(base+2);
-
-       if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
-}
-
-/* read data from the card */
-static void handlefd(struct net_device *dev)
-{
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-       flags=claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma,DMA_MODE_READ);
-       set_dma_addr(dma,virt_to_bus(ltdmabuf));
-       set_dma_count(dma,800);
-       enable_dma(dma);
-       release_dma_lock(flags);
-
-       inb_p(base+3);
-       inb_p(base+2);
-
-       if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
-       sendup_buffer(dev);
-} 
-
-static void handlewrite(struct net_device *dev)
-{
-       /* called *only* from idle, non-reentrant */
-       /* on entry, 0xfb and ltdmabuf holds data */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-       
-       flags=claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma,DMA_MODE_WRITE);
-       set_dma_addr(dma,virt_to_bus(ltdmabuf));
-       set_dma_count(dma,800);
-       enable_dma(dma);
-       release_dma_lock(flags);
-       
-       inb_p(base+3);
-       inb_p(base+2);
-
-       if ( wait_timeout(dev,0xfb) ) {
-               flags=claim_dma_lock();
-               printk("timed out in handlewrite, dma res %d\n",
-                       get_dma_residue(dev->dma) );
-               release_dma_lock(flags);
-       }
-}
-
-static void handleread(struct net_device *dev)
-{
-       /* on entry, 0xfb */
-       /* on exit, ltdmabuf holds data */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-       
-       flags=claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma,DMA_MODE_READ);
-       set_dma_addr(dma,virt_to_bus(ltdmabuf));
-       set_dma_count(dma,800);
-       enable_dma(dma);
-       release_dma_lock(flags);
-
-       inb_p(base+3);
-       inb_p(base+2);
-       if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
-}
-
-static void handlecommand(struct net_device *dev)
-{
-       /* on entry, 0xfa and ltdmacbuf holds command */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-       flags=claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma,DMA_MODE_WRITE);
-       set_dma_addr(dma,virt_to_bus(ltdmacbuf));
-       set_dma_count(dma,50);
-       enable_dma(dma);
-       release_dma_lock(flags);
-       inb_p(base+3);
-       inb_p(base+2);
-       if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
-} 
-
-/* ready made command for getting the result from the card */
-static unsigned char rescbuf[2] = {LT_GETRESULT,0};
-static unsigned char resdbuf[2];
-
-static int QInIdle;
-
-/* idle expects to be called with the IRQ line high -- either because of
- * an interrupt, or because the line is tri-stated
- */
-
-static void idle(struct net_device *dev)
-{
-       unsigned long flags;
-       int state;
-       /* FIXME This is initialized to shut the warning up, but I need to
-        * think this through again.
-        */
-       struct xmitQel *q = NULL;
-       int oops;
-       int i;
-       int base = dev->base_addr;
-
-       spin_lock_irqsave(&txqueue_lock, flags);
-       if(QInIdle) {
-               spin_unlock_irqrestore(&txqueue_lock, flags);
-               return;
-       }
-       QInIdle = 1;
-       spin_unlock_irqrestore(&txqueue_lock, flags);
-
-       /* this tri-states the IRQ line */
-       (void) inb_p(base+6);
-
-       oops = 100;
-
-loop:
-       if (0>oops--) { 
-               printk("idle: looped too many times\n");
-               goto done;
-       }
-
-       state = inb_p(base+6);
-       if (state != inb_p(base+6)) goto loop;
-
-       switch(state) {
-               case 0xfc:
-                       /* incoming command */
-                       if (debug & DEBUG_LOWER) printk("idle: fc\n");
-                       handlefc(dev); 
-                       break;
-               case 0xfd:
-                       /* incoming data */
-                       if(debug & DEBUG_LOWER) printk("idle: fd\n");
-                       handlefd(dev); 
-                       break;
-               case 0xf9:
-                       /* result ready */
-                       if (debug & DEBUG_LOWER) printk("idle: f9\n");
-                       if(!mboxinuse[0]) {
-                               mboxinuse[0] = 1;
-                               qels[0].cbuf = rescbuf;
-                               qels[0].cbuflen = 2;
-                               qels[0].dbuf = resdbuf;
-                               qels[0].dbuflen = 2;
-                               qels[0].QWrite = 0;
-                               qels[0].mailbox = 0;
-                               enQ(&qels[0]);
-                       }
-                       inb_p(dev->base_addr+1);
-                       inb_p(dev->base_addr+0);
-                       if( wait_timeout(dev,0xf9) )
-                               printk("timed out idle f9\n");
-                       break;
-               case 0xf8:
-                       /* ?? */
-                       if (xmQhd) {
-                               inb_p(dev->base_addr+1);
-                               inb_p(dev->base_addr+0);
-                               if(wait_timeout(dev,0xf8) )
-                                       printk("timed out idle f8\n");
-                       } else {
-                               goto done;
-                       }
-                       break;
-               case 0xfa:
-                       /* waiting for command */
-                       if(debug & DEBUG_LOWER) printk("idle: fa\n");
-                       if (xmQhd) {
-                               q=deQ();
-                               memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
-                               ltdmacbuf[1] = q->mailbox;
-                               if (debug>1) { 
-                                       int n;
-                                       printk("ltpc: sent command     ");
-                                       n = q->cbuflen;
-                                       if (n>100) n=100;
-                                       for(i=0;i<n;i++)
-                                               printk("%02x ",ltdmacbuf[i]);
-                                       printk("\n");
-                               }
-                               handlecommand(dev);
-                                       if(0xfa==inb_p(base+6)) {
-                                               /* we timed out, so return */
-                                               goto done;
-                                       } 
-                       } else {
-                               /* we don't seem to have a command */
-                               if (!mboxinuse[0]) {
-                                       mboxinuse[0] = 1;
-                                       qels[0].cbuf = rescbuf;
-                                       qels[0].cbuflen = 2;
-                                       qels[0].dbuf = resdbuf;
-                                       qels[0].dbuflen = 2;
-                                       qels[0].QWrite = 0;
-                                       qels[0].mailbox = 0;
-                                       enQ(&qels[0]);
-                               } else {
-                                       printk("trouble: response command already queued\n");
-                                       goto done;
-                               }
-                       } 
-                       break;
-               case 0Xfb:
-                       /* data transfer ready */
-                       if(debug & DEBUG_LOWER) printk("idle: fb\n");
-                       if(q->QWrite) {
-                               memcpy(ltdmabuf,q->dbuf,q->dbuflen);
-                               handlewrite(dev);
-                       } else {
-                               handleread(dev);
-                               /* non-zero mailbox numbers are for
-                                  commmands, 0 is for GETRESULT
-                                  requests */
-                               if(q->mailbox) {
-                                       memcpy(q->dbuf,ltdmabuf,q->dbuflen);
-                               } else { 
-                                       /* this was a result */
-                                       mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
-                                       mboxinuse[0]=0;
-                               }
-                       }
-                       break;
-       }
-       goto loop;
-
-done:
-       QInIdle=0;
-
-       /* now set the interrupts back as appropriate */
-       /* the first read takes it out of tri-state (but still high) */
-       /* the second resets it */
-       /* note that after this point, any read of base+6 will
-          trigger an interrupt */
-
-       if (dev->irq) {
-               inb_p(base+7);
-               inb_p(base+7);
-       }
-}
-
-
-static int do_write(struct net_device *dev, void *cbuf, int cbuflen,
-       void *dbuf, int dbuflen)
-{
-
-       int i = getmbox();
-       int ret;
-
-       if(i) {
-               qels[i].cbuf = (unsigned char *) cbuf;
-               qels[i].cbuflen = cbuflen;
-               qels[i].dbuf = (unsigned char *) dbuf;
-               qels[i].dbuflen = dbuflen;
-               qels[i].QWrite = 1;
-               qels[i].mailbox = i;  /* this should be initted rather */
-               enQ(&qels[i]);
-               idle(dev);
-               ret = mailbox[i];
-               mboxinuse[i]=0;
-               return ret;
-       }
-       printk("ltpc: could not allocate mbox\n");
-       return -1;
-}
-
-static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
-       void *dbuf, int dbuflen)
-{
-
-       int i = getmbox();
-       int ret;
-
-       if(i) {
-               qels[i].cbuf = (unsigned char *) cbuf;
-               qels[i].cbuflen = cbuflen;
-               qels[i].dbuf = (unsigned char *) dbuf;
-               qels[i].dbuflen = dbuflen;
-               qels[i].QWrite = 0;
-               qels[i].mailbox = i;  /* this should be initted rather */
-               enQ(&qels[i]);
-               idle(dev);
-               ret = mailbox[i];
-               mboxinuse[i]=0;
-               return ret;
-       }
-       printk("ltpc: could not allocate mbox\n");
-       return -1;
-}
-
-/* end of idle handlers -- what should be seen is do_read, do_write */
-
-static struct timer_list ltpc_timer;
-
-static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev);
-
-static int read_30 ( struct net_device *dev)
-{
-       lt_command c;
-       c.getflags.command = LT_GETFLAGS;
-       return do_read(dev, &c, sizeof(c.getflags),&c,0);
-}
-
-static int set_30 (struct net_device *dev,int x)
-{
-       lt_command c;
-       c.setflags.command = LT_SETFLAGS;
-       c.setflags.flags = x;
-       return do_write(dev, &c, sizeof(c.setflags),&c,0);
-}
-
-/* LLAP to DDP translation */
-
-static int sendup_buffer (struct net_device *dev)
-{
-       /* on entry, command is in ltdmacbuf, data in ltdmabuf */
-       /* called from idle, non-reentrant */
-
-       int dnode, snode, llaptype, len; 
-       int sklen;
-       struct sk_buff *skb;
-       struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
-
-       if (ltc->command != LT_RCVLAP) {
-               printk("unknown command 0x%02x from ltpc card\n",ltc->command);
-               return -1;
-       }
-       dnode = ltc->dnode;
-       snode = ltc->snode;
-       llaptype = ltc->laptype;
-       len = ltc->length; 
-
-       sklen = len;
-       if (llaptype == 1) 
-               sklen += 8;  /* correct for short ddp */
-       if(sklen > 800) {
-               printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
-                       dev->name,sklen);
-               return -1;
-       }
-
-       if ( (llaptype==0) || (llaptype>2) ) {
-               printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
-               return -1;
-       }
-
-
-       skb = dev_alloc_skb(3+sklen);
-       if (skb == NULL) 
-       {
-               printk("%s: dropping packet due to memory squeeze.\n",
-                       dev->name);
-               return -1;
-       }
-       skb->dev = dev;
-
-       if (sklen > len)
-               skb_reserve(skb,8);
-       skb_put(skb,len+3);
-       skb->protocol = htons(ETH_P_LOCALTALK);
-       /* add LLAP header */
-       skb->data[0] = dnode;
-       skb->data[1] = snode;
-       skb->data[2] = llaptype;
-       skb_reset_mac_header(skb);      /* save pointer to llap header */
-       skb_pull(skb,3);
-
-       /* copy ddp(s,e)hdr + contents */
-       skb_copy_to_linear_data(skb, ltdmabuf, len);
-
-       skb_reset_transport_header(skb);
-
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
-
-       /* toss it onwards */
-       netif_rx(skb);
-       return 0;
-}
-
-/* the handler for the board interrupt */
-static irqreturn_t
-ltpc_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-
-       if (dev==NULL) {
-               printk("ltpc_interrupt: unknown device.\n");
-               return IRQ_NONE;
-       }
-
-       inb_p(dev->base_addr+6);  /* disable further interrupts from board */
-
-       idle(dev); /* handle whatever is coming in */
-       /* idle re-enables interrupts from board */ 
-
-       return IRQ_HANDLED;
-}
-
-/***
- *
- *    The ioctls that the driver responds to are:
- *
- *    SIOCSIFADDR -- do probe using the passed node hint.
- *    SIOCGIFADDR -- return net, node.
- *
- *    some of this stuff should be done elsewhere.
- *
- ***/
-
-static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-       struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
-       /* we'll keep the localtalk node address in dev->pa_addr */
-       struct ltpc_private *ltpc_priv = netdev_priv(dev);
-       struct atalk_addr *aa = &ltpc_priv->my_addr;
-       struct lt_init c;
-       int ltflags;
-
-       if(debug & DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
-
-       switch(cmd) {
-               case SIOCSIFADDR:
-
-                       aa->s_net  = sa->sat_addr.s_net;
-      
-                       /* this does the probe and returns the node addr */
-                       c.command = LT_INIT;
-                       c.hint = sa->sat_addr.s_node;
-
-                       aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
-
-                       /* get all llap frames raw */
-                       ltflags = read_30(dev);
-                       ltflags |= LT_FLAG_ALLLAP;
-                       set_30 (dev,ltflags);  
-
-                       dev->broadcast[0] = 0xFF;
-                       dev->dev_addr[0] = aa->s_node;
-
-                       dev->addr_len=1;
-   
-                       return 0;
-
-               case SIOCGIFADDR:
-
-                       sa->sat_addr.s_net = aa->s_net;
-                       sa->sat_addr.s_node = aa->s_node;
-
-                       return 0;
-
-               default: 
-                       return -EINVAL;
-       }
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-       /* This needs to be present to keep netatalk happy. */
-       /* Actually netatalk needs fixing! */
-}
-
-static int ltpc_poll_counter;
-
-static void ltpc_poll(unsigned long l)
-{
-       struct net_device *dev = (struct net_device *) l;
-
-       del_timer(&ltpc_timer);
-
-       if(debug & DEBUG_VERBOSE) {
-               if (!ltpc_poll_counter) {
-                       ltpc_poll_counter = 50;
-                       printk("ltpc poll is alive\n");
-               }
-               ltpc_poll_counter--;
-       }
-  
-       if (!dev)
-               return;  /* we've been downed */
-
-       /* poll 20 times per second */
-       idle(dev);
-       ltpc_timer.expires = jiffies + HZ/20;
-       
-       add_timer(&ltpc_timer);
-}
-
-/* DDP to LLAP translation */
-
-static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       /* in kernel 1.3.xx, on entry skb->data points to ddp header,
-        * and skb->len is the length of the ddp data + ddp header
-        */
-       int i;
-       struct lt_sendlap cbuf;
-       unsigned char *hdr;
-
-       cbuf.command = LT_SENDLAP;
-       cbuf.dnode = skb->data[0];
-       cbuf.laptype = skb->data[2];
-       skb_pull(skb,3);        /* skip past LLAP header */
-       cbuf.length = skb->len; /* this is host order */
-       skb_reset_transport_header(skb);
-
-       if(debug & DEBUG_UPPER) {
-               printk("command ");
-               for(i=0;i<6;i++)
-                       printk("%02x ",((unsigned char *)&cbuf)[i]);
-               printk("\n");
-       }
-
-       hdr = skb_transport_header(skb);
-       do_write(dev, &cbuf, sizeof(cbuf), hdr, skb->len);
-
-       if(debug & DEBUG_UPPER) {
-               printk("sent %d ddp bytes\n",skb->len);
-               for (i = 0; i < skb->len; i++)
-                       printk("%02x ", hdr[i]);
-               printk("\n");
-       }
-
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-/* initialization stuff */
-  
-static int __init ltpc_probe_dma(int base, int dma)
-{
-       int want = (dma == 3) ? 2 : (dma == 1) ? 1 : 3;
-       unsigned long timeout;
-       unsigned long f;
-  
-       if (want & 1) {
-               if (request_dma(1,"ltpc")) {
-                       want &= ~1;
-               } else {
-                       f=claim_dma_lock();
-                       disable_dma(1);
-                       clear_dma_ff(1);
-                       set_dma_mode(1,DMA_MODE_WRITE);
-                       set_dma_addr(1,virt_to_bus(ltdmabuf));
-                       set_dma_count(1,sizeof(struct lt_mem));
-                       enable_dma(1);
-                       release_dma_lock(f);
-               }
-       }
-       if (want & 2) {
-               if (request_dma(3,"ltpc")) {
-                       want &= ~2;
-               } else {
-                       f=claim_dma_lock();
-                       disable_dma(3);
-                       clear_dma_ff(3);
-                       set_dma_mode(3,DMA_MODE_WRITE);
-                       set_dma_addr(3,virt_to_bus(ltdmabuf));
-                       set_dma_count(3,sizeof(struct lt_mem));
-                       enable_dma(3);
-                       release_dma_lock(f);
-               }
-       }
-       /* set up request */
-
-       /* FIXME -- do timings better! */
-
-       ltdmabuf[0] = LT_READMEM;
-       ltdmabuf[1] = 1;  /* mailbox */
-       ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
-       ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
-       ltdmabuf[6] = 0; /* dunno if this is necessary */
-
-       inb_p(io+1);
-       inb_p(io+0);
-       timeout = jiffies+100*HZ/100;
-       while(time_before(jiffies, timeout)) {
-               if ( 0xfa == inb_p(io+6) ) break;
-       }
-
-       inb_p(io+3);
-       inb_p(io+2);
-       while(time_before(jiffies, timeout)) {
-               if ( 0xfb == inb_p(io+6) ) break;
-       }
-
-       /* release the other dma channel (if we opened both of them) */
-
-       if ((want & 2) && (get_dma_residue(3)==sizeof(struct lt_mem))) {
-               want &= ~2;
-               free_dma(3);
-       }
-
-       if ((want & 1) && (get_dma_residue(1)==sizeof(struct lt_mem))) {
-               want &= ~1;
-               free_dma(1);
-       }
-
-       if (!want)
-               return 0;
-
-       return (want & 2) ? 3 : 1;
-}
-
-static const struct net_device_ops ltpc_netdev = {
-       .ndo_start_xmit         = ltpc_xmit,
-       .ndo_do_ioctl           = ltpc_ioctl,
-       .ndo_set_multicast_list = set_multicast_list,
-};
-
-struct net_device * __init ltpc_probe(void)
-{
-       struct net_device *dev;
-       int err = -ENOMEM;
-       int x=0,y=0;
-       int autoirq;
-       unsigned long f;
-       unsigned long timeout;
-
-       dev = alloc_ltalkdev(sizeof(struct ltpc_private));
-       if (!dev)
-               goto out;
-
-       /* probe for the I/O port address */
-       
-       if (io != 0x240 && request_region(0x220,8,"ltpc")) {
-               x = inb_p(0x220+6);
-               if ( (x!=0xff) && (x>=0xf0) ) {
-                       io = 0x220;
-                       goto got_port;
-               }
-               release_region(0x220,8);
-       }
-       if (io != 0x220 && request_region(0x240,8,"ltpc")) {
-               y = inb_p(0x240+6);
-               if ( (y!=0xff) && (y>=0xf0) ){ 
-                       io = 0x240;
-                       goto got_port;
-               }
-               release_region(0x240,8);
-       } 
-
-       /* give up in despair */
-       printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y);
-       err = -ENODEV;
-       goto out1;
-
- got_port:
-       /* probe for the IRQ line */
-       if (irq < 2) {
-               unsigned long irq_mask;
-
-               irq_mask = probe_irq_on();
-               /* reset the interrupt line */
-               inb_p(io+7);
-               inb_p(io+7);
-               /* trigger an interrupt (I hope) */
-               inb_p(io+6);
-               mdelay(2);
-               autoirq = probe_irq_off(irq_mask);
-
-               if (autoirq == 0) {
-                       printk(KERN_ERR "ltpc: probe at %#x failed to detect IRQ line.\n", io);
-               } else {
-                       irq = autoirq;
-               }
-       }
-
-       /* allocate a DMA buffer */
-       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-       if (!ltdmabuf) {
-               printk(KERN_ERR "ltpc: mem alloc failed\n");
-               err = -ENOMEM;
-               goto out2;
-       }
-
-       ltdmacbuf = &ltdmabuf[800];
-
-       if(debug & DEBUG_VERBOSE) {
-               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
-       }
-
-       /* reset the card */
-
-       inb_p(io+1);
-       inb_p(io+3);
-
-       msleep(20);
-
-       inb_p(io+0);
-       inb_p(io+2);
-       inb_p(io+7); /* clear reset */
-       inb_p(io+4); 
-       inb_p(io+5);
-       inb_p(io+5); /* enable dma */
-       inb_p(io+6); /* tri-state interrupt line */
-
-       ssleep(1);
-       
-       /* now, figure out which dma channel we're using, unless it's
-          already been specified */
-       /* well, 0 is a legal DMA channel, but the LTPC card doesn't
-          use it... */
-       dma = ltpc_probe_dma(io, dma);
-       if (!dma) {  /* no dma channel */
-               printk(KERN_ERR "No DMA channel found on ltpc card.\n");
-               err = -ENODEV;
-               goto out3;
-       }
-
-       /* print out friendly message */
-       if(irq)
-               printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
-       else
-               printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
-
-       dev->netdev_ops = &ltpc_netdev;
-       dev->base_addr = io;
-       dev->irq = irq;
-       dev->dma = dma;
-
-       /* the card will want to send a result at this point */
-       /* (I think... leaving out this part makes the kernel crash,
-           so I put it back in...) */
-
-       f=claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma,DMA_MODE_READ);
-       set_dma_addr(dma,virt_to_bus(ltdmabuf));
-       set_dma_count(dma,0x100);
-       enable_dma(dma);
-       release_dma_lock(f);
-
-       (void) inb_p(io+3);
-       (void) inb_p(io+2);
-       timeout = jiffies+100*HZ/100;
-
-       while(time_before(jiffies, timeout)) {
-               if( 0xf9 == inb_p(io+6))
-                       break;
-               schedule();
-       }
-
-       if(debug & DEBUG_VERBOSE) {
-               printk("setting up timer and irq\n");
-       }
-
-       /* grab it and don't let go :-) */
-       if (irq && request_irq( irq, ltpc_interrupt, 0, "ltpc", dev) >= 0)
-       {
-               (void) inb_p(io+7);  /* enable interrupts from board */
-               (void) inb_p(io+7);  /* and reset irq line */
-       } else {
-               if( irq )
-                       printk(KERN_ERR "ltpc: IRQ already in use, using polled mode.\n");
-               dev->irq = 0;
-               /* polled mode -- 20 times per second */
-               /* this is really, really slow... should it poll more often? */
-               init_timer(&ltpc_timer);
-               ltpc_timer.function=ltpc_poll;
-               ltpc_timer.data = (unsigned long) dev;
-
-               ltpc_timer.expires = jiffies + HZ/20;
-               add_timer(&ltpc_timer);
-       }
-       err = register_netdev(dev);
-       if (err)
-               goto out4;
-
-       return NULL;
-out4:
-       del_timer_sync(&ltpc_timer);
-       if (dev->irq)
-               free_irq(dev->irq, dev);
-out3:
-       free_pages((unsigned long)ltdmabuf, get_order(1000));
-out2:
-       release_region(io, 8);
-out1:
-       free_netdev(dev);
-out:
-       return ERR_PTR(err);
-}
-
-#ifndef MODULE
-/* handles "ltpc=io,irq,dma" kernel command lines */
-static int __init ltpc_setup(char *str)
-{
-       int ints[5];
-
-       str = get_options(str, ARRAY_SIZE(ints), ints);
-
-       if (ints[0] == 0) {
-               if (str && !strncmp(str, "auto", 4)) {
-                       /* do nothing :-) */
-               }
-               else {
-                       /* usage message */
-                       printk (KERN_ERR
-                               "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
-                       return 0;
-               }
-       } else {
-               io = ints[1];
-               if (ints[0] > 1) {
-                       irq = ints[2];
-               }
-               if (ints[0] > 2) {
-                       dma = ints[3];
-               }
-               /* ignore any other parameters */
-       }
-       return 1;
-}
-
-__setup("ltpc=", ltpc_setup);
-#endif /* MODULE */
-
-static struct net_device *dev_ltpc;
-
-#ifdef MODULE
-
-MODULE_LICENSE("GPL");
-module_param(debug, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-
-
-static int __init ltpc_module_init(void)
-{
-        if(io == 0)
-               printk(KERN_NOTICE
-                      "ltpc: Autoprobing is not recommended for modules\n");
-
-       dev_ltpc = ltpc_probe();
-       if (IS_ERR(dev_ltpc))
-               return PTR_ERR(dev_ltpc);
-       return 0;
-}
-module_init(ltpc_module_init);
-#endif
-
-static void __exit ltpc_cleanup(void)
-{
-
-       if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n");
-       unregister_netdev(dev_ltpc);
-
-       ltpc_timer.data = 0;  /* signal the poll routine that we're done */
-
-       del_timer_sync(&ltpc_timer);
-
-       if(debug & DEBUG_VERBOSE) printk("freeing irq\n");
-
-       if (dev_ltpc->irq)
-               free_irq(dev_ltpc->irq, dev_ltpc);
-
-       if(debug & DEBUG_VERBOSE) printk("freeing dma\n");
-
-       if (dev_ltpc->dma)
-               free_dma(dev_ltpc->dma);
-
-       if(debug & DEBUG_VERBOSE) printk("freeing ioaddr\n");
-
-       if (dev_ltpc->base_addr)
-               release_region(dev_ltpc->base_addr,8);
-
-       free_netdev(dev_ltpc);
-
-       if(debug & DEBUG_VERBOSE) printk("free_pages\n");
-
-       free_pages( (unsigned long) ltdmabuf, get_order(1000));
-
-       if(debug & DEBUG_VERBOSE) printk("returning from cleanup_module\n");
-}
-
-module_exit(ltpc_cleanup);
diff --git a/drivers/net/appletalk/ltpc.h b/drivers/net/appletalk/ltpc.h
deleted file mode 100644 (file)
index cd30544..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/***   ltpc.h
- *
- *
- ***/
-
-#define LT_GETRESULT  0x00
-#define LT_WRITEMEM   0x01
-#define LT_READMEM    0x02
-#define LT_GETFLAGS   0x04
-#define LT_SETFLAGS   0x05
-#define LT_INIT       0x10
-#define LT_SENDLAP    0x13
-#define LT_RCVLAP     0x14
-
-/* the flag that we care about */
-#define LT_FLAG_ALLLAP 0x04
-
-struct lt_getresult {
-       unsigned char command;
-       unsigned char mailbox;
-};
-
-struct lt_mem {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned short addr;    /* host order */
-       unsigned short length;  /* host order */
-};
-
-struct lt_setflags {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned char flags;
-};
-
-struct lt_getflags {
-       unsigned char command;
-       unsigned char mailbox;
-};
-
-struct lt_init {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned char hint;
-};
-
-struct lt_sendlap {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned char dnode;
-       unsigned char laptype;
-       unsigned short length;  /* host order */
-};
-
-struct lt_rcvlap {
-       unsigned char command;
-       unsigned char dnode;
-       unsigned char snode;
-       unsigned char laptype;
-       unsigned short length;  /* host order */
-};
-
-union lt_command {
-       struct lt_getresult getresult;
-       struct lt_mem mem;
-       struct lt_setflags setflags;
-       struct lt_getflags getflags;
-       struct lt_init init;
-       struct lt_sendlap sendlap;
-       struct lt_rcvlap rcvlap;
-};
-typedef union lt_command lt_command;
-
index b80755da5394bd07b315ef090bdb6f2f7769d00f..584d4e264807eb54c8e2544613374b23ab5d8ae5 100644 (file)
@@ -169,6 +169,8 @@ source "drivers/staging/bcm/Kconfig"
 
 source "drivers/staging/ft1000/Kconfig"
 
+source "drivers/staging/appletalk/Kconfig"
+
 source "drivers/staging/intel_sst/Kconfig"
 
 source "drivers/staging/speakup/Kconfig"
index fd26509e5efa052a5d5ddebcb0b112a19dc419bc..88f0c64e7e586e595dcd10ca61652c0b2081fce0 100644 (file)
@@ -65,6 +65,7 @@ obj-$(CONFIG_ATH6K_LEGACY)    += ath6kl/
 obj-$(CONFIG_USB_ENESTORAGE)   += keucr/
 obj-$(CONFIG_BCM_WIMAX)        += bcm/
 obj-$(CONFIG_FT1000)           += ft1000/
+obj-$(CONFIG_DEV_APPLETALK) += appletalk/
 obj-$(CONFIG_SND_INTEL_SST)            += intel_sst/
 obj-$(CONFIG_SPEAKUP)  += speakup/
 obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += cptm1217/
diff --git a/drivers/staging/appletalk/Kconfig b/drivers/staging/appletalk/Kconfig
new file mode 100644 (file)
index 0000000..0b376a9
--- /dev/null
@@ -0,0 +1,126 @@
+#
+# Appletalk driver configuration
+#
+config ATALK
+       tristate "Appletalk protocol support"
+       depends on BKL # waiting to be removed from net/appletalk/ddp.c
+       select LLC
+       ---help---
+         AppleTalk is the protocol that Apple computers can use to communicate
+         on a network.  If your Linux box is connected to such a network and you
+         wish to connect to it, say Y.  You will need to use the netatalk package
+         so that your Linux box can act as a print and file server for Macs as
+         well as access AppleTalk printers.  Check out
+         <http://www.zettabyte.net/netatalk/> on the WWW for details.
+         EtherTalk is the name used for AppleTalk over Ethernet and the
+         cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
+         network using serial links.  EtherTalk and LocalTalk are fully
+         supported by Linux.
+
+         General information about how to connect Linux, Windows machines and
+         Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.  The
+         NET3-4-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>, contains valuable
+         information as well.
+
+         To compile this driver as a module, choose M here: the module will be
+         called appletalk. You almost certainly want to compile it as a
+         module so you can restart your AppleTalk stack without rebooting
+         your machine. I hear that the GNU boycott of Apple is over, so
+         even politically correct people are allowed to say Y here.
+
+config DEV_APPLETALK
+       tristate "Appletalk interfaces support"
+       depends on ATALK
+       help
+         AppleTalk is the protocol that Apple computers can use to communicate
+         on a network.  If your Linux box is connected to such a network, and wish
+         to do IP over it, or you have a LocalTalk card and wish to use it to
+         connect to the AppleTalk network, say Y.
+         
+
+config LTPC
+       tristate "Apple/Farallon LocalTalk PC support"
+       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
+       help
+         This allows you to use the AppleTalk PC card to connect to LocalTalk
+         networks. The card is also known as the Farallon PhoneNet PC card.
+         If you are in doubt, this card is the one with the 65C02 chip on it.
+         You also need version 1.3.3 or later of the netatalk package.
+         This driver is experimental, which means that it may not work.
+         See the file <file:Documentation/networking/ltpc.txt>.
+
+config COPS
+       tristate "COPS LocalTalk PC support"
+       depends on DEV_APPLETALK && (ISA || EISA)
+       help
+         This allows you to use COPS AppleTalk cards to connect to LocalTalk
+         networks. You also need version 1.3.3 or later of the netatalk
+         package. This driver is experimental, which means that it may not
+         work. This driver will only work if you choose "AppleTalk DDP"
+         networking support, above.
+         Please read the file <file:Documentation/networking/cops.txt>.
+
+config COPS_DAYNA
+       bool "Dayna firmware support"
+       depends on COPS
+       help
+         Support COPS compatible cards with Dayna style firmware (Dayna
+         DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC
+         III, Farallon PhoneNET PC II).
+
+config COPS_TANGENT
+       bool "Tangent firmware support"
+       depends on COPS
+       help
+         Support COPS compatible cards with Tangent style firmware (Tangent
+         ATB_II, Novell NL-1000, Daystar Digital LT-200.
+
+config IPDDP
+       tristate "Appletalk-IP driver support"
+       depends on DEV_APPLETALK && ATALK
+       ---help---
+         This allows IP networking for users who only have AppleTalk
+         networking available. This feature is experimental. With this
+         driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux
+         box is stuck on an AppleTalk only network) or decapsulate (e.g. if
+         you want your Linux box to act as an Internet gateway for a zoo of
+         AppleTalk connected Macs). Please see the file
+         <file:Documentation/networking/ipddp.txt> for more information.
+
+         If you say Y here, the AppleTalk-IP support will be compiled into
+         the kernel. In this case, you can either use encapsulation or
+         decapsulation, but not both. With the following two questions, you
+         decide which one you want.
+
+         To compile the AppleTalk-IP support as a module, choose M here: the
+         module will be called ipddp.
+         In this case, you will be able to use both encapsulation and
+         decapsulation simultaneously, by loading two copies of the module
+         and specifying different values for the module option ipddp_mode.
+
+config IPDDP_ENCAP
+       bool "IP to Appletalk-IP Encapsulation support"
+       depends on IPDDP
+       help
+         If you say Y here, the AppleTalk-IP code will be able to encapsulate
+         IP packets inside AppleTalk frames; this is useful if your Linux box
+         is stuck on an AppleTalk network (which hopefully contains a
+         decapsulator somewhere). Please see
+         <file:Documentation/networking/ipddp.txt> for more information. If
+         you said Y to "AppleTalk-IP driver support" above and you say Y
+         here, then you cannot say Y to "AppleTalk-IP to IP Decapsulation
+         support", below.
+
+config IPDDP_DECAP
+       bool "Appletalk-IP to IP Decapsulation support"
+       depends on IPDDP
+       help
+         If you say Y here, the AppleTalk-IP code will be able to decapsulate
+         AppleTalk-IP frames to IP packets; this is useful if you want your
+         Linux box to act as an Internet gateway for an AppleTalk network.
+         Please see <file:Documentation/networking/ipddp.txt> for more
+         information.  If you said Y to "AppleTalk-IP driver support" above
+         and you say Y here, then you cannot say Y to "IP to AppleTalk-IP
+         Encapsulation support", above.
+
diff --git a/drivers/staging/appletalk/Makefile b/drivers/staging/appletalk/Makefile
new file mode 100644 (file)
index 0000000..2a5129a
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for drivers/staging/appletalk
+#
+obj-$(CONFIG_ATALK) += appletalk.o
+
+appletalk-y                    := aarp.o ddp.o dev.o
+appletalk-$(CONFIG_PROC_FS)    += atalk_proc.o
+appletalk-$(CONFIG_SYSCTL)     += sysctl_net_atalk.o
+
+obj-$(CONFIG_IPDDP) += ipddp.o
+obj-$(CONFIG_COPS) += cops.o
+obj-$(CONFIG_LTPC) += ltpc.o
diff --git a/drivers/staging/appletalk/aarp.c b/drivers/staging/appletalk/aarp.c
new file mode 100644 (file)
index 0000000..7163a1d
--- /dev/null
@@ -0,0 +1,1063 @@
+/*
+ *     AARP:           An implementation of the AppleTalk AARP protocol for
+ *                     Ethernet 'ELAP'.
+ *
+ *             Alan Cox  <Alan.Cox@linux.org>
+ *
+ *     This doesn't fit cleanly with the IP arp. Potentially we can use
+ *     the generic neighbour discovery code to clean this up.
+ *
+ *     FIXME:
+ *             We ought to handle the retransmits with a single list and a
+ *     separate fast timer for when it is needed.
+ *             Use neighbour discovery code.
+ *             Token Ring Support.
+ *
+ *             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.
+ *
+ *
+ *     References:
+ *             Inside AppleTalk (2nd Ed).
+ *     Fixes:
+ *             Jaume Grau      -       flush caches on AARP_PROBE
+ *             Rob Newberry    -       Added proxy AARP and AARP proc fs,
+ *                                     moved probing from DDP module.
+ *             Arnaldo C. Melo -       don't mangle rx packets
+ *
+ */
+
+#include <linux/if_arp.h>
+#include <linux/slab.h>
+#include <net/sock.h>
+#include <net/datalink.h>
+#include <net/psnap.h>
+#include "atalk.h"
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
+int sysctl_aarp_tick_time = AARP_TICK_TIME;
+int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT;
+int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME;
+
+/* Lists of aarp entries */
+/**
+ *     struct aarp_entry - AARP entry
+ *     @last_sent - Last time we xmitted the aarp request
+ *     @packet_queue - Queue of frames wait for resolution
+ *     @status - Used for proxy AARP
+ *     expires_at - Entry expiry time
+ *     target_addr - DDP Address
+ *     dev - Device to use
+ *     hwaddr - Physical i/f address of target/router
+ *     xmit_count - When this hits 10 we give up
+ *     next - Next entry in chain
+ */
+struct aarp_entry {
+       /* These first two are only used for unresolved entries */
+       unsigned long           last_sent;
+       struct sk_buff_head     packet_queue;
+       int                     status;
+       unsigned long           expires_at;
+       struct atalk_addr       target_addr;
+       struct net_device       *dev;
+       char                    hwaddr[6];
+       unsigned short          xmit_count;
+       struct aarp_entry       *next;
+};
+
+/* Hashed list of resolved, unresolved and proxy entries */
+static struct aarp_entry *resolved[AARP_HASH_SIZE];
+static struct aarp_entry *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *proxies[AARP_HASH_SIZE];
+static int unresolved_count;
+
+/* One lock protects it all. */
+static DEFINE_RWLOCK(aarp_lock);
+
+/* Used to walk the list and purge/kick entries.  */
+static struct timer_list aarp_timer;
+
+/*
+ *     Delete an aarp queue
+ *
+ *     Must run under aarp_lock.
+ */
+static void __aarp_expire(struct aarp_entry *a)
+{
+       skb_queue_purge(&a->packet_queue);
+       kfree(a);
+}
+
+/*
+ *     Send an aarp queue entry request
+ *
+ *     Must run under aarp_lock.
+ */
+static void __aarp_send_query(struct aarp_entry *a)
+{
+       static unsigned char aarp_eth_multicast[ETH_ALEN] =
+                                       { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+       struct net_device *dev = a->dev;
+       struct elapaarp *eah;
+       int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
+       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
+       struct atalk_addr *sat = atalk_find_dev_addr(dev);
+
+       if (!skb)
+               return;
+
+       if (!sat) {
+               kfree_skb(skb);
+               return;
+       }
+
+       /* Set up the buffer */
+       skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+       skb_put(skb, sizeof(*eah));
+       skb->protocol    = htons(ETH_P_ATALK);
+       skb->dev         = dev;
+       eah              = aarp_hdr(skb);
+
+       /* Set up the ARP */
+       eah->hw_type     = htons(AARP_HW_TYPE_ETHERNET);
+       eah->pa_type     = htons(ETH_P_ATALK);
+       eah->hw_len      = ETH_ALEN;
+       eah->pa_len      = AARP_PA_ALEN;
+       eah->function    = htons(AARP_REQUEST);
+
+       memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
+
+       eah->pa_src_zero = 0;
+       eah->pa_src_net  = sat->s_net;
+       eah->pa_src_node = sat->s_node;
+
+       memset(eah->hw_dst, '\0', ETH_ALEN);
+
+       eah->pa_dst_zero = 0;
+       eah->pa_dst_net  = a->target_addr.s_net;
+       eah->pa_dst_node = a->target_addr.s_node;
+
+       /* Send it */
+       aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
+       /* Update the sending count */
+       a->xmit_count++;
+       a->last_sent = jiffies;
+}
+
+/* This runs under aarp_lock and in softint context, so only atomic memory
+ * allocations can be used. */
+static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us,
+                           struct atalk_addr *them, unsigned char *sha)
+{
+       struct elapaarp *eah;
+       int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
+       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
+
+       if (!skb)
+               return;
+
+       /* Set up the buffer */
+       skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+       skb_put(skb, sizeof(*eah));
+       skb->protocol    = htons(ETH_P_ATALK);
+       skb->dev         = dev;
+       eah              = aarp_hdr(skb);
+
+       /* Set up the ARP */
+       eah->hw_type     = htons(AARP_HW_TYPE_ETHERNET);
+       eah->pa_type     = htons(ETH_P_ATALK);
+       eah->hw_len      = ETH_ALEN;
+       eah->pa_len      = AARP_PA_ALEN;
+       eah->function    = htons(AARP_REPLY);
+
+       memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
+
+       eah->pa_src_zero = 0;
+       eah->pa_src_net  = us->s_net;
+       eah->pa_src_node = us->s_node;
+
+       if (!sha)
+               memset(eah->hw_dst, '\0', ETH_ALEN);
+       else
+               memcpy(eah->hw_dst, sha, ETH_ALEN);
+
+       eah->pa_dst_zero = 0;
+       eah->pa_dst_net  = them->s_net;
+       eah->pa_dst_node = them->s_node;
+
+       /* Send it */
+       aarp_dl->request(aarp_dl, skb, sha);
+}
+
+/*
+ *     Send probe frames. Called from aarp_probe_network and
+ *     aarp_proxy_probe_network.
+ */
+
+static void aarp_send_probe(struct net_device *dev, struct atalk_addr *us)
+{
+       struct elapaarp *eah;
+       int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
+       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
+       static unsigned char aarp_eth_multicast[ETH_ALEN] =
+                                       { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+
+       if (!skb)
+               return;
+
+       /* Set up the buffer */
+       skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+       skb_put(skb, sizeof(*eah));
+       skb->protocol    = htons(ETH_P_ATALK);
+       skb->dev         = dev;
+       eah              = aarp_hdr(skb);
+
+       /* Set up the ARP */
+       eah->hw_type     = htons(AARP_HW_TYPE_ETHERNET);
+       eah->pa_type     = htons(ETH_P_ATALK);
+       eah->hw_len      = ETH_ALEN;
+       eah->pa_len      = AARP_PA_ALEN;
+       eah->function    = htons(AARP_PROBE);
+
+       memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
+
+       eah->pa_src_zero = 0;
+       eah->pa_src_net  = us->s_net;
+       eah->pa_src_node = us->s_node;
+
+       memset(eah->hw_dst, '\0', ETH_ALEN);
+
+       eah->pa_dst_zero = 0;
+       eah->pa_dst_net  = us->s_net;
+       eah->pa_dst_node = us->s_node;
+
+       /* Send it */
+       aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
+}
+
+/*
+ *     Handle an aarp timer expire
+ *
+ *     Must run under the aarp_lock.
+ */
+
+static void __aarp_expire_timer(struct aarp_entry **n)
+{
+       struct aarp_entry *t;
+
+       while (*n)
+               /* Expired ? */
+               if (time_after(jiffies, (*n)->expires_at)) {
+                       t = *n;
+                       *n = (*n)->next;
+                       __aarp_expire(t);
+               } else
+                       n = &((*n)->next);
+}
+
+/*
+ *     Kick all pending requests 5 times a second.
+ *
+ *     Must run under the aarp_lock.
+ */
+static void __aarp_kick(struct aarp_entry **n)
+{
+       struct aarp_entry *t;
+
+       while (*n)
+               /* Expired: if this will be the 11th tx, we delete instead. */
+               if ((*n)->xmit_count >= sysctl_aarp_retransmit_limit) {
+                       t = *n;
+                       *n = (*n)->next;
+                       __aarp_expire(t);
+               } else {
+                       __aarp_send_query(*n);
+                       n = &((*n)->next);
+               }
+}
+
+/*
+ *     A device has gone down. Take all entries referring to the device
+ *     and remove them.
+ *
+ *     Must run under the aarp_lock.
+ */
+static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
+{
+       struct aarp_entry *t;
+
+       while (*n)
+               if ((*n)->dev == dev) {
+                       t = *n;
+                       *n = (*n)->next;
+                       __aarp_expire(t);
+               } else
+                       n = &((*n)->next);
+}
+
+/* Handle the timer event */
+static void aarp_expire_timeout(unsigned long unused)
+{
+       int ct;
+
+       write_lock_bh(&aarp_lock);
+
+       for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+               __aarp_expire_timer(&resolved[ct]);
+               __aarp_kick(&unresolved[ct]);
+               __aarp_expire_timer(&unresolved[ct]);
+               __aarp_expire_timer(&proxies[ct]);
+       }
+
+       write_unlock_bh(&aarp_lock);
+       mod_timer(&aarp_timer, jiffies +
+                              (unresolved_count ? sysctl_aarp_tick_time :
+                               sysctl_aarp_expiry_time));
+}
+
+/* Network device notifier chain handler. */
+static int aarp_device_event(struct notifier_block *this, unsigned long event,
+                            void *ptr)
+{
+       struct net_device *dev = ptr;
+       int ct;
+
+       if (!net_eq(dev_net(dev), &init_net))
+               return NOTIFY_DONE;
+
+       if (event == NETDEV_DOWN) {
+               write_lock_bh(&aarp_lock);
+
+               for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+                       __aarp_expire_device(&resolved[ct], dev);
+                       __aarp_expire_device(&unresolved[ct], dev);
+                       __aarp_expire_device(&proxies[ct], dev);
+               }
+
+               write_unlock_bh(&aarp_lock);
+       }
+       return NOTIFY_DONE;
+}
+
+/* Expire all entries in a hash chain */
+static void __aarp_expire_all(struct aarp_entry **n)
+{
+       struct aarp_entry *t;
+
+       while (*n) {
+               t = *n;
+               *n = (*n)->next;
+               __aarp_expire(t);
+       }
+}
+
+/* Cleanup all hash chains -- module unloading */
+static void aarp_purge(void)
+{
+       int ct;
+
+       write_lock_bh(&aarp_lock);
+       for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+               __aarp_expire_all(&resolved[ct]);
+               __aarp_expire_all(&unresolved[ct]);
+               __aarp_expire_all(&proxies[ct]);
+       }
+       write_unlock_bh(&aarp_lock);
+}
+
+/*
+ *     Create a new aarp entry.  This must use GFP_ATOMIC because it
+ *     runs while holding spinlocks.
+ */
+static struct aarp_entry *aarp_alloc(void)
+{
+       struct aarp_entry *a = kmalloc(sizeof(*a), GFP_ATOMIC);
+
+       if (a)
+               skb_queue_head_init(&a->packet_queue);
+       return a;
+}
+
+/*
+ * Find an entry. We might return an expired but not yet purged entry. We
+ * don't care as it will do no harm.
+ *
+ * This must run under the aarp_lock.
+ */
+static struct aarp_entry *__aarp_find_entry(struct aarp_entry *list,
+                                           struct net_device *dev,
+                                           struct atalk_addr *sat)
+{
+       while (list) {
+               if (list->target_addr.s_net == sat->s_net &&
+                   list->target_addr.s_node == sat->s_node &&
+                   list->dev == dev)
+                       break;
+               list = list->next;
+       }
+
+       return list;
+}
+
+/* Called from the DDP code, and thus must be exported. */
+void aarp_proxy_remove(struct net_device *dev, struct atalk_addr *sa)
+{
+       int hash = sa->s_node % (AARP_HASH_SIZE - 1);
+       struct aarp_entry *a;
+
+       write_lock_bh(&aarp_lock);
+
+       a = __aarp_find_entry(proxies[hash], dev, sa);
+       if (a)
+               a->expires_at = jiffies - 1;
+
+       write_unlock_bh(&aarp_lock);
+}
+
+/* This must run under aarp_lock. */
+static struct atalk_addr *__aarp_proxy_find(struct net_device *dev,
+                                           struct atalk_addr *sa)
+{
+       int hash = sa->s_node % (AARP_HASH_SIZE - 1);
+       struct aarp_entry *a = __aarp_find_entry(proxies[hash], dev, sa);
+
+       return a ? sa : NULL;
+}
+
+/*
+ * Probe a Phase 1 device or a device that requires its Net:Node to
+ * be set via an ioctl.
+ */
+static void aarp_send_probe_phase1(struct atalk_iface *iface)
+{
+       struct ifreq atreq;
+       struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
+       const struct net_device_ops *ops = iface->dev->netdev_ops;
+
+       sa->sat_addr.s_node = iface->address.s_node;
+       sa->sat_addr.s_net = ntohs(iface->address.s_net);
+
+       /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
+       if (!(ops->ndo_do_ioctl(iface->dev, &atreq, SIOCSIFADDR))) {
+               ops->ndo_do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
+               if (iface->address.s_net != htons(sa->sat_addr.s_net) ||
+                   iface->address.s_node != sa->sat_addr.s_node)
+                       iface->status |= ATIF_PROBE_FAIL;
+
+               iface->address.s_net  = htons(sa->sat_addr.s_net);
+               iface->address.s_node = sa->sat_addr.s_node;
+       }
+}
+
+
+void aarp_probe_network(struct atalk_iface *atif)
+{
+       if (atif->dev->type == ARPHRD_LOCALTLK ||
+           atif->dev->type == ARPHRD_PPP)
+               aarp_send_probe_phase1(atif);
+       else {
+               unsigned int count;
+
+               for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
+                       aarp_send_probe(atif->dev, &atif->address);
+
+                       /* Defer 1/10th */
+                       msleep(100);
+
+                       if (atif->status & ATIF_PROBE_FAIL)
+                               break;
+               }
+       }
+}
+
+int aarp_proxy_probe_network(struct atalk_iface *atif, struct atalk_addr *sa)
+{
+       int hash, retval = -EPROTONOSUPPORT;
+       struct aarp_entry *entry;
+       unsigned int count;
+
+       /*
+        * we don't currently support LocalTalk or PPP for proxy AARP;
+        * if someone wants to try and add it, have fun
+        */
+       if (atif->dev->type == ARPHRD_LOCALTLK ||
+           atif->dev->type == ARPHRD_PPP)
+               goto out;
+
+       /*
+        * create a new AARP entry with the flags set to be published --
+        * we need this one to hang around even if it's in use
+        */
+       entry = aarp_alloc();
+       retval = -ENOMEM;
+       if (!entry)
+               goto out;
+
+       entry->expires_at = -1;
+       entry->status = ATIF_PROBE;
+       entry->target_addr.s_node = sa->s_node;
+       entry->target_addr.s_net = sa->s_net;
+       entry->dev = atif->dev;
+
+       write_lock_bh(&aarp_lock);
+
+       hash = sa->s_node % (AARP_HASH_SIZE - 1);
+       entry->next = proxies[hash];
+       proxies[hash] = entry;
+
+       for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
+               aarp_send_probe(atif->dev, sa);
+
+               /* Defer 1/10th */
+               write_unlock_bh(&aarp_lock);
+               msleep(100);
+               write_lock_bh(&aarp_lock);
+
+               if (entry->status & ATIF_PROBE_FAIL)
+                       break;
+       }
+
+       if (entry->status & ATIF_PROBE_FAIL) {
+               entry->expires_at = jiffies - 1; /* free the entry */
+               retval = -EADDRINUSE; /* return network full */
+       } else { /* clear the probing flag */
+               entry->status &= ~ATIF_PROBE;
+               retval = 1;
+       }
+
+       write_unlock_bh(&aarp_lock);
+out:
+       return retval;
+}
+
+/* Send a DDP frame */
+int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
+                 struct atalk_addr *sa, void *hwaddr)
+{
+       static char ddp_eth_multicast[ETH_ALEN] =
+               { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+       int hash;
+       struct aarp_entry *a;
+
+       skb_reset_network_header(skb);
+
+       /* Check for LocalTalk first */
+       if (dev->type == ARPHRD_LOCALTLK) {
+               struct atalk_addr *at = atalk_find_dev_addr(dev);
+               struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
+               int ft = 2;
+
+               /*
+                * Compressible ?
+                *
+                * IFF: src_net == dest_net == device_net
+                * (zero matches anything)
+                */
+
+               if ((!ddp->deh_snet || at->s_net == ddp->deh_snet) &&
+                   (!ddp->deh_dnet || at->s_net == ddp->deh_dnet)) {
+                       skb_pull(skb, sizeof(*ddp) - 4);
+
+                       /*
+                        *      The upper two remaining bytes are the port
+                        *      numbers we just happen to need. Now put the
+                        *      length in the lower two.
+                        */
+                       *((__be16 *)skb->data) = htons(skb->len);
+                       ft = 1;
+               }
+               /*
+                * Nice and easy. No AARP type protocols occur here so we can
+                * just shovel it out with a 3 byte LLAP header
+                */
+
+               skb_push(skb, 3);
+               skb->data[0] = sa->s_node;
+               skb->data[1] = at->s_node;
+               skb->data[2] = ft;
+               skb->dev     = dev;
+               goto sendit;
+       }
+
+       /* On a PPP link we neither compress nor aarp.  */
+       if (dev->type == ARPHRD_PPP) {
+               skb->protocol = htons(ETH_P_PPPTALK);
+               skb->dev = dev;
+               goto sendit;
+       }
+
+       /* Non ELAP we cannot do. */
+       if (dev->type != ARPHRD_ETHER)
+               goto free_it;
+
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_ATALK);
+       hash = sa->s_node % (AARP_HASH_SIZE - 1);
+
+       /* Do we have a resolved entry? */
+       if (sa->s_node == ATADDR_BCAST) {
+               /* Send it */
+               ddp_dl->request(ddp_dl, skb, ddp_eth_multicast);
+               goto sent;
+       }
+
+       write_lock_bh(&aarp_lock);
+       a = __aarp_find_entry(resolved[hash], dev, sa);
+
+       if (a) { /* Return 1 and fill in the address */
+               a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
+               ddp_dl->request(ddp_dl, skb, a->hwaddr);
+               write_unlock_bh(&aarp_lock);
+               goto sent;
+       }
+
+       /* Do we have an unresolved entry: This is the less common path */
+       a = __aarp_find_entry(unresolved[hash], dev, sa);
+       if (a) { /* Queue onto the unresolved queue */
+               skb_queue_tail(&a->packet_queue, skb);
+               goto out_unlock;
+       }
+
+       /* Allocate a new entry */
+       a = aarp_alloc();
+       if (!a) {
+               /* Whoops slipped... good job it's an unreliable protocol 8) */
+               write_unlock_bh(&aarp_lock);
+               goto free_it;
+       }
+
+       /* Set up the queue */
+       skb_queue_tail(&a->packet_queue, skb);
+       a->expires_at    = jiffies + sysctl_aarp_resolve_time;
+       a->dev           = dev;
+       a->next          = unresolved[hash];
+       a->target_addr   = *sa;
+       a->xmit_count    = 0;
+       unresolved[hash] = a;
+       unresolved_count++;
+
+       /* Send an initial request for the address */
+       __aarp_send_query(a);
+
+       /*
+        * Switch to fast timer if needed (That is if this is the first
+        * unresolved entry to get added)
+        */
+
+       if (unresolved_count == 1)
+               mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time);
+
+       /* Now finally, it is safe to drop the lock. */
+out_unlock:
+       write_unlock_bh(&aarp_lock);
+
+       /* Tell the ddp layer we have taken over for this frame. */
+       goto sent;
+
+sendit:
+       if (skb->sk)
+               skb->priority = skb->sk->sk_priority;
+       if (dev_queue_xmit(skb))
+               goto drop;
+sent:
+       return NET_XMIT_SUCCESS;
+free_it:
+       kfree_skb(skb);
+drop:
+       return NET_XMIT_DROP;
+}
+EXPORT_SYMBOL(aarp_send_ddp);
+
+/*
+ *     An entry in the aarp unresolved queue has become resolved. Send
+ *     all the frames queued under it.
+ *
+ *     Must run under aarp_lock.
+ */
+static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a,
+                           int hash)
+{
+       struct sk_buff *skb;
+
+       while (*list)
+               if (*list == a) {
+                       unresolved_count--;
+                       *list = a->next;
+
+                       /* Move into the resolved list */
+                       a->next = resolved[hash];
+                       resolved[hash] = a;
+
+                       /* Kick frames off */
+                       while ((skb = skb_dequeue(&a->packet_queue)) != NULL) {
+                               a->expires_at = jiffies +
+                                               sysctl_aarp_expiry_time * 10;
+                               ddp_dl->request(ddp_dl, skb, a->hwaddr);
+                       }
+               } else
+                       list = &((*list)->next);
+}
+
+/*
+ *     This is called by the SNAP driver whenever we see an AARP SNAP
+ *     frame. We currently only support Ethernet.
+ */
+static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
+                   struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct elapaarp *ea = aarp_hdr(skb);
+       int hash, ret = 0;
+       __u16 function;
+       struct aarp_entry *a;
+       struct atalk_addr sa, *ma, da;
+       struct atalk_iface *ifa;
+
+       if (!net_eq(dev_net(dev), &init_net))
+               goto out0;
+
+       /* We only do Ethernet SNAP AARP. */
+       if (dev->type != ARPHRD_ETHER)
+               goto out0;
+
+       /* Frame size ok? */
+       if (!skb_pull(skb, sizeof(*ea)))
+               goto out0;
+
+       function = ntohs(ea->function);
+
+       /* Sanity check fields. */
+       if (function < AARP_REQUEST || function > AARP_PROBE ||
+           ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN ||
+           ea->pa_src_zero || ea->pa_dst_zero)
+               goto out0;
+
+       /* Looks good. */
+       hash = ea->pa_src_node % (AARP_HASH_SIZE - 1);
+
+       /* Build an address. */
+       sa.s_node = ea->pa_src_node;
+       sa.s_net = ea->pa_src_net;
+
+       /* Process the packet. Check for replies of me. */
+       ifa = atalk_find_dev(dev);
+       if (!ifa)
+               goto out1;
+
+       if (ifa->status & ATIF_PROBE &&
+           ifa->address.s_node == ea->pa_dst_node &&
+           ifa->address.s_net == ea->pa_dst_net) {
+               ifa->status |= ATIF_PROBE_FAIL; /* Fail the probe (in use) */
+               goto out1;
+       }
+
+       /* Check for replies of proxy AARP entries */
+       da.s_node = ea->pa_dst_node;
+       da.s_net  = ea->pa_dst_net;
+
+       write_lock_bh(&aarp_lock);
+       a = __aarp_find_entry(proxies[hash], dev, &da);
+
+       if (a && a->status & ATIF_PROBE) {
+               a->status |= ATIF_PROBE_FAIL;
+               /*
+                * we do not respond to probe or request packets for
+                * this address while we are probing this address
+                */
+               goto unlock;
+       }
+
+       switch (function) {
+               case AARP_REPLY:
+                       if (!unresolved_count)  /* Speed up */
+                               break;
+
+                       /* Find the entry.  */
+                       a = __aarp_find_entry(unresolved[hash], dev, &sa);
+                       if (!a || dev != a->dev)
+                               break;
+
+                       /* We can fill one in - this is good. */
+                       memcpy(a->hwaddr, ea->hw_src, ETH_ALEN);
+                       __aarp_resolved(&unresolved[hash], a, hash);
+                       if (!unresolved_count)
+                               mod_timer(&aarp_timer,
+                                         jiffies + sysctl_aarp_expiry_time);
+                       break;
+
+               case AARP_REQUEST:
+               case AARP_PROBE:
+
+                       /*
+                        * If it is my address set ma to my address and reply.
+                        * We can treat probe and request the same.  Probe
+                        * simply means we shouldn't cache the querying host,
+                        * as in a probe they are proposing an address not
+                        * using one.
+                        *
+                        * Support for proxy-AARP added. We check if the
+                        * address is one of our proxies before we toss the
+                        * packet out.
+                        */
+
+                       sa.s_node = ea->pa_dst_node;
+                       sa.s_net  = ea->pa_dst_net;
+
+                       /* See if we have a matching proxy. */
+                       ma = __aarp_proxy_find(dev, &sa);
+                       if (!ma)
+                               ma = &ifa->address;
+                       else { /* We need to make a copy of the entry. */
+                               da.s_node = sa.s_node;
+                               da.s_net = sa.s_net;
+                               ma = &da;
+                       }
+
+                       if (function == AARP_PROBE) {
+                               /*
+                                * A probe implies someone trying to get an
+                                * address. So as a precaution flush any
+                                * entries we have for this address.
+                                */
+                               a = __aarp_find_entry(resolved[sa.s_node %
+                                                         (AARP_HASH_SIZE - 1)],
+                                                     skb->dev, &sa);
+
+                               /*
+                                * Make it expire next tick - that avoids us
+                                * getting into a probe/flush/learn/probe/
+                                * flush/learn cycle during probing of a slow
+                                * to respond host addr.
+                                */
+                               if (a) {
+                                       a->expires_at = jiffies - 1;
+                                       mod_timer(&aarp_timer, jiffies +
+                                                       sysctl_aarp_tick_time);
+                               }
+                       }
+
+                       if (sa.s_node != ma->s_node)
+                               break;
+
+                       if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
+                               break;
+
+                       sa.s_node = ea->pa_src_node;
+                       sa.s_net = ea->pa_src_net;
+
+                       /* aarp_my_address has found the address to use for us.
+                       */
+                       aarp_send_reply(dev, ma, &sa, ea->hw_src);
+                       break;
+       }
+
+unlock:
+       write_unlock_bh(&aarp_lock);
+out1:
+       ret = 1;
+out0:
+       kfree_skb(skb);
+       return ret;
+}
+
+static struct notifier_block aarp_notifier = {
+       .notifier_call = aarp_device_event,
+};
+
+static unsigned char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
+
+void __init aarp_proto_init(void)
+{
+       aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv);
+       if (!aarp_dl)
+               printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
+       setup_timer(&aarp_timer, aarp_expire_timeout, 0);
+       aarp_timer.expires  = jiffies + sysctl_aarp_expiry_time;
+       add_timer(&aarp_timer);
+       register_netdevice_notifier(&aarp_notifier);
+}
+
+/* Remove the AARP entries associated with a device. */
+void aarp_device_down(struct net_device *dev)
+{
+       int ct;
+
+       write_lock_bh(&aarp_lock);
+
+       for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+               __aarp_expire_device(&resolved[ct], dev);
+               __aarp_expire_device(&unresolved[ct], dev);
+               __aarp_expire_device(&proxies[ct], dev);
+       }
+
+       write_unlock_bh(&aarp_lock);
+}
+
+#ifdef CONFIG_PROC_FS
+struct aarp_iter_state {
+       int bucket;
+       struct aarp_entry **table;
+};
+
+/*
+ * Get the aarp entry that is in the chain described
+ * by the iterator.
+ * If pos is set then skip till that index.
+ * pos = 1 is the first entry
+ */
+static struct aarp_entry *iter_next(struct aarp_iter_state *iter, loff_t *pos)
+{
+       int ct = iter->bucket;
+       struct aarp_entry **table = iter->table;
+       loff_t off = 0;
+       struct aarp_entry *entry;
+
+ rescan:
+       while(ct < AARP_HASH_SIZE) {
+               for (entry = table[ct]; entry; entry = entry->next) {
+                       if (!pos || ++off == *pos) {
+                               iter->table = table;
+                               iter->bucket = ct;
+                               return entry;
+                       }
+               }
+               ++ct;
+       }
+
+       if (table == resolved) {
+               ct = 0;
+               table = unresolved;
+               goto rescan;
+       }
+       if (table == unresolved) {
+               ct = 0;
+               table = proxies;
+               goto rescan;
+       }
+       return NULL;
+}
+
+static void *aarp_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(aarp_lock)
+{
+       struct aarp_iter_state *iter = seq->private;
+
+       read_lock_bh(&aarp_lock);
+       iter->table     = resolved;
+       iter->bucket    = 0;
+
+       return *pos ? iter_next(iter, pos) : SEQ_START_TOKEN;
+}
+
+static void *aarp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct aarp_entry *entry = v;
+       struct aarp_iter_state *iter = seq->private;
+
+       ++*pos;
+
+       /* first line after header */
+       if (v == SEQ_START_TOKEN)
+               entry = iter_next(iter, NULL);
+
+       /* next entry in current bucket */
+       else if (entry->next)
+               entry = entry->next;
+
+       /* next bucket or table */
+       else {
+               ++iter->bucket;
+               entry = iter_next(iter, NULL);
+       }
+       return entry;
+}
+
+static void aarp_seq_stop(struct seq_file *seq, void *v)
+       __releases(aarp_lock)
+{
+       read_unlock_bh(&aarp_lock);
+}
+
+static const char *dt2str(unsigned long ticks)
+{
+       static char buf[32];
+
+       sprintf(buf, "%ld.%02ld", ticks / HZ, ((ticks % HZ) * 100 ) / HZ);
+
+       return buf;
+}
+
+static int aarp_seq_show(struct seq_file *seq, void *v)
+{
+       struct aarp_iter_state *iter = seq->private;
+       struct aarp_entry *entry = v;
+       unsigned long now = jiffies;
+
+       if (v == SEQ_START_TOKEN)
+               seq_puts(seq,
+                        "Address  Interface   Hardware Address"
+                        "   Expires LastSend  Retry Status\n");
+       else {
+               seq_printf(seq, "%04X:%02X  %-12s",
+                          ntohs(entry->target_addr.s_net),
+                          (unsigned int) entry->target_addr.s_node,
+                          entry->dev ? entry->dev->name : "????");
+               seq_printf(seq, "%pM", entry->hwaddr);
+               seq_printf(seq, " %8s",
+                          dt2str((long)entry->expires_at - (long)now));
+               if (iter->table == unresolved)
+                       seq_printf(seq, " %8s %6hu",
+                                  dt2str(now - entry->last_sent),
+                                  entry->xmit_count);
+               else
+                       seq_puts(seq, "                ");
+               seq_printf(seq, " %s\n",
+                          (iter->table == resolved) ? "resolved"
+                          : (iter->table == unresolved) ? "unresolved"
+                          : (iter->table == proxies) ? "proxies"
+                          : "unknown");
+       }
+       return 0;
+}
+
+static const struct seq_operations aarp_seq_ops = {
+       .start  = aarp_seq_start,
+       .next   = aarp_seq_next,
+       .stop   = aarp_seq_stop,
+       .show   = aarp_seq_show,
+};
+
+static int aarp_seq_open(struct inode *inode, struct file *file)
+{
+       return seq_open_private(file, &aarp_seq_ops,
+                       sizeof(struct aarp_iter_state));
+}
+
+const struct file_operations atalk_seq_arp_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aarp_seq_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release_private,
+};
+#endif
+
+/* General module cleanup. Called from cleanup_module() in ddp.c. */
+void aarp_cleanup_module(void)
+{
+       del_timer_sync(&aarp_timer);
+       unregister_netdevice_notifier(&aarp_notifier);
+       unregister_snap_client(aarp_dl);
+       aarp_purge();
+}
diff --git a/drivers/staging/appletalk/atalk.h b/drivers/staging/appletalk/atalk.h
new file mode 100644 (file)
index 0000000..d34c187
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef __LINUX_ATALK_H__
+#define __LINUX_ATALK_H__
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/*
+ * AppleTalk networking structures
+ *
+ * The following are directly referenced from the University Of Michigan
+ * netatalk for compatibility reasons.
+ */
+#define ATPORT_FIRST   1
+#define ATPORT_RESERVED        128
+#define ATPORT_LAST    254             /* 254 is only legal on localtalk */ 
+#define ATADDR_ANYNET  (__u16)0
+#define ATADDR_ANYNODE (__u8)0
+#define ATADDR_ANYPORT  (__u8)0
+#define ATADDR_BCAST   (__u8)255
+#define DDP_MAXSZ      587
+#define DDP_MAXHOPS     15             /* 4 bits of hop counter */
+
+#define SIOCATALKDIFADDR       (SIOCPROTOPRIVATE + 0)
+
+struct atalk_addr {
+       __be16  s_net;
+       __u8    s_node;
+};
+
+struct sockaddr_at {
+       sa_family_t       sat_family;
+       __u8              sat_port;
+       struct atalk_addr sat_addr;
+       char              sat_zero[8];
+};
+
+struct atalk_netrange {
+       __u8    nr_phase;
+       __be16  nr_firstnet;
+       __be16  nr_lastnet;
+};
+
+#ifdef __KERNEL__
+
+#include <net/sock.h>
+
+struct atalk_route {
+       struct net_device  *dev;
+       struct atalk_addr  target;
+       struct atalk_addr  gateway;
+       int                flags;
+       struct atalk_route *next;
+};
+
+/**
+ *     struct atalk_iface - AppleTalk Interface
+ *     @dev - Network device associated with this interface
+ *     @address - Our address
+ *     @status - What are we doing?
+ *     @nets - Associated direct netrange
+ *     @next - next element in the list of interfaces
+ */
+struct atalk_iface {
+       struct net_device       *dev;
+       struct atalk_addr       address;
+       int                     status;
+#define ATIF_PROBE     1               /* Probing for an address */
+#define ATIF_PROBE_FAIL        2               /* Probe collided */
+       struct atalk_netrange   nets;
+       struct atalk_iface      *next;
+};
+       
+struct atalk_sock {
+       /* struct sock has to be the first member of atalk_sock */
+       struct sock     sk;
+       __be16          dest_net;
+       __be16          src_net;
+       unsigned char   dest_node;
+       unsigned char   src_node;
+       unsigned char   dest_port;
+       unsigned char   src_port;
+};
+
+static inline struct atalk_sock *at_sk(struct sock *sk)
+{
+       return (struct atalk_sock *)sk;
+}
+
+struct ddpehdr {
+       __be16  deh_len_hops;   /* lower 10 bits are length, next 4 - hops */
+       __be16  deh_sum;
+       __be16  deh_dnet;
+       __be16  deh_snet;
+       __u8    deh_dnode;
+       __u8    deh_snode;
+       __u8    deh_dport;
+       __u8    deh_sport;
+       /* And netatalk apps expect to stick the type in themselves */
+};
+
+static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb)
+{
+       return (struct ddpehdr *)skb_transport_header(skb);
+}
+
+/* AppleTalk AARP headers */
+struct elapaarp {
+       __be16  hw_type;
+#define AARP_HW_TYPE_ETHERNET          1
+#define AARP_HW_TYPE_TOKENRING         2
+       __be16  pa_type;
+       __u8    hw_len;
+       __u8    pa_len;
+#define AARP_PA_ALEN                   4
+       __be16  function;
+#define AARP_REQUEST                   1
+#define AARP_REPLY                     2
+#define AARP_PROBE                     3
+       __u8    hw_src[ETH_ALEN];
+       __u8    pa_src_zero;
+       __be16  pa_src_net;
+       __u8    pa_src_node;
+       __u8    hw_dst[ETH_ALEN];
+       __u8    pa_dst_zero;
+       __be16  pa_dst_net;
+       __u8    pa_dst_node;
+} __attribute__ ((packed));
+
+static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb)
+{
+       return (struct elapaarp *)skb_transport_header(skb);
+}
+
+/* Not specified - how long till we drop a resolved entry */
+#define AARP_EXPIRY_TIME       (5 * 60 * HZ)
+/* Size of hash table */
+#define AARP_HASH_SIZE         16
+/* Fast retransmission timer when resolving */
+#define AARP_TICK_TIME         (HZ / 5)
+/* Send 10 requests then give up (2 seconds) */
+#define AARP_RETRANSMIT_LIMIT  10
+/*
+ * Some value bigger than total retransmit time + a bit for last reply to
+ * appear and to stop continual requests
+ */
+#define AARP_RESOLVE_TIME      (10 * HZ)
+
+extern struct datalink_proto *ddp_dl, *aarp_dl;
+extern void aarp_proto_init(void);
+
+/* Inter module exports */
+
+/* Give a device find its atif control structure */
+static inline struct atalk_iface *atalk_find_dev(struct net_device *dev)
+{
+       return dev->atalk_ptr;
+}
+
+extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
+extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
+extern int              aarp_send_ddp(struct net_device *dev,
+                                      struct sk_buff *skb,
+                                      struct atalk_addr *sa, void *hwaddr);
+extern void             aarp_device_down(struct net_device *dev);
+extern void             aarp_probe_network(struct atalk_iface *atif);
+extern int              aarp_proxy_probe_network(struct atalk_iface *atif,
+                                    struct atalk_addr *sa);
+extern void             aarp_proxy_remove(struct net_device *dev,
+                                          struct atalk_addr *sa);
+
+extern void            aarp_cleanup_module(void);
+
+extern struct hlist_head atalk_sockets;
+extern rwlock_t atalk_sockets_lock;
+
+extern struct atalk_route *atalk_routes;
+extern rwlock_t atalk_routes_lock;
+
+extern struct atalk_iface *atalk_interfaces;
+extern rwlock_t atalk_interfaces_lock;
+
+extern struct atalk_route atrtr_default;
+
+extern const struct file_operations atalk_seq_arp_fops;
+
+extern int sysctl_aarp_expiry_time;
+extern int sysctl_aarp_tick_time;
+extern int sysctl_aarp_retransmit_limit;
+extern int sysctl_aarp_resolve_time;
+
+#ifdef CONFIG_SYSCTL
+extern void atalk_register_sysctl(void);
+extern void atalk_unregister_sysctl(void);
+#else
+#define atalk_register_sysctl()                do { } while(0)
+#define atalk_unregister_sysctl()      do { } while(0)
+#endif
+
+#ifdef CONFIG_PROC_FS
+extern int atalk_proc_init(void);
+extern void atalk_proc_exit(void);
+#else
+#define atalk_proc_init()      ({ 0; })
+#define atalk_proc_exit()      do { } while(0)
+#endif /* CONFIG_PROC_FS */
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_ATALK_H__ */
diff --git a/drivers/staging/appletalk/atalk_proc.c b/drivers/staging/appletalk/atalk_proc.c
new file mode 100644 (file)
index 0000000..d012ba2
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ *     atalk_proc.c - proc support for Appletalk
+ *
+ *     Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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, version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include "atalk.h"
+
+
+static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos)
+{
+       struct atalk_iface *i;
+
+       for (i = atalk_interfaces; pos && i; i = i->next)
+               --pos;
+
+       return i;
+}
+
+static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos)
+       __acquires(atalk_interfaces_lock)
+{
+       loff_t l = *pos;
+
+       read_lock_bh(&atalk_interfaces_lock);
+       return l ? atalk_get_interface_idx(--l) : SEQ_START_TOKEN;
+}
+
+static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct atalk_iface *i;
+
+       ++*pos;
+       if (v == SEQ_START_TOKEN) {
+               i = NULL;
+               if (atalk_interfaces)
+                       i = atalk_interfaces;
+               goto out;
+       }
+       i = v;
+       i = i->next;
+out:
+       return i;
+}
+
+static void atalk_seq_interface_stop(struct seq_file *seq, void *v)
+       __releases(atalk_interfaces_lock)
+{
+       read_unlock_bh(&atalk_interfaces_lock);
+}
+
+static int atalk_seq_interface_show(struct seq_file *seq, void *v)
+{
+       struct atalk_iface *iface;
+
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(seq, "Interface        Address   Networks  "
+                             "Status\n");
+               goto out;
+       }
+
+       iface = v;
+       seq_printf(seq, "%-16s %04X:%02X  %04X-%04X  %d\n",
+                  iface->dev->name, ntohs(iface->address.s_net),
+                  iface->address.s_node, ntohs(iface->nets.nr_firstnet),
+                  ntohs(iface->nets.nr_lastnet), iface->status);
+out:
+       return 0;
+}
+
+static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos)
+{
+       struct atalk_route *r;
+
+       for (r = atalk_routes; pos && r; r = r->next)
+               --pos;
+
+       return r;
+}
+
+static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos)
+       __acquires(atalk_routes_lock)
+{
+       loff_t l = *pos;
+
+       read_lock_bh(&atalk_routes_lock);
+       return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN;
+}
+
+static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct atalk_route *r;
+
+       ++*pos;
+       if (v == SEQ_START_TOKEN) {
+               r = NULL;
+               if (atalk_routes)
+                       r = atalk_routes;
+               goto out;
+       }
+       r = v;
+       r = r->next;
+out:
+       return r;
+}
+
+static void atalk_seq_route_stop(struct seq_file *seq, void *v)
+       __releases(atalk_routes_lock)
+{
+       read_unlock_bh(&atalk_routes_lock);
+}
+
+static int atalk_seq_route_show(struct seq_file *seq, void *v)
+{
+       struct atalk_route *rt;
+
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(seq, "Target        Router  Flags Dev\n");
+               goto out;
+       }
+
+       if (atrtr_default.dev) {
+               rt = &atrtr_default;
+               seq_printf(seq, "Default     %04X:%02X  %-4d  %s\n",
+                              ntohs(rt->gateway.s_net), rt->gateway.s_node,
+                              rt->flags, rt->dev->name);
+       }
+
+       rt = v;
+       seq_printf(seq, "%04X:%02X     %04X:%02X  %-4d  %s\n",
+                  ntohs(rt->target.s_net), rt->target.s_node,
+                  ntohs(rt->gateway.s_net), rt->gateway.s_node,
+                  rt->flags, rt->dev->name);
+out:
+       return 0;
+}
+
+static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
+       __acquires(atalk_sockets_lock)
+{
+       read_lock_bh(&atalk_sockets_lock);
+       return seq_hlist_start_head(&atalk_sockets, *pos);
+}
+
+static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       return seq_hlist_next(v, &atalk_sockets, pos);
+}
+
+static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
+       __releases(atalk_sockets_lock)
+{
+       read_unlock_bh(&atalk_sockets_lock);
+}
+
+static int atalk_seq_socket_show(struct seq_file *seq, void *v)
+{
+       struct sock *s;
+       struct atalk_sock *at;
+
+       if (v == SEQ_START_TOKEN) {
+               seq_printf(seq, "Type Local_addr  Remote_addr Tx_queue "
+                               "Rx_queue St UID\n");
+               goto out;
+       }
+
+       s = sk_entry(v);
+       at = at_sk(s);
+
+       seq_printf(seq, "%02X   %04X:%02X:%02X  %04X:%02X:%02X  %08X:%08X "
+                       "%02X %d\n",
+                  s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
+                  ntohs(at->dest_net), at->dest_node, at->dest_port,
+                  sk_wmem_alloc_get(s),
+                  sk_rmem_alloc_get(s),
+                  s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
+out:
+       return 0;
+}
+
+static const struct seq_operations atalk_seq_interface_ops = {
+       .start  = atalk_seq_interface_start,
+       .next   = atalk_seq_interface_next,
+       .stop   = atalk_seq_interface_stop,
+       .show   = atalk_seq_interface_show,
+};
+
+static const struct seq_operations atalk_seq_route_ops = {
+       .start  = atalk_seq_route_start,
+       .next   = atalk_seq_route_next,
+       .stop   = atalk_seq_route_stop,
+       .show   = atalk_seq_route_show,
+};
+
+static const struct seq_operations atalk_seq_socket_ops = {
+       .start  = atalk_seq_socket_start,
+       .next   = atalk_seq_socket_next,
+       .stop   = atalk_seq_socket_stop,
+       .show   = atalk_seq_socket_show,
+};
+
+static int atalk_seq_interface_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &atalk_seq_interface_ops);
+}
+
+static int atalk_seq_route_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &atalk_seq_route_ops);
+}
+
+static int atalk_seq_socket_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &atalk_seq_socket_ops);
+}
+
+static const struct file_operations atalk_seq_interface_fops = {
+       .owner          = THIS_MODULE,
+       .open           = atalk_seq_interface_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static const struct file_operations atalk_seq_route_fops = {
+       .owner          = THIS_MODULE,
+       .open           = atalk_seq_route_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static const struct file_operations atalk_seq_socket_fops = {
+       .owner          = THIS_MODULE,
+       .open           = atalk_seq_socket_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static struct proc_dir_entry *atalk_proc_dir;
+
+int __init atalk_proc_init(void)
+{
+       struct proc_dir_entry *p;
+       int rc = -ENOMEM;
+
+       atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net);
+       if (!atalk_proc_dir)
+               goto out;
+
+       p = proc_create("interface", S_IRUGO, atalk_proc_dir,
+                       &atalk_seq_interface_fops);
+       if (!p)
+               goto out_interface;
+
+       p = proc_create("route", S_IRUGO, atalk_proc_dir,
+                       &atalk_seq_route_fops);
+       if (!p)
+               goto out_route;
+
+       p = proc_create("socket", S_IRUGO, atalk_proc_dir,
+                       &atalk_seq_socket_fops);
+       if (!p)
+               goto out_socket;
+
+       p = proc_create("arp", S_IRUGO, atalk_proc_dir, &atalk_seq_arp_fops);
+       if (!p)
+               goto out_arp;
+
+       rc = 0;
+out:
+       return rc;
+out_arp:
+       remove_proc_entry("socket", atalk_proc_dir);
+out_socket:
+       remove_proc_entry("route", atalk_proc_dir);
+out_route:
+       remove_proc_entry("interface", atalk_proc_dir);
+out_interface:
+       remove_proc_entry("atalk", init_net.proc_net);
+       goto out;
+}
+
+void __exit atalk_proc_exit(void)
+{
+       remove_proc_entry("interface", atalk_proc_dir);
+       remove_proc_entry("route", atalk_proc_dir);
+       remove_proc_entry("socket", atalk_proc_dir);
+       remove_proc_entry("arp", atalk_proc_dir);
+       remove_proc_entry("atalk", init_net.proc_net);
+}
diff --git a/drivers/staging/appletalk/cops.c b/drivers/staging/appletalk/cops.c
new file mode 100644 (file)
index 0000000..661d42e
--- /dev/null
@@ -0,0 +1,1013 @@
+/*      cops.c: LocalTalk driver for Linux.
+ *
+ *     Authors:
+ *      - Jay Schulist <jschlst@samba.org>
+ *
+ *     With more than a little help from;
+ *     - Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ *      Derived from:
+ *      - skeleton.c: A network driver outline for linux.
+ *        Written 1993-94 by Donald Becker.
+ *     - ltpc.c: A driver for the LocalTalk PC card.
+ *       Written by Bradford W. Johnson.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *     Changes:
+ *     19970608        Alan Cox        Allowed dual card type support
+ *                                     Can set board type in insmod
+ *                                     Hooks for cops_setup routine
+ *                                     (not yet implemented).
+ *     19971101        Jay Schulist    Fixes for multiple lt* devices.
+ *     19980607        Steven Hirsch   Fixed the badly broken support
+ *                                     for Tangent type cards. Only
+ *                                      tested on Daystar LT200. Some
+ *                                      cleanup of formatting and program
+ *                                      logic.  Added emacs 'local-vars'
+ *                                      setup for Jay's brace style.
+ *     20000211        Alan Cox        Cleaned up for softnet
+ */
+
+static const char *version =
+"cops.c:v0.04 6/7/98 Jay Schulist <jschlst@samba.org>\n";
+/*
+ *  Sources:
+ *      COPS Localtalk SDK. This provides almost all of the information
+ *      needed.
+ */
+
+/*
+ * insmod/modprobe configurable stuff.
+ *     - IO Port, choose one your card supports or 0 if you dare.
+ *     - IRQ, also choose one your card supports or nothing and let
+ *       the driver figure it out.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+#include <linux/delay.h>       /* For udelay() */
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "atalk.h"
+#include "cops.h"              /* Our Stuff */
+#include "cops_ltdrv.h"                /* Firmware code for Tangent type cards. */
+#include "cops_ffdrv.h"                /* Firmware code for Dayna type cards. */
+
+/*
+ *      The name of the card. Is used for messages and in the requests for
+ *      io regions, irqs and dma channels
+ */
+
+static const char *cardname = "cops";
+
+#ifdef CONFIG_COPS_DAYNA
+static int board_type = DAYNA; /* Module exported */
+#else
+static int board_type = TANGENT;
+#endif
+
+static int io = 0x240;         /* Default IO for Dayna */
+static int irq = 5;            /* Default IRQ */
+
+/*
+ *     COPS Autoprobe information.
+ *     Right now if port address is right but IRQ is not 5 this will
+ *      return a 5 no matter what since we will still get a status response.
+ *      Need one more additional check to narrow down after we have gotten
+ *      the ioaddr. But since only other possible IRQs is 3 and 4 so no real
+ *     hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with
+ *     this driver.
+ * 
+ *     This driver has 2 modes and they are: Dayna mode and Tangent mode.
+ *     Each mode corresponds with the type of card. It has been found
+ *     that there are 2 main types of cards and all other cards are
+ *     the same and just have different names or only have minor differences
+ *     such as more IO ports. As this driver is tested it will
+ *     become more clear on exactly what cards are supported. The driver
+ *     defaults to using Dayna mode. To change the drivers mode, simply
+ *     select Dayna or Tangent mode when configuring the kernel.
+ *
+ *      This driver should support:
+ *      TANGENT driver mode:
+ *              Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
+ *             COPS LT-1
+ *      DAYNA driver mode:
+ *              Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 
+ *             Farallon PhoneNET PC III, Farallon PhoneNET PC II
+ *     Other cards possibly supported mode unknown though:
+ *             Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
+ *
+ *     Cards NOT supported by this driver but supported by the ltpc.c
+ *     driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *             Farallon PhoneNET PC
+ *             Original Apple LocalTalk PC card
+ * 
+ *      N.B.
+ *
+ *      The Daystar Digital LT200 boards do not support interrupt-driven
+ *      IO.  You must specify 'irq=0xff' as a module parameter to invoke
+ *      polled mode.  I also believe that the port probing logic is quite
+ *      dangerous at best and certainly hopeless for a polled card.  Best to 
+ *      specify both. - Steve H.
+ *
+ */
+
+/*
+ * Zero terminated list of IO ports to probe.
+ */
+
+static unsigned int ports[] = { 
+       0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 
+       0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360,
+       0
+};
+
+/*
+ * Zero terminated list of IRQ ports to probe.
+ */
+
+static int cops_irqlist[] = {
+       5, 4, 3, 0 
+};
+
+static struct timer_list cops_timer;
+
+/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
+#ifndef COPS_DEBUG
+#define COPS_DEBUG 1 
+#endif
+static unsigned int cops_debug = COPS_DEBUG;
+
+/* The number of low I/O ports used by the card. */
+#define COPS_IO_EXTENT       8
+
+/* Information that needs to be kept for each board. */
+
+struct cops_local
+{
+        int board;                     /* Holds what board type is. */
+       int nodeid;                     /* Set to 1 once have nodeid. */
+        unsigned char node_acquire;    /* Node ID when acquired. */
+        struct atalk_addr node_addr;   /* Full node address */
+       spinlock_t lock;                /* RX/TX lock */
+};
+
+/* Index to functions, as function prototypes. */
+static int  cops_probe1 (struct net_device *dev, int ioaddr);
+static int  cops_irq (int ioaddr, int board);
+
+static int  cops_open (struct net_device *dev);
+static int  cops_jumpstart (struct net_device *dev);
+static void cops_reset (struct net_device *dev, int sleep);
+static void cops_load (struct net_device *dev);
+static int  cops_nodeid (struct net_device *dev, int nodeid);
+
+static irqreturn_t cops_interrupt (int irq, void *dev_id);
+static void cops_poll (unsigned long ltdev);
+static void cops_timeout(struct net_device *dev);
+static void cops_rx (struct net_device *dev);
+static netdev_tx_t  cops_send_packet (struct sk_buff *skb,
+                                           struct net_device *dev);
+static void set_multicast_list (struct net_device *dev);
+static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int  cops_close (struct net_device *dev);
+
+static void cleanup_card(struct net_device *dev)
+{
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+       release_region(dev->base_addr, COPS_IO_EXTENT);
+}
+
+/*
+ *      Check for a network adaptor of this type, and return '0' iff one exists.
+ *      If dev->base_addr == 0, probe all likely locations.
+ *      If dev->base_addr in [1..0x1ff], always return failure.
+ *        otherwise go with what we pass in.
+ */
+struct net_device * __init cops_probe(int unit)
+{
+       struct net_device *dev;
+       unsigned *port;
+       int base_addr;
+       int err = 0;
+
+       dev = alloc_ltalkdev(sizeof(struct cops_local));
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       if (unit >= 0) {
+               sprintf(dev->name, "lt%d", unit);
+               netdev_boot_setup_check(dev);
+               irq = dev->irq;
+               base_addr = dev->base_addr;
+       } else {
+               base_addr = dev->base_addr = io;
+       }
+
+       if (base_addr > 0x1ff) {    /* Check a single specified location. */
+               err = cops_probe1(dev, base_addr);
+       } else if (base_addr != 0) { /* Don't probe at all. */
+               err = -ENXIO;
+       } else {
+               /* FIXME  Does this really work for cards which generate irq?
+                * It's definitely N.G. for polled Tangent. sh
+                * Dayna cards don't autoprobe well at all, but if your card is
+                * at IRQ 5 & IO 0x240 we find it every time. ;) JS
+                */
+               for (port = ports; *port && cops_probe1(dev, *port) < 0; port++)
+                       ;
+               if (!*port)
+                       err = -ENODEV;
+       }
+       if (err)
+               goto out;
+       err = register_netdev(dev);
+       if (err)
+               goto out1;
+       return dev;
+out1:
+       cleanup_card(dev);
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+
+static const struct net_device_ops cops_netdev_ops = {
+       .ndo_open               = cops_open,
+        .ndo_stop               = cops_close,
+       .ndo_start_xmit         = cops_send_packet,
+       .ndo_tx_timeout         = cops_timeout,
+        .ndo_do_ioctl           = cops_ioctl,
+       .ndo_set_multicast_list = set_multicast_list,
+};
+
+/*
+ *      This is the real probe routine. Linux has a history of friendly device
+ *      probes on the ISA bus. A good device probes avoids doing writes, and
+ *      verifies that the correct device exists and functions.
+ */
+static int __init cops_probe1(struct net_device *dev, int ioaddr)
+{
+        struct cops_local *lp;
+       static unsigned version_printed;
+       int board = board_type;
+       int retval;
+       
+        if(cops_debug && version_printed++ == 0)
+               printk("%s", version);
+
+       /* Grab the region so no one else tries to probe our ioports. */
+       if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name))
+               return -EBUSY;
+
+        /*
+         * Since this board has jumpered interrupts, allocate the interrupt
+         * vector now. There is no point in waiting since no other device
+         * can use the interrupt, and this marks the irq as busy. Jumpered
+         * interrupts are typically not reported by the boards, and we must
+         * used AutoIRQ to find them.
+        */
+       dev->irq = irq;
+       switch (dev->irq)
+       {
+               case 0:
+                       /* COPS AutoIRQ routine */
+                       dev->irq = cops_irq(ioaddr, board);
+                       if (dev->irq)
+                               break;
+                       /* No IRQ found on this port, fallthrough */
+               case 1:
+                       retval = -EINVAL;
+                       goto err_out;
+
+               /* Fixup for users that don't know that IRQ 2 is really
+                * IRQ 9, or don't know which one to set.
+                */
+               case 2:
+                       dev->irq = 9;
+                       break;
+
+               /* Polled operation requested. Although irq of zero passed as
+                * a parameter tells the init routines to probe, we'll
+                * overload it to denote polled operation at runtime.
+                */
+               case 0xff:
+                       dev->irq = 0;
+                       break;
+
+               default:
+                       break;
+       }
+
+       /* Reserve any actual interrupt. */
+       if (dev->irq) {
+               retval = request_irq(dev->irq, cops_interrupt, 0, dev->name, dev);
+               if (retval)
+                       goto err_out;
+       }
+
+       dev->base_addr = ioaddr;
+
+        lp = netdev_priv(dev);
+        spin_lock_init(&lp->lock);
+
+       /* Copy local board variable to lp struct. */
+       lp->board               = board;
+
+       dev->netdev_ops         = &cops_netdev_ops;
+       dev->watchdog_timeo     = HZ * 2;
+
+
+       /* Tell the user where the card is and what mode we're in. */
+       if(board==DAYNA)
+               printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
+                       dev->name, cardname, ioaddr, dev->irq);
+       if(board==TANGENT) {
+               if(dev->irq)
+                       printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
+                               dev->name, cardname, ioaddr, dev->irq);
+               else
+                       printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
+                               dev->name, cardname, ioaddr);
+
+       }
+        return 0;
+
+err_out:
+       release_region(ioaddr, COPS_IO_EXTENT);
+       return retval;
+}
+
+static int __init cops_irq (int ioaddr, int board)
+{       /*
+         * This does not use the IRQ to determine where the IRQ is. We just
+         * assume that when we get a correct status response that it's the IRQ.
+         * This really just verifies the IO port but since we only have access
+         * to such a small number of IRQs (5, 4, 3) this is not bad.
+         * This will probably not work for more than one card.
+         */
+        int irqaddr=0;
+        int i, x, status;
+
+        if(board==DAYNA)
+        {
+                outb(0, ioaddr+DAYNA_RESET);
+                inb(ioaddr+DAYNA_RESET);
+                mdelay(333);
+        }
+        if(board==TANGENT)
+        {
+                inb(ioaddr);
+                outb(0, ioaddr);
+                outb(0, ioaddr+TANG_RESET);
+        }
+
+        for(i=0; cops_irqlist[i] !=0; i++)
+        {
+                irqaddr = cops_irqlist[i];
+                for(x = 0xFFFF; x>0; x --)    /* wait for response */
+                {
+                        if(board==DAYNA)
+                        {
+                                status = (inb(ioaddr+DAYNA_CARD_STATUS)&3);
+                                if(status == 1)
+                                        return irqaddr;
+                        }
+                        if(board==TANGENT)
+                        {
+                                if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0)
+                                        return irqaddr;
+                        }
+                }
+        }
+        return 0;       /* no IRQ found */
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ */
+static int cops_open(struct net_device *dev)
+{
+    struct cops_local *lp = netdev_priv(dev);
+
+       if(dev->irq==0)
+       {
+               /*
+                * I don't know if the Dayna-style boards support polled 
+                * operation.  For now, only allow it for Tangent.
+                */
+               if(lp->board==TANGENT)  /* Poll 20 times per second */
+               {
+                   init_timer(&cops_timer);
+                   cops_timer.function = cops_poll;
+                   cops_timer.data     = (unsigned long)dev;
+                   cops_timer.expires  = jiffies + HZ/20;
+                   add_timer(&cops_timer);
+               } 
+               else 
+               {
+                       printk(KERN_WARNING "%s: No irq line set\n", dev->name);
+                       return -EAGAIN;
+               }
+       }
+
+       cops_jumpstart(dev);    /* Start the card up. */
+
+       netif_start_queue(dev);
+        return 0;
+}
+
+/*
+ *     This allows for a dynamic start/restart of the entire card.
+ */
+static int cops_jumpstart(struct net_device *dev)
+{
+       struct cops_local *lp = netdev_priv(dev);
+
+       /*
+         *      Once the card has the firmware loaded and has acquired
+         *      the nodeid, if it is reset it will lose it all.
+         */
+        cops_reset(dev,1);     /* Need to reset card before load firmware. */
+        cops_load(dev);                /* Load the firmware. */
+
+       /*
+        *      If atalkd already gave us a nodeid we will use that
+        *      one again, else we wait for atalkd to give us a nodeid
+        *      in cops_ioctl. This may cause a problem if someone steals
+        *      our nodeid while we are resetting.
+        */     
+       if(lp->nodeid == 1)
+               cops_nodeid(dev,lp->node_acquire);
+
+       return 0;
+}
+
+static void tangent_wait_reset(int ioaddr)
+{
+       int timeout=0;
+
+       while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+               mdelay(1);   /* Wait 1 second */
+}
+
+/*
+ *      Reset the LocalTalk board.
+ */
+static void cops_reset(struct net_device *dev, int sleep)
+{
+        struct cops_local *lp = netdev_priv(dev);
+        int ioaddr=dev->base_addr;
+
+        if(lp->board==TANGENT)
+        {
+                inb(ioaddr);           /* Clear request latch. */
+                outb(0,ioaddr);                /* Clear the TANG_TX_READY flop. */
+                outb(0, ioaddr+TANG_RESET);    /* Reset the adapter. */
+
+               tangent_wait_reset(ioaddr);
+                outb(0, ioaddr+TANG_CLEAR_INT);
+        }
+        if(lp->board==DAYNA)
+        {
+                outb(0, ioaddr+DAYNA_RESET);   /* Assert the reset port */
+                inb(ioaddr+DAYNA_RESET);       /* Clear the reset */
+               if (sleep)
+                       msleep(333);
+               else
+                       mdelay(333);
+        }
+
+       netif_wake_queue(dev);
+}
+
+static void cops_load (struct net_device *dev)
+{
+        struct ifreq ifr;
+        struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru;
+        struct cops_local *lp = netdev_priv(dev);
+        int ioaddr=dev->base_addr;
+       int length, i = 0;
+
+        strcpy(ifr.ifr_name,"lt0");
+
+        /* Get card's firmware code and do some checks on it. */
+#ifdef CONFIG_COPS_DAYNA        
+        if(lp->board==DAYNA)
+        {
+                ltf->length=sizeof(ffdrv_code);
+                ltf->data=ffdrv_code;
+        }
+        else
+#endif        
+#ifdef CONFIG_COPS_TANGENT
+        if(lp->board==TANGENT)
+        {
+                ltf->length=sizeof(ltdrv_code);
+                ltf->data=ltdrv_code;
+        }
+        else
+#endif
+       {
+               printk(KERN_INFO "%s; unsupported board type.\n", dev->name);
+               return;
+       }
+       
+        /* Check to make sure firmware is correct length. */
+        if(lp->board==DAYNA && ltf->length!=5983)
+        {
+                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);
+                return;
+        }
+        if(lp->board==TANGENT && ltf->length!=2501)
+        {
+                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);
+                return;
+        }
+
+        if(lp->board==DAYNA)
+        {
+                /*
+                 *      We must wait for a status response
+                 *      with the DAYNA board.
+                 */
+                while(++i<65536)
+                {
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)
+                                break;
+                }
+
+                if(i==65536)
+                        return;
+        }
+
+        /*
+         *      Upload the firmware and kick. Byte-by-byte works nicely here.
+         */
+       i=0;
+        length = ltf->length;
+        while(length--)
+        {
+                outb(ltf->data[i], ioaddr);
+                i++;
+        }
+
+       if(cops_debug > 1)
+               printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
+                       dev->name, i, ltf->length);
+
+        if(lp->board==DAYNA)   /* Tell Dayna to run the firmware code. */
+                outb(1, ioaddr+DAYNA_INT_CARD);
+       else                    /* Tell Tang to run the firmware code. */
+               inb(ioaddr);
+
+        if(lp->board==TANGENT)
+        {
+                tangent_wait_reset(ioaddr);
+                inb(ioaddr);   /* Clear initial ready signal. */
+        }
+}
+
+/*
+ *     Get the LocalTalk Nodeid from the card. We can suggest
+ *     any nodeid 1-254. The card will try and get that exact
+ *     address else we can specify 0 as the nodeid and the card
+ *     will autoprobe for a nodeid.
+ */
+static int cops_nodeid (struct net_device *dev, int nodeid)
+{
+       struct cops_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+
+       if(lp->board == DAYNA)
+        {
+               /* Empty any pending adapter responses. */
+                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
+                {
+                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+                               cops_rx(dev);   /* Kick any packets waiting. */
+                       schedule();
+                }
+
+                outb(2, ioaddr);               /* Output command packet length as 2. */
+                outb(0, ioaddr);
+                outb(LAP_INIT, ioaddr);        /* Send LAP_INIT command byte. */
+                outb(nodeid, ioaddr);          /* Suggest node address. */
+        }
+
+       if(lp->board == TANGENT)
+        {
+                /* Empty any pending adapter responses. */
+                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
+                {
+                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */
+                       cops_rx(dev);           /* Kick out packets waiting. */
+                       schedule();
+                }
+
+               /* Not sure what Tangent does if nodeid picked is used. */
+                if(nodeid == 0)                                /* Seed. */
+                       nodeid = jiffies&0xFF;          /* Get a random try */
+                outb(2, ioaddr);                       /* Command length LSB */
+                outb(0, ioaddr);                               /* Command length MSB */
+                outb(LAP_INIT, ioaddr);                /* Send LAP_INIT byte */
+                outb(nodeid, ioaddr);                  /* LAP address hint. */
+                outb(0xFF, ioaddr);                    /* Int. level to use */
+        }
+
+       lp->node_acquire=0;             /* Set nodeid holder to 0. */
+        while(lp->node_acquire==0)     /* Get *True* nodeid finally. */
+       {
+               outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */
+
+               if(lp->board == DAYNA)
+               {
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+                               cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
+               }
+               if(lp->board == TANGENT)
+               {       
+                       if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
+                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
+               }
+               schedule();
+       }
+
+       if(cops_debug > 1)
+               printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
+                       dev->name, lp->node_acquire);
+
+       lp->nodeid=1;   /* Set got nodeid to 1. */
+
+        return 0;
+}
+
+/*
+ *     Poll the Tangent type cards to see if we have work.
+ */
+static void cops_poll(unsigned long ltdev)
+{
+       int ioaddr, status;
+       int boguscount = 0;
+
+       struct net_device *dev = (struct net_device *)ltdev;
+
+       del_timer(&cops_timer);
+
+       if(dev == NULL)
+               return; /* We've been downed */
+
+       ioaddr = dev->base_addr;
+       do {
+               status=inb(ioaddr+TANG_CARD_STATUS);
+               if(status & TANG_RX_READY)
+                       cops_rx(dev);
+               if(status & TANG_TX_READY)
+                       netif_wake_queue(dev);
+               status = inb(ioaddr+TANG_CARD_STATUS);
+       } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+
+       /* poll 20 times per second */
+       cops_timer.expires = jiffies + HZ/20;
+       add_timer(&cops_timer);
+}
+
+/*
+ *      The typical workload of the driver:
+ *      Handle the network interface interrupts.
+ */
+static irqreturn_t cops_interrupt(int irq, void *dev_id)
+{
+        struct net_device *dev = dev_id;
+        struct cops_local *lp;
+        int ioaddr, status;
+        int boguscount = 0;
+
+        ioaddr = dev->base_addr;
+        lp = netdev_priv(dev);
+
+       if(lp->board==DAYNA)
+       {
+               do {
+                       outb(0, ioaddr + COPS_CLEAR_INT);
+                               status=inb(ioaddr+DAYNA_CARD_STATUS);
+                               if((status&0x03)==DAYNA_RX_REQUEST)
+                                       cops_rx(dev);
+                       netif_wake_queue(dev);
+               } while(++boguscount < 20);
+       }
+       else
+       {
+               do {
+                               status=inb(ioaddr+TANG_CARD_STATUS);
+                       if(status & TANG_RX_READY)
+                               cops_rx(dev);
+                       if(status & TANG_TX_READY)
+                               netif_wake_queue(dev);
+                       status=inb(ioaddr+TANG_CARD_STATUS);
+               } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+       }
+
+        return IRQ_HANDLED;
+}
+
+/*
+ *      We have a good packet(s), get it/them out of the buffers.
+ */
+static void cops_rx(struct net_device *dev)
+{
+        int pkt_len = 0;
+        int rsp_type = 0;
+        struct sk_buff *skb = NULL;
+        struct cops_local *lp = netdev_priv(dev);
+        int ioaddr = dev->base_addr;
+        int boguscount = 0;
+        unsigned long flags;
+
+
+       spin_lock_irqsave(&lp->lock, flags);
+       
+        if(lp->board==DAYNA)
+        {
+                outb(0, ioaddr);                /* Send out Zero length. */
+                outb(0, ioaddr);
+                outb(DATA_READ, ioaddr);        /* Send read command out. */
+
+                /* Wait for DMA to turn around. */
+                while(++boguscount<1000000)
+                {
+                       barrier();
+                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
+                                break;
+                }
+
+                if(boguscount==1000000)
+                {
+                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);
+                       spin_unlock_irqrestore(&lp->lock, flags);
+                        return;
+                }
+        }
+
+        /* Get response length. */
+       if(lp->board==DAYNA)
+               pkt_len = inb(ioaddr) & 0xFF;
+       else
+               pkt_len = inb(ioaddr) & 0x00FF;
+        pkt_len |= (inb(ioaddr) << 8);
+        /* Input IO code. */
+        rsp_type=inb(ioaddr);
+
+        /* Malloc up new buffer. */
+        skb = dev_alloc_skb(pkt_len);
+        if(skb == NULL)
+        {
+                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
+                       dev->name);
+                dev->stats.rx_dropped++;
+                while(pkt_len--)        /* Discard packet */
+                        inb(ioaddr);
+                spin_unlock_irqrestore(&lp->lock, flags);
+                return;
+        }
+        skb->dev = dev;
+        skb_put(skb, pkt_len);
+        skb->protocol = htons(ETH_P_LOCALTALK);
+
+        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
+
+        if(lp->board==DAYNA)
+                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
+
+        spin_unlock_irqrestore(&lp->lock, flags);  /* Restore interrupts. */
+
+        /* Check for bad response length */
+        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
+        {
+               printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
+                       dev->name, pkt_len);
+                dev->stats.tx_errors++;
+                dev_kfree_skb_any(skb);
+                return;
+        }
+
+        /* Set nodeid and then get out. */
+        if(rsp_type == LAP_INIT_RSP)
+        {      /* Nodeid taken from received packet. */
+                lp->node_acquire = skb->data[0];
+                dev_kfree_skb_any(skb);
+                return;
+        }
+
+        /* One last check to make sure we have a good packet. */
+        if(rsp_type != LAP_RESPONSE)
+        {
+                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
+                dev->stats.tx_errors++;
+                dev_kfree_skb_any(skb);
+                return;
+        }
+
+        skb_reset_mac_header(skb);    /* Point to entire packet. */
+        skb_pull(skb,3);
+        skb_reset_transport_header(skb);    /* Point to data (Skip header). */
+
+        /* Update the counters. */
+        dev->stats.rx_packets++;
+        dev->stats.rx_bytes += skb->len;
+
+        /* Send packet to a higher place. */
+        netif_rx(skb);
+}
+
+static void cops_timeout(struct net_device *dev)
+{
+        struct cops_local *lp = netdev_priv(dev);
+        int ioaddr = dev->base_addr;
+
+       dev->stats.tx_errors++;
+        if(lp->board==TANGENT)
+        {
+               if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+                               printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
+       }
+       printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
+       cops_jumpstart(dev);    /* Restart the card. */
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue(dev);
+}
+
+
+/*
+ *     Make the card transmit a LocalTalk packet.
+ */
+
+static netdev_tx_t cops_send_packet(struct sk_buff *skb,
+                                         struct net_device *dev)
+{
+        struct cops_local *lp = netdev_priv(dev);
+        int ioaddr = dev->base_addr;
+        unsigned long flags;
+
+        /*
+         * Block a timer-based transmit from overlapping. 
+        */
+        
+       netif_stop_queue(dev);
+
+       spin_lock_irqsave(&lp->lock, flags);
+       if(lp->board == DAYNA)   /* Wait for adapter transmit buffer. */
+               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
+                       cpu_relax();
+       if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
+               while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+                       cpu_relax();
+
+       /* Output IO length. */
+       outb(skb->len, ioaddr);
+       if(lp->board == DAYNA)
+                       outb(skb->len >> 8, ioaddr);
+       else
+               outb((skb->len >> 8)&0x0FF, ioaddr);
+
+       /* Output IO code. */
+       outb(LAP_WRITE, ioaddr);
+
+       if(lp->board == DAYNA)  /* Check the transmit buffer again. */
+               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+
+       outsb(ioaddr, skb->data, skb->len);     /* Send out the data. */
+
+       if(lp->board==DAYNA)    /* Dayna requires you kick the card */
+               outb(1, ioaddr+DAYNA_INT_CARD);
+
+       spin_unlock_irqrestore(&lp->lock, flags);       /* Restore interrupts. */
+
+       /* Done sending packet, update counters and cleanup. */
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+       dev_kfree_skb (skb);
+       return NETDEV_TX_OK;
+}
+
+/*
+ *     Dummy function to keep the Appletalk layer happy.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+        if(cops_debug >= 3)
+               printk("%s: set_multicast_list executed\n", dev->name);
+}
+
+/*
+ *      System ioctls for the COPS LocalTalk card.
+ */
+static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        struct cops_local *lp = netdev_priv(dev);
+        struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;
+        struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr;
+
+        switch(cmd)
+        {
+                case SIOCSIFADDR:
+                       /* Get and set the nodeid and network # atalkd wants. */
+                       cops_nodeid(dev, sa->sat_addr.s_node);
+                       aa->s_net               = sa->sat_addr.s_net;
+                        aa->s_node              = lp->node_acquire;
+
+                       /* Set broardcast address. */
+                        dev->broadcast[0]       = 0xFF;
+                       
+                       /* Set hardware address. */
+                        dev->dev_addr[0]        = aa->s_node;
+                        dev->addr_len           = 1;
+                        return 0;
+
+                case SIOCGIFADDR:
+                        sa->sat_addr.s_net      = aa->s_net;
+                        sa->sat_addr.s_node     = aa->s_node;
+                        return 0;
+
+                default:
+                        return -EOPNOTSUPP;
+        }
+}
+
+/*
+ *     The inverse routine to cops_open().
+ */
+static int cops_close(struct net_device *dev)
+{
+       struct cops_local *lp = netdev_priv(dev);
+
+       /* If we were running polled, yank the timer.
+        */
+       if(lp->board==TANGENT && dev->irq==0)
+               del_timer(&cops_timer);
+
+       netif_stop_queue(dev);
+        return 0;
+}
+
+
+#ifdef MODULE
+static struct net_device *cops_dev;
+
+MODULE_LICENSE("GPL");
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param(board_type, int, 0);
+
+static int __init cops_module_init(void)
+{
+       if (io == 0)
+               printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
+                       cardname);
+       cops_dev = cops_probe(-1);
+       if (IS_ERR(cops_dev))
+               return PTR_ERR(cops_dev);
+        return 0;
+}
+
+static void __exit cops_module_exit(void)
+{
+       unregister_netdev(cops_dev);
+       cleanup_card(cops_dev);
+       free_netdev(cops_dev);
+}
+module_init(cops_module_init);
+module_exit(cops_module_exit);
+#endif /* MODULE */
diff --git a/drivers/staging/appletalk/cops.h b/drivers/staging/appletalk/cops.h
new file mode 100644 (file)
index 0000000..fd2750b
--- /dev/null
@@ -0,0 +1,60 @@
+/*      cops.h: LocalTalk driver for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@samba.org>
+ */
+
+#ifndef __LINUX_COPSLTALK_H
+#define __LINUX_COPSLTALK_H
+
+#ifdef __KERNEL__
+
+/* Max LLAP size we will accept. */
+#define MAX_LLAP_SIZE          603
+
+/* Tangent */
+#define TANG_CARD_STATUS        1
+#define TANG_CLEAR_INT          1
+#define TANG_RESET              3
+
+#define TANG_TX_READY           1
+#define TANG_RX_READY           2
+
+/* Dayna */
+#define DAYNA_CMD_DATA          0
+#define DAYNA_CLEAR_INT         1
+#define DAYNA_CARD_STATUS       2
+#define DAYNA_INT_CARD          3
+#define DAYNA_RESET             4
+
+#define DAYNA_RX_READY          0
+#define DAYNA_TX_READY          1
+#define DAYNA_RX_REQUEST        3
+
+/* Same on both card types */
+#define COPS_CLEAR_INT  1
+
+/* LAP response codes received from the cards. */
+#define LAP_INIT        1       /* Init cmd */
+#define LAP_INIT_RSP    2       /* Init response */
+#define LAP_WRITE       3       /* Write cmd */
+#define DATA_READ       4       /* Data read */
+#define LAP_RESPONSE    4       /* Received ALAP frame response */
+#define LAP_GETSTAT     5       /* Get LAP and HW status */
+#define LAP_RSPSTAT     6       /* Status response */
+
+#endif
+
+/*
+ *     Structure to hold the firmware information.
+ */
+struct ltfirmware
+{
+        unsigned int length;
+        const unsigned char *data;
+};
+
+#define DAYNA 1
+#define TANGENT 2
+
+#endif
diff --git a/drivers/staging/appletalk/cops_ffdrv.h b/drivers/staging/appletalk/cops_ffdrv.h
new file mode 100644 (file)
index 0000000..b020050
--- /dev/null
@@ -0,0 +1,532 @@
+
+/*
+ *     The firmware this driver downloads into the Localtalk card is a
+ *     separate program and is not GPL'd source code, even though the Linux
+ *     side driver and the routine that loads this data into the card are.
+ *     
+ *     It is taken from the COPS SDK and is under the following license
+ *
+ *     This material is licensed to you strictly for use in conjunction with
+ *     the use of COPS LocalTalk adapters.
+ *     There is no charge for this SDK. And no waranty express or implied
+ *     about its fitness for any purpose. However, we will cheerefully
+ *     refund every penny you paid for this SDK...
+ *     Regards,
+ *
+ *     Thomas F. Divine
+ *     Chief Scientist
+ */
+
+
+/*      cops_ffdrv.h: LocalTalk driver firmware dump for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@samba.org>
+ */
+
+
+#ifdef CONFIG_COPS_DAYNA
+
+static const unsigned char ffdrv_code[] = {
+       58,3,0,50,228,149,33,255,255,34,226,149,
+       249,17,40,152,33,202,154,183,237,82,77,68,
+       11,107,98,19,54,0,237,176,175,50,80,0,
+       62,128,237,71,62,32,237,57,51,62,12,237,
+       57,50,237,57,54,62,6,237,57,52,62,12,
+       237,57,49,33,107,137,34,32,128,33,83,130,
+       34,40,128,33,86,130,34,42,128,33,112,130,
+       34,36,128,33,211,130,34,38,128,62,0,237,
+       57,16,33,63,148,34,34,128,237,94,205,15,
+       130,251,205,168,145,24,141,67,111,112,121,114,
+       105,103,104,116,32,40,67,41,32,49,57,56,
+       56,32,45,32,68,97,121,110,97,32,67,111,
+       109,109,117,110,105,99,97,116,105,111,110,115,
+       32,32,32,65,108,108,32,114,105,103,104,116,
+       115,32,114,101,115,101,114,118,101,100,46,32,
+       32,40,68,40,68,7,16,8,34,7,22,6,
+       16,5,12,4,8,3,6,140,0,16,39,128,
+       0,4,96,10,224,6,0,7,126,2,64,11,
+       118,12,6,13,0,14,193,15,0,5,96,3,
+       192,1,64,9,8,62,9,211,66,62,192,211,
+       66,62,100,61,32,253,6,28,33,205,129,14,
+       66,237,163,194,253,129,6,28,33,205,129,14,
+       64,237,163,194,9,130,201,62,47,50,71,152,
+       62,47,211,68,58,203,129,237,57,20,58,204,
+       129,237,57,21,33,77,152,54,132,205,233,129,
+       58,228,149,254,209,40,6,56,4,62,0,24,
+       2,219,96,33,233,149,119,230,62,33,232,149,
+       119,213,33,8,152,17,7,0,25,119,19,25,
+       119,209,201,251,237,77,245,197,213,229,221,229,
+       205,233,129,62,1,50,106,137,205,158,139,221,
+       225,225,209,193,241,251,237,77,245,197,213,219,
+       72,237,56,16,230,46,237,57,16,237,56,12,
+       58,72,152,183,32,26,6,20,17,128,2,237,
+       56,46,187,32,35,237,56,47,186,32,29,219,
+       72,230,1,32,3,5,32,232,175,50,72,152,
+       229,221,229,62,1,50,106,137,205,158,139,221,
+       225,225,24,25,62,1,50,72,152,58,201,129,
+       237,57,12,58,202,129,237,57,13,237,56,16,
+       246,17,237,57,16,209,193,241,251,237,77,245,
+       197,229,213,221,229,237,56,16,230,17,237,57,
+       16,237,56,20,58,34,152,246,16,246,8,211,
+       68,62,6,61,32,253,58,34,152,246,8,211,
+       68,58,203,129,237,57,20,58,204,129,237,57,
+       21,237,56,16,246,34,237,57,16,221,225,209,
+       225,193,241,251,237,77,33,2,0,57,126,230,
+       3,237,100,1,40,2,246,128,230,130,245,62,
+       5,211,64,241,211,64,201,229,213,243,237,56,
+       16,230,46,237,57,16,237,56,12,251,70,35,
+       35,126,254,175,202,77,133,254,129,202,15,133,
+       230,128,194,191,132,43,58,44,152,119,33,76,
+       152,119,35,62,132,119,120,254,255,40,4,58,
+       49,152,119,219,72,43,43,112,17,3,0,237,
+       56,52,230,248,237,57,52,219,72,230,1,194,
+       141,131,209,225,237,56,52,246,6,237,57,52,
+       62,1,55,251,201,62,3,211,66,62,192,211,
+       66,62,48,211,66,0,0,219,66,230,1,40,
+       4,219,67,24,240,205,203,135,58,75,152,254,
+       255,202,128,132,58,49,152,254,161,250,207,131,
+       58,34,152,211,68,62,10,211,66,62,128,211,
+       66,62,11,211,66,62,6,211,66,24,0,62,
+       14,211,66,62,33,211,66,62,1,211,66,62,
+       64,211,66,62,3,211,66,62,209,211,66,62,
+       100,71,219,66,230,1,32,6,5,32,247,195,
+       248,132,219,67,71,58,44,152,184,194,248,132,
+       62,100,71,219,66,230,1,32,6,5,32,247,
+       195,248,132,219,67,62,100,71,219,66,230,1,
+       32,6,5,32,247,195,248,132,219,67,254,133,
+       32,7,62,0,50,74,152,24,17,254,173,32,
+       7,62,1,50,74,152,24,6,254,141,194,248,
+       132,71,209,225,58,49,152,254,132,32,10,62,
+       50,205,2,134,205,144,135,24,27,254,140,32,
+       15,62,110,205,2,134,62,141,184,32,5,205,
+       144,135,24,8,62,10,205,2,134,205,8,134,
+       62,1,50,106,137,205,158,139,237,56,52,246,
+       6,237,57,52,175,183,251,201,62,20,135,237,
+       57,20,175,237,57,21,237,56,16,246,2,237,
+       57,16,237,56,20,95,237,56,21,123,254,10,
+       48,244,237,56,16,230,17,237,57,16,209,225,
+       205,144,135,62,1,50,106,137,205,158,139,237,
+       56,52,246,6,237,57,52,175,183,251,201,209,
+       225,243,219,72,230,1,40,13,62,10,211,66,
+       0,0,219,66,230,192,202,226,132,237,56,52,
+       246,6,237,57,52,62,1,55,251,201,205,203,
+       135,62,1,50,106,137,205,158,139,237,56,52,
+       246,6,237,57,52,183,251,201,209,225,62,1,
+       50,106,137,205,158,139,237,56,52,246,6,237,
+       57,52,62,2,55,251,201,209,225,243,219,72,
+       230,1,202,213,132,62,10,211,66,0,0,219,
+       66,230,192,194,213,132,229,62,1,50,106,137,
+       42,40,152,205,65,143,225,17,3,0,205,111,
+       136,62,6,211,66,58,44,152,211,66,237,56,
+       52,246,6,237,57,52,183,251,201,209,197,237,
+       56,52,230,248,237,57,52,219,72,230,1,32,
+       15,193,225,237,56,52,246,6,237,57,52,62,
+       1,55,251,201,14,23,58,37,152,254,0,40,
+       14,14,2,254,1,32,5,62,140,119,24,3,
+       62,132,119,43,43,197,205,203,135,193,62,1,
+       211,66,62,64,211,66,62,3,211,66,62,193,
+       211,66,62,100,203,39,71,219,66,230,1,32,
+       6,5,32,247,195,229,133,33,238,151,219,67,
+       71,58,44,152,184,194,229,133,119,62,100,71,
+       219,66,230,1,32,6,5,32,247,195,229,133,
+       219,67,35,119,13,32,234,193,225,62,1,50,
+       106,137,205,158,139,237,56,52,246,6,237,57,
+       52,175,183,251,201,33,234,151,35,35,62,255,
+       119,193,225,62,1,50,106,137,205,158,139,237,
+       56,52,246,6,237,57,52,175,251,201,243,61,
+       32,253,251,201,62,3,211,66,62,192,211,66,
+       58,49,152,254,140,32,19,197,229,213,17,181,
+       129,33,185,129,1,2,0,237,176,209,225,193,
+       24,27,229,213,33,187,129,58,49,152,230,15,
+       87,30,2,237,92,25,17,181,129,126,18,19,
+       35,126,18,209,225,58,34,152,246,8,211,68,
+       58,49,152,254,165,40,14,254,164,40,10,62,
+       10,211,66,62,224,211,66,24,25,58,74,152,
+       254,0,40,10,62,10,211,66,62,160,211,66,
+       24,8,62,10,211,66,62,128,211,66,62,11,
+       211,66,62,6,211,66,205,147,143,62,5,211,
+       66,62,224,211,66,62,5,211,66,62,96,211,
+       66,62,5,61,32,253,62,5,211,66,62,224,
+       211,66,62,14,61,32,253,62,5,211,66,62,
+       233,211,66,62,128,211,66,58,181,129,61,32,
+       253,62,1,211,66,62,192,211,66,1,254,19,
+       237,56,46,187,32,6,13,32,247,195,226,134,
+       62,192,211,66,0,0,219,66,203,119,40,250,
+       219,66,203,87,40,250,243,237,56,16,230,17,
+       237,57,16,237,56,20,251,62,5,211,66,62,
+       224,211,66,58,182,129,61,32,253,229,33,181,
+       129,58,183,129,203,63,119,35,58,184,129,119,
+       225,62,10,211,66,62,224,211,66,62,11,211,
+       66,62,118,211,66,62,47,211,68,62,5,211,
+       66,62,233,211,66,58,181,129,61,32,253,62,
+       5,211,66,62,224,211,66,58,182,129,61,32,
+       253,62,5,211,66,62,96,211,66,201,229,213,
+       58,50,152,230,15,87,30,2,237,92,33,187,
+       129,25,17,181,129,126,18,35,19,126,18,209,
+       225,58,71,152,246,8,211,68,58,50,152,254,
+       165,40,14,254,164,40,10,62,10,211,66,62,
+       224,211,66,24,8,62,10,211,66,62,128,211,
+       66,62,11,211,66,62,6,211,66,195,248,135,
+       62,3,211,66,62,192,211,66,197,229,213,17,
+       181,129,33,183,129,1,2,0,237,176,209,225,
+       193,62,47,211,68,62,10,211,66,62,224,211,
+       66,62,11,211,66,62,118,211,66,62,1,211,
+       66,62,0,211,66,205,147,143,195,16,136,62,
+       3,211,66,62,192,211,66,197,229,213,17,181,
+       129,33,183,129,1,2,0,237,176,209,225,193,
+       62,47,211,68,62,10,211,66,62,224,211,66,
+       62,11,211,66,62,118,211,66,205,147,143,62,
+       5,211,66,62,224,211,66,62,5,211,66,62,
+       96,211,66,62,5,61,32,253,62,5,211,66,
+       62,224,211,66,62,14,61,32,253,62,5,211,
+       66,62,233,211,66,62,128,211,66,58,181,129,
+       61,32,253,62,1,211,66,62,192,211,66,1,
+       254,19,237,56,46,187,32,6,13,32,247,195,
+       88,136,62,192,211,66,0,0,219,66,203,119,
+       40,250,219,66,203,87,40,250,62,5,211,66,
+       62,224,211,66,58,182,129,61,32,253,62,5,
+       211,66,62,96,211,66,201,197,14,67,6,0,
+       62,3,211,66,62,192,211,66,62,48,211,66,
+       0,0,219,66,230,1,40,4,219,67,24,240,
+       62,5,211,66,62,233,211,66,62,128,211,66,
+       58,181,129,61,32,253,237,163,29,62,192,211,
+       66,219,66,230,4,40,250,237,163,29,32,245,
+       219,66,230,4,40,250,62,255,71,219,66,230,
+       4,40,3,5,32,247,219,66,230,4,40,250,
+       62,5,211,66,62,224,211,66,58,182,129,61,
+       32,253,62,5,211,66,62,96,211,66,58,71,
+       152,254,1,202,18,137,62,16,211,66,62,56,
+       211,66,62,14,211,66,62,33,211,66,62,1,
+       211,66,62,248,211,66,237,56,48,246,153,230,
+       207,237,57,48,62,3,211,66,62,221,211,66,
+       193,201,58,71,152,211,68,62,10,211,66,62,
+       128,211,66,62,11,211,66,62,6,211,66,62,
+       6,211,66,58,44,152,211,66,62,16,211,66,
+       62,56,211,66,62,48,211,66,0,0,62,14,
+       211,66,62,33,211,66,62,1,211,66,62,248,
+       211,66,237,56,48,246,145,246,8,230,207,237,
+       57,48,62,3,211,66,62,221,211,66,193,201,
+       44,3,1,0,70,69,1,245,197,213,229,175,
+       50,72,152,237,56,16,230,46,237,57,16,237,
+       56,12,62,1,211,66,0,0,219,66,95,230,
+       160,32,3,195,20,139,123,230,96,194,72,139,
+       62,48,211,66,62,1,211,66,62,64,211,66,
+       237,91,40,152,205,207,143,25,43,55,237,82,
+       218,70,139,34,42,152,98,107,58,44,152,190,
+       194,210,138,35,35,62,130,190,194,200,137,62,
+       1,50,48,152,62,175,190,202,82,139,62,132,
+       190,32,44,50,50,152,62,47,50,71,152,229,
+       175,50,106,137,42,40,152,205,65,143,225,54,
+       133,43,70,58,44,152,119,43,112,17,3,0,
+       62,10,205,2,134,205,111,136,195,158,138,62,
+       140,190,32,19,50,50,152,58,233,149,230,4,
+       202,222,138,62,1,50,71,152,195,219,137,126,
+       254,160,250,185,138,254,166,242,185,138,50,50,
+       152,43,126,35,229,213,33,234,149,95,22,0,
+       25,126,254,132,40,18,254,140,40,14,58,50,
+       152,230,15,87,126,31,21,242,65,138,56,2,
+       175,119,58,50,152,230,15,87,58,233,149,230,
+       62,31,21,242,85,138,218,98,138,209,225,195,
+       20,139,58,50,152,33,100,137,230,15,95,22,
+       0,25,126,50,71,152,209,225,58,50,152,254,
+       164,250,135,138,58,73,152,254,0,40,4,54,
+       173,24,2,54,133,43,70,58,44,152,119,43,
+       112,17,3,0,205,70,135,175,50,106,137,205,
+       208,139,58,199,129,237,57,12,58,200,129,237,
+       57,13,237,56,16,246,17,237,57,16,225,209,
+       193,241,251,237,77,62,129,190,194,227,138,54,
+       130,43,70,58,44,152,119,43,112,17,3,0,
+       205,144,135,195,20,139,35,35,126,254,132,194,
+       227,138,175,50,106,137,205,158,139,24,42,58,
+       201,154,254,1,40,7,62,1,50,106,137,24,
+       237,58,106,137,254,1,202,222,138,62,128,166,
+       194,222,138,221,229,221,33,67,152,205,127,142,
+       205,109,144,221,225,225,209,193,241,251,237,77,
+       58,106,137,254,1,202,44,139,58,50,152,254,
+       164,250,44,139,58,73,152,238,1,50,73,152,
+       221,229,221,33,51,152,205,127,142,221,225,62,
+       1,50,106,137,205,158,139,195,13,139,24,208,
+       24,206,24,204,230,64,40,3,195,20,139,195,
+       20,139,43,126,33,8,152,119,35,58,44,152,
+       119,43,237,91,35,152,205,203,135,205,158,139,
+       195,13,139,175,50,78,152,62,3,211,66,62,
+       192,211,66,201,197,33,4,0,57,126,35,102,
+       111,62,1,50,106,137,219,72,205,141,139,193,
+       201,62,1,50,78,152,34,40,152,54,0,35,
+       35,54,0,195,163,139,58,78,152,183,200,229,
+       33,181,129,58,183,129,119,35,58,184,129,119,
+       225,62,47,211,68,62,14,211,66,62,193,211,
+       66,62,10,211,66,62,224,211,66,62,11,211,
+       66,62,118,211,66,195,3,140,58,78,152,183,
+       200,58,71,152,211,68,254,69,40,4,254,70,
+       32,17,58,73,152,254,0,40,10,62,10,211,
+       66,62,160,211,66,24,8,62,10,211,66,62,
+       128,211,66,62,11,211,66,62,6,211,66,62,
+       6,211,66,58,44,152,211,66,62,16,211,66,
+       62,56,211,66,62,48,211,66,0,0,219,66,
+       230,1,40,4,219,67,24,240,62,14,211,66,
+       62,33,211,66,42,40,152,205,65,143,62,1,
+       211,66,62,248,211,66,237,56,48,246,145,246,
+       8,230,207,237,57,48,62,3,211,66,62,221,
+       211,66,201,62,16,211,66,62,56,211,66,62,
+       48,211,66,0,0,219,66,230,1,40,4,219,
+       67,24,240,62,14,211,66,62,33,211,66,62,
+       1,211,66,62,248,211,66,237,56,48,246,153,
+       230,207,237,57,48,62,3,211,66,62,221,211,
+       66,201,229,213,33,234,149,95,22,0,25,126,
+       254,132,40,4,254,140,32,2,175,119,123,209,
+       225,201,6,8,14,0,31,48,1,12,16,250,
+       121,201,33,4,0,57,94,35,86,33,2,0,
+       57,126,35,102,111,221,229,34,89,152,237,83,
+       91,152,221,33,63,152,205,127,142,58,81,152,
+       50,82,152,58,80,152,135,50,80,152,205,162,
+       140,254,3,56,16,58,81,152,135,60,230,15,
+       50,81,152,175,50,80,152,24,23,58,79,152,
+       205,162,140,254,3,48,13,58,81,152,203,63,
+       50,81,152,62,255,50,79,152,58,81,152,50,
+       82,152,58,79,152,135,50,79,152,62,32,50,
+       83,152,50,84,152,237,56,16,230,17,237,57,
+       16,219,72,62,192,50,93,152,62,93,50,94,
+       152,58,93,152,61,50,93,152,32,9,58,94,
+       152,61,50,94,152,40,44,62,170,237,57,20,
+       175,237,57,21,237,56,16,246,2,237,57,16,
+       219,72,230,1,202,29,141,237,56,20,71,237,
+       56,21,120,254,10,48,237,237,56,16,230,17,
+       237,57,16,243,62,14,211,66,62,65,211,66,
+       251,58,39,152,23,23,60,50,39,152,71,58,
+       82,152,160,230,15,40,22,71,14,10,219,66,
+       230,16,202,186,141,219,72,230,1,202,186,141,
+       13,32,239,16,235,42,89,152,237,91,91,152,
+       205,47,131,48,7,61,202,186,141,195,227,141,
+       221,225,33,0,0,201,221,33,55,152,205,127,
+       142,58,84,152,61,50,84,152,40,19,58,82,
+       152,246,1,50,82,152,58,79,152,246,1,50,
+       79,152,195,29,141,221,225,33,1,0,201,221,
+       33,59,152,205,127,142,58,80,152,246,1,50,
+       80,152,58,82,152,135,246,1,50,82,152,58,
+       83,152,61,50,83,152,194,29,141,221,225,33,
+       2,0,201,221,229,33,0,0,57,17,4,0,
+       25,126,50,44,152,230,128,50,85,152,58,85,
+       152,183,40,6,221,33,88,2,24,4,221,33,
+       150,0,58,44,152,183,40,53,60,40,50,60,
+       40,47,61,61,33,86,152,119,35,119,35,54,
+       129,175,50,48,152,221,43,221,229,225,124,181,
+       40,42,33,86,152,17,3,0,205,189,140,17,
+       232,3,27,123,178,32,251,58,48,152,183,40,
+       224,58,44,152,71,62,7,128,230,127,71,58,
+       85,152,176,50,44,152,24,162,221,225,201,183,
+       221,52,0,192,221,52,1,192,221,52,2,192,
+       221,52,3,192,55,201,245,62,1,211,100,241,
+       201,245,62,1,211,96,241,201,33,2,0,57,
+       126,35,102,111,237,56,48,230,175,237,57,48,
+       62,48,237,57,49,125,237,57,32,124,237,57,
+       33,62,0,237,57,34,62,88,237,57,35,62,
+       0,237,57,36,237,57,37,33,128,2,125,237,
+       57,38,124,237,57,39,237,56,48,246,97,230,
+       207,237,57,48,62,0,237,57,0,62,0,211,
+       96,211,100,201,33,2,0,57,126,35,102,111,
+       237,56,48,230,175,237,57,48,62,12,237,57,
+       49,62,76,237,57,32,62,0,237,57,33,237,
+       57,34,125,237,57,35,124,237,57,36,62,0,
+       237,57,37,33,128,2,125,237,57,38,124,237,
+       57,39,237,56,48,246,97,230,207,237,57,48,
+       62,1,211,96,201,33,2,0,57,126,35,102,
+       111,229,237,56,48,230,87,237,57,48,125,237,
+       57,40,124,237,57,41,62,0,237,57,42,62,
+       67,237,57,43,62,0,237,57,44,58,106,137,
+       254,1,32,5,33,6,0,24,3,33,128,2,
+       125,237,57,46,124,237,57,47,237,56,50,230,
+       252,246,2,237,57,50,225,201,33,4,0,57,
+       94,35,86,33,2,0,57,126,35,102,111,237,
+       56,48,230,87,237,57,48,125,237,57,40,124,
+       237,57,41,62,0,237,57,42,62,67,237,57,
+       43,62,0,237,57,44,123,237,57,46,122,237,
+       57,47,237,56,50,230,244,246,0,237,57,50,
+       237,56,48,246,145,230,207,237,57,48,201,213,
+       237,56,46,95,237,56,47,87,237,56,46,111,
+       237,56,47,103,183,237,82,32,235,33,128,2,
+       183,237,82,209,201,213,237,56,38,95,237,56,
+       39,87,237,56,38,111,237,56,39,103,183,237,
+       82,32,235,33,128,2,183,237,82,209,201,245,
+       197,1,52,0,237,120,230,253,237,121,193,241,
+       201,245,197,1,52,0,237,120,246,2,237,121,
+       193,241,201,33,2,0,57,126,35,102,111,126,
+       35,110,103,201,33,0,0,34,102,152,34,96,
+       152,34,98,152,33,202,154,34,104,152,237,91,
+       104,152,42,226,149,183,237,82,17,0,255,25,
+       34,100,152,203,124,40,6,33,0,125,34,100,
+       152,42,104,152,35,35,35,229,205,120,139,193,
+       201,205,186,149,229,42,40,152,35,35,35,229,
+       205,39,144,193,124,230,3,103,221,117,254,221,
+       116,255,237,91,42,152,35,35,35,183,237,82,
+       32,12,17,5,0,42,42,152,205,171,149,242,
+       169,144,42,40,152,229,205,120,139,193,195,198,
+       149,237,91,42,152,42,98,152,25,34,98,152,
+       19,19,19,42,102,152,25,34,102,152,237,91,
+       100,152,33,158,253,25,237,91,102,152,205,171,
+       149,242,214,144,33,0,0,34,102,152,62,1,
+       50,95,152,205,225,144,195,198,149,58,95,152,
+       183,200,237,91,96,152,42,102,152,205,171,149,
+       242,5,145,237,91,102,152,33,98,2,25,237,
+       91,96,152,205,171,149,250,37,145,237,91,96,
+       152,42,102,152,183,237,82,32,7,42,98,152,
+       125,180,40,13,237,91,102,152,42,96,152,205,
+       171,149,242,58,145,237,91,104,152,42,102,152,
+       25,35,35,35,229,205,120,139,193,175,50,95,
+       152,201,195,107,139,205,206,149,250,255,243,205,
+       225,144,251,58,230,149,183,194,198,149,17,1,
+       0,42,98,152,205,171,149,250,198,149,62,1,
+       50,230,149,237,91,96,152,42,104,152,25,221,
+       117,252,221,116,253,237,91,104,152,42,96,152,
+       25,35,35,35,221,117,254,221,116,255,35,35,
+       35,229,205,39,144,124,230,3,103,35,35,35,
+       221,117,250,221,116,251,235,221,110,252,221,102,
+       253,115,35,114,35,54,4,62,1,211,100,211,
+       84,195,198,149,33,0,0,34,102,152,34,96,
+       152,34,98,152,33,202,154,34,104,152,237,91,
+       104,152,42,226,149,183,237,82,17,0,255,25,
+       34,100,152,33,109,152,54,0,33,107,152,229,
+       205,240,142,193,62,47,50,34,152,62,132,50,
+       49,152,205,241,145,205,61,145,58,39,152,60,
+       50,39,152,24,241,205,206,149,251,255,33,109,
+       152,126,183,202,198,149,110,221,117,251,33,109,
+       152,54,0,221,126,251,254,1,40,28,254,3,
+       40,101,254,4,202,190,147,254,5,202,147,147,
+       254,8,40,87,33,107,152,229,205,240,142,195,
+       198,149,58,201,154,183,32,21,33,111,152,126,
+       50,229,149,205,52,144,33,110,152,110,38,0,
+       229,205,11,142,193,237,91,96,152,42,104,152,
+       25,221,117,254,221,116,255,35,35,54,2,17,
+       2,0,43,43,115,35,114,58,44,152,35,35,
+       119,58,228,149,35,119,62,1,211,100,211,84,
+       62,1,50,201,154,24,169,205,153,142,58,231,
+       149,183,40,250,175,50,231,149,33,110,152,126,
+       254,255,40,91,58,233,149,230,63,183,40,83,
+       94,22,0,33,234,149,25,126,183,40,13,33,
+       110,152,94,33,234,150,25,126,254,3,32,36,
+       205,81,148,125,180,33,110,152,94,22,0,40,
+       17,33,234,149,25,54,0,33,107,152,229,205,
+       240,142,193,195,198,149,33,234,150,25,54,0,
+       33,110,152,94,22,0,33,234,149,25,126,50,
+       49,152,254,132,32,37,62,47,50,34,152,42,
+       107,152,229,33,110,152,229,205,174,140,193,193,
+       125,180,33,110,152,94,22,0,33,234,150,202,
+       117,147,25,52,195,120,147,58,49,152,254,140,
+       32,7,62,1,50,34,152,24,210,62,32,50,
+       106,152,24,19,58,49,152,95,58,106,152,163,
+       183,58,106,152,32,11,203,63,50,106,152,58,
+       106,152,183,32,231,254,2,40,51,254,4,40,
+       38,254,8,40,26,254,16,40,13,254,32,32,
+       158,62,165,50,49,152,62,69,24,190,62,164,
+       50,49,152,62,70,24,181,62,163,50,49,152,
+       175,24,173,62,162,50,49,152,62,1,24,164,
+       62,161,50,49,152,62,3,24,155,25,54,0,
+       221,126,251,254,8,40,7,58,230,149,183,202,
+       32,146,33,107,152,229,205,240,142,193,211,84,
+       195,198,149,237,91,96,152,42,104,152,25,221,
+       117,254,221,116,255,35,35,54,6,17,2,0,
+       43,43,115,35,114,58,228,149,35,35,119,58,
+       233,149,35,119,205,146,142,195,32,146,237,91,
+       96,152,42,104,152,25,229,205,160,142,193,58,
+       231,149,183,40,250,175,50,231,149,243,237,91,
+       96,152,42,104,152,25,221,117,254,221,116,255,
+       78,35,70,221,113,252,221,112,253,89,80,42,
+       98,152,183,237,82,34,98,152,203,124,40,19,
+       33,0,0,34,98,152,34,102,152,34,96,152,
+       62,1,50,95,152,24,40,221,94,252,221,86,
+       253,19,19,19,42,96,152,25,34,96,152,237,
+       91,100,152,33,158,253,25,237,91,96,152,205,
+       171,149,242,55,148,33,0,0,34,96,152,175,
+       50,230,149,251,195,32,146,245,62,1,50,231,
+       149,62,16,237,57,0,211,80,241,251,237,77,
+       201,205,186,149,229,229,33,0,0,34,37,152,
+       33,110,152,126,50,234,151,58,44,152,33,235,
+       151,119,221,54,253,0,221,54,254,0,195,230,
+       148,33,236,151,54,175,33,3,0,229,33,234,
+       151,229,205,174,140,193,193,33,236,151,126,254,
+       255,40,74,33,245,151,110,221,117,255,33,249,
+       151,126,221,166,255,221,119,255,33,253,151,126,
+       221,166,255,221,119,255,58,232,149,95,221,126,
+       255,163,221,119,255,183,40,15,230,191,33,110,
+       152,94,22,0,33,234,149,25,119,24,12,33,
+       110,152,94,22,0,33,234,149,25,54,132,33,
+       0,0,195,198,149,221,110,253,221,102,254,35,
+       221,117,253,221,116,254,17,32,0,221,110,253,
+       221,102,254,205,171,149,250,117,148,58,233,149,
+       203,87,40,84,33,1,0,34,37,152,221,54,
+       253,0,221,54,254,0,24,53,33,236,151,54,
+       175,33,3,0,229,33,234,151,229,205,174,140,
+       193,193,33,236,151,126,254,255,40,14,33,110,
+       152,94,22,0,33,234,149,25,54,140,24,159,
+       221,110,253,221,102,254,35,221,117,253,221,116,
+       254,17,32,0,221,110,253,221,102,254,205,171,
+       149,250,12,149,33,2,0,34,37,152,221,54,
+       253,0,221,54,254,0,24,54,33,236,151,54,
+       175,33,3,0,229,33,234,151,229,205,174,140,
+       193,193,33,236,151,126,254,255,40,15,33,110,
+       152,94,22,0,33,234,149,25,54,132,195,211,
+       148,221,110,253,221,102,254,35,221,117,253,221,
+       116,254,17,32,0,221,110,253,221,102,254,205,
+       171,149,250,96,149,33,1,0,195,198,149,124,
+       170,250,179,149,237,82,201,124,230,128,237,82,
+       60,201,225,253,229,221,229,221,33,0,0,221,
+       57,233,221,249,221,225,253,225,201,233,225,253,
+       229,221,229,221,33,0,0,221,57,94,35,86,
+       35,235,57,249,235,233,0,0,0,0,0,0,
+       62,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       175,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,133,1,0,0,0,63,
+       255,255,255,255,0,0,0,63,0,0,0,0,
+       0,0,0,0,0,0,0,24,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0
+       } ;
+
+#endif
diff --git a/drivers/staging/appletalk/cops_ltdrv.h b/drivers/staging/appletalk/cops_ltdrv.h
new file mode 100644 (file)
index 0000000..c699b1a
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *     The firmware this driver downloads into the Localtalk card is a
+ *     separate program and is not GPL'd source code, even though the Linux
+ *     side driver and the routine that loads this data into the card are.
+ *     
+ *     It is taken from the COPS SDK and is under the following license
+ *
+ *     This material is licensed to you strictly for use in conjunction with
+ *     the use of COPS LocalTalk adapters.
+ *     There is no charge for this SDK. And no waranty express or implied
+ *     about its fitness for any purpose. However, we will cheerefully
+ *     refund every penny you paid for this SDK...
+ *     Regards,
+ *
+ *     Thomas F. Divine
+ *     Chief Scientist
+ */
+
+
+/*      cops_ltdrv.h: LocalTalk driver firmware dump for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@samba.org>
+ */
+
+#ifdef CONFIG_COPS_TANGENT
+
+static const unsigned char ltdrv_code[] = {
+       58,3,0,50,148,10,33,143,15,62,85,119,
+       190,32,9,62,170,119,190,32,3,35,24,241,
+       34,146,10,249,17,150,10,33,143,15,183,237,
+       82,77,68,11,107,98,19,54,0,237,176,62,
+       16,237,57,51,62,0,237,57,50,237,57,54,
+       62,12,237,57,49,62,195,33,39,2,50,56,
+       0,34,57,0,237,86,205,30,2,251,205,60,
+       10,24,169,67,111,112,121,114,105,103,104,116,
+       32,40,99,41,32,49,57,56,56,45,49,57,
+       57,50,44,32,80,114,105,110,116,105,110,103,
+       32,67,111,109,109,117,110,105,99,97,116,105,
+       111,110,115,32,65,115,115,111,99,105,97,116,
+       101,115,44,32,73,110,99,46,65,108,108,32,
+       114,105,103,104,116,115,32,114,101,115,101,114,
+       118,101,100,46,32,32,4,4,22,40,255,60,
+       4,96,10,224,6,0,7,126,2,64,11,246,
+       12,6,13,0,14,193,15,0,5,96,3,192,
+       1,0,9,8,62,3,211,82,62,192,211,82,
+       201,62,3,211,82,62,213,211,82,201,62,5,
+       211,82,62,224,211,82,201,62,5,211,82,62,
+       224,211,82,201,62,5,211,82,62,96,211,82,
+       201,6,28,33,180,1,14,82,237,163,194,4,
+       2,33,39,2,34,64,0,58,3,0,230,1,
+       192,62,11,237,121,62,118,237,121,201,33,182,
+       10,54,132,205,253,1,201,245,197,213,229,42,
+       150,10,14,83,17,98,2,67,20,237,162,58,
+       179,1,95,219,82,230,1,32,6,29,32,247,
+       195,17,3,62,1,211,82,219,82,95,230,160,
+       32,10,237,162,32,225,21,32,222,195,15,3,
+       237,162,123,230,96,194,21,3,62,48,211,82,
+       62,1,211,82,175,211,82,237,91,150,10,43,
+       55,237,82,218,19,3,34,152,10,98,107,58,
+       154,10,190,32,81,62,1,50,158,10,35,35,
+       62,132,190,32,44,54,133,43,70,58,154,10,
+       119,43,112,17,3,0,205,137,3,62,16,211,
+       82,62,56,211,82,205,217,1,42,150,10,14,
+       83,17,98,2,67,20,58,178,1,95,195,59,
+       2,62,129,190,194,227,2,54,130,43,70,58,
+       154,10,119,43,112,17,3,0,205,137,3,195,
+       254,2,35,35,126,254,132,194,227,2,205,61,
+       3,24,20,62,128,166,194,222,2,221,229,221,
+       33,175,10,205,93,6,205,144,7,221,225,225,
+       209,193,241,251,237,77,221,229,221,33,159,10,
+       205,93,6,221,225,205,61,3,195,247,2,24,
+       237,24,235,24,233,230,64,40,2,24,227,24,
+       225,175,50,179,10,205,208,1,201,197,33,4,
+       0,57,126,35,102,111,205,51,3,193,201,62,
+       1,50,179,10,34,150,10,54,0,58,179,10,
+       183,200,62,14,211,82,62,193,211,82,62,10,
+       211,82,62,224,211,82,62,6,211,82,58,154,
+       10,211,82,62,16,211,82,62,56,211,82,62,
+       48,211,82,219,82,230,1,40,4,219,83,24,
+       242,62,14,211,82,62,33,211,82,62,1,211,
+       82,62,9,211,82,62,32,211,82,205,217,1,
+       201,14,83,205,208,1,24,23,14,83,205,208,
+       1,205,226,1,58,174,1,61,32,253,205,244,
+       1,58,174,1,61,32,253,205,226,1,58,175,
+       1,61,32,253,62,5,211,82,62,233,211,82,
+       62,128,211,82,58,176,1,61,32,253,237,163,
+       27,62,192,211,82,219,82,230,4,40,250,237,
+       163,27,122,179,32,243,219,82,230,4,40,250,
+       58,178,1,71,219,82,230,4,40,3,5,32,
+       247,219,82,230,4,40,250,205,235,1,58,177,
+       1,61,32,253,205,244,1,201,229,213,35,35,
+       126,230,128,194,145,4,43,58,154,10,119,43,
+       70,33,181,10,119,43,112,17,3,0,243,62,
+       10,211,82,219,82,230,128,202,41,4,209,225,
+       62,1,55,251,201,205,144,3,58,180,10,254,
+       255,202,127,4,205,217,1,58,178,1,71,219,
+       82,230,1,32,6,5,32,247,195,173,4,219,
+       83,71,58,154,10,184,194,173,4,58,178,1,
+       71,219,82,230,1,32,6,5,32,247,195,173,
+       4,219,83,58,178,1,71,219,82,230,1,32,
+       6,5,32,247,195,173,4,219,83,254,133,194,
+       173,4,58,179,1,24,4,58,179,1,135,61,
+       32,253,209,225,205,137,3,205,61,3,183,251,
+       201,209,225,243,62,10,211,82,219,82,230,128,
+       202,164,4,62,1,55,251,201,205,144,3,205,
+       61,3,183,251,201,209,225,62,2,55,251,201,
+       243,62,14,211,82,62,33,211,82,251,201,33,
+       4,0,57,94,35,86,33,2,0,57,126,35,
+       102,111,221,229,34,193,10,237,83,195,10,221,
+       33,171,10,205,93,6,58,185,10,50,186,10,
+       58,184,10,135,50,184,10,205,112,6,254,3,
+       56,16,58,185,10,135,60,230,15,50,185,10,
+       175,50,184,10,24,23,58,183,10,205,112,6,
+       254,3,48,13,58,185,10,203,63,50,185,10,
+       62,255,50,183,10,58,185,10,50,186,10,58,
+       183,10,135,50,183,10,62,32,50,187,10,50,
+       188,10,6,255,219,82,230,16,32,3,5,32,
+       247,205,180,4,6,40,219,82,230,16,40,3,
+       5,32,247,62,10,211,82,219,82,230,128,194,
+       46,5,219,82,230,16,40,214,237,95,71,58,
+       186,10,160,230,15,40,32,71,14,10,62,10,
+       211,82,219,82,230,128,202,119,5,205,180,4,
+       195,156,5,219,82,230,16,202,156,5,13,32,
+       229,16,225,42,193,10,237,91,195,10,205,252,
+       3,48,7,61,202,156,5,195,197,5,221,225,
+       33,0,0,201,221,33,163,10,205,93,6,58,
+       188,10,61,50,188,10,40,19,58,186,10,246,
+       1,50,186,10,58,183,10,246,1,50,183,10,
+       195,46,5,221,225,33,1,0,201,221,33,167,
+       10,205,93,6,58,184,10,246,1,50,184,10,
+       58,186,10,135,246,1,50,186,10,58,187,10,
+       61,50,187,10,194,46,5,221,225,33,2,0,
+       201,221,229,33,0,0,57,17,4,0,25,126,
+       50,154,10,230,128,50,189,10,58,189,10,183,
+       40,6,221,33,88,2,24,4,221,33,150,0,
+       58,154,10,183,40,49,60,40,46,61,33,190,
+       10,119,35,119,35,54,129,175,50,158,10,221,
+       43,221,229,225,124,181,40,42,33,190,10,17,
+       3,0,205,206,4,17,232,3,27,123,178,32,
+       251,58,158,10,183,40,224,58,154,10,71,62,
+       7,128,230,127,71,58,189,10,176,50,154,10,
+       24,166,221,225,201,183,221,52,0,192,221,52,
+       1,192,221,52,2,192,221,52,3,192,55,201,
+       6,8,14,0,31,48,1,12,16,250,121,201,
+       33,2,0,57,94,35,86,35,78,35,70,35,
+       126,35,102,105,79,120,68,103,237,176,201,33,
+       2,0,57,126,35,102,111,62,17,237,57,48,
+       125,237,57,40,124,237,57,41,62,0,237,57,
+       42,62,64,237,57,43,62,0,237,57,44,33,
+       128,2,125,237,57,46,124,237,57,47,62,145,
+       237,57,48,211,68,58,149,10,211,66,201,33,
+       2,0,57,126,35,102,111,62,33,237,57,48,
+       62,64,237,57,32,62,0,237,57,33,237,57,
+       34,125,237,57,35,124,237,57,36,62,0,237,
+       57,37,33,128,2,125,237,57,38,124,237,57,
+       39,62,97,237,57,48,211,67,58,149,10,211,
+       66,201,237,56,46,95,237,56,47,87,237,56,
+       46,111,237,56,47,103,183,237,82,32,235,33,
+       128,2,183,237,82,201,237,56,38,95,237,56,
+       39,87,237,56,38,111,237,56,39,103,183,237,
+       82,32,235,33,128,2,183,237,82,201,205,106,
+       10,221,110,6,221,102,7,126,35,110,103,195,
+       118,10,205,106,10,33,0,0,34,205,10,34,
+       198,10,34,200,10,33,143,15,34,207,10,237,
+       91,207,10,42,146,10,183,237,82,17,0,255,
+       25,34,203,10,203,124,40,6,33,0,125,34,
+       203,10,42,207,10,229,205,37,3,195,118,10,
+       205,106,10,229,42,150,10,35,35,35,229,205,
+       70,7,193,124,230,3,103,221,117,254,221,116,
+       255,237,91,152,10,35,35,35,183,237,82,32,
+       12,17,5,0,42,152,10,205,91,10,242,203,
+       7,42,150,10,229,205,37,3,195,118,10,237,
+       91,152,10,42,200,10,25,34,200,10,42,205,
+       10,25,34,205,10,237,91,203,10,33,158,253,
+       25,237,91,205,10,205,91,10,242,245,7,33,
+       0,0,34,205,10,62,1,50,197,10,205,5,
+       8,33,0,0,57,249,195,118,10,205,106,10,
+       58,197,10,183,202,118,10,237,91,198,10,42,
+       205,10,205,91,10,242,46,8,237,91,205,10,
+       33,98,2,25,237,91,198,10,205,91,10,250,
+       78,8,237,91,198,10,42,205,10,183,237,82,
+       32,7,42,200,10,125,180,40,13,237,91,205,
+       10,42,198,10,205,91,10,242,97,8,237,91,
+       207,10,42,205,10,25,229,205,37,3,175,50,
+       197,10,195,118,10,205,29,3,33,0,0,57,
+       249,195,118,10,205,106,10,58,202,10,183,40,
+       22,205,14,7,237,91,209,10,19,19,19,205,
+       91,10,242,139,8,33,1,0,195,118,10,33,
+       0,0,195,118,10,205,126,10,252,255,205,108,
+       8,125,180,194,118,10,237,91,200,10,33,0,
+       0,205,91,10,242,118,10,237,91,207,10,42,
+       198,10,25,221,117,254,221,116,255,35,35,35,
+       229,205,70,7,193,124,230,3,103,35,35,35,
+       221,117,252,221,116,253,229,221,110,254,221,102,
+       255,229,33,212,10,229,205,124,6,193,193,221,
+       110,252,221,102,253,34,209,10,33,211,10,54,
+       4,33,209,10,227,205,147,6,193,62,1,50,
+       202,10,243,221,94,252,221,86,253,42,200,10,
+       183,237,82,34,200,10,203,124,40,17,33,0,
+       0,34,200,10,34,205,10,34,198,10,50,197,
+       10,24,37,221,94,252,221,86,253,42,198,10,
+       25,34,198,10,237,91,203,10,33,158,253,25,
+       237,91,198,10,205,91,10,242,68,9,33,0,
+       0,34,198,10,205,5,8,33,0,0,57,249,
+       251,195,118,10,205,106,10,33,49,13,126,183,
+       40,16,205,42,7,237,91,47,13,19,19,19,
+       205,91,10,242,117,9,58,142,15,198,1,50,
+       142,15,195,118,10,33,49,13,126,254,1,40,
+       25,254,3,202,7,10,254,5,202,21,10,33,
+       49,13,54,0,33,47,13,229,205,207,6,195,
+       118,10,58,141,15,183,32,72,33,51,13,126,
+       50,149,10,205,86,7,33,50,13,126,230,127,
+       183,32,40,58,142,15,230,127,50,142,15,183,
+       32,5,198,1,50,142,15,33,50,13,126,111,
+       23,159,103,203,125,58,142,15,40,5,198,128,
+       50,142,15,33,50,13,119,33,50,13,126,111,
+       23,159,103,229,205,237,5,193,33,211,10,54,
+       2,33,2,0,34,209,10,58,154,10,33,212,
+       10,119,58,148,10,33,213,10,119,33,209,10,
+       229,205,147,6,193,24,128,42,47,13,229,33,
+       50,13,229,205,191,4,193,24,239,33,211,10,
+       54,6,33,3,0,34,209,10,58,154,10,33,
+       212,10,119,58,148,10,33,213,10,119,33,214,
+       10,54,5,33,209,10,229,205,147,6,24,200,
+       205,106,10,33,49,13,54,0,33,47,13,229,
+       205,207,6,33,209,10,227,205,147,6,193,205,
+       80,9,205,145,8,24,248,124,170,250,99,10,
+       237,82,201,124,230,128,237,82,60,201,225,253,
+       229,221,229,221,33,0,0,221,57,233,221,249,
+       221,225,253,225,201,233,225,253,229,221,229,221,
+       33,0,0,221,57,94,35,86,35,235,57,249,
+       235,233,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0
+       } ;
+
+#endif
diff --git a/drivers/staging/appletalk/ddp.c b/drivers/staging/appletalk/ddp.c
new file mode 100644 (file)
index 0000000..940dd19
--- /dev/null
@@ -0,0 +1,1981 @@
+/*
+ *     DDP:    An implementation of the AppleTalk DDP protocol for
+ *             Ethernet 'ELAP'.
+ *
+ *             Alan Cox  <alan@lxorguk.ukuu.org.uk>
+ *
+ *             With more than a little assistance from
+ *
+ *             Wesley Craig <netatalk@umich.edu>
+ *
+ *     Fixes:
+ *             Neil Horman             :       Added missing device ioctls
+ *             Michael Callahan        :       Made routing work
+ *             Wesley Craig            :       Fix probing to listen to a
+ *                                             passed node id.
+ *             Alan Cox                :       Added send/recvmsg support
+ *             Alan Cox                :       Moved at. to protinfo in
+ *                                             socket.
+ *             Alan Cox                :       Added firewall hooks.
+ *             Alan Cox                :       Supports new ARPHRD_LOOPBACK
+ *             Christer Weinigel       :       Routing and /proc fixes.
+ *             Bradford Johnson        :       LocalTalk.
+ *             Tom Dyas                :       Module support.
+ *             Alan Cox                :       Hooks for PPP (based on the
+ *                                             LocalTalk hook).
+ *             Alan Cox                :       Posix bits
+ *             Alan Cox/Mike Freeman   :       Possible fix to NBP problems
+ *             Bradford Johnson        :       IP-over-DDP (experimental)
+ *             Jay Schulist            :       Moved IP-over-DDP to its own
+ *                                             driver file. (ipddp.c & ipddp.h)
+ *             Jay Schulist            :       Made work as module with
+ *                                             AppleTalk drivers, cleaned it.
+ *             Rob Newberry            :       Added proxy AARP and AARP
+ *                                             procfs, moved probing to AARP
+ *                                             module.
+ *              Adrian Sun/
+ *              Michael Zuelsdorff      :       fix for net.0 packets. don't
+ *                                              allow illegal ether/tokentalk
+ *                                              port assignment. we lose a
+ *                                              valid localtalk port as a
+ *                                              result.
+ *             Arnaldo C. de Melo      :       Cleanup, in preparation for
+ *                                             shared skb support 8)
+ *             Arnaldo C. de Melo      :       Move proc stuff to atalk_proc.c,
+ *                                             use seq_file
+ *
+ *             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.
+ *
+ */
+
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/smp_lock.h>
+#include <linux/termios.h>     /* For TIOCOUTQ/INQ */
+#include <linux/compat.h>
+#include <linux/slab.h>
+#include <net/datalink.h>
+#include <net/psnap.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/route.h>
+#include "atalk.h"
+#include "../../net/core/kmap_skb.h"
+
+struct datalink_proto *ddp_dl, *aarp_dl;
+static const struct proto_ops atalk_dgram_ops;
+
+/**************************************************************************\
+*                                                                          *
+* Handlers for the socket list.                                            *
+*                                                                          *
+\**************************************************************************/
+
+HLIST_HEAD(atalk_sockets);
+DEFINE_RWLOCK(atalk_sockets_lock);
+
+static inline void __atalk_insert_socket(struct sock *sk)
+{
+       sk_add_node(sk, &atalk_sockets);
+}
+
+static inline void atalk_remove_socket(struct sock *sk)
+{
+       write_lock_bh(&atalk_sockets_lock);
+       sk_del_node_init(sk);
+       write_unlock_bh(&atalk_sockets_lock);
+}
+
+static struct sock *atalk_search_socket(struct sockaddr_at *to,
+                                       struct atalk_iface *atif)
+{
+       struct sock *s;
+       struct hlist_node *node;
+
+       read_lock_bh(&atalk_sockets_lock);
+       sk_for_each(s, node, &atalk_sockets) {
+               struct atalk_sock *at = at_sk(s);
+
+               if (to->sat_port != at->src_port)
+                       continue;
+
+               if (to->sat_addr.s_net == ATADDR_ANYNET &&
+                   to->sat_addr.s_node == ATADDR_BCAST)
+                       goto found;
+
+               if (to->sat_addr.s_net == at->src_net &&
+                   (to->sat_addr.s_node == at->src_node ||
+                    to->sat_addr.s_node == ATADDR_BCAST ||
+                    to->sat_addr.s_node == ATADDR_ANYNODE))
+                       goto found;
+
+               /* XXXX.0 -- we got a request for this router. make sure
+                * that the node is appropriately set. */
+               if (to->sat_addr.s_node == ATADDR_ANYNODE &&
+                   to->sat_addr.s_net != ATADDR_ANYNET &&
+                   atif->address.s_node == at->src_node) {
+                       to->sat_addr.s_node = atif->address.s_node;
+                       goto found;
+               }
+       }
+       s = NULL;
+found:
+       read_unlock_bh(&atalk_sockets_lock);
+       return s;
+}
+
+/**
+ * atalk_find_or_insert_socket - Try to find a socket matching ADDR
+ * @sk - socket to insert in the list if it is not there already
+ * @sat - address to search for
+ *
+ * Try to find a socket matching ADDR in the socket list, if found then return
+ * it. If not, insert SK into the socket list.
+ *
+ * This entire operation must execute atomically.
+ */
+static struct sock *atalk_find_or_insert_socket(struct sock *sk,
+                                               struct sockaddr_at *sat)
+{
+       struct sock *s;
+       struct hlist_node *node;
+       struct atalk_sock *at;
+
+       write_lock_bh(&atalk_sockets_lock);
+       sk_for_each(s, node, &atalk_sockets) {
+               at = at_sk(s);
+
+               if (at->src_net == sat->sat_addr.s_net &&
+                   at->src_node == sat->sat_addr.s_node &&
+                   at->src_port == sat->sat_port)
+                       goto found;
+       }
+       s = NULL;
+       __atalk_insert_socket(sk); /* Wheee, it's free, assign and insert. */
+found:
+       write_unlock_bh(&atalk_sockets_lock);
+       return s;
+}
+
+static void atalk_destroy_timer(unsigned long data)
+{
+       struct sock *sk = (struct sock *)data;
+
+       if (sk_has_allocations(sk)) {
+               sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
+               add_timer(&sk->sk_timer);
+       } else
+               sock_put(sk);
+}
+
+static inline void atalk_destroy_socket(struct sock *sk)
+{
+       atalk_remove_socket(sk);
+       skb_queue_purge(&sk->sk_receive_queue);
+
+       if (sk_has_allocations(sk)) {
+               setup_timer(&sk->sk_timer, atalk_destroy_timer,
+                               (unsigned long)sk);
+               sk->sk_timer.expires    = jiffies + SOCK_DESTROY_TIME;
+               add_timer(&sk->sk_timer);
+       } else
+               sock_put(sk);
+}
+
+/**************************************************************************\
+*                                                                          *
+* Routing tables for the AppleTalk socket layer.                           *
+*                                                                          *
+\**************************************************************************/
+
+/* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */
+struct atalk_route *atalk_routes;
+DEFINE_RWLOCK(atalk_routes_lock);
+
+struct atalk_iface *atalk_interfaces;
+DEFINE_RWLOCK(atalk_interfaces_lock);
+
+/* For probing devices or in a routerless network */
+struct atalk_route atrtr_default;
+
+/* AppleTalk interface control */
+/*
+ * Drop a device. Doesn't drop any of its routes - that is the caller's
+ * problem. Called when we down the interface or delete the address.
+ */
+static void atif_drop_device(struct net_device *dev)
+{
+       struct atalk_iface **iface = &atalk_interfaces;
+       struct atalk_iface *tmp;
+
+       write_lock_bh(&atalk_interfaces_lock);
+       while ((tmp = *iface) != NULL) {
+               if (tmp->dev == dev) {
+                       *iface = tmp->next;
+                       dev_put(dev);
+                       kfree(tmp);
+                       dev->atalk_ptr = NULL;
+               } else
+                       iface = &tmp->next;
+       }
+       write_unlock_bh(&atalk_interfaces_lock);
+}
+
+static struct atalk_iface *atif_add_device(struct net_device *dev,
+                                          struct atalk_addr *sa)
+{
+       struct atalk_iface *iface = kzalloc(sizeof(*iface), GFP_KERNEL);
+
+       if (!iface)
+               goto out;
+
+       dev_hold(dev);
+       iface->dev = dev;
+       dev->atalk_ptr = iface;
+       iface->address = *sa;
+       iface->status = 0;
+
+       write_lock_bh(&atalk_interfaces_lock);
+       iface->next = atalk_interfaces;
+       atalk_interfaces = iface;
+       write_unlock_bh(&atalk_interfaces_lock);
+out:
+       return iface;
+}
+
+/* Perform phase 2 AARP probing on our tentative address */
+static int atif_probe_device(struct atalk_iface *atif)
+{
+       int netrange = ntohs(atif->nets.nr_lastnet) -
+                       ntohs(atif->nets.nr_firstnet) + 1;
+       int probe_net = ntohs(atif->address.s_net);
+       int probe_node = atif->address.s_node;
+       int netct, nodect;
+
+       /* Offset the network we start probing with */
+       if (probe_net == ATADDR_ANYNET) {
+               probe_net = ntohs(atif->nets.nr_firstnet);
+               if (netrange)
+                       probe_net += jiffies % netrange;
+       }
+       if (probe_node == ATADDR_ANYNODE)
+               probe_node = jiffies & 0xFF;
+
+       /* Scan the networks */
+       atif->status |= ATIF_PROBE;
+       for (netct = 0; netct <= netrange; netct++) {
+               /* Sweep the available nodes from a given start */
+               atif->address.s_net = htons(probe_net);
+               for (nodect = 0; nodect < 256; nodect++) {
+                       atif->address.s_node = (nodect + probe_node) & 0xFF;
+                       if (atif->address.s_node > 0 &&
+                           atif->address.s_node < 254) {
+                               /* Probe a proposed address */
+                               aarp_probe_network(atif);
+
+                               if (!(atif->status & ATIF_PROBE_FAIL)) {
+                                       atif->status &= ~ATIF_PROBE;
+                                       return 0;
+                               }
+                       }
+                       atif->status &= ~ATIF_PROBE_FAIL;
+               }
+               probe_net++;
+               if (probe_net > ntohs(atif->nets.nr_lastnet))
+                       probe_net = ntohs(atif->nets.nr_firstnet);
+       }
+       atif->status &= ~ATIF_PROBE;
+
+       return -EADDRINUSE;     /* Network is full... */
+}
+
+
+/* Perform AARP probing for a proxy address */
+static int atif_proxy_probe_device(struct atalk_iface *atif,
+                                  struct atalk_addr* proxy_addr)
+{
+       int netrange = ntohs(atif->nets.nr_lastnet) -
+                       ntohs(atif->nets.nr_firstnet) + 1;
+       /* we probe the interface's network */
+       int probe_net = ntohs(atif->address.s_net);
+       int probe_node = ATADDR_ANYNODE;            /* we'll take anything */
+       int netct, nodect;
+
+       /* Offset the network we start probing with */
+       if (probe_net == ATADDR_ANYNET) {
+               probe_net = ntohs(atif->nets.nr_firstnet);
+               if (netrange)
+                       probe_net += jiffies % netrange;
+       }
+
+       if (probe_node == ATADDR_ANYNODE)
+               probe_node = jiffies & 0xFF;
+
+       /* Scan the networks */
+       for (netct = 0; netct <= netrange; netct++) {
+               /* Sweep the available nodes from a given start */
+               proxy_addr->s_net = htons(probe_net);
+               for (nodect = 0; nodect < 256; nodect++) {
+                       proxy_addr->s_node = (nodect + probe_node) & 0xFF;
+                       if (proxy_addr->s_node > 0 &&
+                           proxy_addr->s_node < 254) {
+                               /* Tell AARP to probe a proposed address */
+                               int ret = aarp_proxy_probe_network(atif,
+                                                                   proxy_addr);
+
+                               if (ret != -EADDRINUSE)
+                                       return ret;
+                       }
+               }
+               probe_net++;
+               if (probe_net > ntohs(atif->nets.nr_lastnet))
+                       probe_net = ntohs(atif->nets.nr_firstnet);
+       }
+
+       return -EADDRINUSE;     /* Network is full... */
+}
+
+
+struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
+{
+       struct atalk_iface *iface = dev->atalk_ptr;
+       return iface ? &iface->address : NULL;
+}
+
+static struct atalk_addr *atalk_find_primary(void)
+{
+       struct atalk_iface *fiface = NULL;
+       struct atalk_addr *retval;
+       struct atalk_iface *iface;
+
+       /*
+        * Return a point-to-point interface only if
+        * there is no non-ptp interface available.
+        */
+       read_lock_bh(&atalk_interfaces_lock);
+       for (iface = atalk_interfaces; iface; iface = iface->next) {
+               if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))
+                       fiface = iface;
+               if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+                       retval = &iface->address;
+                       goto out;
+               }
+       }
+
+       if (fiface)
+               retval = &fiface->address;
+       else if (atalk_interfaces)
+               retval = &atalk_interfaces->address;
+       else
+               retval = NULL;
+out:
+       read_unlock_bh(&atalk_interfaces_lock);
+       return retval;
+}
+
+/*
+ * Find a match for 'any network' - ie any of our interfaces with that
+ * node number will do just nicely.
+ */
+static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
+{
+       struct atalk_iface *iface = dev->atalk_ptr;
+
+       if (!iface || iface->status & ATIF_PROBE)
+               goto out_err;
+
+       if (node != ATADDR_BCAST &&
+           iface->address.s_node != node &&
+           node != ATADDR_ANYNODE)
+               goto out_err;
+out:
+       return iface;
+out_err:
+       iface = NULL;
+       goto out;
+}
+
+/* Find a match for a specific network:node pair */
+static struct atalk_iface *atalk_find_interface(__be16 net, int node)
+{
+       struct atalk_iface *iface;
+
+       read_lock_bh(&atalk_interfaces_lock);
+       for (iface = atalk_interfaces; iface; iface = iface->next) {
+               if ((node == ATADDR_BCAST ||
+                    node == ATADDR_ANYNODE ||
+                    iface->address.s_node == node) &&
+                   iface->address.s_net == net &&
+                   !(iface->status & ATIF_PROBE))
+                       break;
+
+               /* XXXX.0 -- net.0 returns the iface associated with net */
+               if (node == ATADDR_ANYNODE && net != ATADDR_ANYNET &&
+                   ntohs(iface->nets.nr_firstnet) <= ntohs(net) &&
+                   ntohs(net) <= ntohs(iface->nets.nr_lastnet))
+                       break;
+       }
+       read_unlock_bh(&atalk_interfaces_lock);
+       return iface;
+}
+
+
+/*
+ * Find a route for an AppleTalk packet. This ought to get cached in
+ * the socket (later on...). We know about host routes and the fact
+ * that a route must be direct to broadcast.
+ */
+static struct atalk_route *atrtr_find(struct atalk_addr *target)
+{
+       /*
+        * we must search through all routes unless we find a
+        * host route, because some host routes might overlap
+        * network routes
+        */
+       struct atalk_route *net_route = NULL;
+       struct atalk_route *r;
+
+       read_lock_bh(&atalk_routes_lock);
+       for (r = atalk_routes; r; r = r->next) {
+               if (!(r->flags & RTF_UP))
+                       continue;
+
+               if (r->target.s_net == target->s_net) {
+                       if (r->flags & RTF_HOST) {
+                               /*
+                                * if this host route is for the target,
+                                * the we're done
+                                */
+                               if (r->target.s_node == target->s_node)
+                                       goto out;
+                       } else
+                               /*
+                                * this route will work if there isn't a
+                                * direct host route, so cache it
+                                */
+                               net_route = r;
+               }
+       }
+
+       /*
+        * if we found a network route but not a direct host
+        * route, then return it
+        */
+       if (net_route)
+               r = net_route;
+       else if (atrtr_default.dev)
+               r = &atrtr_default;
+       else /* No route can be found */
+               r = NULL;
+out:
+       read_unlock_bh(&atalk_routes_lock);
+       return r;
+}
+
+
+/*
+ * Given an AppleTalk network, find the device to use. This can be
+ * a simple lookup.
+ */
+struct net_device *atrtr_get_dev(struct atalk_addr *sa)
+{
+       struct atalk_route *atr = atrtr_find(sa);
+       return atr ? atr->dev : NULL;
+}
+
+/* Set up a default router */
+static void atrtr_set_default(struct net_device *dev)
+{
+       atrtr_default.dev            = dev;
+       atrtr_default.flags          = RTF_UP;
+       atrtr_default.gateway.s_net  = htons(0);
+       atrtr_default.gateway.s_node = 0;
+}
+
+/*
+ * Add a router. Basically make sure it looks valid and stuff the
+ * entry in the list. While it uses netranges we always set them to one
+ * entry to work like netatalk.
+ */
+static int atrtr_create(struct rtentry *r, struct net_device *devhint)
+{
+       struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst;
+       struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway;
+       struct atalk_route *rt;
+       struct atalk_iface *iface, *riface;
+       int retval = -EINVAL;
+
+       /*
+        * Fixme: Raise/Lower a routing change semaphore for these
+        * operations.
+        */
+
+       /* Validate the request */
+       if (ta->sat_family != AF_APPLETALK ||
+           (!devhint && ga->sat_family != AF_APPLETALK))
+               goto out;
+
+       /* Now walk the routing table and make our decisions */
+       write_lock_bh(&atalk_routes_lock);
+       for (rt = atalk_routes; rt; rt = rt->next) {
+               if (r->rt_flags != rt->flags)
+                       continue;
+
+               if (ta->sat_addr.s_net == rt->target.s_net) {
+                       if (!(rt->flags & RTF_HOST))
+                               break;
+                       if (ta->sat_addr.s_node == rt->target.s_node)
+                               break;
+               }
+       }
+
+       if (!devhint) {
+               riface = NULL;
+
+               read_lock_bh(&atalk_interfaces_lock);
+               for (iface = atalk_interfaces; iface; iface = iface->next) {
+                       if (!riface &&
+                           ntohs(ga->sat_addr.s_net) >=
+                                       ntohs(iface->nets.nr_firstnet) &&
+                           ntohs(ga->sat_addr.s_net) <=
+                                       ntohs(iface->nets.nr_lastnet))
+                               riface = iface;
+
+                       if (ga->sat_addr.s_net == iface->address.s_net &&
+                           ga->sat_addr.s_node == iface->address.s_node)
+                               riface = iface;
+               }
+               read_unlock_bh(&atalk_interfaces_lock);
+
+               retval = -ENETUNREACH;
+               if (!riface)
+                       goto out_unlock;
+
+               devhint = riface->dev;
+       }
+
+       if (!rt) {
+               rt = kzalloc(sizeof(*rt), GFP_ATOMIC);
+
+               retval = -ENOBUFS;
+               if (!rt)
+                       goto out_unlock;
+
+               rt->next = atalk_routes;
+               atalk_routes = rt;
+       }
+
+       /* Fill in the routing entry */
+       rt->target  = ta->sat_addr;
+       dev_hold(devhint);
+       rt->dev     = devhint;
+       rt->flags   = r->rt_flags;
+       rt->gateway = ga->sat_addr;
+
+       retval = 0;
+out_unlock:
+       write_unlock_bh(&atalk_routes_lock);
+out:
+       return retval;
+}
+
+/* Delete a route. Find it and discard it */
+static int atrtr_delete(struct atalk_addr * addr)
+{
+       struct atalk_route **r = &atalk_routes;
+       int retval = 0;
+       struct atalk_route *tmp;
+
+       write_lock_bh(&atalk_routes_lock);
+       while ((tmp = *r) != NULL) {
+               if (tmp->target.s_net == addr->s_net &&
+                   (!(tmp->flags&RTF_GATEWAY) ||
+                    tmp->target.s_node == addr->s_node)) {
+                       *r = tmp->next;
+                       dev_put(tmp->dev);
+                       kfree(tmp);
+                       goto out;
+               }
+               r = &tmp->next;
+       }
+       retval = -ENOENT;
+out:
+       write_unlock_bh(&atalk_routes_lock);
+       return retval;
+}
+
+/*
+ * Called when a device is downed. Just throw away any routes
+ * via it.
+ */
+static void atrtr_device_down(struct net_device *dev)
+{
+       struct atalk_route **r = &atalk_routes;
+       struct atalk_route *tmp;
+
+       write_lock_bh(&atalk_routes_lock);
+       while ((tmp = *r) != NULL) {
+               if (tmp->dev == dev) {
+                       *r = tmp->next;
+                       dev_put(dev);
+                       kfree(tmp);
+               } else
+                       r = &tmp->next;
+       }
+       write_unlock_bh(&atalk_routes_lock);
+
+       if (atrtr_default.dev == dev)
+               atrtr_set_default(NULL);
+}
+
+/* Actually down the interface */
+static inline void atalk_dev_down(struct net_device *dev)
+{
+       atrtr_device_down(dev); /* Remove all routes for the device */
+       aarp_device_down(dev);  /* Remove AARP entries for the device */
+       atif_drop_device(dev);  /* Remove the device */
+}
+
+/*
+ * A device event has occurred. Watch for devices going down and
+ * delete our use of them (iface and route).
+ */
+static int ddp_device_event(struct notifier_block *this, unsigned long event,
+                           void *ptr)
+{
+       struct net_device *dev = ptr;
+
+       if (!net_eq(dev_net(dev), &init_net))
+               return NOTIFY_DONE;
+
+       if (event == NETDEV_DOWN)
+               /* Discard any use of this */
+               atalk_dev_down(dev);
+
+       return NOTIFY_DONE;
+}
+
+/* ioctl calls. Shouldn't even need touching */
+/* Device configuration ioctl calls */
+static int atif_ioctl(int cmd, void __user *arg)
+{
+       static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF };
+       struct ifreq atreq;
+       struct atalk_netrange *nr;
+       struct sockaddr_at *sa;
+       struct net_device *dev;
+       struct atalk_iface *atif;
+       int ct;
+       int limit;
+       struct rtentry rtdef;
+       int add_route;
+
+       if (copy_from_user(&atreq, arg, sizeof(atreq)))
+               return -EFAULT;
+
+       dev = __dev_get_by_name(&init_net, atreq.ifr_name);
+       if (!dev)
+               return -ENODEV;
+
+       sa = (struct sockaddr_at *)&atreq.ifr_addr;
+       atif = atalk_find_dev(dev);
+
+       switch (cmd) {
+               case SIOCSIFADDR:
+                       if (!capable(CAP_NET_ADMIN))
+                               return -EPERM;
+                       if (sa->sat_family != AF_APPLETALK)
+                               return -EINVAL;
+                       if (dev->type != ARPHRD_ETHER &&
+                           dev->type != ARPHRD_LOOPBACK &&
+                           dev->type != ARPHRD_LOCALTLK &&
+                           dev->type != ARPHRD_PPP)
+                               return -EPROTONOSUPPORT;
+
+                       nr = (struct atalk_netrange *)&sa->sat_zero[0];
+                       add_route = 1;
+
+                       /*
+                        * if this is a point-to-point iface, and we already
+                        * have an iface for this AppleTalk address, then we
+                        * should not add a route
+                        */
+                       if ((dev->flags & IFF_POINTOPOINT) &&
+                           atalk_find_interface(sa->sat_addr.s_net,
+                                                sa->sat_addr.s_node)) {
+                               printk(KERN_DEBUG "AppleTalk: point-to-point "
+                                                 "interface added with "
+                                                 "existing address\n");
+                               add_route = 0;
+                       }
+
+                       /*
+                        * Phase 1 is fine on LocalTalk but we don't do
+                        * EtherTalk phase 1. Anyone wanting to add it go ahead.
+                        */
+                       if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+                               return -EPROTONOSUPPORT;
+                       if (sa->sat_addr.s_node == ATADDR_BCAST ||
+                           sa->sat_addr.s_node == 254)
+                               return -EINVAL;
+                       if (atif) {
+                               /* Already setting address */
+                               if (atif->status & ATIF_PROBE)
+                                       return -EBUSY;
+
+                               atif->address.s_net  = sa->sat_addr.s_net;
+                               atif->address.s_node = sa->sat_addr.s_node;
+                               atrtr_device_down(dev); /* Flush old routes */
+                       } else {
+                               atif = atif_add_device(dev, &sa->sat_addr);
+                               if (!atif)
+                                       return -ENOMEM;
+                       }
+                       atif->nets = *nr;
+
+                       /*
+                        * Check if the chosen address is used. If so we
+                        * error and atalkd will try another.
+                        */
+
+                       if (!(dev->flags & IFF_LOOPBACK) &&
+                           !(dev->flags & IFF_POINTOPOINT) &&
+                           atif_probe_device(atif) < 0) {
+                               atif_drop_device(dev);
+                               return -EADDRINUSE;
+                       }
+
+                       /* Hey it worked - add the direct routes */
+                       sa = (struct sockaddr_at *)&rtdef.rt_gateway;
+                       sa->sat_family = AF_APPLETALK;
+                       sa->sat_addr.s_net  = atif->address.s_net;
+                       sa->sat_addr.s_node = atif->address.s_node;
+                       sa = (struct sockaddr_at *)&rtdef.rt_dst;
+                       rtdef.rt_flags = RTF_UP;
+                       sa->sat_family = AF_APPLETALK;
+                       sa->sat_addr.s_node = ATADDR_ANYNODE;
+                       if (dev->flags & IFF_LOOPBACK ||
+                           dev->flags & IFF_POINTOPOINT)
+                               rtdef.rt_flags |= RTF_HOST;
+
+                       /* Routerless initial state */
+                       if (nr->nr_firstnet == htons(0) &&
+                           nr->nr_lastnet == htons(0xFFFE)) {
+                               sa->sat_addr.s_net = atif->address.s_net;
+                               atrtr_create(&rtdef, dev);
+                               atrtr_set_default(dev);
+                       } else {
+                               limit = ntohs(nr->nr_lastnet);
+                               if (limit - ntohs(nr->nr_firstnet) > 4096) {
+                                       printk(KERN_WARNING "Too many routes/"
+                                                           "iface.\n");
+                                       return -EINVAL;
+                               }
+                               if (add_route)
+                                       for (ct = ntohs(nr->nr_firstnet);
+                                            ct <= limit; ct++) {
+                                               sa->sat_addr.s_net = htons(ct);
+                                               atrtr_create(&rtdef, dev);
+                                       }
+                       }
+                       dev_mc_add_global(dev, aarp_mcast);
+                       return 0;
+
+               case SIOCGIFADDR:
+                       if (!atif)
+                               return -EADDRNOTAVAIL;
+
+                       sa->sat_family = AF_APPLETALK;
+                       sa->sat_addr = atif->address;
+                       break;
+
+               case SIOCGIFBRDADDR:
+                       if (!atif)
+                               return -EADDRNOTAVAIL;
+
+                       sa->sat_family = AF_APPLETALK;
+                       sa->sat_addr.s_net = atif->address.s_net;
+                       sa->sat_addr.s_node = ATADDR_BCAST;
+                       break;
+
+               case SIOCATALKDIFADDR:
+               case SIOCDIFADDR:
+                       if (!capable(CAP_NET_ADMIN))
+                               return -EPERM;
+                       if (sa->sat_family != AF_APPLETALK)
+                               return -EINVAL;
+                       atalk_dev_down(dev);
+                       break;
+
+               case SIOCSARP:
+                       if (!capable(CAP_NET_ADMIN))
+                               return -EPERM;
+                       if (sa->sat_family != AF_APPLETALK)
+                               return -EINVAL;
+                       /*
+                        * for now, we only support proxy AARP on ELAP;
+                        * we should be able to do it for LocalTalk, too.
+                        */
+                       if (dev->type != ARPHRD_ETHER)
+                               return -EPROTONOSUPPORT;
+
+                       /*
+                        * atif points to the current interface on this network;
+                        * we aren't concerned about its current status (at
+                        * least for now), but it has all the settings about
+                        * the network we're going to probe. Consequently, it
+                        * must exist.
+                        */
+                       if (!atif)
+                               return -EADDRNOTAVAIL;
+
+                       nr = (struct atalk_netrange *)&(atif->nets);
+                       /*
+                        * Phase 1 is fine on Localtalk but we don't do
+                        * Ethertalk phase 1. Anyone wanting to add it go ahead.
+                        */
+                       if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+                               return -EPROTONOSUPPORT;
+
+                       if (sa->sat_addr.s_node == ATADDR_BCAST ||
+                           sa->sat_addr.s_node == 254)
+                               return -EINVAL;
+
+                       /*
+                        * Check if the chosen address is used. If so we
+                        * error and ATCP will try another.
+                        */
+                       if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
+                               return -EADDRINUSE;
+
+                       /*
+                        * We now have an address on the local network, and
+                        * the AARP code will defend it for us until we take it
+                        * down. We don't set up any routes right now, because
+                        * ATCP will install them manually via SIOCADDRT.
+                        */
+                       break;
+
+               case SIOCDARP:
+                       if (!capable(CAP_NET_ADMIN))
+                               return -EPERM;
+                       if (sa->sat_family != AF_APPLETALK)
+                               return -EINVAL;
+                       if (!atif)
+                               return -EADDRNOTAVAIL;
+
+                       /* give to aarp module to remove proxy entry */
+                       aarp_proxy_remove(atif->dev, &(sa->sat_addr));
+                       return 0;
+       }
+
+       return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;
+}
+
+/* Routing ioctl() calls */
+static int atrtr_ioctl(unsigned int cmd, void __user *arg)
+{
+       struct rtentry rt;
+
+       if (copy_from_user(&rt, arg, sizeof(rt)))
+               return -EFAULT;
+
+       switch (cmd) {
+               case SIOCDELRT:
+                       if (rt.rt_dst.sa_family != AF_APPLETALK)
+                               return -EINVAL;
+                       return atrtr_delete(&((struct sockaddr_at *)
+                                               &rt.rt_dst)->sat_addr);
+
+               case SIOCADDRT: {
+                       struct net_device *dev = NULL;
+                       if (rt.rt_dev) {
+                               char name[IFNAMSIZ];
+                               if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))
+                                       return -EFAULT;
+                               name[IFNAMSIZ-1] = '\0';
+                               dev = __dev_get_by_name(&init_net, name);
+                               if (!dev)
+                                       return -ENODEV;
+                       }
+                       return atrtr_create(&rt, dev);
+               }
+       }
+       return -EINVAL;
+}
+
+/**************************************************************************\
+*                                                                          *
+* Handling for system calls applied via the various interfaces to an       *
+* AppleTalk socket object.                                                 *
+*                                                                          *
+\**************************************************************************/
+
+/*
+ * Checksum: This is 'optional'. It's quite likely also a good
+ * candidate for assembler hackery 8)
+ */
+static unsigned long atalk_sum_partial(const unsigned char *data,
+                                      int len, unsigned long sum)
+{
+       /* This ought to be unwrapped neatly. I'll trust gcc for now */
+       while (len--) {
+               sum += *data++;
+               sum = rol16(sum, 1);
+       }
+       return sum;
+}
+
+/*  Checksum skb data --  similar to skb_checksum  */
+static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
+                                  int len, unsigned long sum)
+{
+       int start = skb_headlen(skb);
+       struct sk_buff *frag_iter;
+       int i, copy;
+
+       /* checksum stuff in header space */
+       if ( (copy = start - offset) > 0) {
+               if (copy > len)
+                       copy = len;
+               sum = atalk_sum_partial(skb->data + offset, copy, sum);
+               if ( (len -= copy) == 0)
+                       return sum;
+
+               offset += copy;
+       }
+
+       /* checksum stuff in frags */
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + skb_shinfo(skb)->frags[i].size;
+               if ((copy = end - offset) > 0) {
+                       u8 *vaddr;
+                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+                       if (copy > len)
+                               copy = len;
+                       vaddr = kmap_skb_frag(frag);
+                       sum = atalk_sum_partial(vaddr + frag->page_offset +
+                                                 offset - start, copy, sum);
+                       kunmap_skb_frag(vaddr);
+
+                       if (!(len -= copy))
+                               return sum;
+                       offset += copy;
+               }
+               start = end;
+       }
+
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       sum = atalk_sum_skb(frag_iter, offset - start,
+                                           copy, sum);
+                       if ((len -= copy) == 0)
+                               return sum;
+                       offset += copy;
+               }
+               start = end;
+       }
+
+       BUG_ON(len > 0);
+
+       return sum;
+}
+
+static __be16 atalk_checksum(const struct sk_buff *skb, int len)
+{
+       unsigned long sum;
+
+       /* skip header 4 bytes */
+       sum = atalk_sum_skb(skb, 4, len-4, 0);
+
+       /* Use 0xFFFF for 0. 0 itself means none */
+       return sum ? htons((unsigned short)sum) : htons(0xFFFF);
+}
+
+static struct proto ddp_proto = {
+       .name     = "DDP",
+       .owner    = THIS_MODULE,
+       .obj_size = sizeof(struct atalk_sock),
+};
+
+/*
+ * Create a socket. Initialise the socket, blank the addresses
+ * set the state.
+ */
+static int atalk_create(struct net *net, struct socket *sock, int protocol,
+                       int kern)
+{
+       struct sock *sk;
+       int rc = -ESOCKTNOSUPPORT;
+
+       if (!net_eq(net, &init_net))
+               return -EAFNOSUPPORT;
+
+       /*
+        * We permit SOCK_DGRAM and RAW is an extension. It is trivial to do
+        * and gives you the full ELAP frame. Should be handy for CAP 8)
+        */
+       if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
+               goto out;
+       rc = -ENOMEM;
+       sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto);
+       if (!sk)
+               goto out;
+       rc = 0;
+       sock->ops = &atalk_dgram_ops;
+       sock_init_data(sock, sk);
+
+       /* Checksums on by default */
+       sock_set_flag(sk, SOCK_ZAPPED);
+out:
+       return rc;
+}
+
+/* Free a socket. No work needed */
+static int atalk_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+
+       lock_kernel();
+       if (sk) {
+               sock_orphan(sk);
+               sock->sk = NULL;
+               atalk_destroy_socket(sk);
+       }
+       unlock_kernel();
+       return 0;
+}
+
+/**
+ * atalk_pick_and_bind_port - Pick a source port when one is not given
+ * @sk - socket to insert into the tables
+ * @sat - address to search for
+ *
+ * Pick a source port when one is not given. If we can find a suitable free
+ * one, we insert the socket into the tables using it.
+ *
+ * This whole operation must be atomic.
+ */
+static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat)
+{
+       int retval;
+
+       write_lock_bh(&atalk_sockets_lock);
+
+       for (sat->sat_port = ATPORT_RESERVED;
+            sat->sat_port < ATPORT_LAST;
+            sat->sat_port++) {
+               struct sock *s;
+               struct hlist_node *node;
+
+               sk_for_each(s, node, &atalk_sockets) {
+                       struct atalk_sock *at = at_sk(s);
+
+                       if (at->src_net == sat->sat_addr.s_net &&
+                           at->src_node == sat->sat_addr.s_node &&
+                           at->src_port == sat->sat_port)
+                               goto try_next_port;
+               }
+
+               /* Wheee, it's free, assign and insert. */
+               __atalk_insert_socket(sk);
+               at_sk(sk)->src_port = sat->sat_port;
+               retval = 0;
+               goto out;
+
+try_next_port:;
+       }
+
+       retval = -EBUSY;
+out:
+       write_unlock_bh(&atalk_sockets_lock);
+       return retval;
+}
+
+static int atalk_autobind(struct sock *sk)
+{
+       struct atalk_sock *at = at_sk(sk);
+       struct sockaddr_at sat;
+       struct atalk_addr *ap = atalk_find_primary();
+       int n = -EADDRNOTAVAIL;
+
+       if (!ap || ap->s_net == htons(ATADDR_ANYNET))
+               goto out;
+
+       at->src_net  = sat.sat_addr.s_net  = ap->s_net;
+       at->src_node = sat.sat_addr.s_node = ap->s_node;
+
+       n = atalk_pick_and_bind_port(sk, &sat);
+       if (!n)
+               sock_reset_flag(sk, SOCK_ZAPPED);
+out:
+       return n;
+}
+
+/* Set the address 'our end' of the connection */
+static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+       struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;
+       struct sock *sk = sock->sk;
+       struct atalk_sock *at = at_sk(sk);
+       int err;
+
+       if (!sock_flag(sk, SOCK_ZAPPED) ||
+           addr_len != sizeof(struct sockaddr_at))
+               return -EINVAL;
+
+       if (addr->sat_family != AF_APPLETALK)
+               return -EAFNOSUPPORT;
+
+       lock_kernel();
+       if (addr->sat_addr.s_net == htons(ATADDR_ANYNET)) {
+               struct atalk_addr *ap = atalk_find_primary();
+
+               err = -EADDRNOTAVAIL;
+               if (!ap)
+                       goto out;
+
+               at->src_net  = addr->sat_addr.s_net = ap->s_net;
+               at->src_node = addr->sat_addr.s_node= ap->s_node;
+       } else {
+               err = -EADDRNOTAVAIL;
+               if (!atalk_find_interface(addr->sat_addr.s_net,
+                                         addr->sat_addr.s_node))
+                       goto out;
+
+               at->src_net  = addr->sat_addr.s_net;
+               at->src_node = addr->sat_addr.s_node;
+       }
+
+       if (addr->sat_port == ATADDR_ANYPORT) {
+               err = atalk_pick_and_bind_port(sk, addr);
+
+               if (err < 0)
+                       goto out;
+       } else {
+               at->src_port = addr->sat_port;
+
+               err = -EADDRINUSE;
+               if (atalk_find_or_insert_socket(sk, addr))
+                       goto out;
+       }
+
+       sock_reset_flag(sk, SOCK_ZAPPED);
+       err = 0;
+out:
+       unlock_kernel();
+       return err;
+}
+
+/* Set the address we talk to */
+static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
+                        int addr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct atalk_sock *at = at_sk(sk);
+       struct sockaddr_at *addr;
+       int err;
+
+       sk->sk_state   = TCP_CLOSE;
+       sock->state = SS_UNCONNECTED;
+
+       if (addr_len != sizeof(*addr))
+               return -EINVAL;
+
+       addr = (struct sockaddr_at *)uaddr;
+
+       if (addr->sat_family != AF_APPLETALK)
+               return -EAFNOSUPPORT;
+
+       if (addr->sat_addr.s_node == ATADDR_BCAST &&
+           !sock_flag(sk, SOCK_BROADCAST)) {
+#if 1
+               printk(KERN_WARNING "%s is broken and did not set "
+                                   "SO_BROADCAST. It will break when 2.2 is "
+                                   "released.\n",
+                       current->comm);
+#else
+               return -EACCES;
+#endif
+       }
+
+       lock_kernel();
+       err = -EBUSY;
+       if (sock_flag(sk, SOCK_ZAPPED))
+               if (atalk_autobind(sk) < 0)
+                       goto out;
+
+       err = -ENETUNREACH;
+       if (!atrtr_get_dev(&addr->sat_addr))
+               goto out;
+
+       at->dest_port = addr->sat_port;
+       at->dest_net  = addr->sat_addr.s_net;
+       at->dest_node = addr->sat_addr.s_node;
+
+       sock->state  = SS_CONNECTED;
+       sk->sk_state = TCP_ESTABLISHED;
+       err = 0;
+out:
+       unlock_kernel();
+       return err;
+}
+
+/*
+ * Find the name of an AppleTalk socket. Just copy the right
+ * fields into the sockaddr.
+ */
+static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
+                        int *uaddr_len, int peer)
+{
+       struct sockaddr_at sat;
+       struct sock *sk = sock->sk;
+       struct atalk_sock *at = at_sk(sk);
+       int err;
+
+       lock_kernel();
+       err = -ENOBUFS;
+       if (sock_flag(sk, SOCK_ZAPPED))
+               if (atalk_autobind(sk) < 0)
+                       goto out;
+
+       *uaddr_len = sizeof(struct sockaddr_at);
+       memset(&sat.sat_zero, 0, sizeof(sat.sat_zero));
+
+       if (peer) {
+               err = -ENOTCONN;
+               if (sk->sk_state != TCP_ESTABLISHED)
+                       goto out;
+
+               sat.sat_addr.s_net  = at->dest_net;
+               sat.sat_addr.s_node = at->dest_node;
+               sat.sat_port        = at->dest_port;
+       } else {
+               sat.sat_addr.s_net  = at->src_net;
+               sat.sat_addr.s_node = at->src_node;
+               sat.sat_port        = at->src_port;
+       }
+
+       err = 0;
+       sat.sat_family = AF_APPLETALK;
+       memcpy(uaddr, &sat, sizeof(sat));
+
+out:
+       unlock_kernel();
+       return err;
+}
+
+static unsigned int atalk_poll(struct file *file, struct socket *sock,
+                          poll_table *wait)
+{
+       int err;
+       lock_kernel();
+       err = datagram_poll(file, sock, wait);
+       unlock_kernel();
+       return err;
+}
+
+#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)
+static __inline__ int is_ip_over_ddp(struct sk_buff *skb)
+{
+       return skb->data[12] == 22;
+}
+
+static int handle_ip_over_ddp(struct sk_buff *skb)
+{
+       struct net_device *dev = __dev_get_by_name(&init_net, "ipddp0");
+       struct net_device_stats *stats;
+
+       /* This needs to be able to handle ipddp"N" devices */
+       if (!dev) {
+               kfree_skb(skb);
+               return NET_RX_DROP;
+       }
+
+       skb->protocol = htons(ETH_P_IP);
+       skb_pull(skb, 13);
+       skb->dev   = dev;
+       skb_reset_transport_header(skb);
+
+       stats = netdev_priv(dev);
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len + 13;
+       return netif_rx(skb);  /* Send the SKB up to a higher place. */
+}
+#else
+/* make it easy for gcc to optimize this test out, i.e. kill the code */
+#define is_ip_over_ddp(skb) 0
+#define handle_ip_over_ddp(skb) 0
+#endif
+
+static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
+                             struct ddpehdr *ddp, __u16 len_hops, int origlen)
+{
+       struct atalk_route *rt;
+       struct atalk_addr ta;
+
+       /*
+        * Don't route multicast, etc., packets, or packets sent to "this
+        * network"
+        */
+       if (skb->pkt_type != PACKET_HOST || !ddp->deh_dnet) {
+               /*
+                * FIXME:
+                *
+                * Can it ever happen that a packet is from a PPP iface and
+                * needs to be broadcast onto the default network?
+                */
+               if (dev->type == ARPHRD_PPP)
+                       printk(KERN_DEBUG "AppleTalk: didn't forward broadcast "
+                                         "packet received from PPP iface\n");
+               goto free_it;
+       }
+
+       ta.s_net  = ddp->deh_dnet;
+       ta.s_node = ddp->deh_dnode;
+
+       /* Route the packet */
+       rt = atrtr_find(&ta);
+       /* increment hops count */
+       len_hops += 1 << 10;
+       if (!rt || !(len_hops & (15 << 10)))
+               goto free_it;
+
+       /* FIXME: use skb->cb to be able to use shared skbs */
+
+       /*
+        * Route goes through another gateway, so set the target to the
+        * gateway instead.
+        */
+
+       if (rt->flags & RTF_GATEWAY) {
+               ta.s_net  = rt->gateway.s_net;
+               ta.s_node = rt->gateway.s_node;
+       }
+
+       /* Fix up skb->len field */
+       skb_trim(skb, min_t(unsigned int, origlen,
+                           (rt->dev->hard_header_len +
+                            ddp_dl->header_length + (len_hops & 1023))));
+
+       /* FIXME: use skb->cb to be able to use shared skbs */
+       ddp->deh_len_hops = htons(len_hops);
+
+       /*
+        * Send the buffer onwards
+        *
+        * Now we must always be careful. If it's come from LocalTalk to
+        * EtherTalk it might not fit
+        *
+        * Order matters here: If a packet has to be copied to make a new
+        * headroom (rare hopefully) then it won't need unsharing.
+        *
+        * Note. ddp-> becomes invalid at the realloc.
+        */
+       if (skb_headroom(skb) < 22) {
+               /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
+               struct sk_buff *nskb = skb_realloc_headroom(skb, 32);
+               kfree_skb(skb);
+               skb = nskb;
+       } else
+               skb = skb_unshare(skb, GFP_ATOMIC);
+
+       /*
+        * If the buffer didn't vanish into the lack of space bitbucket we can
+        * send it.
+        */
+       if (skb == NULL)
+               goto drop;
+
+       if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP)
+               return NET_RX_DROP;
+       return NET_RX_SUCCESS;
+free_it:
+       kfree_skb(skb);
+drop:
+       return NET_RX_DROP;
+}
+
+/**
+ *     atalk_rcv - Receive a packet (in skb) from device dev
+ *     @skb - packet received
+ *     @dev - network device where the packet comes from
+ *     @pt - packet type
+ *
+ *     Receive a packet (in skb) from device dev. This has come from the SNAP
+ *     decoder, and on entry skb->transport_header is the DDP header, skb->len
+ *     is the DDP header, skb->len is the DDP length. The physical headers
+ *     have been extracted. PPP should probably pass frames marked as for this
+ *     layer.  [ie ARPHRD_ETHERTALK]
+ */
+static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
+                    struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct ddpehdr *ddp;
+       struct sock *sock;
+       struct atalk_iface *atif;
+       struct sockaddr_at tosat;
+       int origlen;
+       __u16 len_hops;
+
+       if (!net_eq(dev_net(dev), &init_net))
+               goto drop;
+
+       /* Don't mangle buffer if shared */
+       if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+               goto out;
+
+       /* Size check and make sure header is contiguous */
+       if (!pskb_may_pull(skb, sizeof(*ddp)))
+               goto drop;
+
+       ddp = ddp_hdr(skb);
+
+       len_hops = ntohs(ddp->deh_len_hops);
+
+       /* Trim buffer in case of stray trailing data */
+       origlen = skb->len;
+       skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));
+
+       /*
+        * Size check to see if ddp->deh_len was crap
+        * (Otherwise we'll detonate most spectacularly
+        * in the middle of atalk_checksum() or recvmsg()).
+        */
+       if (skb->len < sizeof(*ddp) || skb->len < (len_hops & 1023)) {
+               pr_debug("AppleTalk: dropping corrupted frame (deh_len=%u, "
+                        "skb->len=%u)\n", len_hops & 1023, skb->len);
+               goto drop;
+       }
+
+       /*
+        * Any checksums. Note we don't do htons() on this == is assumed to be
+        * valid for net byte orders all over the networking code...
+        */
+       if (ddp->deh_sum &&
+           atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
+               /* Not a valid AppleTalk frame - dustbin time */
+               goto drop;
+
+       /* Check the packet is aimed at us */
+       if (!ddp->deh_dnet)     /* Net 0 is 'this network' */
+               atif = atalk_find_anynet(ddp->deh_dnode, dev);
+       else
+               atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
+
+       if (!atif) {
+               /* Not ours, so we route the packet via the correct
+                * AppleTalk iface
+                */
+               return atalk_route_packet(skb, dev, ddp, len_hops, origlen);
+       }
+
+       /* if IP over DDP is not selected this code will be optimized out */
+       if (is_ip_over_ddp(skb))
+               return handle_ip_over_ddp(skb);
+       /*
+        * Which socket - atalk_search_socket() looks for a *full match*
+        * of the <net, node, port> tuple.
+        */
+       tosat.sat_addr.s_net  = ddp->deh_dnet;
+       tosat.sat_addr.s_node = ddp->deh_dnode;
+       tosat.sat_port        = ddp->deh_dport;
+
+       sock = atalk_search_socket(&tosat, atif);
+       if (!sock) /* But not one of our sockets */
+               goto drop;
+
+       /* Queue packet (standard) */
+       skb->sk = sock;
+
+       if (sock_queue_rcv_skb(sock, skb) < 0)
+               goto drop;
+
+       return NET_RX_SUCCESS;
+
+drop:
+       kfree_skb(skb);
+out:
+       return NET_RX_DROP;
+
+}
+
+/*
+ * Receive a LocalTalk frame. We make some demands on the caller here.
+ * Caller must provide enough headroom on the packet to pull the short
+ * header and append a long one.
+ */
+static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
+                    struct packet_type *pt, struct net_device *orig_dev)
+{
+       if (!net_eq(dev_net(dev), &init_net))
+               goto freeit;
+
+       /* Expand any short form frames */
+       if (skb_mac_header(skb)[2] == 1) {
+               struct ddpehdr *ddp;
+               /* Find our address */
+               struct atalk_addr *ap = atalk_find_dev_addr(dev);
+
+               if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
+                       goto freeit;
+
+               /* Don't mangle buffer if shared */
+               if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+                       return 0;
+
+               /*
+                * The push leaves us with a ddephdr not an shdr, and
+                * handily the port bytes in the right place preset.
+                */
+               ddp = (struct ddpehdr *) skb_push(skb, sizeof(*ddp) - 4);
+
+               /* Now fill in the long header */
+
+               /*
+                * These two first. The mac overlays the new source/dest
+                * network information so we MUST copy these before
+                * we write the network numbers !
+                */
+
+               ddp->deh_dnode = skb_mac_header(skb)[0];     /* From physical header */
+               ddp->deh_snode = skb_mac_header(skb)[1];     /* From physical header */
+
+               ddp->deh_dnet  = ap->s_net;     /* Network number */
+               ddp->deh_snet  = ap->s_net;
+               ddp->deh_sum   = 0;             /* No checksum */
+               /*
+                * Not sure about this bit...
+                */
+               /* Non routable, so force a drop if we slip up later */
+               ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
+       }
+       skb_reset_transport_header(skb);
+
+       return atalk_rcv(skb, dev, pt, orig_dev);
+freeit:
+       kfree_skb(skb);
+       return 0;
+}
+
+static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+                        size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct atalk_sock *at = at_sk(sk);
+       struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name;
+       int flags = msg->msg_flags;
+       int loopback = 0;
+       struct sockaddr_at local_satalk, gsat;
+       struct sk_buff *skb;
+       struct net_device *dev;
+       struct ddpehdr *ddp;
+       int size;
+       struct atalk_route *rt;
+       int err;
+
+       if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
+               return -EINVAL;
+
+       if (len > DDP_MAXSZ)
+               return -EMSGSIZE;
+
+       lock_kernel();
+       if (usat) {
+               err = -EBUSY;
+               if (sock_flag(sk, SOCK_ZAPPED))
+                       if (atalk_autobind(sk) < 0)
+                               goto out;
+
+               err = -EINVAL;
+               if (msg->msg_namelen < sizeof(*usat) ||
+                   usat->sat_family != AF_APPLETALK)
+                       goto out;
+
+               err = -EPERM;
+               /* netatalk didn't implement this check */
+               if (usat->sat_addr.s_node == ATADDR_BCAST &&
+                   !sock_flag(sk, SOCK_BROADCAST)) {
+                       goto out;
+               }
+       } else {
+               err = -ENOTCONN;
+               if (sk->sk_state != TCP_ESTABLISHED)
+                       goto out;
+               usat = &local_satalk;
+               usat->sat_family      = AF_APPLETALK;
+               usat->sat_port        = at->dest_port;
+               usat->sat_addr.s_node = at->dest_node;
+               usat->sat_addr.s_net  = at->dest_net;
+       }
+
+       /* Build a packet */
+       SOCK_DEBUG(sk, "SK %p: Got address.\n", sk);
+
+       /* For headers */
+       size = sizeof(struct ddpehdr) + len + ddp_dl->header_length;
+
+       if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
+               rt = atrtr_find(&usat->sat_addr);
+       } else {
+               struct atalk_addr at_hint;
+
+               at_hint.s_node = 0;
+               at_hint.s_net  = at->src_net;
+
+               rt = atrtr_find(&at_hint);
+       }
+       err = ENETUNREACH;
+       if (!rt)
+               goto out;
+
+       dev = rt->dev;
+
+       SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",
+                       sk, size, dev->name);
+
+       size += dev->hard_header_len;
+       skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
+       if (!skb)
+               goto out;
+
+       skb->sk = sk;
+       skb_reserve(skb, ddp_dl->header_length);
+       skb_reserve(skb, dev->hard_header_len);
+       skb->dev = dev;
+
+       SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
+
+       ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
+       ddp->deh_len_hops  = htons(len + sizeof(*ddp));
+       ddp->deh_dnet  = usat->sat_addr.s_net;
+       ddp->deh_snet  = at->src_net;
+       ddp->deh_dnode = usat->sat_addr.s_node;
+       ddp->deh_snode = at->src_node;
+       ddp->deh_dport = usat->sat_port;
+       ddp->deh_sport = at->src_port;
+
+       SOCK_DEBUG(sk, "SK %p: Copy user data (%Zd bytes).\n", sk, len);
+
+       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+       if (err) {
+               kfree_skb(skb);
+               err = -EFAULT;
+               goto out;
+       }
+
+       if (sk->sk_no_check == 1)
+               ddp->deh_sum = 0;
+       else
+               ddp->deh_sum = atalk_checksum(skb, len + sizeof(*ddp));
+
+       /*
+        * Loopback broadcast packets to non gateway targets (ie routes
+        * to group we are in)
+        */
+       if (ddp->deh_dnode == ATADDR_BCAST &&
+           !(rt->flags & RTF_GATEWAY) && !(dev->flags & IFF_LOOPBACK)) {
+               struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL);
+
+               if (skb2) {
+                       loopback = 1;
+                       SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);
+                       /*
+                        * If it fails it is queued/sent above in the aarp queue
+                        */
+                       aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL);
+               }
+       }
+
+       if (dev->flags & IFF_LOOPBACK || loopback) {
+               SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
+               /* loop back */
+               skb_orphan(skb);
+               if (ddp->deh_dnode == ATADDR_BCAST) {
+                       struct atalk_addr at_lo;
+
+                       at_lo.s_node = 0;
+                       at_lo.s_net  = 0;
+
+                       rt = atrtr_find(&at_lo);
+                       if (!rt) {
+                               kfree_skb(skb);
+                               err = -ENETUNREACH;
+                               goto out;
+                       }
+                       dev = rt->dev;
+                       skb->dev = dev;
+               }
+               ddp_dl->request(ddp_dl, skb, dev->dev_addr);
+       } else {
+               SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
+               if (rt->flags & RTF_GATEWAY) {
+                   gsat.sat_addr = rt->gateway;
+                   usat = &gsat;
+               }
+
+               /*
+                * If it fails it is queued/sent above in the aarp queue
+                */
+               aarp_send_ddp(dev, skb, &usat->sat_addr, NULL);
+       }
+       SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len);
+
+out:
+       unlock_kernel();
+       return err ? : len;
+}
+
+static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+                        size_t size, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
+       struct ddpehdr *ddp;
+       int copied = 0;
+       int offset = 0;
+       int err = 0;
+       struct sk_buff *skb;
+
+       lock_kernel();
+       skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+                                               flags & MSG_DONTWAIT, &err);
+       if (!skb)
+               goto out;
+
+       /* FIXME: use skb->cb to be able to use shared skbs */
+       ddp = ddp_hdr(skb);
+       copied = ntohs(ddp->deh_len_hops) & 1023;
+
+       if (sk->sk_type != SOCK_RAW) {
+               offset = sizeof(*ddp);
+               copied -= offset;
+       }
+
+       if (copied > size) {
+               copied = size;
+               msg->msg_flags |= MSG_TRUNC;
+       }
+       err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
+
+       if (!err) {
+               if (sat) {
+                       sat->sat_family      = AF_APPLETALK;
+                       sat->sat_port        = ddp->deh_sport;
+                       sat->sat_addr.s_node = ddp->deh_snode;
+                       sat->sat_addr.s_net  = ddp->deh_snet;
+               }
+               msg->msg_namelen = sizeof(*sat);
+       }
+
+       skb_free_datagram(sk, skb);     /* Free the datagram. */
+
+out:
+       unlock_kernel();
+       return err ? : copied;
+}
+
+
+/*
+ * AppleTalk ioctl calls.
+ */
+static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       int rc = -ENOIOCTLCMD;
+       struct sock *sk = sock->sk;
+       void __user *argp = (void __user *)arg;
+
+       switch (cmd) {
+               /* Protocol layer */
+               case TIOCOUTQ: {
+                       long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
+
+                       if (amount < 0)
+                               amount = 0;
+                       rc = put_user(amount, (int __user *)argp);
+                       break;
+               }
+               case TIOCINQ: {
+                       /*
+                        * These two are safe on a single CPU system as only
+                        * user tasks fiddle here
+                        */
+                       struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
+                       long amount = 0;
+
+                       if (skb)
+                               amount = skb->len - sizeof(struct ddpehdr);
+                       rc = put_user(amount, (int __user *)argp);
+                       break;
+               }
+               case SIOCGSTAMP:
+                       rc = sock_get_timestamp(sk, argp);
+                       break;
+               case SIOCGSTAMPNS:
+                       rc = sock_get_timestampns(sk, argp);
+                       break;
+               /* Routing */
+               case SIOCADDRT:
+               case SIOCDELRT:
+                       rc = -EPERM;
+                       if (capable(CAP_NET_ADMIN))
+                               rc = atrtr_ioctl(cmd, argp);
+                       break;
+               /* Interface */
+               case SIOCGIFADDR:
+               case SIOCSIFADDR:
+               case SIOCGIFBRDADDR:
+               case SIOCATALKDIFADDR:
+               case SIOCDIFADDR:
+               case SIOCSARP:          /* proxy AARP */
+               case SIOCDARP:          /* proxy AARP */
+                       rtnl_lock();
+                       rc = atif_ioctl(cmd, argp);
+                       rtnl_unlock();
+                       break;
+       }
+
+       return rc;
+}
+
+
+#ifdef CONFIG_COMPAT
+static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       /*
+        * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we
+        * cannot handle it in common code. The data we access if ifreq
+        * here is compatible, so we can simply call the native
+        * handler.
+        */
+       if (cmd == SIOCATALKDIFADDR)
+               return atalk_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+
+       return -ENOIOCTLCMD;
+}
+#endif
+
+
+static const struct net_proto_family atalk_family_ops = {
+       .family         = PF_APPLETALK,
+       .create         = atalk_create,
+       .owner          = THIS_MODULE,
+};
+
+static const struct proto_ops atalk_dgram_ops = {
+       .family         = PF_APPLETALK,
+       .owner          = THIS_MODULE,
+       .release        = atalk_release,
+       .bind           = atalk_bind,
+       .connect        = atalk_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = sock_no_accept,
+       .getname        = atalk_getname,
+       .poll           = atalk_poll,
+       .ioctl          = atalk_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = atalk_compat_ioctl,
+#endif
+       .listen         = sock_no_listen,
+       .shutdown       = sock_no_shutdown,
+       .setsockopt     = sock_no_setsockopt,
+       .getsockopt     = sock_no_getsockopt,
+       .sendmsg        = atalk_sendmsg,
+       .recvmsg        = atalk_recvmsg,
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage,
+};
+
+static struct notifier_block ddp_notifier = {
+       .notifier_call  = ddp_device_event,
+};
+
+static struct packet_type ltalk_packet_type __read_mostly = {
+       .type           = cpu_to_be16(ETH_P_LOCALTALK),
+       .func           = ltalk_rcv,
+};
+
+static struct packet_type ppptalk_packet_type __read_mostly = {
+       .type           = cpu_to_be16(ETH_P_PPPTALK),
+       .func           = atalk_rcv,
+};
+
+static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B };
+
+/* Export symbols for use by drivers when AppleTalk is a module */
+EXPORT_SYMBOL(atrtr_get_dev);
+EXPORT_SYMBOL(atalk_find_dev_addr);
+
+static const char atalk_err_snap[] __initconst =
+       KERN_CRIT "Unable to register DDP with SNAP.\n";
+
+/* Called by proto.c on kernel start up */
+static int __init atalk_init(void)
+{
+       int rc = proto_register(&ddp_proto, 0);
+
+       if (rc != 0)
+               goto out;
+
+       (void)sock_register(&atalk_family_ops);
+       ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
+       if (!ddp_dl)
+               printk(atalk_err_snap);
+
+       dev_add_pack(&ltalk_packet_type);
+       dev_add_pack(&ppptalk_packet_type);
+
+       register_netdevice_notifier(&ddp_notifier);
+       aarp_proto_init();
+       atalk_proc_init();
+       atalk_register_sysctl();
+out:
+       return rc;
+}
+module_init(atalk_init);
+
+/*
+ * No explicit module reference count manipulation is needed in the
+ * protocol. Socket layer sets module reference count for us
+ * and interfaces reference counting is done
+ * by the network device layer.
+ *
+ * Ergo, before the AppleTalk module can be removed, all AppleTalk
+ * sockets be closed from user space.
+ */
+static void __exit atalk_exit(void)
+{
+#ifdef CONFIG_SYSCTL
+       atalk_unregister_sysctl();
+#endif /* CONFIG_SYSCTL */
+       atalk_proc_exit();
+       aarp_cleanup_module();  /* General aarp clean-up. */
+       unregister_netdevice_notifier(&ddp_notifier);
+       dev_remove_pack(&ltalk_packet_type);
+       dev_remove_pack(&ppptalk_packet_type);
+       unregister_snap_client(ddp_dl);
+       sock_unregister(PF_APPLETALK);
+       proto_unregister(&ddp_proto);
+}
+module_exit(atalk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
+MODULE_DESCRIPTION("AppleTalk 0.20\n");
+MODULE_ALIAS_NETPROTO(PF_APPLETALK);
diff --git a/drivers/staging/appletalk/dev.c b/drivers/staging/appletalk/dev.c
new file mode 100644 (file)
index 0000000..6c8016f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Moved here from drivers/net/net_init.c, which is:
+ *     Written 1993,1994,1995 by Donald Becker.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+
+static void ltalk_setup(struct net_device *dev)
+{
+       /* Fill in the fields of the device structure with localtalk-generic values. */
+
+       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;
+}
+
+/**
+ * alloc_ltalkdev - Allocates and sets up an localtalk device
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+ *     for this localtalk device
+ *
+ * Fill in the fields of the device structure with localtalk-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_ltalkdev(int sizeof_priv)
+{
+       return alloc_netdev(sizeof_priv, "lt%d", ltalk_setup);
+}
+EXPORT_SYMBOL(alloc_ltalkdev);
diff --git a/drivers/staging/appletalk/ipddp.c b/drivers/staging/appletalk/ipddp.c
new file mode 100644 (file)
index 0000000..58b4e60
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *     ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
+ *              Appletalk-IP to IP Decapsulation driver for Linux
+ *
+ *     Authors:
+ *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *     - DDP-IP Decap by: Jay Schulist <jschlst@samba.org>
+ *
+ *     Derived from:
+ *     - Almost all code already existed in net/appletalk/ddp.c I just
+ *       moved/reorginized it into a driver file. Original IP-over-DDP code
+ *       was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *      - skeleton.c: A network driver outline for linux.
+ *        Written 1993-94 by Donald Becker.
+ *     - dummy.c: A dummy net driver. By Nick Holloway.
+ *     - MacGate: A user space Daemon for Appletalk-IP Decap for
+ *       Linux by Jay Schulist <jschlst@samba.org>
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/slab.h>
+#include <net/route.h>
+#include <asm/uaccess.h>
+
+#include "atalk.h"
+#include "ipddp.h"             /* Our stuff */
+
+static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+
+static struct ipddp_route *ipddp_route_list;
+static DEFINE_SPINLOCK(ipddp_route_lock);
+
+#ifdef CONFIG_IPDDP_ENCAP
+static int ipddp_mode = IPDDP_ENCAP;
+#else
+static int ipddp_mode = IPDDP_DECAP;
+#endif
+
+/* Index to functions, as function prototypes. */
+static netdev_tx_t ipddp_xmit(struct sk_buff *skb,
+                                   struct net_device *dev);
+static int ipddp_create(struct ipddp_route *new_rt);
+static int ipddp_delete(struct ipddp_route *rt);
+static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
+static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+static const struct net_device_ops ipddp_netdev_ops = {
+       .ndo_start_xmit         = ipddp_xmit,
+       .ndo_do_ioctl           = ipddp_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static struct net_device * __init ipddp_init(void)
+{
+       static unsigned version_printed;
+       struct net_device *dev;
+       int err;
+
+       dev = alloc_etherdev(0);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+       strcpy(dev->name, "ipddp%d");
+
+       if (version_printed++ == 0)
+                printk(version);
+
+       /* Initialize the device structure. */
+       dev->netdev_ops = &ipddp_netdev_ops;
+
+        dev->type = ARPHRD_IPDDP;              /* IP over DDP tunnel */
+        dev->mtu = 585;
+        dev->flags |= IFF_NOARP;
+
+        /*
+         *      The worst case header we will need is currently a
+         *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
+         *      We send over SNAP so that takes another 8 bytes.
+         */
+        dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
+
+       err = register_netdev(dev);
+       if (err) {
+               free_netdev(dev);
+               return ERR_PTR(err);
+       }
+
+       /* Let the user now what mode we are in */
+       if(ipddp_mode == IPDDP_ENCAP)
+               printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
+                       dev->name);
+       if(ipddp_mode == IPDDP_DECAP)
+               printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>\n", 
+                       dev->name);
+
+        return dev;
+}
+
+
+/*
+ * Transmit LLAP/ELAP frame using aarp_send_ddp.
+ */
+static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       __be32 paddr = skb_rtable(skb)->rt_gateway;
+        struct ddpehdr *ddp;
+        struct ipddp_route *rt;
+        struct atalk_addr *our_addr;
+
+       spin_lock(&ipddp_route_lock);
+
+       /*
+         * Find appropriate route to use, based only on IP number.
+         */
+        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
+        {
+                if(rt->ip == paddr)
+                        break;
+        }
+        if(rt == NULL) {
+               spin_unlock(&ipddp_route_lock);
+                return NETDEV_TX_OK;
+       }
+
+        our_addr = atalk_find_dev_addr(rt->dev);
+
+       if(ipddp_mode == IPDDP_DECAP)
+               /* 
+                * Pull off the excess room that should not be there.
+                * This is due to a hard-header problem. This is the
+                * quick fix for now though, till it breaks.
+                */
+               skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
+
+       /* Create the Extended DDP header */
+       ddp = (struct ddpehdr *)skb->data;
+        ddp->deh_len_hops = htons(skb->len + (1<<10));
+        ddp->deh_sum = 0;
+
+       /*
+         * For Localtalk we need aarp_send_ddp to strip the
+         * long DDP header and place a shot DDP header on it.
+         */
+        if(rt->dev->type == ARPHRD_LOCALTLK)
+        {
+                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
+                ddp->deh_snet  = 0;
+        }
+        else
+        {
+                ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
+                ddp->deh_snet  = our_addr->s_net;
+        }
+        ddp->deh_dnode = rt->at.s_node;
+        ddp->deh_snode = our_addr->s_node;
+        ddp->deh_dport = 72;
+        ddp->deh_sport = 72;
+
+        *((__u8 *)(ddp+1)) = 22;               /* ddp type = IP */
+
+        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       aarp_send_ddp(rt->dev, skb, &rt->at, NULL);
+
+       spin_unlock(&ipddp_route_lock);
+
+        return NETDEV_TX_OK;
+}
+
+/*
+ * Create a routing entry. We first verify that the
+ * record does not already exist. If it does we return -EEXIST
+ */
+static int ipddp_create(struct ipddp_route *new_rt)
+{
+        struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL);
+
+        if (rt == NULL)
+                return -ENOMEM;
+
+        rt->ip = new_rt->ip;
+        rt->at = new_rt->at;
+        rt->next = NULL;
+        if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
+               kfree(rt);
+                return -ENETUNREACH;
+        }
+
+       spin_lock_bh(&ipddp_route_lock);
+       if (__ipddp_find_route(rt)) {
+               spin_unlock_bh(&ipddp_route_lock);
+               kfree(rt);
+               return -EEXIST;
+       }
+
+        rt->next = ipddp_route_list;
+        ipddp_route_list = rt;
+
+       spin_unlock_bh(&ipddp_route_lock);
+
+        return 0;
+}
+
+/*
+ * Delete a route, we only delete a FULL match.
+ * If route does not exist we return -ENOENT.
+ */
+static int ipddp_delete(struct ipddp_route *rt)
+{
+        struct ipddp_route **r = &ipddp_route_list;
+        struct ipddp_route *tmp;
+
+       spin_lock_bh(&ipddp_route_lock);
+        while((tmp = *r) != NULL)
+        {
+                if(tmp->ip == rt->ip &&
+                  tmp->at.s_net == rt->at.s_net &&
+                  tmp->at.s_node == rt->at.s_node)
+                {
+                        *r = tmp->next;
+                       spin_unlock_bh(&ipddp_route_lock);
+                        kfree(tmp);
+                        return 0;
+                }
+                r = &tmp->next;
+        }
+
+       spin_unlock_bh(&ipddp_route_lock);
+        return -ENOENT;
+}
+
+/*
+ * Find a routing entry, we only return a FULL match
+ */
+static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
+{
+        struct ipddp_route *f;
+
+        for(f = ipddp_route_list; f != NULL; f = f->next)
+        {
+                if(f->ip == rt->ip &&
+                  f->at.s_net == rt->at.s_net &&
+                  f->at.s_node == rt->at.s_node)
+                        return f;
+        }
+
+        return NULL;
+}
+
+static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        struct ipddp_route __user *rt = ifr->ifr_data;
+        struct ipddp_route rcp, rcp2, *rp;
+
+        if(!capable(CAP_NET_ADMIN))
+                return -EPERM;
+
+       if(copy_from_user(&rcp, rt, sizeof(rcp)))
+               return -EFAULT;
+
+        switch(cmd)
+        {
+               case SIOCADDIPDDPRT:
+                        return ipddp_create(&rcp);
+
+                case SIOCFINDIPDDPRT:
+                       spin_lock_bh(&ipddp_route_lock);
+                       rp = __ipddp_find_route(&rcp);
+                       if (rp)
+                               memcpy(&rcp2, rp, sizeof(rcp2));
+                       spin_unlock_bh(&ipddp_route_lock);
+
+                       if (rp) {
+                               if (copy_to_user(rt, &rcp2,
+                                                sizeof(struct ipddp_route)))
+                                       return -EFAULT;
+                               return 0;
+                       } else
+                               return -ENOENT;
+
+                case SIOCDELIPDDPRT:
+                        return ipddp_delete(&rcp);
+
+                default:
+                        return -EINVAL;
+        }
+}
+
+static struct net_device *dev_ipddp;
+
+MODULE_LICENSE("GPL");
+module_param(ipddp_mode, int, 0);
+
+static int __init ipddp_init_module(void)
+{
+       dev_ipddp = ipddp_init();
+        if (IS_ERR(dev_ipddp))
+                return PTR_ERR(dev_ipddp);
+       return 0;
+}
+
+static void __exit ipddp_cleanup_module(void)
+{
+        struct ipddp_route *p;
+
+       unregister_netdev(dev_ipddp);
+        free_netdev(dev_ipddp);
+
+        while (ipddp_route_list) {
+                p = ipddp_route_list->next;
+                kfree(ipddp_route_list);
+                ipddp_route_list = p;
+        }
+}
+
+module_init(ipddp_init_module);
+module_exit(ipddp_cleanup_module);
diff --git a/drivers/staging/appletalk/ipddp.h b/drivers/staging/appletalk/ipddp.h
new file mode 100644 (file)
index 0000000..531519d
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *     ipddp.h: Header for IP-over-DDP driver for Linux.
+ */
+
+#ifndef __LINUX_IPDDP_H
+#define __LINUX_IPDDP_H
+
+#ifdef __KERNEL__
+
+#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
+#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
+#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
+
+struct ipddp_route
+{
+        struct net_device *dev;             /* Carrier device */
+        __be32 ip;                       /* IP address */
+        struct atalk_addr at;              /* Gateway appletalk address */
+        int flags;
+        struct ipddp_route *next;
+};
+
+#define IPDDP_ENCAP    1
+#define IPDDP_DECAP    2
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_IPDDP_H */
diff --git a/drivers/staging/appletalk/ltpc.c b/drivers/staging/appletalk/ltpc.c
new file mode 100644 (file)
index 0000000..60caf89
--- /dev/null
@@ -0,0 +1,1288 @@
+/***    ltpc.c -- a driver for the LocalTalk PC card.
+ *
+ *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *      This is ALPHA code at best.  It may not work for you.  It may
+ *      damage your equipment.  It may damage your relations with other
+ *      users of your network.  Use it at your own risk!
+ *
+ *      Based in part on:
+ *      skeleton.c      by Donald Becker
+ *      dummy.c         by Nick Holloway and Alan Cox
+ *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
+ *      the netatalk source code (UMICH)
+ *      lots of work on the card...
+ *
+ *      I do not have access to the (proprietary) SDK that goes with the card.
+ *      If you do, I don't want to know about it, and you can probably write
+ *      a better driver yourself anyway.  This does mean that the pieces that
+ *      talk to the card are guesswork on my part, so use at your own risk!
+ *
+ *      This is my first try at writing Linux networking code, and is also
+ *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
+ *      welcome suggestions)
+ *
+ *      This is a loadable kernel module which seems to work at my site
+ *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
+ *      the kernel support from 1.3.3b2 including patches routing.patch
+ *      and ddp.disappears.from.chooser.  In order to run it, you will need
+ *      to patch ddp.c and aarp.c in the kernel, but only a little...
+ *
+ *      I'm fairly confident that while this is arguably badly written, the
+ *      problems that people experience will be "higher level", that is, with
+ *      complications in the netatalk code.  The driver itself doesn't do
+ *      anything terribly complicated -- it pretends to be an ether device
+ *      as far as netatalk is concerned, strips the DDP data out of the ether
+ *      frame and builds a LLAP packet to send out the card.  In the other
+ *      direction, it receives LLAP frames from the card and builds a fake
+ *      ether packet that it then tosses up to the networking code.  You can
+ *      argue (correctly) that this is an ugly way to do things, but it
+ *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
+ *
+ *      The card will do a lot more than is used here -- I *think* it has the
+ *      layers up through ATP.  Even if you knew how that part works (which I
+ *      don't) it would be a big job to carve up the kernel ddp code to insert
+ *      things at a higher level, and probably a bad idea...
+ *
+ *      There are a number of other cards that do LocalTalk on the PC.  If
+ *      nobody finds any insurmountable (at the netatalk level) problems
+ *      here, this driver should encourage people to put some work into the
+ *      other cards (some of which I gather are still commercially available)
+ *      and also to put hooks for LocalTalk into the official ddp code.
+ *
+ *      I welcome comments and suggestions.  This is my first try at Linux
+ *      networking stuff, and there are probably lots of things that I did
+ *      suboptimally.  
+ *
+ ***/
+
+/***
+ *
+ * $Log: ltpc.c,v $
+ * Revision 1.1.2.1  2000/03/01 05:35:07  jgarzik
+ * at and tr cleanup
+ *
+ * Revision 1.8  1997/01/28 05:44:54  bradford
+ * Clean up for non-module a little.
+ * Hacked about a bit to clean things up - Alan Cox 
+ * Probably broken it from the origina 1.8
+ *
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+   and to probe for things in the standard order of i/o, irq, dma.  This
+   removes the "reset the reset" hack, because I couldn't figure out an
+   easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+   line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+   other localtalk driver, and to clear up the inconsistency between the
+   module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+   codes and the register offsets, but I'm still not sure exactly what their
+   semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+   I'm responsible for that...
+
+ *
+ * Revision 1.7  1996/12/12 03:42:33  bradford
+ * DMA alloc cribbed from 3c505.c.
+ *
+ * Revision 1.6  1996/12/12 03:18:58  bradford
+ * Added virt_to_bus; works in 2.1.13.
+ *
+ * Revision 1.5  1996/12/12 03:13:22  root
+ * xmitQel initialization -- think through better though.
+ *
+ * Revision 1.4  1996/06/18 14:55:55  root
+ * Change names to ltpc. Tabs. Took a shot at dma alloc,
+ * although more needs to be done eventually.
+ *
+ * Revision 1.3  1996/05/22 14:59:39  root
+ * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
+ *
+ * Revision 1.2  1996/05/22 14:58:24  root
+ * Change tabs mostly.
+ *
+ * Revision 1.1  1996/04/23 04:45:09  root
+ * Initial revision
+ *
+ * Revision 0.16  1996/03/05 15:59:56  root
+ * Change ARPHRD_LOCALTLK definition to the "real" one.
+ *
+ * Revision 0.15  1996/03/05 06:28:30  root
+ * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
+ * it's getting closer.
+ *
+ * Revision 0.14  1996/02/25 17:38:32  root
+ * More cleanups.  Removed query to card on get_stats.
+ *
+ * Revision 0.13  1996/02/21  16:27:40  root
+ * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
+ * Clean up receive code a little.
+ *
+ * Revision 0.12  1996/02/19  16:34:53  root
+ * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
+ * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
+ * including packet printing, 4 for lower level (card i/o) stuff.
+ *
+ * Revision 0.11  1996/02/12  15:53:38  root
+ * Added router sends (requires new aarp.c patch)
+ *
+ * Revision 0.10  1996/02/11  00:19:35  root
+ * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
+ *
+ * Revision 0.9  1996/02/10  23:59:35  root
+ * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
+ * has a *different* definition of struct sockaddr_at than the Linux kernel
+ * does.  This is an "insidious and invidious" bug...
+ * (Actually the preceding comment is false -- it's the atalk.h in the
+ * ancient atalk-0.06 that's the problem)
+ *
+ * Revision 0.8  1996/02/10 19:09:00  root
+ * Merge 1.3 changes.  Tested OK under 1.3.60.
+ *
+ * Revision 0.7  1996/02/10 17:56:56  root
+ * Added debug=1 parameter on insmod for debugging prints.  Tried
+ * to fix timer unload on rmmod, but I don't think that's the problem.
+ *
+ * Revision 0.6  1995/12/31  19:01:09  root
+ * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
+ * Clean up initial probing -- sometimes the card wakes up latched in reset.
+ *
+ * Revision 0.5  1995/12/22  06:03:44  root
+ * Added comments in front and cleaned up a bit.
+ * This version sent out to people.
+ *
+ * Revision 0.4  1995/12/18  03:46:44  root
+ * Return shortDDP to longDDP fake to 0/0.  Added command structs.
+ *
+ ***/
+
+/* ltpc jumpers are:
+*
+*      Interrupts -- set at most one.  If none are set, the driver uses
+*      polled mode.  Because the card was developed in the XT era, the
+*      original documentation refers to IRQ2.  Since you'll be running
+*      this on an AT (or later) class machine, that really means IRQ9.
+*
+*      SW1     IRQ 4
+*      SW2     IRQ 3
+*      SW3     IRQ 9 (2 in original card documentation only applies to XT)
+*
+*
+*      DMA -- choose DMA 1 or 3, and set both corresponding switches.
+*
+*      SW4     DMA 3
+*      SW5     DMA 1
+*      SW6     DMA 3
+*      SW7     DMA 1
+*
+*
+*      I/O address -- choose one.  
+*
+*      SW8     220 / 240
+*/
+
+/*     To have some stuff logged, do 
+*      insmod ltpc.o debug=1
+*
+*      For a whole bunch of stuff, use higher numbers.
+*
+*      The default is 0, i.e. no messages except for the probe results.
+*/
+
+/* insmod-tweakable variables */
+static int debug;
+#define DEBUG_VERBOSE 1
+#define DEBUG_UPPER 2
+#define DEBUG_LOWER 4
+
+static int io;
+static int irq;
+static int dma;
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+/* our stuff */
+#include "atalk.h"
+#include "ltpc.h"
+
+static DEFINE_SPINLOCK(txqueue_lock);
+static DEFINE_SPINLOCK(mbox_lock);
+
+/* function prototypes */
+static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen);
+static int sendup_buffer (struct net_device *dev);
+
+/* Dma Memory related stuff, cribbed directly from 3c505.c */
+
+static unsigned long dma_mem_alloc(int size)
+{
+        int order = get_order(size);
+
+        return __get_dma_pages(GFP_KERNEL, order);
+}
+
+/* DMA data buffer, DMA command buffer */
+static unsigned char *ltdmabuf;
+static unsigned char *ltdmacbuf;
+
+/* private struct, holds our appletalk address */
+
+struct ltpc_private
+{
+       struct atalk_addr my_addr;
+};
+
+/* transmit queue element struct */
+
+struct xmitQel {
+       struct xmitQel *next;
+       /* command buffer */
+       unsigned char *cbuf;
+       short cbuflen;
+       /* data buffer */
+       unsigned char *dbuf;
+       short dbuflen;
+       unsigned char QWrite;   /* read or write data */
+       unsigned char mailbox;
+};
+
+/* the transmit queue itself */
+
+static struct xmitQel *xmQhd, *xmQtl;
+
+static void enQ(struct xmitQel *qel)
+{
+       unsigned long flags;
+       qel->next = NULL;
+       
+       spin_lock_irqsave(&txqueue_lock, flags);
+       if (xmQtl) {
+               xmQtl->next = qel;
+       } else {
+               xmQhd = qel;
+       }
+       xmQtl = qel;
+       spin_unlock_irqrestore(&txqueue_lock, flags);
+
+       if (debug & DEBUG_LOWER)
+               printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
+}
+
+static struct xmitQel *deQ(void)
+{
+       unsigned long flags;
+       int i;
+       struct xmitQel *qel=NULL;
+       
+       spin_lock_irqsave(&txqueue_lock, flags);
+       if (xmQhd) {
+               qel = xmQhd;
+               xmQhd = qel->next;
+               if(!xmQhd) xmQtl = NULL;
+       }
+       spin_unlock_irqrestore(&txqueue_lock, flags);
+
+       if ((debug & DEBUG_LOWER) && qel) {
+               int n;
+               printk(KERN_DEBUG "ltpc: dequeued command ");
+               n = qel->cbuflen;
+               if (n>100) n=100;
+               for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
+               printk("\n");
+       }
+
+       return qel;
+}
+
+/* and... the queue elements we'll be using */
+static struct xmitQel qels[16];
+
+/* and their corresponding mailboxes */
+static unsigned char mailbox[16];
+static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static int wait_timeout(struct net_device *dev, int c)
+{
+       /* returns true if it stayed c */
+       /* this uses base+6, but it's ok */
+       int i;
+
+       /* twenty second or so total */
+
+       for(i=0;i<200000;i++) {
+               if ( c != inb_p(dev->base_addr+6) ) return 0;
+               udelay(100);
+       }
+       return 1; /* timed out */
+}
+
+/* get the first free mailbox */
+
+static int getmbox(void)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&mbox_lock, flags);
+       for(i=1;i<16;i++) if(!mboxinuse[i]) {
+               mboxinuse[i]=1;
+               spin_unlock_irqrestore(&mbox_lock, flags);
+               return i;
+       }
+       spin_unlock_irqrestore(&mbox_lock, flags);
+       return 0;
+}
+
+/* read a command from the card */
+static void handlefc(struct net_device *dev)
+{
+       /* called *only* from idle, non-reentrant */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+
+       flags=claim_dma_lock();
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+       set_dma_count(dma,50);
+       enable_dma(dma);
+       release_dma_lock(flags);
+
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
+}
+
+/* read data from the card */
+static void handlefd(struct net_device *dev)
+{
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+       flags=claim_dma_lock();
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,800);
+       enable_dma(dma);
+       release_dma_lock(flags);
+
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
+       sendup_buffer(dev);
+} 
+
+static void handlewrite(struct net_device *dev)
+{
+       /* called *only* from idle, non-reentrant */
+       /* on entry, 0xfb and ltdmabuf holds data */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+       
+       flags=claim_dma_lock();
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_WRITE);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,800);
+       enable_dma(dma);
+       release_dma_lock(flags);
+       
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfb) ) {
+               flags=claim_dma_lock();
+               printk("timed out in handlewrite, dma res %d\n",
+                       get_dma_residue(dev->dma) );
+               release_dma_lock(flags);
+       }
+}
+
+static void handleread(struct net_device *dev)
+{
+       /* on entry, 0xfb */
+       /* on exit, ltdmabuf holds data */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+       
+       flags=claim_dma_lock();
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,800);
+       enable_dma(dma);
+       release_dma_lock(flags);
+
+       inb_p(base+3);
+       inb_p(base+2);
+       if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
+}
+
+static void handlecommand(struct net_device *dev)
+{
+       /* on entry, 0xfa and ltdmacbuf holds command */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+       flags=claim_dma_lock();
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_WRITE);
+       set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+       set_dma_count(dma,50);
+       enable_dma(dma);
+       release_dma_lock(flags);
+       inb_p(base+3);
+       inb_p(base+2);
+       if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
+} 
+
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,0};
+static unsigned char resdbuf[2];
+
+static int QInIdle;
+
+/* idle expects to be called with the IRQ line high -- either because of
+ * an interrupt, or because the line is tri-stated
+ */
+
+static void idle(struct net_device *dev)
+{
+       unsigned long flags;
+       int state;
+       /* FIXME This is initialized to shut the warning up, but I need to
+        * think this through again.
+        */
+       struct xmitQel *q = NULL;
+       int oops;
+       int i;
+       int base = dev->base_addr;
+
+       spin_lock_irqsave(&txqueue_lock, flags);
+       if(QInIdle) {
+               spin_unlock_irqrestore(&txqueue_lock, flags);
+               return;
+       }
+       QInIdle = 1;
+       spin_unlock_irqrestore(&txqueue_lock, flags);
+
+       /* this tri-states the IRQ line */
+       (void) inb_p(base+6);
+
+       oops = 100;
+
+loop:
+       if (0>oops--) { 
+               printk("idle: looped too many times\n");
+               goto done;
+       }
+
+       state = inb_p(base+6);
+       if (state != inb_p(base+6)) goto loop;
+
+       switch(state) {
+               case 0xfc:
+                       /* incoming command */
+                       if (debug & DEBUG_LOWER) printk("idle: fc\n");
+                       handlefc(dev); 
+                       break;
+               case 0xfd:
+                       /* incoming data */
+                       if(debug & DEBUG_LOWER) printk("idle: fd\n");
+                       handlefd(dev); 
+                       break;
+               case 0xf9:
+                       /* result ready */
+                       if (debug & DEBUG_LOWER) printk("idle: f9\n");
+                       if(!mboxinuse[0]) {
+                               mboxinuse[0] = 1;
+                               qels[0].cbuf = rescbuf;
+                               qels[0].cbuflen = 2;
+                               qels[0].dbuf = resdbuf;
+                               qels[0].dbuflen = 2;
+                               qels[0].QWrite = 0;
+                               qels[0].mailbox = 0;
+                               enQ(&qels[0]);
+                       }
+                       inb_p(dev->base_addr+1);
+                       inb_p(dev->base_addr+0);
+                       if( wait_timeout(dev,0xf9) )
+                               printk("timed out idle f9\n");
+                       break;
+               case 0xf8:
+                       /* ?? */
+                       if (xmQhd) {
+                               inb_p(dev->base_addr+1);
+                               inb_p(dev->base_addr+0);
+                               if(wait_timeout(dev,0xf8) )
+                                       printk("timed out idle f8\n");
+                       } else {
+                               goto done;
+                       }
+                       break;
+               case 0xfa:
+                       /* waiting for command */
+                       if(debug & DEBUG_LOWER) printk("idle: fa\n");
+                       if (xmQhd) {
+                               q=deQ();
+                               memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
+                               ltdmacbuf[1] = q->mailbox;
+                               if (debug>1) { 
+                                       int n;
+                                       printk("ltpc: sent command     ");
+                                       n = q->cbuflen;
+                                       if (n>100) n=100;
+                                       for(i=0;i<n;i++)
+                                               printk("%02x ",ltdmacbuf[i]);
+                                       printk("\n");
+                               }
+                               handlecommand(dev);
+                                       if(0xfa==inb_p(base+6)) {
+                                               /* we timed out, so return */
+                                               goto done;
+                                       } 
+                       } else {
+                               /* we don't seem to have a command */
+                               if (!mboxinuse[0]) {
+                                       mboxinuse[0] = 1;
+                                       qels[0].cbuf = rescbuf;
+                                       qels[0].cbuflen = 2;
+                                       qels[0].dbuf = resdbuf;
+                                       qels[0].dbuflen = 2;
+                                       qels[0].QWrite = 0;
+                                       qels[0].mailbox = 0;
+                                       enQ(&qels[0]);
+                               } else {
+                                       printk("trouble: response command already queued\n");
+                                       goto done;
+                               }
+                       } 
+                       break;
+               case 0Xfb:
+                       /* data transfer ready */
+                       if(debug & DEBUG_LOWER) printk("idle: fb\n");
+                       if(q->QWrite) {
+                               memcpy(ltdmabuf,q->dbuf,q->dbuflen);
+                               handlewrite(dev);
+                       } else {
+                               handleread(dev);
+                               /* non-zero mailbox numbers are for
+                                  commmands, 0 is for GETRESULT
+                                  requests */
+                               if(q->mailbox) {
+                                       memcpy(q->dbuf,ltdmabuf,q->dbuflen);
+                               } else { 
+                                       /* this was a result */
+                                       mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
+                                       mboxinuse[0]=0;
+                               }
+                       }
+                       break;
+       }
+       goto loop;
+
+done:
+       QInIdle=0;
+
+       /* now set the interrupts back as appropriate */
+       /* the first read takes it out of tri-state (but still high) */
+       /* the second resets it */
+       /* note that after this point, any read of base+6 will
+          trigger an interrupt */
+
+       if (dev->irq) {
+               inb_p(base+7);
+               inb_p(base+7);
+       }
+}
+
+
+static int do_write(struct net_device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen)
+{
+
+       int i = getmbox();
+       int ret;
+
+       if(i) {
+               qels[i].cbuf = (unsigned char *) cbuf;
+               qels[i].cbuflen = cbuflen;
+               qels[i].dbuf = (unsigned char *) dbuf;
+               qels[i].dbuflen = dbuflen;
+               qels[i].QWrite = 1;
+               qels[i].mailbox = i;  /* this should be initted rather */
+               enQ(&qels[i]);
+               idle(dev);
+               ret = mailbox[i];
+               mboxinuse[i]=0;
+               return ret;
+       }
+       printk("ltpc: could not allocate mbox\n");
+       return -1;
+}
+
+static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen)
+{
+
+       int i = getmbox();
+       int ret;
+
+       if(i) {
+               qels[i].cbuf = (unsigned char *) cbuf;
+               qels[i].cbuflen = cbuflen;
+               qels[i].dbuf = (unsigned char *) dbuf;
+               qels[i].dbuflen = dbuflen;
+               qels[i].QWrite = 0;
+               qels[i].mailbox = i;  /* this should be initted rather */
+               enQ(&qels[i]);
+               idle(dev);
+               ret = mailbox[i];
+               mboxinuse[i]=0;
+               return ret;
+       }
+       printk("ltpc: could not allocate mbox\n");
+       return -1;
+}
+
+/* end of idle handlers -- what should be seen is do_read, do_write */
+
+static struct timer_list ltpc_timer;
+
+static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev);
+
+static int read_30 ( struct net_device *dev)
+{
+       lt_command c;
+       c.getflags.command = LT_GETFLAGS;
+       return do_read(dev, &c, sizeof(c.getflags),&c,0);
+}
+
+static int set_30 (struct net_device *dev,int x)
+{
+       lt_command c;
+       c.setflags.command = LT_SETFLAGS;
+       c.setflags.flags = x;
+       return do_write(dev, &c, sizeof(c.setflags),&c,0);
+}
+
+/* LLAP to DDP translation */
+
+static int sendup_buffer (struct net_device *dev)
+{
+       /* on entry, command is in ltdmacbuf, data in ltdmabuf */
+       /* called from idle, non-reentrant */
+
+       int dnode, snode, llaptype, len; 
+       int sklen;
+       struct sk_buff *skb;
+       struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
+
+       if (ltc->command != LT_RCVLAP) {
+               printk("unknown command 0x%02x from ltpc card\n",ltc->command);
+               return -1;
+       }
+       dnode = ltc->dnode;
+       snode = ltc->snode;
+       llaptype = ltc->laptype;
+       len = ltc->length; 
+
+       sklen = len;
+       if (llaptype == 1) 
+               sklen += 8;  /* correct for short ddp */
+       if(sklen > 800) {
+               printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
+                       dev->name,sklen);
+               return -1;
+       }
+
+       if ( (llaptype==0) || (llaptype>2) ) {
+               printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
+               return -1;
+       }
+
+
+       skb = dev_alloc_skb(3+sklen);
+       if (skb == NULL) 
+       {
+               printk("%s: dropping packet due to memory squeeze.\n",
+                       dev->name);
+               return -1;
+       }
+       skb->dev = dev;
+
+       if (sklen > len)
+               skb_reserve(skb,8);
+       skb_put(skb,len+3);
+       skb->protocol = htons(ETH_P_LOCALTALK);
+       /* add LLAP header */
+       skb->data[0] = dnode;
+       skb->data[1] = snode;
+       skb->data[2] = llaptype;
+       skb_reset_mac_header(skb);      /* save pointer to llap header */
+       skb_pull(skb,3);
+
+       /* copy ddp(s,e)hdr + contents */
+       skb_copy_to_linear_data(skb, ltdmabuf, len);
+
+       skb_reset_transport_header(skb);
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+
+       /* toss it onwards */
+       netif_rx(skb);
+       return 0;
+}
+
+/* the handler for the board interrupt */
+static irqreturn_t
+ltpc_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+
+       if (dev==NULL) {
+               printk("ltpc_interrupt: unknown device.\n");
+               return IRQ_NONE;
+       }
+
+       inb_p(dev->base_addr+6);  /* disable further interrupts from board */
+
+       idle(dev); /* handle whatever is coming in */
+       /* idle re-enables interrupts from board */ 
+
+       return IRQ_HANDLED;
+}
+
+/***
+ *
+ *    The ioctls that the driver responds to are:
+ *
+ *    SIOCSIFADDR -- do probe using the passed node hint.
+ *    SIOCGIFADDR -- return net, node.
+ *
+ *    some of this stuff should be done elsewhere.
+ *
+ ***/
+
+static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
+       /* we'll keep the localtalk node address in dev->pa_addr */
+       struct ltpc_private *ltpc_priv = netdev_priv(dev);
+       struct atalk_addr *aa = &ltpc_priv->my_addr;
+       struct lt_init c;
+       int ltflags;
+
+       if(debug & DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
+
+       switch(cmd) {
+               case SIOCSIFADDR:
+
+                       aa->s_net  = sa->sat_addr.s_net;
+      
+                       /* this does the probe and returns the node addr */
+                       c.command = LT_INIT;
+                       c.hint = sa->sat_addr.s_node;
+
+                       aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
+
+                       /* get all llap frames raw */
+                       ltflags = read_30(dev);
+                       ltflags |= LT_FLAG_ALLLAP;
+                       set_30 (dev,ltflags);  
+
+                       dev->broadcast[0] = 0xFF;
+                       dev->dev_addr[0] = aa->s_node;
+
+                       dev->addr_len=1;
+   
+                       return 0;
+
+               case SIOCGIFADDR:
+
+                       sa->sat_addr.s_net = aa->s_net;
+                       sa->sat_addr.s_node = aa->s_node;
+
+                       return 0;
+
+               default: 
+                       return -EINVAL;
+       }
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+       /* This needs to be present to keep netatalk happy. */
+       /* Actually netatalk needs fixing! */
+}
+
+static int ltpc_poll_counter;
+
+static void ltpc_poll(unsigned long l)
+{
+       struct net_device *dev = (struct net_device *) l;
+
+       del_timer(&ltpc_timer);
+
+       if(debug & DEBUG_VERBOSE) {
+               if (!ltpc_poll_counter) {
+                       ltpc_poll_counter = 50;
+                       printk("ltpc poll is alive\n");
+               }
+               ltpc_poll_counter--;
+       }
+  
+       if (!dev)
+               return;  /* we've been downed */
+
+       /* poll 20 times per second */
+       idle(dev);
+       ltpc_timer.expires = jiffies + HZ/20;
+       
+       add_timer(&ltpc_timer);
+}
+
+/* DDP to LLAP translation */
+
+static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       /* in kernel 1.3.xx, on entry skb->data points to ddp header,
+        * and skb->len is the length of the ddp data + ddp header
+        */
+       int i;
+       struct lt_sendlap cbuf;
+       unsigned char *hdr;
+
+       cbuf.command = LT_SENDLAP;
+       cbuf.dnode = skb->data[0];
+       cbuf.laptype = skb->data[2];
+       skb_pull(skb,3);        /* skip past LLAP header */
+       cbuf.length = skb->len; /* this is host order */
+       skb_reset_transport_header(skb);
+
+       if(debug & DEBUG_UPPER) {
+               printk("command ");
+               for(i=0;i<6;i++)
+                       printk("%02x ",((unsigned char *)&cbuf)[i]);
+               printk("\n");
+       }
+
+       hdr = skb_transport_header(skb);
+       do_write(dev, &cbuf, sizeof(cbuf), hdr, skb->len);
+
+       if(debug & DEBUG_UPPER) {
+               printk("sent %d ddp bytes\n",skb->len);
+               for (i = 0; i < skb->len; i++)
+                       printk("%02x ", hdr[i]);
+               printk("\n");
+       }
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+/* initialization stuff */
+  
+static int __init ltpc_probe_dma(int base, int dma)
+{
+       int want = (dma == 3) ? 2 : (dma == 1) ? 1 : 3;
+       unsigned long timeout;
+       unsigned long f;
+  
+       if (want & 1) {
+               if (request_dma(1,"ltpc")) {
+                       want &= ~1;
+               } else {
+                       f=claim_dma_lock();
+                       disable_dma(1);
+                       clear_dma_ff(1);
+                       set_dma_mode(1,DMA_MODE_WRITE);
+                       set_dma_addr(1,virt_to_bus(ltdmabuf));
+                       set_dma_count(1,sizeof(struct lt_mem));
+                       enable_dma(1);
+                       release_dma_lock(f);
+               }
+       }
+       if (want & 2) {
+               if (request_dma(3,"ltpc")) {
+                       want &= ~2;
+               } else {
+                       f=claim_dma_lock();
+                       disable_dma(3);
+                       clear_dma_ff(3);
+                       set_dma_mode(3,DMA_MODE_WRITE);
+                       set_dma_addr(3,virt_to_bus(ltdmabuf));
+                       set_dma_count(3,sizeof(struct lt_mem));
+                       enable_dma(3);
+                       release_dma_lock(f);
+               }
+       }
+       /* set up request */
+
+       /* FIXME -- do timings better! */
+
+       ltdmabuf[0] = LT_READMEM;
+       ltdmabuf[1] = 1;  /* mailbox */
+       ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
+       ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
+       ltdmabuf[6] = 0; /* dunno if this is necessary */
+
+       inb_p(io+1);
+       inb_p(io+0);
+       timeout = jiffies+100*HZ/100;
+       while(time_before(jiffies, timeout)) {
+               if ( 0xfa == inb_p(io+6) ) break;
+       }
+
+       inb_p(io+3);
+       inb_p(io+2);
+       while(time_before(jiffies, timeout)) {
+               if ( 0xfb == inb_p(io+6) ) break;
+       }
+
+       /* release the other dma channel (if we opened both of them) */
+
+       if ((want & 2) && (get_dma_residue(3)==sizeof(struct lt_mem))) {
+               want &= ~2;
+               free_dma(3);
+       }
+
+       if ((want & 1) && (get_dma_residue(1)==sizeof(struct lt_mem))) {
+               want &= ~1;
+               free_dma(1);
+       }
+
+       if (!want)
+               return 0;
+
+       return (want & 2) ? 3 : 1;
+}
+
+static const struct net_device_ops ltpc_netdev = {
+       .ndo_start_xmit         = ltpc_xmit,
+       .ndo_do_ioctl           = ltpc_ioctl,
+       .ndo_set_multicast_list = set_multicast_list,
+};
+
+struct net_device * __init ltpc_probe(void)
+{
+       struct net_device *dev;
+       int err = -ENOMEM;
+       int x=0,y=0;
+       int autoirq;
+       unsigned long f;
+       unsigned long timeout;
+
+       dev = alloc_ltalkdev(sizeof(struct ltpc_private));
+       if (!dev)
+               goto out;
+
+       /* probe for the I/O port address */
+       
+       if (io != 0x240 && request_region(0x220,8,"ltpc")) {
+               x = inb_p(0x220+6);
+               if ( (x!=0xff) && (x>=0xf0) ) {
+                       io = 0x220;
+                       goto got_port;
+               }
+               release_region(0x220,8);
+       }
+       if (io != 0x220 && request_region(0x240,8,"ltpc")) {
+               y = inb_p(0x240+6);
+               if ( (y!=0xff) && (y>=0xf0) ){ 
+                       io = 0x240;
+                       goto got_port;
+               }
+               release_region(0x240,8);
+       } 
+
+       /* give up in despair */
+       printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y);
+       err = -ENODEV;
+       goto out1;
+
+ got_port:
+       /* probe for the IRQ line */
+       if (irq < 2) {
+               unsigned long irq_mask;
+
+               irq_mask = probe_irq_on();
+               /* reset the interrupt line */
+               inb_p(io+7);
+               inb_p(io+7);
+               /* trigger an interrupt (I hope) */
+               inb_p(io+6);
+               mdelay(2);
+               autoirq = probe_irq_off(irq_mask);
+
+               if (autoirq == 0) {
+                       printk(KERN_ERR "ltpc: probe at %#x failed to detect IRQ line.\n", io);
+               } else {
+                       irq = autoirq;
+               }
+       }
+
+       /* allocate a DMA buffer */
+       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+       if (!ltdmabuf) {
+               printk(KERN_ERR "ltpc: mem alloc failed\n");
+               err = -ENOMEM;
+               goto out2;
+       }
+
+       ltdmacbuf = &ltdmabuf[800];
+
+       if(debug & DEBUG_VERBOSE) {
+               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+       }
+
+       /* reset the card */
+
+       inb_p(io+1);
+       inb_p(io+3);
+
+       msleep(20);
+
+       inb_p(io+0);
+       inb_p(io+2);
+       inb_p(io+7); /* clear reset */
+       inb_p(io+4); 
+       inb_p(io+5);
+       inb_p(io+5); /* enable dma */
+       inb_p(io+6); /* tri-state interrupt line */
+
+       ssleep(1);
+       
+       /* now, figure out which dma channel we're using, unless it's
+          already been specified */
+       /* well, 0 is a legal DMA channel, but the LTPC card doesn't
+          use it... */
+       dma = ltpc_probe_dma(io, dma);
+       if (!dma) {  /* no dma channel */
+               printk(KERN_ERR "No DMA channel found on ltpc card.\n");
+               err = -ENODEV;
+               goto out3;
+       }
+
+       /* print out friendly message */
+       if(irq)
+               printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
+       else
+               printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
+
+       dev->netdev_ops = &ltpc_netdev;
+       dev->base_addr = io;
+       dev->irq = irq;
+       dev->dma = dma;
+
+       /* the card will want to send a result at this point */
+       /* (I think... leaving out this part makes the kernel crash,
+           so I put it back in...) */
+
+       f=claim_dma_lock();
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,0x100);
+       enable_dma(dma);
+       release_dma_lock(f);
+
+       (void) inb_p(io+3);
+       (void) inb_p(io+2);
+       timeout = jiffies+100*HZ/100;
+
+       while(time_before(jiffies, timeout)) {
+               if( 0xf9 == inb_p(io+6))
+                       break;
+               schedule();
+       }
+
+       if(debug & DEBUG_VERBOSE) {
+               printk("setting up timer and irq\n");
+       }
+
+       /* grab it and don't let go :-) */
+       if (irq && request_irq( irq, ltpc_interrupt, 0, "ltpc", dev) >= 0)
+       {
+               (void) inb_p(io+7);  /* enable interrupts from board */
+               (void) inb_p(io+7);  /* and reset irq line */
+       } else {
+               if( irq )
+                       printk(KERN_ERR "ltpc: IRQ already in use, using polled mode.\n");
+               dev->irq = 0;
+               /* polled mode -- 20 times per second */
+               /* this is really, really slow... should it poll more often? */
+               init_timer(&ltpc_timer);
+               ltpc_timer.function=ltpc_poll;
+               ltpc_timer.data = (unsigned long) dev;
+
+               ltpc_timer.expires = jiffies + HZ/20;
+               add_timer(&ltpc_timer);
+       }
+       err = register_netdev(dev);
+       if (err)
+               goto out4;
+
+       return NULL;
+out4:
+       del_timer_sync(&ltpc_timer);
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+out3:
+       free_pages((unsigned long)ltdmabuf, get_order(1000));
+out2:
+       release_region(io, 8);
+out1:
+       free_netdev(dev);
+out:
+       return ERR_PTR(err);
+}
+
+#ifndef MODULE
+/* handles "ltpc=io,irq,dma" kernel command lines */
+static int __init ltpc_setup(char *str)
+{
+       int ints[5];
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       if (ints[0] == 0) {
+               if (str && !strncmp(str, "auto", 4)) {
+                       /* do nothing :-) */
+               }
+               else {
+                       /* usage message */
+                       printk (KERN_ERR
+                               "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+                       return 0;
+               }
+       } else {
+               io = ints[1];
+               if (ints[0] > 1) {
+                       irq = ints[2];
+               }
+               if (ints[0] > 2) {
+                       dma = ints[3];
+               }
+               /* ignore any other parameters */
+       }
+       return 1;
+}
+
+__setup("ltpc=", ltpc_setup);
+#endif /* MODULE */
+
+static struct net_device *dev_ltpc;
+
+#ifdef MODULE
+
+MODULE_LICENSE("GPL");
+module_param(debug, int, 0);
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param(dma, int, 0);
+
+
+static int __init ltpc_module_init(void)
+{
+        if(io == 0)
+               printk(KERN_NOTICE
+                      "ltpc: Autoprobing is not recommended for modules\n");
+
+       dev_ltpc = ltpc_probe();
+       if (IS_ERR(dev_ltpc))
+               return PTR_ERR(dev_ltpc);
+       return 0;
+}
+module_init(ltpc_module_init);
+#endif
+
+static void __exit ltpc_cleanup(void)
+{
+
+       if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n");
+       unregister_netdev(dev_ltpc);
+
+       ltpc_timer.data = 0;  /* signal the poll routine that we're done */
+
+       del_timer_sync(&ltpc_timer);
+
+       if(debug & DEBUG_VERBOSE) printk("freeing irq\n");
+
+       if (dev_ltpc->irq)
+               free_irq(dev_ltpc->irq, dev_ltpc);
+
+       if(debug & DEBUG_VERBOSE) printk("freeing dma\n");
+
+       if (dev_ltpc->dma)
+               free_dma(dev_ltpc->dma);
+
+       if(debug & DEBUG_VERBOSE) printk("freeing ioaddr\n");
+
+       if (dev_ltpc->base_addr)
+               release_region(dev_ltpc->base_addr,8);
+
+       free_netdev(dev_ltpc);
+
+       if(debug & DEBUG_VERBOSE) printk("free_pages\n");
+
+       free_pages( (unsigned long) ltdmabuf, get_order(1000));
+
+       if(debug & DEBUG_VERBOSE) printk("returning from cleanup_module\n");
+}
+
+module_exit(ltpc_cleanup);
diff --git a/drivers/staging/appletalk/ltpc.h b/drivers/staging/appletalk/ltpc.h
new file mode 100644 (file)
index 0000000..cd30544
--- /dev/null
@@ -0,0 +1,73 @@
+/***   ltpc.h
+ *
+ *
+ ***/
+
+#define LT_GETRESULT  0x00
+#define LT_WRITEMEM   0x01
+#define LT_READMEM    0x02
+#define LT_GETFLAGS   0x04
+#define LT_SETFLAGS   0x05
+#define LT_INIT       0x10
+#define LT_SENDLAP    0x13
+#define LT_RCVLAP     0x14
+
+/* the flag that we care about */
+#define LT_FLAG_ALLLAP 0x04
+
+struct lt_getresult {
+       unsigned char command;
+       unsigned char mailbox;
+};
+
+struct lt_mem {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned short addr;    /* host order */
+       unsigned short length;  /* host order */
+};
+
+struct lt_setflags {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char flags;
+};
+
+struct lt_getflags {
+       unsigned char command;
+       unsigned char mailbox;
+};
+
+struct lt_init {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char hint;
+};
+
+struct lt_sendlap {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char dnode;
+       unsigned char laptype;
+       unsigned short length;  /* host order */
+};
+
+struct lt_rcvlap {
+       unsigned char command;
+       unsigned char dnode;
+       unsigned char snode;
+       unsigned char laptype;
+       unsigned short length;  /* host order */
+};
+
+union lt_command {
+       struct lt_getresult getresult;
+       struct lt_mem mem;
+       struct lt_setflags setflags;
+       struct lt_getflags getflags;
+       struct lt_init init;
+       struct lt_sendlap sendlap;
+       struct lt_rcvlap rcvlap;
+};
+typedef union lt_command lt_command;
+
diff --git a/drivers/staging/appletalk/sysctl_net_atalk.c b/drivers/staging/appletalk/sysctl_net_atalk.c
new file mode 100644 (file)
index 0000000..4c896b6
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * sysctl_net_atalk.c: sysctl interface to net AppleTalk subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/atalk directory entry (empty =) ). [MS]
+ * Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
+ */
+
+#include <linux/sysctl.h>
+#include <net/sock.h>
+#include "atalk.h"
+
+static struct ctl_table atalk_table[] = {
+       {
+               .procname       = "aarp-expiry-time",
+               .data           = &sysctl_aarp_expiry_time,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+       },
+       {
+               .procname       = "aarp-tick-time",
+               .data           = &sysctl_aarp_tick_time,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+       },
+       {
+               .procname       = "aarp-retransmit-limit",
+               .data           = &sysctl_aarp_retransmit_limit,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "aarp-resolve-time",
+               .data           = &sysctl_aarp_resolve_time,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+       },
+       { },
+};
+
+static struct ctl_path atalk_path[] = {
+       { .procname = "net", },
+       { .procname = "appletalk", },
+       { }
+};
+
+static struct ctl_table_header *atalk_table_header;
+
+void atalk_register_sysctl(void)
+{
+       atalk_table_header = register_sysctl_paths(atalk_path, atalk_table);
+}
+
+void atalk_unregister_sysctl(void)
+{
+       unregister_sysctl_table(atalk_table_header);
+}
index 61abb638b4bfdcef8c2a47446fb778714b9b25b8..86a2d7d905c070fe42f033051ec2a85720c3e05a 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/syscalls.h>
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
-#include <linux/atalk.h>
 #include <linux/gfp.h>
 
 #include <net/bluetooth/bluetooth.h>
index 2296d8b1931f694a6ffa6fc1ea0ec7064728c2c6..362041b73a2fc17d549844c17794a03bed49ea77 100644 (file)
@@ -43,7 +43,6 @@ header-y += agpgart.h
 header-y += aio_abi.h
 header-y += apm_bios.h
 header-y += arcfb.h
-header-y += atalk.h
 header-y += atm.h
 header-y += atm_eni.h
 header-y += atm_he.h
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
deleted file mode 100644 (file)
index d34c187..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef __LINUX_ATALK_H__
-#define __LINUX_ATALK_H__
-
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-/*
- * AppleTalk networking structures
- *
- * The following are directly referenced from the University Of Michigan
- * netatalk for compatibility reasons.
- */
-#define ATPORT_FIRST   1
-#define ATPORT_RESERVED        128
-#define ATPORT_LAST    254             /* 254 is only legal on localtalk */ 
-#define ATADDR_ANYNET  (__u16)0
-#define ATADDR_ANYNODE (__u8)0
-#define ATADDR_ANYPORT  (__u8)0
-#define ATADDR_BCAST   (__u8)255
-#define DDP_MAXSZ      587
-#define DDP_MAXHOPS     15             /* 4 bits of hop counter */
-
-#define SIOCATALKDIFADDR       (SIOCPROTOPRIVATE + 0)
-
-struct atalk_addr {
-       __be16  s_net;
-       __u8    s_node;
-};
-
-struct sockaddr_at {
-       sa_family_t       sat_family;
-       __u8              sat_port;
-       struct atalk_addr sat_addr;
-       char              sat_zero[8];
-};
-
-struct atalk_netrange {
-       __u8    nr_phase;
-       __be16  nr_firstnet;
-       __be16  nr_lastnet;
-};
-
-#ifdef __KERNEL__
-
-#include <net/sock.h>
-
-struct atalk_route {
-       struct net_device  *dev;
-       struct atalk_addr  target;
-       struct atalk_addr  gateway;
-       int                flags;
-       struct atalk_route *next;
-};
-
-/**
- *     struct atalk_iface - AppleTalk Interface
- *     @dev - Network device associated with this interface
- *     @address - Our address
- *     @status - What are we doing?
- *     @nets - Associated direct netrange
- *     @next - next element in the list of interfaces
- */
-struct atalk_iface {
-       struct net_device       *dev;
-       struct atalk_addr       address;
-       int                     status;
-#define ATIF_PROBE     1               /* Probing for an address */
-#define ATIF_PROBE_FAIL        2               /* Probe collided */
-       struct atalk_netrange   nets;
-       struct atalk_iface      *next;
-};
-       
-struct atalk_sock {
-       /* struct sock has to be the first member of atalk_sock */
-       struct sock     sk;
-       __be16          dest_net;
-       __be16          src_net;
-       unsigned char   dest_node;
-       unsigned char   src_node;
-       unsigned char   dest_port;
-       unsigned char   src_port;
-};
-
-static inline struct atalk_sock *at_sk(struct sock *sk)
-{
-       return (struct atalk_sock *)sk;
-}
-
-struct ddpehdr {
-       __be16  deh_len_hops;   /* lower 10 bits are length, next 4 - hops */
-       __be16  deh_sum;
-       __be16  deh_dnet;
-       __be16  deh_snet;
-       __u8    deh_dnode;
-       __u8    deh_snode;
-       __u8    deh_dport;
-       __u8    deh_sport;
-       /* And netatalk apps expect to stick the type in themselves */
-};
-
-static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb)
-{
-       return (struct ddpehdr *)skb_transport_header(skb);
-}
-
-/* AppleTalk AARP headers */
-struct elapaarp {
-       __be16  hw_type;
-#define AARP_HW_TYPE_ETHERNET          1
-#define AARP_HW_TYPE_TOKENRING         2
-       __be16  pa_type;
-       __u8    hw_len;
-       __u8    pa_len;
-#define AARP_PA_ALEN                   4
-       __be16  function;
-#define AARP_REQUEST                   1
-#define AARP_REPLY                     2
-#define AARP_PROBE                     3
-       __u8    hw_src[ETH_ALEN];
-       __u8    pa_src_zero;
-       __be16  pa_src_net;
-       __u8    pa_src_node;
-       __u8    hw_dst[ETH_ALEN];
-       __u8    pa_dst_zero;
-       __be16  pa_dst_net;
-       __u8    pa_dst_node;
-} __attribute__ ((packed));
-
-static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb)
-{
-       return (struct elapaarp *)skb_transport_header(skb);
-}
-
-/* Not specified - how long till we drop a resolved entry */
-#define AARP_EXPIRY_TIME       (5 * 60 * HZ)
-/* Size of hash table */
-#define AARP_HASH_SIZE         16
-/* Fast retransmission timer when resolving */
-#define AARP_TICK_TIME         (HZ / 5)
-/* Send 10 requests then give up (2 seconds) */
-#define AARP_RETRANSMIT_LIMIT  10
-/*
- * Some value bigger than total retransmit time + a bit for last reply to
- * appear and to stop continual requests
- */
-#define AARP_RESOLVE_TIME      (10 * HZ)
-
-extern struct datalink_proto *ddp_dl, *aarp_dl;
-extern void aarp_proto_init(void);
-
-/* Inter module exports */
-
-/* Give a device find its atif control structure */
-static inline struct atalk_iface *atalk_find_dev(struct net_device *dev)
-{
-       return dev->atalk_ptr;
-}
-
-extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
-extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
-extern int              aarp_send_ddp(struct net_device *dev,
-                                      struct sk_buff *skb,
-                                      struct atalk_addr *sa, void *hwaddr);
-extern void             aarp_device_down(struct net_device *dev);
-extern void             aarp_probe_network(struct atalk_iface *atif);
-extern int              aarp_proxy_probe_network(struct atalk_iface *atif,
-                                    struct atalk_addr *sa);
-extern void             aarp_proxy_remove(struct net_device *dev,
-                                          struct atalk_addr *sa);
-
-extern void            aarp_cleanup_module(void);
-
-extern struct hlist_head atalk_sockets;
-extern rwlock_t atalk_sockets_lock;
-
-extern struct atalk_route *atalk_routes;
-extern rwlock_t atalk_routes_lock;
-
-extern struct atalk_iface *atalk_interfaces;
-extern rwlock_t atalk_interfaces_lock;
-
-extern struct atalk_route atrtr_default;
-
-extern const struct file_operations atalk_seq_arp_fops;
-
-extern int sysctl_aarp_expiry_time;
-extern int sysctl_aarp_tick_time;
-extern int sysctl_aarp_retransmit_limit;
-extern int sysctl_aarp_resolve_time;
-
-#ifdef CONFIG_SYSCTL
-extern void atalk_register_sysctl(void);
-extern void atalk_unregister_sysctl(void);
-#else
-#define atalk_register_sysctl()                do { } while(0)
-#define atalk_unregister_sysctl()      do { } while(0)
-#endif
-
-#ifdef CONFIG_PROC_FS
-extern int atalk_proc_init(void);
-extern void atalk_proc_exit(void);
-#else
-#define atalk_proc_init()      ({ 0; })
-#define atalk_proc_exit()      do { } while(0)
-#endif /* CONFIG_PROC_FS */
-
-#endif /* __KERNEL__ */
-#endif /* __LINUX_ATALK_H__ */
index 72840626284bc74b4fcd3d6564781ff909fae75f..082c8bc977e17a7151b2063a2772af4d82930158 100644 (file)
@@ -204,7 +204,6 @@ source "net/8021q/Kconfig"
 source "net/decnet/Kconfig"
 source "net/llc/Kconfig"
 source "net/ipx/Kconfig"
-source "drivers/net/appletalk/Kconfig"
 source "net/x25/Kconfig"
 source "net/lapb/Kconfig"
 source "net/econet/Kconfig"
index a3330ebe2c5345a32140e9b8b84445ac756dcecb..16d9947b4b956692c6b87a7f4f09f7417daa8c86 100644 (file)
@@ -27,7 +27,6 @@ obj-$(CONFIG_NET_KEY)         += key/
 obj-$(CONFIG_BRIDGE)           += bridge/
 obj-$(CONFIG_NET_DSA)          += dsa/
 obj-$(CONFIG_IPX)              += ipx/
-obj-$(CONFIG_ATALK)            += appletalk/
 obj-$(CONFIG_WAN_ROUTER)       += wanrouter/
 obj-$(CONFIG_X25)              += x25/
 obj-$(CONFIG_LAPB)             += lapb/
diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile
deleted file mode 100644 (file)
index 5cda56e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for the Linux AppleTalk layer.
-#
-
-obj-$(CONFIG_ATALK) += appletalk.o
-
-appletalk-y                    := aarp.o ddp.o dev.o
-appletalk-$(CONFIG_PROC_FS)    += atalk_proc.o
-appletalk-$(CONFIG_SYSCTL)     += sysctl_net_atalk.o
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
deleted file mode 100644 (file)
index 50dce79..0000000
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- *     AARP:           An implementation of the AppleTalk AARP protocol for
- *                     Ethernet 'ELAP'.
- *
- *             Alan Cox  <Alan.Cox@linux.org>
- *
- *     This doesn't fit cleanly with the IP arp. Potentially we can use
- *     the generic neighbour discovery code to clean this up.
- *
- *     FIXME:
- *             We ought to handle the retransmits with a single list and a
- *     separate fast timer for when it is needed.
- *             Use neighbour discovery code.
- *             Token Ring Support.
- *
- *             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.
- *
- *
- *     References:
- *             Inside AppleTalk (2nd Ed).
- *     Fixes:
- *             Jaume Grau      -       flush caches on AARP_PROBE
- *             Rob Newberry    -       Added proxy AARP and AARP proc fs,
- *                                     moved probing from DDP module.
- *             Arnaldo C. Melo -       don't mangle rx packets
- *
- */
-
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <net/sock.h>
-#include <net/datalink.h>
-#include <net/psnap.h>
-#include <linux/atalk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
-int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
-int sysctl_aarp_tick_time = AARP_TICK_TIME;
-int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT;
-int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME;
-
-/* Lists of aarp entries */
-/**
- *     struct aarp_entry - AARP entry
- *     @last_sent - Last time we xmitted the aarp request
- *     @packet_queue - Queue of frames wait for resolution
- *     @status - Used for proxy AARP
- *     expires_at - Entry expiry time
- *     target_addr - DDP Address
- *     dev - Device to use
- *     hwaddr - Physical i/f address of target/router
- *     xmit_count - When this hits 10 we give up
- *     next - Next entry in chain
- */
-struct aarp_entry {
-       /* These first two are only used for unresolved entries */
-       unsigned long           last_sent;
-       struct sk_buff_head     packet_queue;
-       int                     status;
-       unsigned long           expires_at;
-       struct atalk_addr       target_addr;
-       struct net_device       *dev;
-       char                    hwaddr[6];
-       unsigned short          xmit_count;
-       struct aarp_entry       *next;
-};
-
-/* Hashed list of resolved, unresolved and proxy entries */
-static struct aarp_entry *resolved[AARP_HASH_SIZE];
-static struct aarp_entry *unresolved[AARP_HASH_SIZE];
-static struct aarp_entry *proxies[AARP_HASH_SIZE];
-static int unresolved_count;
-
-/* One lock protects it all. */
-static DEFINE_RWLOCK(aarp_lock);
-
-/* Used to walk the list and purge/kick entries.  */
-static struct timer_list aarp_timer;
-
-/*
- *     Delete an aarp queue
- *
- *     Must run under aarp_lock.
- */
-static void __aarp_expire(struct aarp_entry *a)
-{
-       skb_queue_purge(&a->packet_queue);
-       kfree(a);
-}
-
-/*
- *     Send an aarp queue entry request
- *
- *     Must run under aarp_lock.
- */
-static void __aarp_send_query(struct aarp_entry *a)
-{
-       static unsigned char aarp_eth_multicast[ETH_ALEN] =
-                                       { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
-       struct net_device *dev = a->dev;
-       struct elapaarp *eah;
-       int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
-       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
-       struct atalk_addr *sat = atalk_find_dev_addr(dev);
-
-       if (!skb)
-               return;
-
-       if (!sat) {
-               kfree_skb(skb);
-               return;
-       }
-
-       /* Set up the buffer */
-       skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-       skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
-       skb_put(skb, sizeof(*eah));
-       skb->protocol    = htons(ETH_P_ATALK);
-       skb->dev         = dev;
-       eah              = aarp_hdr(skb);
-
-       /* Set up the ARP */
-       eah->hw_type     = htons(AARP_HW_TYPE_ETHERNET);
-       eah->pa_type     = htons(ETH_P_ATALK);
-       eah->hw_len      = ETH_ALEN;
-       eah->pa_len      = AARP_PA_ALEN;
-       eah->function    = htons(AARP_REQUEST);
-
-       memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-
-       eah->pa_src_zero = 0;
-       eah->pa_src_net  = sat->s_net;
-       eah->pa_src_node = sat->s_node;
-
-       memset(eah->hw_dst, '\0', ETH_ALEN);
-
-       eah->pa_dst_zero = 0;
-       eah->pa_dst_net  = a->target_addr.s_net;
-       eah->pa_dst_node = a->target_addr.s_node;
-
-       /* Send it */
-       aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
-       /* Update the sending count */
-       a->xmit_count++;
-       a->last_sent = jiffies;
-}
-
-/* This runs under aarp_lock and in softint context, so only atomic memory
- * allocations can be used. */
-static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us,
-                           struct atalk_addr *them, unsigned char *sha)
-{
-       struct elapaarp *eah;
-       int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
-       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
-
-       if (!skb)
-               return;
-
-       /* Set up the buffer */
-       skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-       skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
-       skb_put(skb, sizeof(*eah));
-       skb->protocol    = htons(ETH_P_ATALK);
-       skb->dev         = dev;
-       eah              = aarp_hdr(skb);
-
-       /* Set up the ARP */
-       eah->hw_type     = htons(AARP_HW_TYPE_ETHERNET);
-       eah->pa_type     = htons(ETH_P_ATALK);
-       eah->hw_len      = ETH_ALEN;
-       eah->pa_len      = AARP_PA_ALEN;
-       eah->function    = htons(AARP_REPLY);
-
-       memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-
-       eah->pa_src_zero = 0;
-       eah->pa_src_net  = us->s_net;
-       eah->pa_src_node = us->s_node;
-
-       if (!sha)
-               memset(eah->hw_dst, '\0', ETH_ALEN);
-       else
-               memcpy(eah->hw_dst, sha, ETH_ALEN);
-
-       eah->pa_dst_zero = 0;
-       eah->pa_dst_net  = them->s_net;
-       eah->pa_dst_node = them->s_node;
-
-       /* Send it */
-       aarp_dl->request(aarp_dl, skb, sha);
-}
-
-/*
- *     Send probe frames. Called from aarp_probe_network and
- *     aarp_proxy_probe_network.
- */
-
-static void aarp_send_probe(struct net_device *dev, struct atalk_addr *us)
-{
-       struct elapaarp *eah;
-       int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
-       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
-       static unsigned char aarp_eth_multicast[ETH_ALEN] =
-                                       { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
-
-       if (!skb)
-               return;
-
-       /* Set up the buffer */
-       skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-       skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
-       skb_put(skb, sizeof(*eah));
-       skb->protocol    = htons(ETH_P_ATALK);
-       skb->dev         = dev;
-       eah              = aarp_hdr(skb);
-
-       /* Set up the ARP */
-       eah->hw_type     = htons(AARP_HW_TYPE_ETHERNET);
-       eah->pa_type     = htons(ETH_P_ATALK);
-       eah->hw_len      = ETH_ALEN;
-       eah->pa_len      = AARP_PA_ALEN;
-       eah->function    = htons(AARP_PROBE);
-
-       memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-
-       eah->pa_src_zero = 0;
-       eah->pa_src_net  = us->s_net;
-       eah->pa_src_node = us->s_node;
-
-       memset(eah->hw_dst, '\0', ETH_ALEN);
-
-       eah->pa_dst_zero = 0;
-       eah->pa_dst_net  = us->s_net;
-       eah->pa_dst_node = us->s_node;
-
-       /* Send it */
-       aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
-}
-
-/*
- *     Handle an aarp timer expire
- *
- *     Must run under the aarp_lock.
- */
-
-static void __aarp_expire_timer(struct aarp_entry **n)
-{
-       struct aarp_entry *t;
-
-       while (*n)
-               /* Expired ? */
-               if (time_after(jiffies, (*n)->expires_at)) {
-                       t = *n;
-                       *n = (*n)->next;
-                       __aarp_expire(t);
-               } else
-                       n = &((*n)->next);
-}
-
-/*
- *     Kick all pending requests 5 times a second.
- *
- *     Must run under the aarp_lock.
- */
-static void __aarp_kick(struct aarp_entry **n)
-{
-       struct aarp_entry *t;
-
-       while (*n)
-               /* Expired: if this will be the 11th tx, we delete instead. */
-               if ((*n)->xmit_count >= sysctl_aarp_retransmit_limit) {
-                       t = *n;
-                       *n = (*n)->next;
-                       __aarp_expire(t);
-               } else {
-                       __aarp_send_query(*n);
-                       n = &((*n)->next);
-               }
-}
-
-/*
- *     A device has gone down. Take all entries referring to the device
- *     and remove them.
- *
- *     Must run under the aarp_lock.
- */
-static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
-{
-       struct aarp_entry *t;
-
-       while (*n)
-               if ((*n)->dev == dev) {
-                       t = *n;
-                       *n = (*n)->next;
-                       __aarp_expire(t);
-               } else
-                       n = &((*n)->next);
-}
-
-/* Handle the timer event */
-static void aarp_expire_timeout(unsigned long unused)
-{
-       int ct;
-
-       write_lock_bh(&aarp_lock);
-
-       for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
-               __aarp_expire_timer(&resolved[ct]);
-               __aarp_kick(&unresolved[ct]);
-               __aarp_expire_timer(&unresolved[ct]);
-               __aarp_expire_timer(&proxies[ct]);
-       }
-
-       write_unlock_bh(&aarp_lock);
-       mod_timer(&aarp_timer, jiffies +
-                              (unresolved_count ? sysctl_aarp_tick_time :
-                               sysctl_aarp_expiry_time));
-}
-
-/* Network device notifier chain handler. */
-static int aarp_device_event(struct notifier_block *this, unsigned long event,
-                            void *ptr)
-{
-       struct net_device *dev = ptr;
-       int ct;
-
-       if (!net_eq(dev_net(dev), &init_net))
-               return NOTIFY_DONE;
-
-       if (event == NETDEV_DOWN) {
-               write_lock_bh(&aarp_lock);
-
-               for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
-                       __aarp_expire_device(&resolved[ct], dev);
-                       __aarp_expire_device(&unresolved[ct], dev);
-                       __aarp_expire_device(&proxies[ct], dev);
-               }
-
-               write_unlock_bh(&aarp_lock);
-       }
-       return NOTIFY_DONE;
-}
-
-/* Expire all entries in a hash chain */
-static void __aarp_expire_all(struct aarp_entry **n)
-{
-       struct aarp_entry *t;
-
-       while (*n) {
-               t = *n;
-               *n = (*n)->next;
-               __aarp_expire(t);
-       }
-}
-
-/* Cleanup all hash chains -- module unloading */
-static void aarp_purge(void)
-{
-       int ct;
-
-       write_lock_bh(&aarp_lock);
-       for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
-               __aarp_expire_all(&resolved[ct]);
-               __aarp_expire_all(&unresolved[ct]);
-               __aarp_expire_all(&proxies[ct]);
-       }
-       write_unlock_bh(&aarp_lock);
-}
-
-/*
- *     Create a new aarp entry.  This must use GFP_ATOMIC because it
- *     runs while holding spinlocks.
- */
-static struct aarp_entry *aarp_alloc(void)
-{
-       struct aarp_entry *a = kmalloc(sizeof(*a), GFP_ATOMIC);
-
-       if (a)
-               skb_queue_head_init(&a->packet_queue);
-       return a;
-}
-
-/*
- * Find an entry. We might return an expired but not yet purged entry. We
- * don't care as it will do no harm.
- *
- * This must run under the aarp_lock.
- */
-static struct aarp_entry *__aarp_find_entry(struct aarp_entry *list,
-                                           struct net_device *dev,
-                                           struct atalk_addr *sat)
-{
-       while (list) {
-               if (list->target_addr.s_net == sat->s_net &&
-                   list->target_addr.s_node == sat->s_node &&
-                   list->dev == dev)
-                       break;
-               list = list->next;
-       }
-
-       return list;
-}
-
-/* Called from the DDP code, and thus must be exported. */
-void aarp_proxy_remove(struct net_device *dev, struct atalk_addr *sa)
-{
-       int hash = sa->s_node % (AARP_HASH_SIZE - 1);
-       struct aarp_entry *a;
-
-       write_lock_bh(&aarp_lock);
-
-       a = __aarp_find_entry(proxies[hash], dev, sa);
-       if (a)
-               a->expires_at = jiffies - 1;
-
-       write_unlock_bh(&aarp_lock);
-}
-
-/* This must run under aarp_lock. */
-static struct atalk_addr *__aarp_proxy_find(struct net_device *dev,
-                                           struct atalk_addr *sa)
-{
-       int hash = sa->s_node % (AARP_HASH_SIZE - 1);
-       struct aarp_entry *a = __aarp_find_entry(proxies[hash], dev, sa);
-
-       return a ? sa : NULL;
-}
-
-/*
- * Probe a Phase 1 device or a device that requires its Net:Node to
- * be set via an ioctl.
- */
-static void aarp_send_probe_phase1(struct atalk_iface *iface)
-{
-       struct ifreq atreq;
-       struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
-       const struct net_device_ops *ops = iface->dev->netdev_ops;
-
-       sa->sat_addr.s_node = iface->address.s_node;
-       sa->sat_addr.s_net = ntohs(iface->address.s_net);
-
-       /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
-       if (!(ops->ndo_do_ioctl(iface->dev, &atreq, SIOCSIFADDR))) {
-               ops->ndo_do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
-               if (iface->address.s_net != htons(sa->sat_addr.s_net) ||
-                   iface->address.s_node != sa->sat_addr.s_node)
-                       iface->status |= ATIF_PROBE_FAIL;
-
-               iface->address.s_net  = htons(sa->sat_addr.s_net);
-               iface->address.s_node = sa->sat_addr.s_node;
-       }
-}
-
-
-void aarp_probe_network(struct atalk_iface *atif)
-{
-       if (atif->dev->type == ARPHRD_LOCALTLK ||
-           atif->dev->type == ARPHRD_PPP)
-               aarp_send_probe_phase1(atif);
-       else {
-               unsigned int count;
-
-               for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
-                       aarp_send_probe(atif->dev, &atif->address);
-
-                       /* Defer 1/10th */
-                       msleep(100);
-
-                       if (atif->status & ATIF_PROBE_FAIL)
-                               break;
-               }
-       }
-}
-
-int aarp_proxy_probe_network(struct atalk_iface *atif, struct atalk_addr *sa)
-{
-       int hash, retval = -EPROTONOSUPPORT;
-       struct aarp_entry *entry;
-       unsigned int count;
-
-       /*
-        * we don't currently support LocalTalk or PPP for proxy AARP;
-        * if someone wants to try and add it, have fun
-        */
-       if (atif->dev->type == ARPHRD_LOCALTLK ||
-           atif->dev->type == ARPHRD_PPP)
-               goto out;
-
-       /*
-        * create a new AARP entry with the flags set to be published --
-        * we need this one to hang around even if it's in use
-        */
-       entry = aarp_alloc();
-       retval = -ENOMEM;
-       if (!entry)
-               goto out;
-
-       entry->expires_at = -1;
-       entry->status = ATIF_PROBE;
-       entry->target_addr.s_node = sa->s_node;
-       entry->target_addr.s_net = sa->s_net;
-       entry->dev = atif->dev;
-
-       write_lock_bh(&aarp_lock);
-
-       hash = sa->s_node % (AARP_HASH_SIZE - 1);
-       entry->next = proxies[hash];
-       proxies[hash] = entry;
-
-       for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
-               aarp_send_probe(atif->dev, sa);
-
-               /* Defer 1/10th */
-               write_unlock_bh(&aarp_lock);
-               msleep(100);
-               write_lock_bh(&aarp_lock);
-
-               if (entry->status & ATIF_PROBE_FAIL)
-                       break;
-       }
-
-       if (entry->status & ATIF_PROBE_FAIL) {
-               entry->expires_at = jiffies - 1; /* free the entry */
-               retval = -EADDRINUSE; /* return network full */
-       } else { /* clear the probing flag */
-               entry->status &= ~ATIF_PROBE;
-               retval = 1;
-       }
-
-       write_unlock_bh(&aarp_lock);
-out:
-       return retval;
-}
-
-/* Send a DDP frame */
-int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
-                 struct atalk_addr *sa, void *hwaddr)
-{
-       static char ddp_eth_multicast[ETH_ALEN] =
-               { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
-       int hash;
-       struct aarp_entry *a;
-
-       skb_reset_network_header(skb);
-
-       /* Check for LocalTalk first */
-       if (dev->type == ARPHRD_LOCALTLK) {
-               struct atalk_addr *at = atalk_find_dev_addr(dev);
-               struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
-               int ft = 2;
-
-               /*
-                * Compressible ?
-                *
-                * IFF: src_net == dest_net == device_net
-                * (zero matches anything)
-                */
-
-               if ((!ddp->deh_snet || at->s_net == ddp->deh_snet) &&
-                   (!ddp->deh_dnet || at->s_net == ddp->deh_dnet)) {
-                       skb_pull(skb, sizeof(*ddp) - 4);
-
-                       /*
-                        *      The upper two remaining bytes are the port
-                        *      numbers we just happen to need. Now put the
-                        *      length in the lower two.
-                        */
-                       *((__be16 *)skb->data) = htons(skb->len);
-                       ft = 1;
-               }
-               /*
-                * Nice and easy. No AARP type protocols occur here so we can
-                * just shovel it out with a 3 byte LLAP header
-                */
-
-               skb_push(skb, 3);
-               skb->data[0] = sa->s_node;
-               skb->data[1] = at->s_node;
-               skb->data[2] = ft;
-               skb->dev     = dev;
-               goto sendit;
-       }
-
-       /* On a PPP link we neither compress nor aarp.  */
-       if (dev->type == ARPHRD_PPP) {
-               skb->protocol = htons(ETH_P_PPPTALK);
-               skb->dev = dev;
-               goto sendit;
-       }
-
-       /* Non ELAP we cannot do. */
-       if (dev->type != ARPHRD_ETHER)
-               goto free_it;
-
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_ATALK);
-       hash = sa->s_node % (AARP_HASH_SIZE - 1);
-
-       /* Do we have a resolved entry? */
-       if (sa->s_node == ATADDR_BCAST) {
-               /* Send it */
-               ddp_dl->request(ddp_dl, skb, ddp_eth_multicast);
-               goto sent;
-       }
-
-       write_lock_bh(&aarp_lock);
-       a = __aarp_find_entry(resolved[hash], dev, sa);
-
-       if (a) { /* Return 1 and fill in the address */
-               a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
-               ddp_dl->request(ddp_dl, skb, a->hwaddr);
-               write_unlock_bh(&aarp_lock);
-               goto sent;
-       }
-
-       /* Do we have an unresolved entry: This is the less common path */
-       a = __aarp_find_entry(unresolved[hash], dev, sa);
-       if (a) { /* Queue onto the unresolved queue */
-               skb_queue_tail(&a->packet_queue, skb);
-               goto out_unlock;
-       }
-
-       /* Allocate a new entry */
-       a = aarp_alloc();
-       if (!a) {
-               /* Whoops slipped... good job it's an unreliable protocol 8) */
-               write_unlock_bh(&aarp_lock);
-               goto free_it;
-       }
-
-       /* Set up the queue */
-       skb_queue_tail(&a->packet_queue, skb);
-       a->expires_at    = jiffies + sysctl_aarp_resolve_time;
-       a->dev           = dev;
-       a->next          = unresolved[hash];
-       a->target_addr   = *sa;
-       a->xmit_count    = 0;
-       unresolved[hash] = a;
-       unresolved_count++;
-
-       /* Send an initial request for the address */
-       __aarp_send_query(a);
-
-       /*
-        * Switch to fast timer if needed (That is if this is the first
-        * unresolved entry to get added)
-        */
-
-       if (unresolved_count == 1)
-               mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time);
-
-       /* Now finally, it is safe to drop the lock. */
-out_unlock:
-       write_unlock_bh(&aarp_lock);
-
-       /* Tell the ddp layer we have taken over for this frame. */
-       goto sent;
-
-sendit:
-       if (skb->sk)
-               skb->priority = skb->sk->sk_priority;
-       if (dev_queue_xmit(skb))
-               goto drop;
-sent:
-       return NET_XMIT_SUCCESS;
-free_it:
-       kfree_skb(skb);
-drop:
-       return NET_XMIT_DROP;
-}
-EXPORT_SYMBOL(aarp_send_ddp);
-
-/*
- *     An entry in the aarp unresolved queue has become resolved. Send
- *     all the frames queued under it.
- *
- *     Must run under aarp_lock.
- */
-static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a,
-                           int hash)
-{
-       struct sk_buff *skb;
-
-       while (*list)
-               if (*list == a) {
-                       unresolved_count--;
-                       *list = a->next;
-
-                       /* Move into the resolved list */
-                       a->next = resolved[hash];
-                       resolved[hash] = a;
-
-                       /* Kick frames off */
-                       while ((skb = skb_dequeue(&a->packet_queue)) != NULL) {
-                               a->expires_at = jiffies +
-                                               sysctl_aarp_expiry_time * 10;
-                               ddp_dl->request(ddp_dl, skb, a->hwaddr);
-                       }
-               } else
-                       list = &((*list)->next);
-}
-
-/*
- *     This is called by the SNAP driver whenever we see an AARP SNAP
- *     frame. We currently only support Ethernet.
- */
-static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
-                   struct packet_type *pt, struct net_device *orig_dev)
-{
-       struct elapaarp *ea = aarp_hdr(skb);
-       int hash, ret = 0;
-       __u16 function;
-       struct aarp_entry *a;
-       struct atalk_addr sa, *ma, da;
-       struct atalk_iface *ifa;
-
-       if (!net_eq(dev_net(dev), &init_net))
-               goto out0;
-
-       /* We only do Ethernet SNAP AARP. */
-       if (dev->type != ARPHRD_ETHER)
-               goto out0;
-
-       /* Frame size ok? */
-       if (!skb_pull(skb, sizeof(*ea)))
-               goto out0;
-
-       function = ntohs(ea->function);
-
-       /* Sanity check fields. */
-       if (function < AARP_REQUEST || function > AARP_PROBE ||
-           ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN ||
-           ea->pa_src_zero || ea->pa_dst_zero)
-               goto out0;
-
-       /* Looks good. */
-       hash = ea->pa_src_node % (AARP_HASH_SIZE - 1);
-
-       /* Build an address. */
-       sa.s_node = ea->pa_src_node;
-       sa.s_net = ea->pa_src_net;
-
-       /* Process the packet. Check for replies of me. */
-       ifa = atalk_find_dev(dev);
-       if (!ifa)
-               goto out1;
-
-       if (ifa->status & ATIF_PROBE &&
-           ifa->address.s_node == ea->pa_dst_node &&
-           ifa->address.s_net == ea->pa_dst_net) {
-               ifa->status |= ATIF_PROBE_FAIL; /* Fail the probe (in use) */
-               goto out1;
-       }
-
-       /* Check for replies of proxy AARP entries */
-       da.s_node = ea->pa_dst_node;
-       da.s_net  = ea->pa_dst_net;
-
-       write_lock_bh(&aarp_lock);
-       a = __aarp_find_entry(proxies[hash], dev, &da);
-
-       if (a && a->status & ATIF_PROBE) {
-               a->status |= ATIF_PROBE_FAIL;
-               /*
-                * we do not respond to probe or request packets for
-                * this address while we are probing this address
-                */
-               goto unlock;
-       }
-
-       switch (function) {
-               case AARP_REPLY:
-                       if (!unresolved_count)  /* Speed up */
-                               break;
-
-                       /* Find the entry.  */
-                       a = __aarp_find_entry(unresolved[hash], dev, &sa);
-                       if (!a || dev != a->dev)
-                               break;
-
-                       /* We can fill one in - this is good. */
-                       memcpy(a->hwaddr, ea->hw_src, ETH_ALEN);
-                       __aarp_resolved(&unresolved[hash], a, hash);
-                       if (!unresolved_count)
-                               mod_timer(&aarp_timer,
-                                         jiffies + sysctl_aarp_expiry_time);
-                       break;
-
-               case AARP_REQUEST:
-               case AARP_PROBE:
-
-                       /*
-                        * If it is my address set ma to my address and reply.
-                        * We can treat probe and request the same.  Probe
-                        * simply means we shouldn't cache the querying host,
-                        * as in a probe they are proposing an address not
-                        * using one.
-                        *
-                        * Support for proxy-AARP added. We check if the
-                        * address is one of our proxies before we toss the
-                        * packet out.
-                        */
-
-                       sa.s_node = ea->pa_dst_node;
-                       sa.s_net  = ea->pa_dst_net;
-
-                       /* See if we have a matching proxy. */
-                       ma = __aarp_proxy_find(dev, &sa);
-                       if (!ma)
-                               ma = &ifa->address;
-                       else { /* We need to make a copy of the entry. */
-                               da.s_node = sa.s_node;
-                               da.s_net = sa.s_net;
-                               ma = &da;
-                       }
-
-                       if (function == AARP_PROBE) {
-                               /*
-                                * A probe implies someone trying to get an
-                                * address. So as a precaution flush any
-                                * entries we have for this address.
-                                */
-                               a = __aarp_find_entry(resolved[sa.s_node %
-                                                         (AARP_HASH_SIZE - 1)],
-                                                     skb->dev, &sa);
-
-                               /*
-                                * Make it expire next tick - that avoids us
-                                * getting into a probe/flush/learn/probe/
-                                * flush/learn cycle during probing of a slow
-                                * to respond host addr.
-                                */
-                               if (a) {
-                                       a->expires_at = jiffies - 1;
-                                       mod_timer(&aarp_timer, jiffies +
-                                                       sysctl_aarp_tick_time);
-                               }
-                       }
-
-                       if (sa.s_node != ma->s_node)
-                               break;
-
-                       if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
-                               break;
-
-                       sa.s_node = ea->pa_src_node;
-                       sa.s_net = ea->pa_src_net;
-
-                       /* aarp_my_address has found the address to use for us.
-                       */
-                       aarp_send_reply(dev, ma, &sa, ea->hw_src);
-                       break;
-       }
-
-unlock:
-       write_unlock_bh(&aarp_lock);
-out1:
-       ret = 1;
-out0:
-       kfree_skb(skb);
-       return ret;
-}
-
-static struct notifier_block aarp_notifier = {
-       .notifier_call = aarp_device_event,
-};
-
-static unsigned char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
-
-void __init aarp_proto_init(void)
-{
-       aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv);
-       if (!aarp_dl)
-               printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
-       setup_timer(&aarp_timer, aarp_expire_timeout, 0);
-       aarp_timer.expires  = jiffies + sysctl_aarp_expiry_time;
-       add_timer(&aarp_timer);
-       register_netdevice_notifier(&aarp_notifier);
-}
-
-/* Remove the AARP entries associated with a device. */
-void aarp_device_down(struct net_device *dev)
-{
-       int ct;
-
-       write_lock_bh(&aarp_lock);
-
-       for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
-               __aarp_expire_device(&resolved[ct], dev);
-               __aarp_expire_device(&unresolved[ct], dev);
-               __aarp_expire_device(&proxies[ct], dev);
-       }
-
-       write_unlock_bh(&aarp_lock);
-}
-
-#ifdef CONFIG_PROC_FS
-struct aarp_iter_state {
-       int bucket;
-       struct aarp_entry **table;
-};
-
-/*
- * Get the aarp entry that is in the chain described
- * by the iterator.
- * If pos is set then skip till that index.
- * pos = 1 is the first entry
- */
-static struct aarp_entry *iter_next(struct aarp_iter_state *iter, loff_t *pos)
-{
-       int ct = iter->bucket;
-       struct aarp_entry **table = iter->table;
-       loff_t off = 0;
-       struct aarp_entry *entry;
-
- rescan:
-       while(ct < AARP_HASH_SIZE) {
-               for (entry = table[ct]; entry; entry = entry->next) {
-                       if (!pos || ++off == *pos) {
-                               iter->table = table;
-                               iter->bucket = ct;
-                               return entry;
-                       }
-               }
-               ++ct;
-       }
-
-       if (table == resolved) {
-               ct = 0;
-               table = unresolved;
-               goto rescan;
-       }
-       if (table == unresolved) {
-               ct = 0;
-               table = proxies;
-               goto rescan;
-       }
-       return NULL;
-}
-
-static void *aarp_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(aarp_lock)
-{
-       struct aarp_iter_state *iter = seq->private;
-
-       read_lock_bh(&aarp_lock);
-       iter->table     = resolved;
-       iter->bucket    = 0;
-
-       return *pos ? iter_next(iter, pos) : SEQ_START_TOKEN;
-}
-
-static void *aarp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       struct aarp_entry *entry = v;
-       struct aarp_iter_state *iter = seq->private;
-
-       ++*pos;
-
-       /* first line after header */
-       if (v == SEQ_START_TOKEN)
-               entry = iter_next(iter, NULL);
-
-       /* next entry in current bucket */
-       else if (entry->next)
-               entry = entry->next;
-
-       /* next bucket or table */
-       else {
-               ++iter->bucket;
-               entry = iter_next(iter, NULL);
-       }
-       return entry;
-}
-
-static void aarp_seq_stop(struct seq_file *seq, void *v)
-       __releases(aarp_lock)
-{
-       read_unlock_bh(&aarp_lock);
-}
-
-static const char *dt2str(unsigned long ticks)
-{
-       static char buf[32];
-
-       sprintf(buf, "%ld.%02ld", ticks / HZ, ((ticks % HZ) * 100 ) / HZ);
-
-       return buf;
-}
-
-static int aarp_seq_show(struct seq_file *seq, void *v)
-{
-       struct aarp_iter_state *iter = seq->private;
-       struct aarp_entry *entry = v;
-       unsigned long now = jiffies;
-
-       if (v == SEQ_START_TOKEN)
-               seq_puts(seq,
-                        "Address  Interface   Hardware Address"
-                        "   Expires LastSend  Retry Status\n");
-       else {
-               seq_printf(seq, "%04X:%02X  %-12s",
-                          ntohs(entry->target_addr.s_net),
-                          (unsigned int) entry->target_addr.s_node,
-                          entry->dev ? entry->dev->name : "????");
-               seq_printf(seq, "%pM", entry->hwaddr);
-               seq_printf(seq, " %8s",
-                          dt2str((long)entry->expires_at - (long)now));
-               if (iter->table == unresolved)
-                       seq_printf(seq, " %8s %6hu",
-                                  dt2str(now - entry->last_sent),
-                                  entry->xmit_count);
-               else
-                       seq_puts(seq, "                ");
-               seq_printf(seq, " %s\n",
-                          (iter->table == resolved) ? "resolved"
-                          : (iter->table == unresolved) ? "unresolved"
-                          : (iter->table == proxies) ? "proxies"
-                          : "unknown");
-       }
-       return 0;
-}
-
-static const struct seq_operations aarp_seq_ops = {
-       .start  = aarp_seq_start,
-       .next   = aarp_seq_next,
-       .stop   = aarp_seq_stop,
-       .show   = aarp_seq_show,
-};
-
-static int aarp_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open_private(file, &aarp_seq_ops,
-                       sizeof(struct aarp_iter_state));
-}
-
-const struct file_operations atalk_seq_arp_fops = {
-       .owner          = THIS_MODULE,
-       .open           = aarp_seq_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release_private,
-};
-#endif
-
-/* General module cleanup. Called from cleanup_module() in ddp.c. */
-void aarp_cleanup_module(void)
-{
-       del_timer_sync(&aarp_timer);
-       unregister_netdevice_notifier(&aarp_notifier);
-       unregister_snap_client(aarp_dl);
-       aarp_purge();
-}
diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
deleted file mode 100644 (file)
index 6ef0e76..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- *     atalk_proc.c - proc support for Appletalk
- *
- *     Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- *     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, version 2.
- */
-
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <net/net_namespace.h>
-#include <net/sock.h>
-#include <linux/atalk.h>
-
-
-static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos)
-{
-       struct atalk_iface *i;
-
-       for (i = atalk_interfaces; pos && i; i = i->next)
-               --pos;
-
-       return i;
-}
-
-static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos)
-       __acquires(atalk_interfaces_lock)
-{
-       loff_t l = *pos;
-
-       read_lock_bh(&atalk_interfaces_lock);
-       return l ? atalk_get_interface_idx(--l) : SEQ_START_TOKEN;
-}
-
-static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       struct atalk_iface *i;
-
-       ++*pos;
-       if (v == SEQ_START_TOKEN) {
-               i = NULL;
-               if (atalk_interfaces)
-                       i = atalk_interfaces;
-               goto out;
-       }
-       i = v;
-       i = i->next;
-out:
-       return i;
-}
-
-static void atalk_seq_interface_stop(struct seq_file *seq, void *v)
-       __releases(atalk_interfaces_lock)
-{
-       read_unlock_bh(&atalk_interfaces_lock);
-}
-
-static int atalk_seq_interface_show(struct seq_file *seq, void *v)
-{
-       struct atalk_iface *iface;
-
-       if (v == SEQ_START_TOKEN) {
-               seq_puts(seq, "Interface        Address   Networks  "
-                             "Status\n");
-               goto out;
-       }
-
-       iface = v;
-       seq_printf(seq, "%-16s %04X:%02X  %04X-%04X  %d\n",
-                  iface->dev->name, ntohs(iface->address.s_net),
-                  iface->address.s_node, ntohs(iface->nets.nr_firstnet),
-                  ntohs(iface->nets.nr_lastnet), iface->status);
-out:
-       return 0;
-}
-
-static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos)
-{
-       struct atalk_route *r;
-
-       for (r = atalk_routes; pos && r; r = r->next)
-               --pos;
-
-       return r;
-}
-
-static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos)
-       __acquires(atalk_routes_lock)
-{
-       loff_t l = *pos;
-
-       read_lock_bh(&atalk_routes_lock);
-       return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN;
-}
-
-static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       struct atalk_route *r;
-
-       ++*pos;
-       if (v == SEQ_START_TOKEN) {
-               r = NULL;
-               if (atalk_routes)
-                       r = atalk_routes;
-               goto out;
-       }
-       r = v;
-       r = r->next;
-out:
-       return r;
-}
-
-static void atalk_seq_route_stop(struct seq_file *seq, void *v)
-       __releases(atalk_routes_lock)
-{
-       read_unlock_bh(&atalk_routes_lock);
-}
-
-static int atalk_seq_route_show(struct seq_file *seq, void *v)
-{
-       struct atalk_route *rt;
-
-       if (v == SEQ_START_TOKEN) {
-               seq_puts(seq, "Target        Router  Flags Dev\n");
-               goto out;
-       }
-
-       if (atrtr_default.dev) {
-               rt = &atrtr_default;
-               seq_printf(seq, "Default     %04X:%02X  %-4d  %s\n",
-                              ntohs(rt->gateway.s_net), rt->gateway.s_node,
-                              rt->flags, rt->dev->name);
-       }
-
-       rt = v;
-       seq_printf(seq, "%04X:%02X     %04X:%02X  %-4d  %s\n",
-                  ntohs(rt->target.s_net), rt->target.s_node,
-                  ntohs(rt->gateway.s_net), rt->gateway.s_node,
-                  rt->flags, rt->dev->name);
-out:
-       return 0;
-}
-
-static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
-       __acquires(atalk_sockets_lock)
-{
-       read_lock_bh(&atalk_sockets_lock);
-       return seq_hlist_start_head(&atalk_sockets, *pos);
-}
-
-static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return seq_hlist_next(v, &atalk_sockets, pos);
-}
-
-static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
-       __releases(atalk_sockets_lock)
-{
-       read_unlock_bh(&atalk_sockets_lock);
-}
-
-static int atalk_seq_socket_show(struct seq_file *seq, void *v)
-{
-       struct sock *s;
-       struct atalk_sock *at;
-
-       if (v == SEQ_START_TOKEN) {
-               seq_printf(seq, "Type Local_addr  Remote_addr Tx_queue "
-                               "Rx_queue St UID\n");
-               goto out;
-       }
-
-       s = sk_entry(v);
-       at = at_sk(s);
-
-       seq_printf(seq, "%02X   %04X:%02X:%02X  %04X:%02X:%02X  %08X:%08X "
-                       "%02X %d\n",
-                  s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
-                  ntohs(at->dest_net), at->dest_node, at->dest_port,
-                  sk_wmem_alloc_get(s),
-                  sk_rmem_alloc_get(s),
-                  s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
-out:
-       return 0;
-}
-
-static const struct seq_operations atalk_seq_interface_ops = {
-       .start  = atalk_seq_interface_start,
-       .next   = atalk_seq_interface_next,
-       .stop   = atalk_seq_interface_stop,
-       .show   = atalk_seq_interface_show,
-};
-
-static const struct seq_operations atalk_seq_route_ops = {
-       .start  = atalk_seq_route_start,
-       .next   = atalk_seq_route_next,
-       .stop   = atalk_seq_route_stop,
-       .show   = atalk_seq_route_show,
-};
-
-static const struct seq_operations atalk_seq_socket_ops = {
-       .start  = atalk_seq_socket_start,
-       .next   = atalk_seq_socket_next,
-       .stop   = atalk_seq_socket_stop,
-       .show   = atalk_seq_socket_show,
-};
-
-static int atalk_seq_interface_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &atalk_seq_interface_ops);
-}
-
-static int atalk_seq_route_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &atalk_seq_route_ops);
-}
-
-static int atalk_seq_socket_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &atalk_seq_socket_ops);
-}
-
-static const struct file_operations atalk_seq_interface_fops = {
-       .owner          = THIS_MODULE,
-       .open           = atalk_seq_interface_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static const struct file_operations atalk_seq_route_fops = {
-       .owner          = THIS_MODULE,
-       .open           = atalk_seq_route_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static const struct file_operations atalk_seq_socket_fops = {
-       .owner          = THIS_MODULE,
-       .open           = atalk_seq_socket_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static struct proc_dir_entry *atalk_proc_dir;
-
-int __init atalk_proc_init(void)
-{
-       struct proc_dir_entry *p;
-       int rc = -ENOMEM;
-
-       atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net);
-       if (!atalk_proc_dir)
-               goto out;
-
-       p = proc_create("interface", S_IRUGO, atalk_proc_dir,
-                       &atalk_seq_interface_fops);
-       if (!p)
-               goto out_interface;
-
-       p = proc_create("route", S_IRUGO, atalk_proc_dir,
-                       &atalk_seq_route_fops);
-       if (!p)
-               goto out_route;
-
-       p = proc_create("socket", S_IRUGO, atalk_proc_dir,
-                       &atalk_seq_socket_fops);
-       if (!p)
-               goto out_socket;
-
-       p = proc_create("arp", S_IRUGO, atalk_proc_dir, &atalk_seq_arp_fops);
-       if (!p)
-               goto out_arp;
-
-       rc = 0;
-out:
-       return rc;
-out_arp:
-       remove_proc_entry("socket", atalk_proc_dir);
-out_socket:
-       remove_proc_entry("route", atalk_proc_dir);
-out_route:
-       remove_proc_entry("interface", atalk_proc_dir);
-out_interface:
-       remove_proc_entry("atalk", init_net.proc_net);
-       goto out;
-}
-
-void __exit atalk_proc_exit(void)
-{
-       remove_proc_entry("interface", atalk_proc_dir);
-       remove_proc_entry("route", atalk_proc_dir);
-       remove_proc_entry("socket", atalk_proc_dir);
-       remove_proc_entry("arp", atalk_proc_dir);
-       remove_proc_entry("atalk", init_net.proc_net);
-}
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
deleted file mode 100644 (file)
index c410b93..0000000
+++ /dev/null
@@ -1,1981 +0,0 @@
-/*
- *     DDP:    An implementation of the AppleTalk DDP protocol for
- *             Ethernet 'ELAP'.
- *
- *             Alan Cox  <alan@lxorguk.ukuu.org.uk>
- *
- *             With more than a little assistance from
- *
- *             Wesley Craig <netatalk@umich.edu>
- *
- *     Fixes:
- *             Neil Horman             :       Added missing device ioctls
- *             Michael Callahan        :       Made routing work
- *             Wesley Craig            :       Fix probing to listen to a
- *                                             passed node id.
- *             Alan Cox                :       Added send/recvmsg support
- *             Alan Cox                :       Moved at. to protinfo in
- *                                             socket.
- *             Alan Cox                :       Added firewall hooks.
- *             Alan Cox                :       Supports new ARPHRD_LOOPBACK
- *             Christer Weinigel       :       Routing and /proc fixes.
- *             Bradford Johnson        :       LocalTalk.
- *             Tom Dyas                :       Module support.
- *             Alan Cox                :       Hooks for PPP (based on the
- *                                             LocalTalk hook).
- *             Alan Cox                :       Posix bits
- *             Alan Cox/Mike Freeman   :       Possible fix to NBP problems
- *             Bradford Johnson        :       IP-over-DDP (experimental)
- *             Jay Schulist            :       Moved IP-over-DDP to its own
- *                                             driver file. (ipddp.c & ipddp.h)
- *             Jay Schulist            :       Made work as module with
- *                                             AppleTalk drivers, cleaned it.
- *             Rob Newberry            :       Added proxy AARP and AARP
- *                                             procfs, moved probing to AARP
- *                                             module.
- *              Adrian Sun/
- *              Michael Zuelsdorff      :       fix for net.0 packets. don't
- *                                              allow illegal ether/tokentalk
- *                                              port assignment. we lose a
- *                                              valid localtalk port as a
- *                                              result.
- *             Arnaldo C. de Melo      :       Cleanup, in preparation for
- *                                             shared skb support 8)
- *             Arnaldo C. de Melo      :       Move proc stuff to atalk_proc.c,
- *                                             use seq_file
- *
- *             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.
- *
- */
-
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/if_arp.h>
-#include <linux/smp_lock.h>
-#include <linux/termios.h>     /* For TIOCOUTQ/INQ */
-#include <linux/compat.h>
-#include <linux/slab.h>
-#include <net/datalink.h>
-#include <net/psnap.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <net/route.h>
-#include <linux/atalk.h>
-#include "../core/kmap_skb.h"
-
-struct datalink_proto *ddp_dl, *aarp_dl;
-static const struct proto_ops atalk_dgram_ops;
-
-/**************************************************************************\
-*                                                                          *
-* Handlers for the socket list.                                            *
-*                                                                          *
-\**************************************************************************/
-
-HLIST_HEAD(atalk_sockets);
-DEFINE_RWLOCK(atalk_sockets_lock);
-
-static inline void __atalk_insert_socket(struct sock *sk)
-{
-       sk_add_node(sk, &atalk_sockets);
-}
-
-static inline void atalk_remove_socket(struct sock *sk)
-{
-       write_lock_bh(&atalk_sockets_lock);
-       sk_del_node_init(sk);
-       write_unlock_bh(&atalk_sockets_lock);
-}
-
-static struct sock *atalk_search_socket(struct sockaddr_at *to,
-                                       struct atalk_iface *atif)
-{
-       struct sock *s;
-       struct hlist_node *node;
-
-       read_lock_bh(&atalk_sockets_lock);
-       sk_for_each(s, node, &atalk_sockets) {
-               struct atalk_sock *at = at_sk(s);
-
-               if (to->sat_port != at->src_port)
-                       continue;
-
-               if (to->sat_addr.s_net == ATADDR_ANYNET &&
-                   to->sat_addr.s_node == ATADDR_BCAST)
-                       goto found;
-
-               if (to->sat_addr.s_net == at->src_net &&
-                   (to->sat_addr.s_node == at->src_node ||
-                    to->sat_addr.s_node == ATADDR_BCAST ||
-                    to->sat_addr.s_node == ATADDR_ANYNODE))
-                       goto found;
-
-               /* XXXX.0 -- we got a request for this router. make sure
-                * that the node is appropriately set. */
-               if (to->sat_addr.s_node == ATADDR_ANYNODE &&
-                   to->sat_addr.s_net != ATADDR_ANYNET &&
-                   atif->address.s_node == at->src_node) {
-                       to->sat_addr.s_node = atif->address.s_node;
-                       goto found;
-               }
-       }
-       s = NULL;
-found:
-       read_unlock_bh(&atalk_sockets_lock);
-       return s;
-}
-
-/**
- * atalk_find_or_insert_socket - Try to find a socket matching ADDR
- * @sk - socket to insert in the list if it is not there already
- * @sat - address to search for
- *
- * Try to find a socket matching ADDR in the socket list, if found then return
- * it. If not, insert SK into the socket list.
- *
- * This entire operation must execute atomically.
- */
-static struct sock *atalk_find_or_insert_socket(struct sock *sk,
-                                               struct sockaddr_at *sat)
-{
-       struct sock *s;
-       struct hlist_node *node;
-       struct atalk_sock *at;
-
-       write_lock_bh(&atalk_sockets_lock);
-       sk_for_each(s, node, &atalk_sockets) {
-               at = at_sk(s);
-
-               if (at->src_net == sat->sat_addr.s_net &&
-                   at->src_node == sat->sat_addr.s_node &&
-                   at->src_port == sat->sat_port)
-                       goto found;
-       }
-       s = NULL;
-       __atalk_insert_socket(sk); /* Wheee, it's free, assign and insert. */
-found:
-       write_unlock_bh(&atalk_sockets_lock);
-       return s;
-}
-
-static void atalk_destroy_timer(unsigned long data)
-{
-       struct sock *sk = (struct sock *)data;
-
-       if (sk_has_allocations(sk)) {
-               sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
-               add_timer(&sk->sk_timer);
-       } else
-               sock_put(sk);
-}
-
-static inline void atalk_destroy_socket(struct sock *sk)
-{
-       atalk_remove_socket(sk);
-       skb_queue_purge(&sk->sk_receive_queue);
-
-       if (sk_has_allocations(sk)) {
-               setup_timer(&sk->sk_timer, atalk_destroy_timer,
-                               (unsigned long)sk);
-               sk->sk_timer.expires    = jiffies + SOCK_DESTROY_TIME;
-               add_timer(&sk->sk_timer);
-       } else
-               sock_put(sk);
-}
-
-/**************************************************************************\
-*                                                                          *
-* Routing tables for the AppleTalk socket layer.                           *
-*                                                                          *
-\**************************************************************************/
-
-/* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */
-struct atalk_route *atalk_routes;
-DEFINE_RWLOCK(atalk_routes_lock);
-
-struct atalk_iface *atalk_interfaces;
-DEFINE_RWLOCK(atalk_interfaces_lock);
-
-/* For probing devices or in a routerless network */
-struct atalk_route atrtr_default;
-
-/* AppleTalk interface control */
-/*
- * Drop a device. Doesn't drop any of its routes - that is the caller's
- * problem. Called when we down the interface or delete the address.
- */
-static void atif_drop_device(struct net_device *dev)
-{
-       struct atalk_iface **iface = &atalk_interfaces;
-       struct atalk_iface *tmp;
-
-       write_lock_bh(&atalk_interfaces_lock);
-       while ((tmp = *iface) != NULL) {
-               if (tmp->dev == dev) {
-                       *iface = tmp->next;
-                       dev_put(dev);
-                       kfree(tmp);
-                       dev->atalk_ptr = NULL;
-               } else
-                       iface = &tmp->next;
-       }
-       write_unlock_bh(&atalk_interfaces_lock);
-}
-
-static struct atalk_iface *atif_add_device(struct net_device *dev,
-                                          struct atalk_addr *sa)
-{
-       struct atalk_iface *iface = kzalloc(sizeof(*iface), GFP_KERNEL);
-
-       if (!iface)
-               goto out;
-
-       dev_hold(dev);
-       iface->dev = dev;
-       dev->atalk_ptr = iface;
-       iface->address = *sa;
-       iface->status = 0;
-
-       write_lock_bh(&atalk_interfaces_lock);
-       iface->next = atalk_interfaces;
-       atalk_interfaces = iface;
-       write_unlock_bh(&atalk_interfaces_lock);
-out:
-       return iface;
-}
-
-/* Perform phase 2 AARP probing on our tentative address */
-static int atif_probe_device(struct atalk_iface *atif)
-{
-       int netrange = ntohs(atif->nets.nr_lastnet) -
-                       ntohs(atif->nets.nr_firstnet) + 1;
-       int probe_net = ntohs(atif->address.s_net);
-       int probe_node = atif->address.s_node;
-       int netct, nodect;
-
-       /* Offset the network we start probing with */
-       if (probe_net == ATADDR_ANYNET) {
-               probe_net = ntohs(atif->nets.nr_firstnet);
-               if (netrange)
-                       probe_net += jiffies % netrange;
-       }
-       if (probe_node == ATADDR_ANYNODE)
-               probe_node = jiffies & 0xFF;
-
-       /* Scan the networks */
-       atif->status |= ATIF_PROBE;
-       for (netct = 0; netct <= netrange; netct++) {
-               /* Sweep the available nodes from a given start */
-               atif->address.s_net = htons(probe_net);
-               for (nodect = 0; nodect < 256; nodect++) {
-                       atif->address.s_node = (nodect + probe_node) & 0xFF;
-                       if (atif->address.s_node > 0 &&
-                           atif->address.s_node < 254) {
-                               /* Probe a proposed address */
-                               aarp_probe_network(atif);
-
-                               if (!(atif->status & ATIF_PROBE_FAIL)) {
-                                       atif->status &= ~ATIF_PROBE;
-                                       return 0;
-                               }
-                       }
-                       atif->status &= ~ATIF_PROBE_FAIL;
-               }
-               probe_net++;
-               if (probe_net > ntohs(atif->nets.nr_lastnet))
-                       probe_net = ntohs(atif->nets.nr_firstnet);
-       }
-       atif->status &= ~ATIF_PROBE;
-
-       return -EADDRINUSE;     /* Network is full... */
-}
-
-
-/* Perform AARP probing for a proxy address */
-static int atif_proxy_probe_device(struct atalk_iface *atif,
-                                  struct atalk_addr* proxy_addr)
-{
-       int netrange = ntohs(atif->nets.nr_lastnet) -
-                       ntohs(atif->nets.nr_firstnet) + 1;
-       /* we probe the interface's network */
-       int probe_net = ntohs(atif->address.s_net);
-       int probe_node = ATADDR_ANYNODE;            /* we'll take anything */
-       int netct, nodect;
-
-       /* Offset the network we start probing with */
-       if (probe_net == ATADDR_ANYNET) {
-               probe_net = ntohs(atif->nets.nr_firstnet);
-               if (netrange)
-                       probe_net += jiffies % netrange;
-       }
-
-       if (probe_node == ATADDR_ANYNODE)
-               probe_node = jiffies & 0xFF;
-
-       /* Scan the networks */
-       for (netct = 0; netct <= netrange; netct++) {
-               /* Sweep the available nodes from a given start */
-               proxy_addr->s_net = htons(probe_net);
-               for (nodect = 0; nodect < 256; nodect++) {
-                       proxy_addr->s_node = (nodect + probe_node) & 0xFF;
-                       if (proxy_addr->s_node > 0 &&
-                           proxy_addr->s_node < 254) {
-                               /* Tell AARP to probe a proposed address */
-                               int ret = aarp_proxy_probe_network(atif,
-                                                                   proxy_addr);
-
-                               if (ret != -EADDRINUSE)
-                                       return ret;
-                       }
-               }
-               probe_net++;
-               if (probe_net > ntohs(atif->nets.nr_lastnet))
-                       probe_net = ntohs(atif->nets.nr_firstnet);
-       }
-
-       return -EADDRINUSE;     /* Network is full... */
-}
-
-
-struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
-{
-       struct atalk_iface *iface = dev->atalk_ptr;
-       return iface ? &iface->address : NULL;
-}
-
-static struct atalk_addr *atalk_find_primary(void)
-{
-       struct atalk_iface *fiface = NULL;
-       struct atalk_addr *retval;
-       struct atalk_iface *iface;
-
-       /*
-        * Return a point-to-point interface only if
-        * there is no non-ptp interface available.
-        */
-       read_lock_bh(&atalk_interfaces_lock);
-       for (iface = atalk_interfaces; iface; iface = iface->next) {
-               if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))
-                       fiface = iface;
-               if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
-                       retval = &iface->address;
-                       goto out;
-               }
-       }
-
-       if (fiface)
-               retval = &fiface->address;
-       else if (atalk_interfaces)
-               retval = &atalk_interfaces->address;
-       else
-               retval = NULL;
-out:
-       read_unlock_bh(&atalk_interfaces_lock);
-       return retval;
-}
-
-/*
- * Find a match for 'any network' - ie any of our interfaces with that
- * node number will do just nicely.
- */
-static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
-{
-       struct atalk_iface *iface = dev->atalk_ptr;
-
-       if (!iface || iface->status & ATIF_PROBE)
-               goto out_err;
-
-       if (node != ATADDR_BCAST &&
-           iface->address.s_node != node &&
-           node != ATADDR_ANYNODE)
-               goto out_err;
-out:
-       return iface;
-out_err:
-       iface = NULL;
-       goto out;
-}
-
-/* Find a match for a specific network:node pair */
-static struct atalk_iface *atalk_find_interface(__be16 net, int node)
-{
-       struct atalk_iface *iface;
-
-       read_lock_bh(&atalk_interfaces_lock);
-       for (iface = atalk_interfaces; iface; iface = iface->next) {
-               if ((node == ATADDR_BCAST ||
-                    node == ATADDR_ANYNODE ||
-                    iface->address.s_node == node) &&
-                   iface->address.s_net == net &&
-                   !(iface->status & ATIF_PROBE))
-                       break;
-
-               /* XXXX.0 -- net.0 returns the iface associated with net */
-               if (node == ATADDR_ANYNODE && net != ATADDR_ANYNET &&
-                   ntohs(iface->nets.nr_firstnet) <= ntohs(net) &&
-                   ntohs(net) <= ntohs(iface->nets.nr_lastnet))
-                       break;
-       }
-       read_unlock_bh(&atalk_interfaces_lock);
-       return iface;
-}
-
-
-/*
- * Find a route for an AppleTalk packet. This ought to get cached in
- * the socket (later on...). We know about host routes and the fact
- * that a route must be direct to broadcast.
- */
-static struct atalk_route *atrtr_find(struct atalk_addr *target)
-{
-       /*
-        * we must search through all routes unless we find a
-        * host route, because some host routes might overlap
-        * network routes
-        */
-       struct atalk_route *net_route = NULL;
-       struct atalk_route *r;
-
-       read_lock_bh(&atalk_routes_lock);
-       for (r = atalk_routes; r; r = r->next) {
-               if (!(r->flags & RTF_UP))
-                       continue;
-
-               if (r->target.s_net == target->s_net) {
-                       if (r->flags & RTF_HOST) {
-                               /*
-                                * if this host route is for the target,
-                                * the we're done
-                                */
-                               if (r->target.s_node == target->s_node)
-                                       goto out;
-                       } else
-                               /*
-                                * this route will work if there isn't a
-                                * direct host route, so cache it
-                                */
-                               net_route = r;
-               }
-       }
-
-       /*
-        * if we found a network route but not a direct host
-        * route, then return it
-        */
-       if (net_route)
-               r = net_route;
-       else if (atrtr_default.dev)
-               r = &atrtr_default;
-       else /* No route can be found */
-               r = NULL;
-out:
-       read_unlock_bh(&atalk_routes_lock);
-       return r;
-}
-
-
-/*
- * Given an AppleTalk network, find the device to use. This can be
- * a simple lookup.
- */
-struct net_device *atrtr_get_dev(struct atalk_addr *sa)
-{
-       struct atalk_route *atr = atrtr_find(sa);
-       return atr ? atr->dev : NULL;
-}
-
-/* Set up a default router */
-static void atrtr_set_default(struct net_device *dev)
-{
-       atrtr_default.dev            = dev;
-       atrtr_default.flags          = RTF_UP;
-       atrtr_default.gateway.s_net  = htons(0);
-       atrtr_default.gateway.s_node = 0;
-}
-
-/*
- * Add a router. Basically make sure it looks valid and stuff the
- * entry in the list. While it uses netranges we always set them to one
- * entry to work like netatalk.
- */
-static int atrtr_create(struct rtentry *r, struct net_device *devhint)
-{
-       struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst;
-       struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway;
-       struct atalk_route *rt;
-       struct atalk_iface *iface, *riface;
-       int retval = -EINVAL;
-
-       /*
-        * Fixme: Raise/Lower a routing change semaphore for these
-        * operations.
-        */
-
-       /* Validate the request */
-       if (ta->sat_family != AF_APPLETALK ||
-           (!devhint && ga->sat_family != AF_APPLETALK))
-               goto out;
-
-       /* Now walk the routing table and make our decisions */
-       write_lock_bh(&atalk_routes_lock);
-       for (rt = atalk_routes; rt; rt = rt->next) {
-               if (r->rt_flags != rt->flags)
-                       continue;
-
-               if (ta->sat_addr.s_net == rt->target.s_net) {
-                       if (!(rt->flags & RTF_HOST))
-                               break;
-                       if (ta->sat_addr.s_node == rt->target.s_node)
-                               break;
-               }
-       }
-
-       if (!devhint) {
-               riface = NULL;
-
-               read_lock_bh(&atalk_interfaces_lock);
-               for (iface = atalk_interfaces; iface; iface = iface->next) {
-                       if (!riface &&
-                           ntohs(ga->sat_addr.s_net) >=
-                                       ntohs(iface->nets.nr_firstnet) &&
-                           ntohs(ga->sat_addr.s_net) <=
-                                       ntohs(iface->nets.nr_lastnet))
-                               riface = iface;
-
-                       if (ga->sat_addr.s_net == iface->address.s_net &&
-                           ga->sat_addr.s_node == iface->address.s_node)
-                               riface = iface;
-               }
-               read_unlock_bh(&atalk_interfaces_lock);
-
-               retval = -ENETUNREACH;
-               if (!riface)
-                       goto out_unlock;
-
-               devhint = riface->dev;
-       }
-
-       if (!rt) {
-               rt = kzalloc(sizeof(*rt), GFP_ATOMIC);
-
-               retval = -ENOBUFS;
-               if (!rt)
-                       goto out_unlock;
-
-               rt->next = atalk_routes;
-               atalk_routes = rt;
-       }
-
-       /* Fill in the routing entry */
-       rt->target  = ta->sat_addr;
-       dev_hold(devhint);
-       rt->dev     = devhint;
-       rt->flags   = r->rt_flags;
-       rt->gateway = ga->sat_addr;
-
-       retval = 0;
-out_unlock:
-       write_unlock_bh(&atalk_routes_lock);
-out:
-       return retval;
-}
-
-/* Delete a route. Find it and discard it */
-static int atrtr_delete(struct atalk_addr * addr)
-{
-       struct atalk_route **r = &atalk_routes;
-       int retval = 0;
-       struct atalk_route *tmp;
-
-       write_lock_bh(&atalk_routes_lock);
-       while ((tmp = *r) != NULL) {
-               if (tmp->target.s_net == addr->s_net &&
-                   (!(tmp->flags&RTF_GATEWAY) ||
-                    tmp->target.s_node == addr->s_node)) {
-                       *r = tmp->next;
-                       dev_put(tmp->dev);
-                       kfree(tmp);
-                       goto out;
-               }
-               r = &tmp->next;
-       }
-       retval = -ENOENT;
-out:
-       write_unlock_bh(&atalk_routes_lock);
-       return retval;
-}
-
-/*
- * Called when a device is downed. Just throw away any routes
- * via it.
- */
-static void atrtr_device_down(struct net_device *dev)
-{
-       struct atalk_route **r = &atalk_routes;
-       struct atalk_route *tmp;
-
-       write_lock_bh(&atalk_routes_lock);
-       while ((tmp = *r) != NULL) {
-               if (tmp->dev == dev) {
-                       *r = tmp->next;
-                       dev_put(dev);
-                       kfree(tmp);
-               } else
-                       r = &tmp->next;
-       }
-       write_unlock_bh(&atalk_routes_lock);
-
-       if (atrtr_default.dev == dev)
-               atrtr_set_default(NULL);
-}
-
-/* Actually down the interface */
-static inline void atalk_dev_down(struct net_device *dev)
-{
-       atrtr_device_down(dev); /* Remove all routes for the device */
-       aarp_device_down(dev);  /* Remove AARP entries for the device */
-       atif_drop_device(dev);  /* Remove the device */
-}
-
-/*
- * A device event has occurred. Watch for devices going down and
- * delete our use of them (iface and route).
- */
-static int ddp_device_event(struct notifier_block *this, unsigned long event,
-                           void *ptr)
-{
-       struct net_device *dev = ptr;
-
-       if (!net_eq(dev_net(dev), &init_net))
-               return NOTIFY_DONE;
-
-       if (event == NETDEV_DOWN)
-               /* Discard any use of this */
-               atalk_dev_down(dev);
-
-       return NOTIFY_DONE;
-}
-
-/* ioctl calls. Shouldn't even need touching */
-/* Device configuration ioctl calls */
-static int atif_ioctl(int cmd, void __user *arg)
-{
-       static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF };
-       struct ifreq atreq;
-       struct atalk_netrange *nr;
-       struct sockaddr_at *sa;
-       struct net_device *dev;
-       struct atalk_iface *atif;
-       int ct;
-       int limit;
-       struct rtentry rtdef;
-       int add_route;
-
-       if (copy_from_user(&atreq, arg, sizeof(atreq)))
-               return -EFAULT;
-
-       dev = __dev_get_by_name(&init_net, atreq.ifr_name);
-       if (!dev)
-               return -ENODEV;
-
-       sa = (struct sockaddr_at *)&atreq.ifr_addr;
-       atif = atalk_find_dev(dev);
-
-       switch (cmd) {
-               case SIOCSIFADDR:
-                       if (!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       if (sa->sat_family != AF_APPLETALK)
-                               return -EINVAL;
-                       if (dev->type != ARPHRD_ETHER &&
-                           dev->type != ARPHRD_LOOPBACK &&
-                           dev->type != ARPHRD_LOCALTLK &&
-                           dev->type != ARPHRD_PPP)
-                               return -EPROTONOSUPPORT;
-
-                       nr = (struct atalk_netrange *)&sa->sat_zero[0];
-                       add_route = 1;
-
-                       /*
-                        * if this is a point-to-point iface, and we already
-                        * have an iface for this AppleTalk address, then we
-                        * should not add a route
-                        */
-                       if ((dev->flags & IFF_POINTOPOINT) &&
-                           atalk_find_interface(sa->sat_addr.s_net,
-                                                sa->sat_addr.s_node)) {
-                               printk(KERN_DEBUG "AppleTalk: point-to-point "
-                                                 "interface added with "
-                                                 "existing address\n");
-                               add_route = 0;
-                       }
-
-                       /*
-                        * Phase 1 is fine on LocalTalk but we don't do
-                        * EtherTalk phase 1. Anyone wanting to add it go ahead.
-                        */
-                       if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
-                               return -EPROTONOSUPPORT;
-                       if (sa->sat_addr.s_node == ATADDR_BCAST ||
-                           sa->sat_addr.s_node == 254)
-                               return -EINVAL;
-                       if (atif) {
-                               /* Already setting address */
-                               if (atif->status & ATIF_PROBE)
-                                       return -EBUSY;
-
-                               atif->address.s_net  = sa->sat_addr.s_net;
-                               atif->address.s_node = sa->sat_addr.s_node;
-                               atrtr_device_down(dev); /* Flush old routes */
-                       } else {
-                               atif = atif_add_device(dev, &sa->sat_addr);
-                               if (!atif)
-                                       return -ENOMEM;
-                       }
-                       atif->nets = *nr;
-
-                       /*
-                        * Check if the chosen address is used. If so we
-                        * error and atalkd will try another.
-                        */
-
-                       if (!(dev->flags & IFF_LOOPBACK) &&
-                           !(dev->flags & IFF_POINTOPOINT) &&
-                           atif_probe_device(atif) < 0) {
-                               atif_drop_device(dev);
-                               return -EADDRINUSE;
-                       }
-
-                       /* Hey it worked - add the direct routes */
-                       sa = (struct sockaddr_at *)&rtdef.rt_gateway;
-                       sa->sat_family = AF_APPLETALK;
-                       sa->sat_addr.s_net  = atif->address.s_net;
-                       sa->sat_addr.s_node = atif->address.s_node;
-                       sa = (struct sockaddr_at *)&rtdef.rt_dst;
-                       rtdef.rt_flags = RTF_UP;
-                       sa->sat_family = AF_APPLETALK;
-                       sa->sat_addr.s_node = ATADDR_ANYNODE;
-                       if (dev->flags & IFF_LOOPBACK ||
-                           dev->flags & IFF_POINTOPOINT)
-                               rtdef.rt_flags |= RTF_HOST;
-
-                       /* Routerless initial state */
-                       if (nr->nr_firstnet == htons(0) &&
-                           nr->nr_lastnet == htons(0xFFFE)) {
-                               sa->sat_addr.s_net = atif->address.s_net;
-                               atrtr_create(&rtdef, dev);
-                               atrtr_set_default(dev);
-                       } else {
-                               limit = ntohs(nr->nr_lastnet);
-                               if (limit - ntohs(nr->nr_firstnet) > 4096) {
-                                       printk(KERN_WARNING "Too many routes/"
-                                                           "iface.\n");
-                                       return -EINVAL;
-                               }
-                               if (add_route)
-                                       for (ct = ntohs(nr->nr_firstnet);
-                                            ct <= limit; ct++) {
-                                               sa->sat_addr.s_net = htons(ct);
-                                               atrtr_create(&rtdef, dev);
-                                       }
-                       }
-                       dev_mc_add_global(dev, aarp_mcast);
-                       return 0;
-
-               case SIOCGIFADDR:
-                       if (!atif)
-                               return -EADDRNOTAVAIL;
-
-                       sa->sat_family = AF_APPLETALK;
-                       sa->sat_addr = atif->address;
-                       break;
-
-               case SIOCGIFBRDADDR:
-                       if (!atif)
-                               return -EADDRNOTAVAIL;
-
-                       sa->sat_family = AF_APPLETALK;
-                       sa->sat_addr.s_net = atif->address.s_net;
-                       sa->sat_addr.s_node = ATADDR_BCAST;
-                       break;
-
-               case SIOCATALKDIFADDR:
-               case SIOCDIFADDR:
-                       if (!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       if (sa->sat_family != AF_APPLETALK)
-                               return -EINVAL;
-                       atalk_dev_down(dev);
-                       break;
-
-               case SIOCSARP:
-                       if (!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       if (sa->sat_family != AF_APPLETALK)
-                               return -EINVAL;
-                       /*
-                        * for now, we only support proxy AARP on ELAP;
-                        * we should be able to do it for LocalTalk, too.
-                        */
-                       if (dev->type != ARPHRD_ETHER)
-                               return -EPROTONOSUPPORT;
-
-                       /*
-                        * atif points to the current interface on this network;
-                        * we aren't concerned about its current status (at
-                        * least for now), but it has all the settings about
-                        * the network we're going to probe. Consequently, it
-                        * must exist.
-                        */
-                       if (!atif)
-                               return -EADDRNOTAVAIL;
-
-                       nr = (struct atalk_netrange *)&(atif->nets);
-                       /*
-                        * Phase 1 is fine on Localtalk but we don't do
-                        * Ethertalk phase 1. Anyone wanting to add it go ahead.
-                        */
-                       if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
-                               return -EPROTONOSUPPORT;
-
-                       if (sa->sat_addr.s_node == ATADDR_BCAST ||
-                           sa->sat_addr.s_node == 254)
-                               return -EINVAL;
-
-                       /*
-                        * Check if the chosen address is used. If so we
-                        * error and ATCP will try another.
-                        */
-                       if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
-                               return -EADDRINUSE;
-
-                       /*
-                        * We now have an address on the local network, and
-                        * the AARP code will defend it for us until we take it
-                        * down. We don't set up any routes right now, because
-                        * ATCP will install them manually via SIOCADDRT.
-                        */
-                       break;
-
-               case SIOCDARP:
-                       if (!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       if (sa->sat_family != AF_APPLETALK)
-                               return -EINVAL;
-                       if (!atif)
-                               return -EADDRNOTAVAIL;
-
-                       /* give to aarp module to remove proxy entry */
-                       aarp_proxy_remove(atif->dev, &(sa->sat_addr));
-                       return 0;
-       }
-
-       return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;
-}
-
-/* Routing ioctl() calls */
-static int atrtr_ioctl(unsigned int cmd, void __user *arg)
-{
-       struct rtentry rt;
-
-       if (copy_from_user(&rt, arg, sizeof(rt)))
-               return -EFAULT;
-
-       switch (cmd) {
-               case SIOCDELRT:
-                       if (rt.rt_dst.sa_family != AF_APPLETALK)
-                               return -EINVAL;
-                       return atrtr_delete(&((struct sockaddr_at *)
-                                               &rt.rt_dst)->sat_addr);
-
-               case SIOCADDRT: {
-                       struct net_device *dev = NULL;
-                       if (rt.rt_dev) {
-                               char name[IFNAMSIZ];
-                               if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))
-                                       return -EFAULT;
-                               name[IFNAMSIZ-1] = '\0';
-                               dev = __dev_get_by_name(&init_net, name);
-                               if (!dev)
-                                       return -ENODEV;
-                       }
-                       return atrtr_create(&rt, dev);
-               }
-       }
-       return -EINVAL;
-}
-
-/**************************************************************************\
-*                                                                          *
-* Handling for system calls applied via the various interfaces to an       *
-* AppleTalk socket object.                                                 *
-*                                                                          *
-\**************************************************************************/
-
-/*
- * Checksum: This is 'optional'. It's quite likely also a good
- * candidate for assembler hackery 8)
- */
-static unsigned long atalk_sum_partial(const unsigned char *data,
-                                      int len, unsigned long sum)
-{
-       /* This ought to be unwrapped neatly. I'll trust gcc for now */
-       while (len--) {
-               sum += *data++;
-               sum = rol16(sum, 1);
-       }
-       return sum;
-}
-
-/*  Checksum skb data --  similar to skb_checksum  */
-static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
-                                  int len, unsigned long sum)
-{
-       int start = skb_headlen(skb);
-       struct sk_buff *frag_iter;
-       int i, copy;
-
-       /* checksum stuff in header space */
-       if ( (copy = start - offset) > 0) {
-               if (copy > len)
-                       copy = len;
-               sum = atalk_sum_partial(skb->data + offset, copy, sum);
-               if ( (len -= copy) == 0)
-                       return sum;
-
-               offset += copy;
-       }
-
-       /* checksum stuff in frags */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               int end;
-
-               WARN_ON(start > offset + len);
-
-               end = start + skb_shinfo(skb)->frags[i].size;
-               if ((copy = end - offset) > 0) {
-                       u8 *vaddr;
-                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-                       if (copy > len)
-                               copy = len;
-                       vaddr = kmap_skb_frag(frag);
-                       sum = atalk_sum_partial(vaddr + frag->page_offset +
-                                                 offset - start, copy, sum);
-                       kunmap_skb_frag(vaddr);
-
-                       if (!(len -= copy))
-                               return sum;
-                       offset += copy;
-               }
-               start = end;
-       }
-
-       skb_walk_frags(skb, frag_iter) {
-               int end;
-
-               WARN_ON(start > offset + len);
-
-               end = start + frag_iter->len;
-               if ((copy = end - offset) > 0) {
-                       if (copy > len)
-                               copy = len;
-                       sum = atalk_sum_skb(frag_iter, offset - start,
-                                           copy, sum);
-                       if ((len -= copy) == 0)
-                               return sum;
-                       offset += copy;
-               }
-               start = end;
-       }
-
-       BUG_ON(len > 0);
-
-       return sum;
-}
-
-static __be16 atalk_checksum(const struct sk_buff *skb, int len)
-{
-       unsigned long sum;
-
-       /* skip header 4 bytes */
-       sum = atalk_sum_skb(skb, 4, len-4, 0);
-
-       /* Use 0xFFFF for 0. 0 itself means none */
-       return sum ? htons((unsigned short)sum) : htons(0xFFFF);
-}
-
-static struct proto ddp_proto = {
-       .name     = "DDP",
-       .owner    = THIS_MODULE,
-       .obj_size = sizeof(struct atalk_sock),
-};
-
-/*
- * Create a socket. Initialise the socket, blank the addresses
- * set the state.
- */
-static int atalk_create(struct net *net, struct socket *sock, int protocol,
-                       int kern)
-{
-       struct sock *sk;
-       int rc = -ESOCKTNOSUPPORT;
-
-       if (!net_eq(net, &init_net))
-               return -EAFNOSUPPORT;
-
-       /*
-        * We permit SOCK_DGRAM and RAW is an extension. It is trivial to do
-        * and gives you the full ELAP frame. Should be handy for CAP 8)
-        */
-       if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
-               goto out;
-       rc = -ENOMEM;
-       sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto);
-       if (!sk)
-               goto out;
-       rc = 0;
-       sock->ops = &atalk_dgram_ops;
-       sock_init_data(sock, sk);
-
-       /* Checksums on by default */
-       sock_set_flag(sk, SOCK_ZAPPED);
-out:
-       return rc;
-}
-
-/* Free a socket. No work needed */
-static int atalk_release(struct socket *sock)
-{
-       struct sock *sk = sock->sk;
-
-       lock_kernel();
-       if (sk) {
-               sock_orphan(sk);
-               sock->sk = NULL;
-               atalk_destroy_socket(sk);
-       }
-       unlock_kernel();
-       return 0;
-}
-
-/**
- * atalk_pick_and_bind_port - Pick a source port when one is not given
- * @sk - socket to insert into the tables
- * @sat - address to search for
- *
- * Pick a source port when one is not given. If we can find a suitable free
- * one, we insert the socket into the tables using it.
- *
- * This whole operation must be atomic.
- */
-static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat)
-{
-       int retval;
-
-       write_lock_bh(&atalk_sockets_lock);
-
-       for (sat->sat_port = ATPORT_RESERVED;
-            sat->sat_port < ATPORT_LAST;
-            sat->sat_port++) {
-               struct sock *s;
-               struct hlist_node *node;
-
-               sk_for_each(s, node, &atalk_sockets) {
-                       struct atalk_sock *at = at_sk(s);
-
-                       if (at->src_net == sat->sat_addr.s_net &&
-                           at->src_node == sat->sat_addr.s_node &&
-                           at->src_port == sat->sat_port)
-                               goto try_next_port;
-               }
-
-               /* Wheee, it's free, assign and insert. */
-               __atalk_insert_socket(sk);
-               at_sk(sk)->src_port = sat->sat_port;
-               retval = 0;
-               goto out;
-
-try_next_port:;
-       }
-
-       retval = -EBUSY;
-out:
-       write_unlock_bh(&atalk_sockets_lock);
-       return retval;
-}
-
-static int atalk_autobind(struct sock *sk)
-{
-       struct atalk_sock *at = at_sk(sk);
-       struct sockaddr_at sat;
-       struct atalk_addr *ap = atalk_find_primary();
-       int n = -EADDRNOTAVAIL;
-
-       if (!ap || ap->s_net == htons(ATADDR_ANYNET))
-               goto out;
-
-       at->src_net  = sat.sat_addr.s_net  = ap->s_net;
-       at->src_node = sat.sat_addr.s_node = ap->s_node;
-
-       n = atalk_pick_and_bind_port(sk, &sat);
-       if (!n)
-               sock_reset_flag(sk, SOCK_ZAPPED);
-out:
-       return n;
-}
-
-/* Set the address 'our end' of the connection */
-static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-{
-       struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;
-       struct sock *sk = sock->sk;
-       struct atalk_sock *at = at_sk(sk);
-       int err;
-
-       if (!sock_flag(sk, SOCK_ZAPPED) ||
-           addr_len != sizeof(struct sockaddr_at))
-               return -EINVAL;
-
-       if (addr->sat_family != AF_APPLETALK)
-               return -EAFNOSUPPORT;
-
-       lock_kernel();
-       if (addr->sat_addr.s_net == htons(ATADDR_ANYNET)) {
-               struct atalk_addr *ap = atalk_find_primary();
-
-               err = -EADDRNOTAVAIL;
-               if (!ap)
-                       goto out;
-
-               at->src_net  = addr->sat_addr.s_net = ap->s_net;
-               at->src_node = addr->sat_addr.s_node= ap->s_node;
-       } else {
-               err = -EADDRNOTAVAIL;
-               if (!atalk_find_interface(addr->sat_addr.s_net,
-                                         addr->sat_addr.s_node))
-                       goto out;
-
-               at->src_net  = addr->sat_addr.s_net;
-               at->src_node = addr->sat_addr.s_node;
-       }
-
-       if (addr->sat_port == ATADDR_ANYPORT) {
-               err = atalk_pick_and_bind_port(sk, addr);
-
-               if (err < 0)
-                       goto out;
-       } else {
-               at->src_port = addr->sat_port;
-
-               err = -EADDRINUSE;
-               if (atalk_find_or_insert_socket(sk, addr))
-                       goto out;
-       }
-
-       sock_reset_flag(sk, SOCK_ZAPPED);
-       err = 0;
-out:
-       unlock_kernel();
-       return err;
-}
-
-/* Set the address we talk to */
-static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
-                        int addr_len, int flags)
-{
-       struct sock *sk = sock->sk;
-       struct atalk_sock *at = at_sk(sk);
-       struct sockaddr_at *addr;
-       int err;
-
-       sk->sk_state   = TCP_CLOSE;
-       sock->state = SS_UNCONNECTED;
-
-       if (addr_len != sizeof(*addr))
-               return -EINVAL;
-
-       addr = (struct sockaddr_at *)uaddr;
-
-       if (addr->sat_family != AF_APPLETALK)
-               return -EAFNOSUPPORT;
-
-       if (addr->sat_addr.s_node == ATADDR_BCAST &&
-           !sock_flag(sk, SOCK_BROADCAST)) {
-#if 1
-               printk(KERN_WARNING "%s is broken and did not set "
-                                   "SO_BROADCAST. It will break when 2.2 is "
-                                   "released.\n",
-                       current->comm);
-#else
-               return -EACCES;
-#endif
-       }
-
-       lock_kernel();
-       err = -EBUSY;
-       if (sock_flag(sk, SOCK_ZAPPED))
-               if (atalk_autobind(sk) < 0)
-                       goto out;
-
-       err = -ENETUNREACH;
-       if (!atrtr_get_dev(&addr->sat_addr))
-               goto out;
-
-       at->dest_port = addr->sat_port;
-       at->dest_net  = addr->sat_addr.s_net;
-       at->dest_node = addr->sat_addr.s_node;
-
-       sock->state  = SS_CONNECTED;
-       sk->sk_state = TCP_ESTABLISHED;
-       err = 0;
-out:
-       unlock_kernel();
-       return err;
-}
-
-/*
- * Find the name of an AppleTalk socket. Just copy the right
- * fields into the sockaddr.
- */
-static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
-                        int *uaddr_len, int peer)
-{
-       struct sockaddr_at sat;
-       struct sock *sk = sock->sk;
-       struct atalk_sock *at = at_sk(sk);
-       int err;
-
-       lock_kernel();
-       err = -ENOBUFS;
-       if (sock_flag(sk, SOCK_ZAPPED))
-               if (atalk_autobind(sk) < 0)
-                       goto out;
-
-       *uaddr_len = sizeof(struct sockaddr_at);
-       memset(&sat.sat_zero, 0, sizeof(sat.sat_zero));
-
-       if (peer) {
-               err = -ENOTCONN;
-               if (sk->sk_state != TCP_ESTABLISHED)
-                       goto out;
-
-               sat.sat_addr.s_net  = at->dest_net;
-               sat.sat_addr.s_node = at->dest_node;
-               sat.sat_port        = at->dest_port;
-       } else {
-               sat.sat_addr.s_net  = at->src_net;
-               sat.sat_addr.s_node = at->src_node;
-               sat.sat_port        = at->src_port;
-       }
-
-       err = 0;
-       sat.sat_family = AF_APPLETALK;
-       memcpy(uaddr, &sat, sizeof(sat));
-
-out:
-       unlock_kernel();
-       return err;
-}
-
-static unsigned int atalk_poll(struct file *file, struct socket *sock,
-                          poll_table *wait)
-{
-       int err;
-       lock_kernel();
-       err = datagram_poll(file, sock, wait);
-       unlock_kernel();
-       return err;
-}
-
-#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)
-static __inline__ int is_ip_over_ddp(struct sk_buff *skb)
-{
-       return skb->data[12] == 22;
-}
-
-static int handle_ip_over_ddp(struct sk_buff *skb)
-{
-       struct net_device *dev = __dev_get_by_name(&init_net, "ipddp0");
-       struct net_device_stats *stats;
-
-       /* This needs to be able to handle ipddp"N" devices */
-       if (!dev) {
-               kfree_skb(skb);
-               return NET_RX_DROP;
-       }
-
-       skb->protocol = htons(ETH_P_IP);
-       skb_pull(skb, 13);
-       skb->dev   = dev;
-       skb_reset_transport_header(skb);
-
-       stats = netdev_priv(dev);
-       stats->rx_packets++;
-       stats->rx_bytes += skb->len + 13;
-       return netif_rx(skb);  /* Send the SKB up to a higher place. */
-}
-#else
-/* make it easy for gcc to optimize this test out, i.e. kill the code */
-#define is_ip_over_ddp(skb) 0
-#define handle_ip_over_ddp(skb) 0
-#endif
-
-static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
-                             struct ddpehdr *ddp, __u16 len_hops, int origlen)
-{
-       struct atalk_route *rt;
-       struct atalk_addr ta;
-
-       /*
-        * Don't route multicast, etc., packets, or packets sent to "this
-        * network"
-        */
-       if (skb->pkt_type != PACKET_HOST || !ddp->deh_dnet) {
-               /*
-                * FIXME:
-                *
-                * Can it ever happen that a packet is from a PPP iface and
-                * needs to be broadcast onto the default network?
-                */
-               if (dev->type == ARPHRD_PPP)
-                       printk(KERN_DEBUG "AppleTalk: didn't forward broadcast "
-                                         "packet received from PPP iface\n");
-               goto free_it;
-       }
-
-       ta.s_net  = ddp->deh_dnet;
-       ta.s_node = ddp->deh_dnode;
-
-       /* Route the packet */
-       rt = atrtr_find(&ta);
-       /* increment hops count */
-       len_hops += 1 << 10;
-       if (!rt || !(len_hops & (15 << 10)))
-               goto free_it;
-
-       /* FIXME: use skb->cb to be able to use shared skbs */
-
-       /*
-        * Route goes through another gateway, so set the target to the
-        * gateway instead.
-        */
-
-       if (rt->flags & RTF_GATEWAY) {
-               ta.s_net  = rt->gateway.s_net;
-               ta.s_node = rt->gateway.s_node;
-       }
-
-       /* Fix up skb->len field */
-       skb_trim(skb, min_t(unsigned int, origlen,
-                           (rt->dev->hard_header_len +
-                            ddp_dl->header_length + (len_hops & 1023))));
-
-       /* FIXME: use skb->cb to be able to use shared skbs */
-       ddp->deh_len_hops = htons(len_hops);
-
-       /*
-        * Send the buffer onwards
-        *
-        * Now we must always be careful. If it's come from LocalTalk to
-        * EtherTalk it might not fit
-        *
-        * Order matters here: If a packet has to be copied to make a new
-        * headroom (rare hopefully) then it won't need unsharing.
-        *
-        * Note. ddp-> becomes invalid at the realloc.
-        */
-       if (skb_headroom(skb) < 22) {
-               /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
-               struct sk_buff *nskb = skb_realloc_headroom(skb, 32);
-               kfree_skb(skb);
-               skb = nskb;
-       } else
-               skb = skb_unshare(skb, GFP_ATOMIC);
-
-       /*
-        * If the buffer didn't vanish into the lack of space bitbucket we can
-        * send it.
-        */
-       if (skb == NULL)
-               goto drop;
-
-       if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP)
-               return NET_RX_DROP;
-       return NET_RX_SUCCESS;
-free_it:
-       kfree_skb(skb);
-drop:
-       return NET_RX_DROP;
-}
-
-/**
- *     atalk_rcv - Receive a packet (in skb) from device dev
- *     @skb - packet received
- *     @dev - network device where the packet comes from
- *     @pt - packet type
- *
- *     Receive a packet (in skb) from device dev. This has come from the SNAP
- *     decoder, and on entry skb->transport_header is the DDP header, skb->len
- *     is the DDP header, skb->len is the DDP length. The physical headers
- *     have been extracted. PPP should probably pass frames marked as for this
- *     layer.  [ie ARPHRD_ETHERTALK]
- */
-static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
-                    struct packet_type *pt, struct net_device *orig_dev)
-{
-       struct ddpehdr *ddp;
-       struct sock *sock;
-       struct atalk_iface *atif;
-       struct sockaddr_at tosat;
-       int origlen;
-       __u16 len_hops;
-
-       if (!net_eq(dev_net(dev), &init_net))
-               goto drop;
-
-       /* Don't mangle buffer if shared */
-       if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
-               goto out;
-
-       /* Size check and make sure header is contiguous */
-       if (!pskb_may_pull(skb, sizeof(*ddp)))
-               goto drop;
-
-       ddp = ddp_hdr(skb);
-
-       len_hops = ntohs(ddp->deh_len_hops);
-
-       /* Trim buffer in case of stray trailing data */
-       origlen = skb->len;
-       skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));
-
-       /*
-        * Size check to see if ddp->deh_len was crap
-        * (Otherwise we'll detonate most spectacularly
-        * in the middle of atalk_checksum() or recvmsg()).
-        */
-       if (skb->len < sizeof(*ddp) || skb->len < (len_hops & 1023)) {
-               pr_debug("AppleTalk: dropping corrupted frame (deh_len=%u, "
-                        "skb->len=%u)\n", len_hops & 1023, skb->len);
-               goto drop;
-       }
-
-       /*
-        * Any checksums. Note we don't do htons() on this == is assumed to be
-        * valid for net byte orders all over the networking code...
-        */
-       if (ddp->deh_sum &&
-           atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
-               /* Not a valid AppleTalk frame - dustbin time */
-               goto drop;
-
-       /* Check the packet is aimed at us */
-       if (!ddp->deh_dnet)     /* Net 0 is 'this network' */
-               atif = atalk_find_anynet(ddp->deh_dnode, dev);
-       else
-               atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
-
-       if (!atif) {
-               /* Not ours, so we route the packet via the correct
-                * AppleTalk iface
-                */
-               return atalk_route_packet(skb, dev, ddp, len_hops, origlen);
-       }
-
-       /* if IP over DDP is not selected this code will be optimized out */
-       if (is_ip_over_ddp(skb))
-               return handle_ip_over_ddp(skb);
-       /*
-        * Which socket - atalk_search_socket() looks for a *full match*
-        * of the <net, node, port> tuple.
-        */
-       tosat.sat_addr.s_net  = ddp->deh_dnet;
-       tosat.sat_addr.s_node = ddp->deh_dnode;
-       tosat.sat_port        = ddp->deh_dport;
-
-       sock = atalk_search_socket(&tosat, atif);
-       if (!sock) /* But not one of our sockets */
-               goto drop;
-
-       /* Queue packet (standard) */
-       skb->sk = sock;
-
-       if (sock_queue_rcv_skb(sock, skb) < 0)
-               goto drop;
-
-       return NET_RX_SUCCESS;
-
-drop:
-       kfree_skb(skb);
-out:
-       return NET_RX_DROP;
-
-}
-
-/*
- * Receive a LocalTalk frame. We make some demands on the caller here.
- * Caller must provide enough headroom on the packet to pull the short
- * header and append a long one.
- */
-static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
-                    struct packet_type *pt, struct net_device *orig_dev)
-{
-       if (!net_eq(dev_net(dev), &init_net))
-               goto freeit;
-
-       /* Expand any short form frames */
-       if (skb_mac_header(skb)[2] == 1) {
-               struct ddpehdr *ddp;
-               /* Find our address */
-               struct atalk_addr *ap = atalk_find_dev_addr(dev);
-
-               if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
-                       goto freeit;
-
-               /* Don't mangle buffer if shared */
-               if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
-                       return 0;
-
-               /*
-                * The push leaves us with a ddephdr not an shdr, and
-                * handily the port bytes in the right place preset.
-                */
-               ddp = (struct ddpehdr *) skb_push(skb, sizeof(*ddp) - 4);
-
-               /* Now fill in the long header */
-
-               /*
-                * These two first. The mac overlays the new source/dest
-                * network information so we MUST copy these before
-                * we write the network numbers !
-                */
-
-               ddp->deh_dnode = skb_mac_header(skb)[0];     /* From physical header */
-               ddp->deh_snode = skb_mac_header(skb)[1];     /* From physical header */
-
-               ddp->deh_dnet  = ap->s_net;     /* Network number */
-               ddp->deh_snet  = ap->s_net;
-               ddp->deh_sum   = 0;             /* No checksum */
-               /*
-                * Not sure about this bit...
-                */
-               /* Non routable, so force a drop if we slip up later */
-               ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
-       }
-       skb_reset_transport_header(skb);
-
-       return atalk_rcv(skb, dev, pt, orig_dev);
-freeit:
-       kfree_skb(skb);
-       return 0;
-}
-
-static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
-                        size_t len)
-{
-       struct sock *sk = sock->sk;
-       struct atalk_sock *at = at_sk(sk);
-       struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name;
-       int flags = msg->msg_flags;
-       int loopback = 0;
-       struct sockaddr_at local_satalk, gsat;
-       struct sk_buff *skb;
-       struct net_device *dev;
-       struct ddpehdr *ddp;
-       int size;
-       struct atalk_route *rt;
-       int err;
-
-       if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
-               return -EINVAL;
-
-       if (len > DDP_MAXSZ)
-               return -EMSGSIZE;
-
-       lock_kernel();
-       if (usat) {
-               err = -EBUSY;
-               if (sock_flag(sk, SOCK_ZAPPED))
-                       if (atalk_autobind(sk) < 0)
-                               goto out;
-
-               err = -EINVAL;
-               if (msg->msg_namelen < sizeof(*usat) ||
-                   usat->sat_family != AF_APPLETALK)
-                       goto out;
-
-               err = -EPERM;
-               /* netatalk didn't implement this check */
-               if (usat->sat_addr.s_node == ATADDR_BCAST &&
-                   !sock_flag(sk, SOCK_BROADCAST)) {
-                       goto out;
-               }
-       } else {
-               err = -ENOTCONN;
-               if (sk->sk_state != TCP_ESTABLISHED)
-                       goto out;
-               usat = &local_satalk;
-               usat->sat_family      = AF_APPLETALK;
-               usat->sat_port        = at->dest_port;
-               usat->sat_addr.s_node = at->dest_node;
-               usat->sat_addr.s_net  = at->dest_net;
-       }
-
-       /* Build a packet */
-       SOCK_DEBUG(sk, "SK %p: Got address.\n", sk);
-
-       /* For headers */
-       size = sizeof(struct ddpehdr) + len + ddp_dl->header_length;
-
-       if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
-               rt = atrtr_find(&usat->sat_addr);
-       } else {
-               struct atalk_addr at_hint;
-
-               at_hint.s_node = 0;
-               at_hint.s_net  = at->src_net;
-
-               rt = atrtr_find(&at_hint);
-       }
-       err = ENETUNREACH;
-       if (!rt)
-               goto out;
-
-       dev = rt->dev;
-
-       SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",
-                       sk, size, dev->name);
-
-       size += dev->hard_header_len;
-       skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
-       if (!skb)
-               goto out;
-
-       skb->sk = sk;
-       skb_reserve(skb, ddp_dl->header_length);
-       skb_reserve(skb, dev->hard_header_len);
-       skb->dev = dev;
-
-       SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
-
-       ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
-       ddp->deh_len_hops  = htons(len + sizeof(*ddp));
-       ddp->deh_dnet  = usat->sat_addr.s_net;
-       ddp->deh_snet  = at->src_net;
-       ddp->deh_dnode = usat->sat_addr.s_node;
-       ddp->deh_snode = at->src_node;
-       ddp->deh_dport = usat->sat_port;
-       ddp->deh_sport = at->src_port;
-
-       SOCK_DEBUG(sk, "SK %p: Copy user data (%Zd bytes).\n", sk, len);
-
-       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
-       if (err) {
-               kfree_skb(skb);
-               err = -EFAULT;
-               goto out;
-       }
-
-       if (sk->sk_no_check == 1)
-               ddp->deh_sum = 0;
-       else
-               ddp->deh_sum = atalk_checksum(skb, len + sizeof(*ddp));
-
-       /*
-        * Loopback broadcast packets to non gateway targets (ie routes
-        * to group we are in)
-        */
-       if (ddp->deh_dnode == ATADDR_BCAST &&
-           !(rt->flags & RTF_GATEWAY) && !(dev->flags & IFF_LOOPBACK)) {
-               struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL);
-
-               if (skb2) {
-                       loopback = 1;
-                       SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);
-                       /*
-                        * If it fails it is queued/sent above in the aarp queue
-                        */
-                       aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL);
-               }
-       }
-
-       if (dev->flags & IFF_LOOPBACK || loopback) {
-               SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
-               /* loop back */
-               skb_orphan(skb);
-               if (ddp->deh_dnode == ATADDR_BCAST) {
-                       struct atalk_addr at_lo;
-
-                       at_lo.s_node = 0;
-                       at_lo.s_net  = 0;
-
-                       rt = atrtr_find(&at_lo);
-                       if (!rt) {
-                               kfree_skb(skb);
-                               err = -ENETUNREACH;
-                               goto out;
-                       }
-                       dev = rt->dev;
-                       skb->dev = dev;
-               }
-               ddp_dl->request(ddp_dl, skb, dev->dev_addr);
-       } else {
-               SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
-               if (rt->flags & RTF_GATEWAY) {
-                   gsat.sat_addr = rt->gateway;
-                   usat = &gsat;
-               }
-
-               /*
-                * If it fails it is queued/sent above in the aarp queue
-                */
-               aarp_send_ddp(dev, skb, &usat->sat_addr, NULL);
-       }
-       SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len);
-
-out:
-       unlock_kernel();
-       return err ? : len;
-}
-
-static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
-                        size_t size, int flags)
-{
-       struct sock *sk = sock->sk;
-       struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
-       struct ddpehdr *ddp;
-       int copied = 0;
-       int offset = 0;
-       int err = 0;
-       struct sk_buff *skb;
-
-       lock_kernel();
-       skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
-                                               flags & MSG_DONTWAIT, &err);
-       if (!skb)
-               goto out;
-
-       /* FIXME: use skb->cb to be able to use shared skbs */
-       ddp = ddp_hdr(skb);
-       copied = ntohs(ddp->deh_len_hops) & 1023;
-
-       if (sk->sk_type != SOCK_RAW) {
-               offset = sizeof(*ddp);
-               copied -= offset;
-       }
-
-       if (copied > size) {
-               copied = size;
-               msg->msg_flags |= MSG_TRUNC;
-       }
-       err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
-
-       if (!err) {
-               if (sat) {
-                       sat->sat_family      = AF_APPLETALK;
-                       sat->sat_port        = ddp->deh_sport;
-                       sat->sat_addr.s_node = ddp->deh_snode;
-                       sat->sat_addr.s_net  = ddp->deh_snet;
-               }
-               msg->msg_namelen = sizeof(*sat);
-       }
-
-       skb_free_datagram(sk, skb);     /* Free the datagram. */
-
-out:
-       unlock_kernel();
-       return err ? : copied;
-}
-
-
-/*
- * AppleTalk ioctl calls.
- */
-static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-       int rc = -ENOIOCTLCMD;
-       struct sock *sk = sock->sk;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-               /* Protocol layer */
-               case TIOCOUTQ: {
-                       long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
-
-                       if (amount < 0)
-                               amount = 0;
-                       rc = put_user(amount, (int __user *)argp);
-                       break;
-               }
-               case TIOCINQ: {
-                       /*
-                        * These two are safe on a single CPU system as only
-                        * user tasks fiddle here
-                        */
-                       struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
-                       long amount = 0;
-
-                       if (skb)
-                               amount = skb->len - sizeof(struct ddpehdr);
-                       rc = put_user(amount, (int __user *)argp);
-                       break;
-               }
-               case SIOCGSTAMP:
-                       rc = sock_get_timestamp(sk, argp);
-                       break;
-               case SIOCGSTAMPNS:
-                       rc = sock_get_timestampns(sk, argp);
-                       break;
-               /* Routing */
-               case SIOCADDRT:
-               case SIOCDELRT:
-                       rc = -EPERM;
-                       if (capable(CAP_NET_ADMIN))
-                               rc = atrtr_ioctl(cmd, argp);
-                       break;
-               /* Interface */
-               case SIOCGIFADDR:
-               case SIOCSIFADDR:
-               case SIOCGIFBRDADDR:
-               case SIOCATALKDIFADDR:
-               case SIOCDIFADDR:
-               case SIOCSARP:          /* proxy AARP */
-               case SIOCDARP:          /* proxy AARP */
-                       rtnl_lock();
-                       rc = atif_ioctl(cmd, argp);
-                       rtnl_unlock();
-                       break;
-       }
-
-       return rc;
-}
-
-
-#ifdef CONFIG_COMPAT
-static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-       /*
-        * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we
-        * cannot handle it in common code. The data we access if ifreq
-        * here is compatible, so we can simply call the native
-        * handler.
-        */
-       if (cmd == SIOCATALKDIFADDR)
-               return atalk_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
-
-       return -ENOIOCTLCMD;
-}
-#endif
-
-
-static const struct net_proto_family atalk_family_ops = {
-       .family         = PF_APPLETALK,
-       .create         = atalk_create,
-       .owner          = THIS_MODULE,
-};
-
-static const struct proto_ops atalk_dgram_ops = {
-       .family         = PF_APPLETALK,
-       .owner          = THIS_MODULE,
-       .release        = atalk_release,
-       .bind           = atalk_bind,
-       .connect        = atalk_connect,
-       .socketpair     = sock_no_socketpair,
-       .accept         = sock_no_accept,
-       .getname        = atalk_getname,
-       .poll           = atalk_poll,
-       .ioctl          = atalk_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = atalk_compat_ioctl,
-#endif
-       .listen         = sock_no_listen,
-       .shutdown       = sock_no_shutdown,
-       .setsockopt     = sock_no_setsockopt,
-       .getsockopt     = sock_no_getsockopt,
-       .sendmsg        = atalk_sendmsg,
-       .recvmsg        = atalk_recvmsg,
-       .mmap           = sock_no_mmap,
-       .sendpage       = sock_no_sendpage,
-};
-
-static struct notifier_block ddp_notifier = {
-       .notifier_call  = ddp_device_event,
-};
-
-static struct packet_type ltalk_packet_type __read_mostly = {
-       .type           = cpu_to_be16(ETH_P_LOCALTALK),
-       .func           = ltalk_rcv,
-};
-
-static struct packet_type ppptalk_packet_type __read_mostly = {
-       .type           = cpu_to_be16(ETH_P_PPPTALK),
-       .func           = atalk_rcv,
-};
-
-static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B };
-
-/* Export symbols for use by drivers when AppleTalk is a module */
-EXPORT_SYMBOL(atrtr_get_dev);
-EXPORT_SYMBOL(atalk_find_dev_addr);
-
-static const char atalk_err_snap[] __initconst =
-       KERN_CRIT "Unable to register DDP with SNAP.\n";
-
-/* Called by proto.c on kernel start up */
-static int __init atalk_init(void)
-{
-       int rc = proto_register(&ddp_proto, 0);
-
-       if (rc != 0)
-               goto out;
-
-       (void)sock_register(&atalk_family_ops);
-       ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
-       if (!ddp_dl)
-               printk(atalk_err_snap);
-
-       dev_add_pack(&ltalk_packet_type);
-       dev_add_pack(&ppptalk_packet_type);
-
-       register_netdevice_notifier(&ddp_notifier);
-       aarp_proto_init();
-       atalk_proc_init();
-       atalk_register_sysctl();
-out:
-       return rc;
-}
-module_init(atalk_init);
-
-/*
- * No explicit module reference count manipulation is needed in the
- * protocol. Socket layer sets module reference count for us
- * and interfaces reference counting is done
- * by the network device layer.
- *
- * Ergo, before the AppleTalk module can be removed, all AppleTalk
- * sockets be closed from user space.
- */
-static void __exit atalk_exit(void)
-{
-#ifdef CONFIG_SYSCTL
-       atalk_unregister_sysctl();
-#endif /* CONFIG_SYSCTL */
-       atalk_proc_exit();
-       aarp_cleanup_module();  /* General aarp clean-up. */
-       unregister_netdevice_notifier(&ddp_notifier);
-       dev_remove_pack(&ltalk_packet_type);
-       dev_remove_pack(&ppptalk_packet_type);
-       unregister_snap_client(ddp_dl);
-       sock_unregister(PF_APPLETALK);
-       proto_unregister(&ddp_proto);
-}
-module_exit(atalk_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
-MODULE_DESCRIPTION("AppleTalk 0.20\n");
-MODULE_ALIAS_NETPROTO(PF_APPLETALK);
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c
deleted file mode 100644 (file)
index 6c8016f..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Moved here from drivers/net/net_init.c, which is:
- *     Written 1993,1994,1995 by Donald Becker.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>
-
-static void ltalk_setup(struct net_device *dev)
-{
-       /* Fill in the fields of the device structure with localtalk-generic values. */
-
-       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;
-}
-
-/**
- * alloc_ltalkdev - Allocates and sets up an localtalk device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- *     for this localtalk device
- *
- * Fill in the fields of the device structure with localtalk-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_ltalkdev(int sizeof_priv)
-{
-       return alloc_netdev(sizeof_priv, "lt%d", ltalk_setup);
-}
-EXPORT_SYMBOL(alloc_ltalkdev);
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
deleted file mode 100644 (file)
index 04e9c0d..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * sysctl_net_atalk.c: sysctl interface to net AppleTalk subsystem.
- *
- * Begun April 1, 1996, Mike Shaver.
- * Added /proc/sys/net/atalk directory entry (empty =) ). [MS]
- * Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
- */
-
-#include <linux/sysctl.h>
-#include <net/sock.h>
-#include <linux/atalk.h>
-
-static struct ctl_table atalk_table[] = {
-       {
-               .procname       = "aarp-expiry-time",
-               .data           = &sysctl_aarp_expiry_time,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
-       {
-               .procname       = "aarp-tick-time",
-               .data           = &sysctl_aarp_tick_time,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
-       {
-               .procname       = "aarp-retransmit-limit",
-               .data           = &sysctl_aarp_retransmit_limit,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "aarp-resolve-time",
-               .data           = &sysctl_aarp_resolve_time,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
-       { },
-};
-
-static struct ctl_path atalk_path[] = {
-       { .procname = "net", },
-       { .procname = "appletalk", },
-       { }
-};
-
-static struct ctl_table_header *atalk_table_header;
-
-void atalk_register_sysctl(void)
-{
-       atalk_table_header = register_sysctl_paths(atalk_path, atalk_table);
-}
-
-void atalk_unregister_sysctl(void)
-{
-       unregister_sysctl_table(atalk_table_header);
-}
index ac2219f90d5dd45bed66ab827b26a5f96cf7ca09..26f7bcf36810903351d6859bdeffd196f068284c 100644 (file)
 #include <linux/ipv6_route.h>
 #include <linux/route.h>
 #include <linux/sockios.h>
-#include <linux/atalk.h>
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
 static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,