VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 16
+SUBLEVEL = 17
all: Version zImage
comment 'Skipping ethercard configuration options...'
else
+bool 'Dummy net driver support' CONFIG_DUMMY y
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' SL_COMPRESSED y
#bool 'NI52EE support' CONFIG_NI52 n
#bool 'NI65EE support' CONFIG_NI65 n
#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
-#bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n
+#bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
fi
NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c589.o)
endif
+ifdef CONFIG_DUMMY
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(dummy.o)
+dummy.o: dummy.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+endif
+
ifdef CONFIG_DE600
NETDRV_OBJS := $(NETDRV_OBJS) net.a(de600.o)
endif
--- /dev/null
+/* dummy.c: a dummy net driver
+
+ The purpose of this driver is to provide a device to point a
+ route through, but not to actually transmit packets.
+
+ Why? If you have a machine whose only connection is an occasional
+ PPP/SLIP/PLIP link, you can only connect to your own hostname
+ when the link is up. Otherwise you have to use localhost.
+ This isn't very consistent.
+
+ One solution is to set up a dummy link using PPP/SLIP/PLIP,
+ but this seems (to me) too much overhead for too little gain.
+ This driver provides a small alternative. Thus you can do
+
+ [when not running slip]
+ ifconfig dummy slip.addr.ess.here up
+ [to go to slip]
+ ifconfig dummy down
+ dip whatever
+
+ This was written by looking at Donald Becker's skeleton driver
+ and the loopback driver. I then threw away anything that didn't
+ apply! Thanks to Alan Cox for the key clue on what to do with
+ misguided packets.
+
+ Nick Holloway, 27th May 1994
+ [I tweaked this explanation a little but thats all]
+ Alan Cox, 30th May 1994
+*/
+
+/* To have statistics (just packets sent) define this */
+#undef DUMMY_STATS
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.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/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+static int dummy_xmit(struct sk_buff *skb, struct device *dev);
+#ifdef DUMMY_STATS
+static struct enet_statistics *dummy_get_stats(struct device *dev);
+#endif
+
+int
+dummy_init(struct device *dev)
+{
+/* I commented this out as bootup is noisy enough anyway and this driver
+ seems pretty reliable 8) 8) 8) */
+/* printk ( KERN_INFO "Dummy net driver (94/05/27 v1.0)\n" ); */
+
+ /* Initialize the device structure. */
+ dev->hard_start_xmit = dummy_xmit;
+
+#if DUMMY_STATS
+ dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct enet_statistics));
+ dev->get_stats = dummy_get_stats;
+#endif
+
+ /* Fill in the fields of the device structure with ethernet-generic values. */
+ ether_setup(dev);
+
+ return 0;
+}
+
+static int
+dummy_xmit(struct sk_buff *skb, struct device *dev)
+{
+#if DUMMY_STATS
+ struct enet_statistics *stats;
+#endif
+
+ if (skb == NULL || dev == NULL)
+ return 0;
+
+ if (skb->free)
+ kfree_skb(skb, FREE_WRITE);
+
+#if DUMMY_STATS
+ stats = (struct enet_statistics *)dev->priv;
+ stats->tx_packets++;
+#endif
+
+ return 0;
+}
+
+#if DUMMY_STATS
+static struct enet_statistics *
+dummy_get_stats(struct device *dev)
+{
+ struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
+ return stats;
+}
+#endif
A secondary advantage is that the dangerous NE*000 netcards can reserve
their I/O port region before the SCSI probes start.
- register_netdev()/unregister_netdev() by Bjorn Ekwall <bj0rn@blox.se>
+ Modifications/additions by Bjorn Ekwall <bj0rn@blox.se>:
+ ethdev_index[MAX_ETH_CARDS]
+ register_netdev() / unregister_netdev()
*/
#include <linux/config.h>
by magic we get them, but otherwise they are un-needed and a space waste]
*/
-/* The next device number/name to assign: "eth0", "eth1", etc. */
-static int next_ethdev_number = 0;
+/* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
+#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
+static struct device *ethdev_index[MAX_ETH_CARDS];
unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
long.
*/
-struct device *init_etherdev(struct device *dev, int sizeof_private,
- unsigned long *mem_startp)
+struct device *
+init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
{
- int i;
int new_device = 0;
+ int i;
if (dev == NULL) {
int alloc_size = sizeof(struct device) + sizeof("eth%d ")
new_device = 1;
}
- if (dev->name && dev->name[0] == '\0')
- sprintf(dev->name, "eth%d", next_ethdev_number++);
-
- for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init(&dev->buffs[i]);
-
- dev->hard_header = eth_header;
- dev->rebuild_header = eth_rebuild_header;
- dev->type_trans = eth_type_trans;
-
- dev->type = ARPHRD_ETHER;
- dev->hard_header_len = ETH_HLEN;
- dev->mtu = 1500; /* eth_mtu */
- dev->addr_len = ETH_ALEN;
- for (i = 0; i < ETH_ALEN; i++) {
- dev->broadcast[i]=0xff;
+ if (dev->name &&
+ ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
+ for (i = 0; i < MAX_ETH_CARDS; ++i)
+ if (ethdev_index[i] == NULL) {
+ sprintf(dev->name, "eth%d", i);
+ ethdev_index[i] = dev;
+ break;
+ }
}
-
- /* New-style flags. */
- dev->flags = IFF_BROADCAST;
- dev->family = AF_INET;
- dev->pa_addr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = sizeof(unsigned long);
+
+ ether_setup(dev); /* should this be called here? */
if (new_device) {
/* Append the device to the device queue. */
for (i = 0; i < DEV_NUMBUFFS; i++)
skb_queue_head_init(&dev->buffs[i]);
+ /* register boot-defined "eth" devices */
+ if (dev->name && (strncmp(dev->name, "eth", 3) == 0)) {
+ i = simple_strtoul(dev->name + 3, NULL, 0);
+ if (ethdev_index[i] == NULL) {
+ ethdev_index[i] = dev;
+ }
+ else if (dev != ethdev_index[i]) {
+ /* Really shouldn't happen! */
+ printk("ether_setup: Ouch! Someone else took %s\n",
+ dev->name);
+ }
+ }
+
dev->hard_header = eth_header;
dev->rebuild_header = eth_rebuild_header;
dev->type_trans = eth_type_trans;
{
struct device *d = dev_base;
unsigned long flags;
-
+ int i;
+
save_flags(flags);
cli();
- if (dev && dev->init)
- {
- if (dev->init(dev) != 0)
- {
+ if (dev && dev->init) {
+ if (dev->init(dev) != 0) {
restore_flags(flags);
return -EIO;
}
-
- if (dev->name && dev->name[0] == '\0')
- sprintf(dev->name, "eth%d", next_ethdev_number++);
+
+ if (dev->name &&
+ ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
+ for (i = 0; i < MAX_ETH_CARDS; ++i)
+ if (ethdev_index[i] == NULL) {
+ sprintf(dev->name, "eth%d", i);
+ printk("device '%s' loaded\n", dev->name);
+ ethdev_index[i] = dev;
+ break;
+ }
+ }
/* Add device to end of chain */
- if (dev_base)
- {
+ if (dev_base) {
while (d->next)
d = d->next;
d->next = dev;
{
struct device *d = dev_base;
unsigned long flags;
-
+ int i;
+
save_flags(flags);
cli();
printk("unregister_netdev: device ");
- if (dev) {
- if (dev->start)
- printk("'%s' busy", dev->name);
+
+ if (dev == NULL) {
+ printk("was NULL\n");
+ restore_flags(flags);
+ return;
+ }
+ /* else */
+ if (dev->start)
+ printk("'%s' busy\n", dev->name);
+ else {
+ if (dev_base == dev)
+ dev_base = dev->next;
else {
- if (dev_base == dev)
- dev_base = dev->next;
- else {
- while (d && (d->next != dev))
- d = d->next;
+ while (d && (d->next != dev))
+ d = d->next;
- if (d && (d->next == dev)) {
- d->next = dev->next;
- printk("'%s' unlinked", dev->name);
- }
- else
- printk("'%s' not found", dev->name);
+ if (d && (d->next == dev)) {
+ d->next = dev->next;
+ printk("'%s' unlinked\n", dev->name);
+ }
+ else {
+ printk("'%s' not found\n", dev->name);
+ restore_flags(flags);
+ return;
+ }
+ }
+ for (i = 0; i < MAX_ETH_CARDS; ++i) {
+ if (ethdev_index[i] == dev) {
+ ethdev_index[i] = NULL;
+ break;
}
}
}
- else
- printk("was NULL");
- printk("\n");
restore_flags(flags);
}
+
\f
/*
* Local variables:
*
***** So we can all compare loads of different PLIP drivers for a bit I've modularised this beastie too.
***** In addition a seperate bidirectional plip module can be done.
+ *
+ * WARNING: The PRE 1.1.16 plip will NOT work with this PLIP driver. We
+ * can't avoid this due to an error in the old plip module. If you must
+ * mix PLIP's you'll need to fix the _OLD_ one to use 0xFC 0xFC as its
+ * MAC header not 0xFD.
+ *
*/
static char *version =
{
/*
* set physical address to
- * 0xfd.0xfd.ipaddr
+ * 0xfc.0xfc.ipaddr
*/
unsigned char *addr = dev->dev_addr;
This is snapshot 014
+Fixes added for 1.1.17
+
+o Charles Hedrick's fixes broken fragmentation totally. Mended.
+o Contributed 'dummy' device added. Apparently some slip people want it.
+o Tried to kill the memory problems with fragments by setting things
+ up more carefully and guarding them.
+o Module fixes by Bj0rn.
+o PLIP fix by Tanabe.
+
+Fixes added for 1.1.16
+o Charles Hedricks fixes to TCP.
+o Small fixes all over the place.
+
Fixes added for 1.1.15
o Modular PLIP and 3c501 drivers. Now you -can- have multiple 3c501's
(sort of).
{
struct arp_table *entry;
unsigned long hash;
-/* SHOULD BE FIXED NOW */
- if(paddr==0)
- {
- printk("ADDRESS BOTCH 0\n");
- if(skb)
- {
- printk("skb(saddr=%lx, daddr=%lx, raddr=%lx)\n",
- skb->saddr,skb->daddr,skb->raddr);
- }
- }
-/* ------------- */
switch (ip_chk_addr(paddr))
{
case IS_MYADDR:
{
mac = -mac;
skb->arp = 0;
- skb->raddr = daddr; /* next routing address */
+ skb->raddr = daddr; /* next routing address */
}
}
return mac;
* If the frame is from us and going off machine it MUST MUST MUST
* have the output device ip address and never the loopback
*/
- if (saddr == 0x0100007FL && daddr != 0x0100007FL)
+ if (saddr == htonl(0x7F000001L) && daddr != htonl(0x7F000001L))
saddr = src;/*rt->rt_dev->pa_addr;*/
raddr = rt->rt_gateway;
/* Finally, release the queue descriptor itself. */
kfree_s(qp, sizeof(struct ipq));
-/* printk("ip_free:done\n");*/
sti();
}
{
printk("IP: create: no memory left !\n");
return(NULL);
- skb->dev = qp->dev;
+ skb->dev = qp->dev;
}
memset(qp, 0, sizeof(struct ipq));
ihl = (iph->ihl * sizeof(unsigned long));
end = offset + ntohs(iph->tot_len) - ihl;
-
+
/*
* Point into the IP datagram 'data' part.
*/
struct sk_buff *skb2;
int left, mtu, hlen, len;
int offset;
+ unsigned long flags;
/*
* Point into the IP datagram header.
* Set up data on packet
*/
- skb2->arp = 0;/*skb->arp;*/
- skb2->free = skb->free;
+ skb2->arp = skb->arp;
+ if(skb->free==0)
+ printk("IP fragmenter: BUG free!=1 in fragmenter\n");
+ skb2->free = 1;
skb2->len = len + hlen;
skb2->h.raw=(char *) skb2->data;
- skb2->raddr = skb->raddr; /* For rebuild_header */
/*
* Charge the memory for the fragment to any owner
* it might posess
*/
+ save_flags(flags);
if (sk)
+ {
+ cli();
sk->wmem_alloc += skb2->mem_len;
-
+ skb2->sk=sk;
+ }
+ restore_flags(flags);
+ skb2->raddr = skb->raddr; /* For rebuild_header - must be here */
+
/*
* Copy the packet header into the new buffer.
*/
ip_statistics.IpFragCreates++;
- ip_queue_xmit(sk, dev, skb2, 1);
+ ip_queue_xmit(sk, dev, skb2, 2);
}
ip_statistics.IpFragOKs++;
}
#ifdef CONFIG_IP_FORWARD
-/*
+/*
* Forward an IP datagram to its next destination.
*/
/*
* Queues a packet to be sent, and starts the transmitter
* if necessary. if free = 1 then we free the block after
- * transmit, otherwise we don't.
+ * transmit, otherwise we don't. If free==2 we not only
+ * free the block but also dont assign a new ip seq number.
* This routine also needs to put in the total length,
* and compute the checksum
*/
* Do some book-keeping in the packet for later
*/
- skb->free = free;
+
skb->dev = dev;
skb->when = jiffies;
iph = (struct iphdr *)ptr;
skb->ip_hdr = iph;
iph->tot_len = ntohs(skb->len-dev->hard_header_len);
- iph->id = htons(ip_id_count++);
+
+ /*
+ * No reassigning numbers to fragments...
+ */
+
+ if(free!=2)
+ iph->id = htons(ip_id_count++);
+ else
+ free=1;
+
+ skb->free = free;
/*
* Do we need to fragment. Again this is inefficient.
* Matthew Dillon : Reworked TCP machine states as per RFC
* Gerhard Koerting: PC/TCP workarounds
* Adam Caldwell : Assorted timer/timing errors
+ * Matthew Dillon : Fixed another RST bug
*
*
* To Fix:
* it causes a select. Linux can - given the official select semantics I
* feel that _really_ its the BSD network programs that are bust (notably
* inetd, which hangs occasionally because of this).
- * Protocol closedown badly messed up.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
printk("Clean rcv queue\n");
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{
- if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
+ /* The +1 is not needed because the FIN takes up sequence space and
+ is not read!!! */
+ if(skb->len > 0 && after(skb->h.th->seq + skb->len/* + 1 */ , sk->copied_seq))
need_reset = 1;
kfree_skb(skb, FREE_READ);
}
return;
}
+ /*
+ * Various people wanted BSD UDP semantics. Well they've come
+ * back out because they slow down response to stuff like dead
+ * or unreachable name servers and they screw term users something
+ * chronic. Oh and it violates RFC1122. So basically fix your
+ * client code people.
+ */
+
+#ifdef CONFIG_I_AM_A_BROKEN_BSD_WEENIE
/*
* It's only fatal if we have connected to them. I'm not happy
* with this code. Some BSD comparisons need doing.
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED)
{
sk->err = icmp_err_convert[err & 0xff].errno;
-/* sk->err=ECONNREFUSED;*/
+ sk->error_report(sk);
}
-
- sk->error_report(sk);
+#else
+ if (icmp_err_convert[err & 0xff].fatal)
+ {
+ sk->err = icmp_err_convert[err & 0xff].errno;
+ sk->error_report(sk);
+ }
+#endif
}