diff -u --recursive --new-file v1.1.3/linux/Makefile linux/Makefile --- v1.1.3/linux/Makefile Wed Apr 13 18:37:54 1994 +++ linux/Makefile Wed Apr 13 12:53:29 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 3 +SUBLEVEL = 4 all: Version zImage diff -u --recursive --new-file v1.1.3/linux/config.in linux/config.in --- v1.1.3/linux/config.in Wed Apr 13 18:37:54 1994 +++ linux/config.in Wed Apr 13 18:57:47 1994 @@ -65,7 +65,7 @@ #bool 'PPP (point-to-point) support' CONFIG_PPP n bool 'PLIP (parallel port) support' CONFIG_PLIP n bool 'NE2000/NE1000 support' CONFIG_NE2000 n -bool 'WD80E3 support' CONFIG_WD80x3 y +bool 'WD80*3 support' CONFIG_WD80x3 y bool 'SMC Ultra support' CONFIG_ULTRA n bool '3c501 support' CONFIG_EL1 n bool '3c503 support' CONFIG_EL2 n diff -u --recursive --new-file v1.1.3/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.1.3/linux/drivers/net/3c501.c Sun Mar 6 16:12:04 1994 +++ linux/drivers/net/3c501.c Wed Apr 13 12:52:16 1994 @@ -37,10 +37,9 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include #ifndef HAVE_AUTOIRQ /* From auto_irq.c, should be in a *.h file. */ @@ -49,11 +48,6 @@ extern struct device *irq2dev_map[16]; #endif -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(addr, size) kfree_s(addr,size); -#endif - /* Index to functions. */ int el1_probe(struct device *dev); @@ -64,9 +58,7 @@ static void el_reset(struct device *dev); static int el1_close(struct device *dev); static struct enet_statistics *el1_get_stats(struct device *dev); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif #define EL_NAME "EtherLink 3c501" @@ -202,35 +194,9 @@ dev->hard_start_xmit = &el_start_xmit; dev->stop = &el1_close; dev->get_stats = &el1_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif - - /* Fill in the generic field of the device structure. */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); + /* Setup the generic properties */ + ether_setup(dev); return 0; } @@ -291,14 +257,6 @@ return 0; } - /* Fill in the ethernet header. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - if (skb->len <= 0) return 0; @@ -431,7 +389,7 @@ static void el_receive(struct device *dev) { - int sksize, pkt_len; + int pkt_len; struct sk_buff *skb; pkt_len = inw(RX_LOW); @@ -447,31 +405,19 @@ } outb(AX_SYS, AX_CMD); - sksize = sizeof(struct sk_buff) + pkt_len; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); outw(0x00, GP_LOW); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); el_status.stats.rx_dropped++; return; } else { - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; insb(DATAPORT, skb->data, pkt_len); -#ifdef HAVE_NETIF_RX - netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_skbmem(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif + netif_rx(skb); el_status.stats.rx_packets++; } return; @@ -526,7 +472,6 @@ return &el_status.stats; } -#ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list @@ -547,7 +492,6 @@ inb(RX_STATUS); } } -#endif /* * Local variables: diff -u --recursive --new-file v1.1.3/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v1.1.3/linux/drivers/net/3c503.c Wed Apr 13 11:33:50 1994 +++ linux/drivers/net/3c503.c Wed Apr 13 12:52:16 1994 @@ -26,7 +26,7 @@ #include #include -#include "dev.h" +#include #include "8390.h" #include "3c503.h" diff -u --recursive --new-file v1.1.3/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v1.1.3/linux/drivers/net/3c507.c Wed Apr 13 11:33:50 1994 +++ linux/drivers/net/3c507.c Wed Apr 13 12:52:16 1994 @@ -51,17 +51,10 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" - -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(addr, size) kfree_s(addr,size); -#else +#include +#include +#include #include -#endif /* use 0 for production, 1 for verification, 2..7 for debug */ #ifndef NET_DEBUG @@ -409,32 +402,7 @@ dev->hard_start_xmit = el16_send_packet; dev->get_stats = el16_get_stats; - /* Fill in the fields of the device structure with ethernet-generic values. - This should be in a common file instead of per-driver. */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); /* Generic ethernet behaviour */ return 0; } @@ -496,15 +464,6 @@ return 0; } - /* For ethernet, fill in the header. This should really be done by a - higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - /* Block a timer-based transmit from overlapping. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); @@ -855,35 +814,22 @@ if (frame_status & 0x0080) lp->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ - int sksize; struct sk_buff *skb; pkt_len &= 0x3fff; - sksize = sizeof(struct sk_buff) + pkt_len; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; /* 'skb->data' points to the start of sk_buff data area. */ memcpy(skb->data, data_frame + 5, pkt_len); -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_skbmem(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } diff -u --recursive --new-file v1.1.3/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.1.3/linux/drivers/net/3c509.c Thu Mar 31 09:40:04 1994 +++ linux/drivers/net/3c509.c Wed Apr 13 12:52:17 1994 @@ -28,14 +28,10 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#endif #ifdef EL3_DEBUG @@ -95,20 +91,17 @@ /* First check for a board on the EISA bus. */ if (EISA_bus) { for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - /* Check the standard EISA ID register for an encoded '3Com'. */ - if (inw(ioaddr + 0xC80) != 0x6d50) + if (inw(ioaddr) != 0x6d50) continue; - /* Change the register set to the configuration window 0. */ - outw(0x0800, ioaddr + 0xC80 + EL3_CMD); - irq = inw(ioaddr + 8) >> 12; if_port = inw(ioaddr + 6)>>14; for (i = 0; i < 3; i++) phys_addr[i] = htons(read_eeprom(ioaddr, i)); - /* Restore the "Product ID" to the EEPROM read register. */ - read_eeprom(ioaddr, 3); + /* Restore the "Manufacturer ID" to the EEPROM read register. */ + /* The manual says to restore "Product ID" (reg. 3). !???! */ + read_eeprom(ioaddr, 7); /* Was the EISA code an add-on hack? Nahhhhh... */ goto found; @@ -219,31 +212,7 @@ #endif /* Fill in the generic fields of the device structure. */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); return 0; } @@ -368,14 +337,6 @@ return 0; } - /* Fill in the ethernet header. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - if (skb->len <= 0) return 0; @@ -480,7 +441,7 @@ if (++i > 10) { printk("%s: Infinite loop in interrupt, status %4.4x.\n", dev->name, status); - /* Clear all interrupts we have handled. */ + /* Clear all interrupts we have handled */ outw(0x68FF, ioaddr + EL3_CMD); break; } @@ -568,16 +529,13 @@ if ( (! (rx_status & 0x4000)) || ! (rx_status & 0x1000)) { /* Dribble bits are OK. */ short pkt_len = rx_status & 0x7ff; - int sksize = sizeof(struct sk_buff) + pkt_len + 3; struct sk_buff *skb; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len+3, GFP_ATOMIC); if (el3_debug > 4) - printk(" Receiving packet size %d status %4.4x.\n", + printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; @@ -606,12 +564,12 @@ continue; } else { printk("%s: receive buffers full.\n", dev->name); - kfree_s(skb, sksize); + kfree_s(skb, FREE_READ); } #endif } else if (el3_debug) printk("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, sksize); + dev->name, pkt_len); } lp->stats.rx_dropped++; outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */ diff -u --recursive --new-file v1.1.3/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v1.1.3/linux/drivers/net/8390.c Tue Mar 22 09:03:31 1994 +++ linux/drivers/net/8390.c Wed Apr 13 13:13:53 1994 @@ -47,14 +47,9 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include "skbuff.h" -#include "sock.h" -#include "arp.h" +#include +#include +#include #include "8390.h" @@ -153,8 +148,8 @@ else { /* The 8390 probably hasn't gotten on the cable yet. */ printk(KERN_DEBUG "%s: Possible network cable problem?\n", dev->name); - if (ei_local->stat.tx_packets == 0) - ei_local->interface_num ^= 1; /* Try a different xcvr. */ + if(ei_local->stat.tx_packets==0) + ei_local->interface_num ^= 1; /* Try a different xcvr. */ } /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); @@ -169,13 +164,6 @@ dev_tint(dev); return 0; } - /* Fill in the ethernet header. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; length = skb->len; if (skb->len <= 0) @@ -449,19 +437,16 @@ rx_frame.next); ei_local->stat.rx_errors++; } else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) { - int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { if (ei_debug > 1) printk("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, sksize); + dev->name, pkt_len); ei_local->stat.rx_dropped++; break; } else { - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; @@ -580,8 +565,6 @@ /* Initialize the rest of the 8390 device structure. */ int ethdev_init(struct device *dev) { - int i; - if (ei_debug > 1) printk(version); @@ -605,32 +588,9 @@ #ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; #endif - - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); + return 0; } diff -u --recursive --new-file v1.1.3/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.1.3/linux/drivers/net/Makefile Tue Feb 22 08:38:04 1994 +++ linux/drivers/net/Makefile Wed Apr 13 12:52:17 1994 @@ -7,7 +7,7 @@ # are difficult for users to deal with. include CONFIG -NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o) +NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o) net.a(loopback.o) CFLAGS := $(CFLAGS) -I../../net/inet CPP := $(CPP) -I../../net/inet diff -u --recursive --new-file v1.1.3/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.1.3/linux/drivers/net/Space.c Fri Feb 18 11:18:28 1994 +++ linux/drivers/net/Space.c Wed Apr 13 12:52:17 1994 @@ -26,7 +26,7 @@ */ #include #include -#include "dev.h" +#include #define LOOPBACK /* always present, right? */ diff -u --recursive --new-file v1.1.3/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v1.1.3/linux/drivers/net/at1700.c Sun Mar 6 16:13:56 1994 +++ linux/drivers/net/at1700.c Wed Apr 13 12:52:17 1994 @@ -40,10 +40,9 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include #ifndef HAVE_AUTOIRQ /* From auto_irq.c, in ioport.h for later versions. */ @@ -54,11 +53,6 @@ extern struct device *irq2dev_map[16]; #endif -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(addr, size) kfree_s(addr,size); -#endif - /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG #define NET_DEBUG 2 @@ -121,9 +115,7 @@ static void net_rx(struct device *dev); static int net_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif /* Check for a network adaptor of this type, and return '0' iff one exists. @@ -258,37 +250,11 @@ dev->stop = net_close; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif - /* Fill in the fields of the device structure with ethernet-generic values. - This should be in a common file instead of per-driver. */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); - + /* Fill in the fields of the device structure with ethernet-generic values. */ + + ether_setup(dev); return 0; } @@ -410,15 +376,6 @@ return 0; } - /* For ethernet, fill in the header. This should really be done by a - higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) @@ -534,7 +491,6 @@ } else { ushort pkt_len = inw(ioaddr + DATAPORT); /* Malloc up new buffer. */ - int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; if (pkt_len > 1550) { @@ -544,7 +500,7 @@ lp->stats.rx_errors++; break; } - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet (len %d).\n", dev->name, pkt_len); @@ -552,8 +508,6 @@ lp->stats.rx_dropped++; break; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; @@ -567,16 +521,7 @@ printk(".\n"); } -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_s(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } if (--boguscount <= 0) @@ -637,7 +582,6 @@ return &lp->stats; } -#ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list @@ -653,7 +597,6 @@ } else outw(2, ioaddr + RX_MODE); /* Disable promiscuous, use normal mode */ } -#endif /* * Local variables: diff -u --recursive --new-file v1.1.3/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v1.1.3/linux/drivers/net/atp.c Tue Mar 1 19:29:05 1994 +++ linux/drivers/net/atp.c Wed Apr 13 12:52:17 1994 @@ -91,10 +91,9 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include #include "atp.h" @@ -132,7 +131,6 @@ extern int atp_probe(struct device *dev); static int atp_probe1(struct device *dev, short ioaddr); -static void init_dev(struct device *dev); static void get_node_ID(struct device *dev); static unsigned short eeprom_op(short ioaddr, unsigned int cmd); static int net_open(struct device *dev); @@ -145,9 +143,7 @@ static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode); static int net_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif /* Check for a network adaptor of this type, and return '0' iff one exists. @@ -232,7 +228,7 @@ printk(version); /* Initialize the device structure. */ - init_dev(dev); + ether_setup(dev); dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); memset(dev->priv, 0, sizeof(struct net_local)); @@ -251,45 +247,11 @@ dev->stop = net_close; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif return 0; } -/* Fill in the fields of the device structure with ethernet-generic values. - This should be in a common file instead of per-driver. */ -static void init_dev(struct device *dev) -{ - int i; - - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); -} - /* Read the station address PROM, usually a word-wide EEPROM. */ static void get_node_ID(struct device *dev) { @@ -475,15 +437,6 @@ return 0; } - /* For ethernet, fill in the header. This should really be done by a - higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) @@ -674,17 +627,14 @@ } else { /* Malloc up new buffer. */ int pkt_len = (rx_head.rx_count & 0x7ff) - 4; /* The "-4" is omits the FCS (CRC). */ - int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; goto done; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; @@ -699,16 +649,7 @@ data[12], data[13]); } -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_s(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } done: @@ -770,7 +711,6 @@ return &lp->stats; } -#ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list @@ -785,7 +725,6 @@ lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; write_reg_high(ioaddr, CMR2, lp->addr_mode); } -#endif /* * Local variables: diff -u --recursive --new-file v1.1.3/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c --- v1.1.3/linux/drivers/net/auto_irq.c Wed Dec 1 14:44:15 1993 +++ linux/drivers/net/auto_irq.c Wed Apr 13 12:52:17 1994 @@ -35,7 +35,7 @@ #include #include #include -#include "dev.h" +#include /*#include */ struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */}; diff -u --recursive --new-file v1.1.3/linux/drivers/net/d_link.c linux/drivers/net/d_link.c --- v1.1.3/linux/drivers/net/d_link.c Wed Feb 2 17:30:03 1994 +++ linux/drivers/net/d_link.c Wed Apr 13 12:52:17 1994 @@ -76,23 +76,13 @@ #include #include -#include "inet.h" -#include "dev.h" -#include "eth.h" -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "tcp.h" -#include "skbuff.h" -#include "sock.h" -#include "arp.h" +#include +#include +#include +#include #define netstats enet_statistics -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size,pri) (struct sk_buff *)kmalloc(size,pri) -#endif - /************************************************** * * * Definition of D-Link Ethernet Pocket adapter * @@ -334,8 +324,11 @@ * * This fix is better than changing in tcp.h IMHO */ +#if 0 tcp_prot.rspace = d_link_rspace; /* was: sock_rspace */ +#endif + return 0; } @@ -355,8 +348,9 @@ free_irq(D_LINK_IRQ); irq2dev_map[D_LINK_IRQ] = NULL; dev->start = 0; +#if 0 tcp_prot.rspace = sock_rspace; /* see comment above! */ - +#endif return 0; } @@ -399,15 +393,6 @@ return 0; } - /* For ethernet, fill in the header (hardware addresses) with an arp. */ - if (!skb->arp) - if(dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp = 1; - if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ tickssofar = jiffies - dev->trans_start; @@ -559,7 +544,6 @@ int i; int read_from; int size; - int sksize; register unsigned char *buffer; cli(); @@ -577,19 +561,16 @@ if ((size < 32) || (size > 1535)) printk("%s: Bogus packet size %d.\n", dev->name, size); - sksize = sizeof(struct sk_buff) + size; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(size, GFP_ATOMIC); sti(); if (skb == NULL) { printk("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, sksize); + dev->name, size); return; } /* else */ skb->lock = 0; - skb->mem_len = sksize; - skb->mem_addr = skb; /* 'skb->data' points to the start of sk_buff data area. */ buffer = skb->data; @@ -663,35 +644,14 @@ /* Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL); memset(dev->priv, 0, sizeof(struct netstats)); - - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - dev->get_stats = get_stats; - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - dev->rebuild_header = eth_rebuild_header; - dev->type_trans = eth_type_trans; dev->open = d_link_open; dev->stop = d_link_close; dev->hard_start_xmit = &d_link_start_xmit; - /* These are ethernet specific. */ - dev->type = ARPHRD_ETHER; - dev->hard_header_len = ETH_HLEN; - dev->mtu = 1500; /* eth_mtu */ - dev->addr_len = ETH_ALEN; - - /* 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); + select_prn(); return 0; } diff -u --recursive --new-file v1.1.3/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v1.1.3/linux/drivers/net/depca.c Wed Apr 13 11:33:51 1994 +++ linux/drivers/net/depca.c Wed Apr 13 12:52:18 1994 @@ -147,11 +147,10 @@ #include #include -#include "dev.h" +#include #include "iow.h" /* left in for pl13/14 compatibility... */ -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include #include "depca.h" #ifdef DEPCA_DEBUG @@ -216,11 +215,6 @@ #endif /* CRC_POLYNOMIAL */ #endif /* HAVE_MULTICAST */ -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(buff, size) kfree_s(buff,size) -#endif /* HAVE_ALLOC_SKB */ - /* ** The DEPCA Rx and Tx ring descriptors. */ @@ -1066,17 +1060,14 @@ if (status & R_BUFF) lp->stats.rx_fifo_errors++; } else { /* Malloc up new buffer, compatible with net-2e. */ short pkt_len = lp->rx_ring[entry].msg_length; - int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; memcpy(skb->data, @@ -1086,16 +1077,7 @@ ** Notify the upper protocol layers that there is another ** packet to handle */ -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_skbmem(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } diff -u --recursive --new-file v1.1.3/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v1.1.3/linux/drivers/net/eexpress.c Wed Apr 13 11:33:51 1994 +++ linux/drivers/net/eexpress.c Wed Apr 13 12:52:18 1994 @@ -1,3 +1,4 @@ + /* eexpress.c: Intel EtherExpress device driver for Linux. */ /* Written 1993 by Donald Becker. @@ -41,25 +42,19 @@ #include #include #include -#include #include +#include #include #include #include #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#else -/* This isn't quite right, but it's the best version define I can find right now. */ #include -#endif /* use 0 for production, 1 for verification, 2..7 for debug */ #ifndef NET_DEBUG @@ -292,9 +287,7 @@ static void eexp_rx(struct device *dev); static int eexp_close(struct device *dev); static struct enet_statistics *eexp_get_stats(struct device *dev); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif static int read_eeprom(int ioaddr, int location); static void hardware_send_packet(struct device *dev, void *buf, short length); @@ -405,37 +398,12 @@ dev->stop = eexp_close; dev->hard_start_xmit = eexp_send_packet; dev->get_stats = eexp_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif - - /* Fill in the fields of the device structure with ethernet-generic values. - This should be in a common file instead of per-driver. */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); + /* Fill in the fields of the device structure with ethernet-generic values. */ + + ether_setup(dev); + return 0; } @@ -511,15 +479,6 @@ return 0; } - /* For ethernet, fill in the header. This should really be done by a - higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - /* Block a timer-based transmit from overlapping. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); @@ -704,7 +663,6 @@ return &lp->stats; } -#ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list @@ -731,7 +689,6 @@ outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */ } } -#endif /* The horrible routine to read a word from the serial EEPROM. */ @@ -964,19 +921,15 @@ if (frame_status & 0x0080) lp->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ - int sksize; struct sk_buff *skb; pkt_len &= 0x3fff; - sksize = sizeof(struct sk_buff) + pkt_len; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; @@ -984,16 +937,7 @@ insw(ioaddr, skb->data, (pkt_len + 1) >> 1); -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_s(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } diff -u --recursive --new-file v1.1.3/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v1.1.3/linux/drivers/net/hp.c Sun Mar 6 16:12:05 1994 +++ linux/drivers/net/hp.c Wed Apr 13 12:52:18 1994 @@ -23,7 +23,7 @@ #include #include -#include "dev.h" +#include #include "8390.h" #ifndef HAVE_PORTRESERVE diff -u --recursive --new-file v1.1.3/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.1.3/linux/drivers/net/lance.c Fri Mar 4 09:16:19 1994 +++ linux/drivers/net/lance.c Wed Apr 13 12:52:18 1994 @@ -29,21 +29,15 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include #ifndef HAVE_PORTRESERVE #define check_region(addr, size) 0 #define snarf_region(addr, size) do ; while(0) #endif -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(buff, size) kfree_s(buff,size) -#endif - struct device *init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp); @@ -359,9 +353,7 @@ dev->hard_start_xmit = &lance_start_xmit; dev->stop = &lance_close; dev->get_stats = &lance_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif return mem_start; } @@ -511,14 +503,6 @@ return 0; } - /* Fill in the ethernet header. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - if (skb->len <= 0) return 0; @@ -720,32 +704,20 @@ } else { /* Malloc up new buffer, compatible with net-2e. */ short pkt_len = lp->rx_ring[entry].msg_length; - int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; memcpy(skb->data, (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), pkt_len); -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_skbmem(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } @@ -808,7 +780,6 @@ return &lp->stats; } -#ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list @@ -842,7 +813,6 @@ outw(0, ioaddr+LANCE_ADDR); outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */ } -#endif #ifdef HAVE_DEVLIST static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0}; diff -u --recursive --new-file v1.1.3/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v1.1.3/linux/drivers/net/loopback.c +++ linux/drivers/net/loopback.c Wed Apr 13 17:12:39 1994 @@ -0,0 +1,141 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Pseudo-driver for the loopback interface. + * + * Version: @(#)loopback.c 1.0.4b 08/16/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Donald Becker, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ + +#include +#include +#include + +#include +#include +#include +#include + + +static int +loopback_xmit(struct sk_buff *skb, struct device *dev) +{ + struct enet_statistics *stats = (struct enet_statistics *)dev->priv; + int done; + + DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb)); + if (skb == NULL || dev == NULL) return(0); + + cli(); + if (dev->tbusy != 0) { + sti(); + printk("loopback error: called by %08lx\n", + ((unsigned long *)&skb)[-1]); + stats->tx_errors++; + return(1); + } + dev->tbusy = 1; + sti(); + + start_bh_atomic(); + done = dev_rint(skb->data, skb->len, 0, dev); + if (skb->free) kfree_skb(skb, FREE_WRITE); + end_bh_atomic(); + + while (done != 1) { + start_bh_atomic(); + done = dev_rint(NULL, 0, 0, dev); + end_bh_atomic(); + } + stats->tx_packets++; + + dev->tbusy = 0; + +#if 1 + __asm__("cmpl $0,_intr_count\n\t" + "jne 1f\n\t" + "movl _bh_active,%%eax\n\t" + "testl _bh_mask,%%eax\n\t" + "je 1f\n\t" + "incl _intr_count\n\t" + "call _do_bottom_half\n\t" + "decl _intr_count\n" + "1:" + : + : + : "ax", "dx", "cx"); +#endif + + return(0); +} + +static struct enet_statistics * +get_stats(struct device *dev) +{ + return (struct enet_statistics *)dev->priv; +} + +/* Initialize the rest of the LOOPBACK device. */ +int +loopback_init(struct device *dev) +{ + int i; + + dev->mtu = 2000; /* MTU */ + dev->tbusy = 0; + dev->hard_start_xmit = loopback_xmit; + dev->open = NULL; +#if 1 + dev->hard_header = eth_header; + dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->addr_len = ETH_ALEN; /* 6 */ + dev->type = ARPHRD_ETHER; /* 0x0001 */ + dev->type_trans = eth_type_trans; + dev->rebuild_header = eth_rebuild_header; +#else + dev->hard_header_length = 0; + dev->addr_len = 0; + dev->type = 0; /* loopback_type (0) */ + dev->hard_header = NULL; + dev->type_trans = NULL; + dev->rebuild_header = NULL; +#endif + + /* New-style flags. */ + dev->flags = IFF_LOOPBACK; + dev->family = AF_INET; + dev->pa_addr = in_aton("127.0.0.1"); + dev->pa_brdaddr = in_aton("127.255.255.255"); + dev->pa_mask = in_aton("255.0.0.0"); + dev->pa_alen = sizeof(unsigned long); + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct enet_statistics)); + dev->get_stats = get_stats; + + /* Fill in the generic fields of the device structure. */ + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + return(0); +}; diff -u --recursive --new-file v1.1.3/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v1.1.3/linux/drivers/net/ne.c Sun Mar 6 16:12:04 1994 +++ linux/drivers/net/ne.c Wed Apr 13 12:52:18 1994 @@ -26,7 +26,7 @@ #include #include -#include "dev.h" +#include #include "8390.h" #define NE_BASE (dev->base_addr) diff -u --recursive --new-file v1.1.3/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v1.1.3/linux/drivers/net/net_init.c Wed Apr 13 11:33:51 1994 +++ linux/drivers/net/net_init.c Wed Apr 13 12:52:18 1994 @@ -24,8 +24,8 @@ #include #include #include -#include "dev.h" -#include "eth.h" +#include +#include /* The network devices currently exist only in the socket namespace, so these entries are unused. The only ones that make sense are @@ -38,26 +38,14 @@ Given that almost all of these functions are handled in the current socket-based scheme, putting ethercard devices in /dev/ seems pointless. + + [Removed all support for /dev network devices. When someone adds streams then + by magic we get them, but otherwise they are un-needed and a space waste] */ /* The next device number/name to assign: "eth0", "eth1", etc. */ static int next_ethdev_number = 0; -#ifdef NET_MAJOR_NUM -static struct file_operations netcard_fops = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* release */ - NULL /* fsync */ -}; -#endif - unsigned long lance_init(unsigned long mem_start, unsigned long mem_end); /* @@ -69,12 +57,6 @@ unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end) { -#ifdef NET_MAJOR_NUM - if (register_chrdev(NET_MAJOR_NUM, "network",&netcard_fops)) - printk("WARNING: Unable to get major %d for the network devices.\n", - NET_MAJOR_NUM); -#endif - #if defined(CONFIG_LANCE) /* Note this is _not_ CONFIG_AT1500. */ mem_start = lance_init(mem_start, mem_end); #endif @@ -117,11 +99,9 @@ sprintf(dev->name, "eth%d", next_ethdev_number++); for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; + skb_queue_head_init(&dev->buffs[i]); dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; dev->rebuild_header = eth_rebuild_header; dev->type_trans = eth_type_trans; @@ -151,6 +131,36 @@ } return dev; } + +void ether_setup(struct device *dev) +{ + int i; + /* Fill in the fields of the device structure with ethernet-generic values. + This should be in a common file instead of per-driver. */ + 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; + } + + /* 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); +} + /* diff -u --recursive --new-file v1.1.3/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v1.1.3/linux/drivers/net/plip.c Wed Feb 2 17:30:05 1994 +++ linux/drivers/net/plip.c Wed Apr 13 12:52:19 1994 @@ -1,45 +1,49 @@ -/* Plip.c: A parallel port "network" driver for linux. */ /* - Written 1993 by Donald Becker and TANABE Hiroyasu. - This code is distributed under the GPL. - - The current author is reached as hiro@sanpo.t.u-tokyo.ac.jp . - For more information do 'whois -h whois.nic.ad.jp HT043JP' - - The original author may be reached as becker@super.org or - C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 - - This is parallel port packet pusher. It's actually more general - than the "IP" in its name suggests -- but 'plip' is just such a - great name! - - This driver was first developed by D. Becker, when he was inspired by - Russ Nelson's parallel port packet driver. He also did the update - to 0.99.10. - - It was further developed by Tommy Thorn (tthorn@daimi.aau.dk). - - Recent versions were debugged and maintained by TANABE Hiroyasu. + * Plip.c: A parallel port "network" driver for linux. + */ - Updated for 0.99pl12 by Donald Becker. - - Changes even more Alan Cox - Fixed: sets skb->arp=1, always claims success like ethernet, doesn't - free skb and then claim fail. Incorrect brackets causing reset problem - Attempting to make it work (works for me - email me if it does work) - - Bugs: - Should be timer oriented state machine. - Should never use jiffies for timeouts. - Protocol is buggy when broadcasts occur (Must ask Russ Nelson) - Can hang forever on collisions (tough - you fix it!). - I get 15K/second NFS throughput (about 20-25K second IP). - Change the protocol back. - -*/ +/* + * Developement History: + * + * Original version and the name 'PLIP' from Donald Becker + * inspired by Russ Nelson's parallel port packet driver. + * Further development by Tommy Thorn + * Some changes by Tanabe Hiroyasu + * Upgraded for PL12 by Donald Becker + * Minor hacks by Alan Cox to get it working + * more reliably (Ha!) + * Changes even more Peter Bauer (100136.3530@compuserve.com) + * Protocol changed back to original plip as in crynwr's packet-drivers. + * Tested this against ncsa-telnet 2.3 and pcip_pkt using plip.com (which + * contains "version equ 0" and ";History:562,1" in the firts 2 + * source-lines 28-Mar-94 + * + * + * + * This is parallel port packet pusher. It's actually more general + * than the "IP" in its name suggests -- but 'plip' is just such a + * great name! + * + * + * Bugs: Please read this: The PLIP driver is a nasty hack and like all nasty hacks + * has some 'features'. + * + * Can lock machines solid if one end goes down or crashes, or due to cable faults. + * Can lock both machines solid on a broadcast collision. + * Some laptops don't have all the wires we use. + * Doesn't match the original Russ Nelson protocol so won't talk to Amiga or PC drivers. + * Waits far too long with interrupts off [X is unbearable, forget action games, xntp is a joke] + * Doesn't work on some fast 486DX machines + * + * If it works be thankful, if not fix it! + * + * Info: + * I got 15K/second NFS throughput (about 20-25K second IP). I also got some ethernet cards + * so don't ask me for help. This code needs a real major rewrite. Any volunteers ? + */ static char *version = - "Net2Debugged PLIP 1.01 (from plip.c:v0.15 for 0.99pl12+, 8/11/93)\n"; + "NET3 PLIP.010 (from plip.c:v0.15 for 0.99pl12+, 8/11/93)\n"; #include @@ -87,14 +91,9 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include "skbuff.h" -#include "sock.h" -#include "arp.h" +#include +#include +#include #ifdef PRINTK #undef PRINTK @@ -138,8 +137,8 @@ static int plip_close(struct device *dev); static int plip_tx_packet(struct sk_buff *skb, struct device *dev); static int plip_header (unsigned char *buff, struct device *dev, - unsigned short type, unsigned long h_dest, - unsigned long h_source, unsigned len); + unsigned short type, void *dest, + void *source, unsigned len, struct sk_buff *skb); /* variables used internally. */ #define INITIALTIMEOUTFACTOR 4 @@ -151,10 +150,6 @@ static void plip_receiver_error(struct device *dev); static void plip_set_physicaladdr(struct device *dev, unsigned long ipaddr); static int plip_addrcmp(struct ethhdr *eth); -static int plip_send_enethdr(struct device *dev, struct ethhdr *eth); -static int plip_rebuild_enethdr(struct device *dev, struct ethhdr *eth, - unsigned char h_dest, unsigned char h_source, - unsigned short type); static void cold_sleep(int tics); static void plip_interrupt(int reg_ptr); /* Dispatch from interrupts. */ static int plip_receive_packet(struct device *dev); @@ -189,10 +184,9 @@ memset(dev->priv, 0, sizeof(struct netstats)); for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; + skb_queue_head_init(&dev->buffs[i]); + dev->hard_header = &plip_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; dev->rebuild_header = eth_rebuild_header; dev->type_trans = eth_type_trans; @@ -283,15 +277,6 @@ return 0; } - /* Pretend we are an ethernet and fill in the header. This could use - a simplified routine someday. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - dev->trans_start = jiffies; ret_val = plip_send_packet(dev, skb->data, skb->len); if (skb->free) @@ -303,14 +288,14 @@ static int plip_header (unsigned char *buff, struct device *dev, - unsigned short type, unsigned long h_dest, - unsigned long h_source, unsigned len) + unsigned short type, void *daddr , + void *saddr, unsigned len, struct sk_buff *skb) { if (dev->dev_addr[0] == 0) { /* set physical address */ - plip_set_physicaladdr(dev, h_source); + plip_set_physicaladdr(dev, dev->pa_addr); } - return eth_header(buff, dev, type, h_dest, h_source, len); + return eth_header(buff, dev, type, daddr, saddr, len, skb); } static void @@ -351,7 +336,7 @@ } while ( (val & 0x80) ); val = inb(dev->base_addr + PAR_STATUS); low_nibble = (val >> 3) & 0x0f; - outb(0x11, dev->base_addr + PAR_DATA); + outb(0x10, dev->base_addr + PAR_DATA); timeout = jiffies + timeoutfactor * 2; do { oldval = val; @@ -365,7 +350,7 @@ val = inb(dev->base_addr + PAR_STATUS); PRINTK2(("%02x %s ", low_nibble | ((val << 1) & 0xf0), error ? "t":"")); - outb(0x01, dev->base_addr + PAR_DATA); + outb(0x00, dev->base_addr + PAR_DATA); if (error) { /* timeout error */ double_timeoutfactor(); @@ -418,7 +403,6 @@ static int plip_receive_packet(struct device *dev) { - int plip_type; unsigned length; int checksum = 0; struct sk_buff *skb; @@ -431,34 +415,16 @@ { /* get header octet and length of packet */ - plip_type = get_byte(dev); - if (plip_type < 0) return 1; /* probably wrong interrupt */ - length = get_byte(dev) << 8; - length |= get_byte(dev); - switch ( plip_type ) { - case PLIP_HEADER_TYPE1: - { - int i; - unsigned char *eth_p = (unsigned char*)ð - for ( i = 0; i < sizeof(eth); i++, eth_p++) { - *eth_p = get_byte(dev); - } - } - break; - case PLIP_HEADER_TYPE2: - { - unsigned char h_dest, h_source; - unsigned short type; - h_dest = get_byte(dev); - h_source = get_byte(dev); - type = get_byte(dev) << 8; - type |= get_byte(dev); - plip_rebuild_enethdr(dev, ð, h_dest, h_source, type); - } - break; - default: - PRINTK(("%s: wrong header octet\n", dev->name)); - } + + length = get_byte(dev); + length |= get_byte(dev) << 8; + { + int i; + unsigned char *eth_p = (unsigned char*)ð + for ( i = 0; i < sizeof(eth); i++, eth_p++) { + *eth_p = get_byte(dev); + } + } PRINTK2(("length = %d\n", length)); if (length > dev->mtu || length < 8) { PRINTK2(("%s: bogus packet size %d.\n", dev->name, length)); @@ -469,17 +435,13 @@ /* get skb area from kernel and * set appropriate values to skb */ - int sksize; - sksize = sizeof(struct sk_buff) + length; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(length, GFP_ATOMIC); if (skb == NULL) { PRINTK(("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, sksize)); + dev->name,length)); return 1; } skb->lock = 0; - skb->mem_len = sksize; - skb->mem_addr = skb; } { /* phase of receiving the data */ @@ -531,13 +493,10 @@ { int timeout; int error = 0; - if (!(inb(dev->base_addr+PAR_STATUS) & 0x08)) { - PRINTK(("remote end become unready while sending\n")); - return -1; - } PRINTK2((" S%02x", val)); - outb(val, dev->base_addr); /* this makes data bits more stable */ - outb(0x10 | val, dev->base_addr); + outb((val & 0xf), dev->base_addr); /* this makes data bits more stable */ + /* (especially the &0xf :-> PB ) */ + outb(0x10 | (val & 0xf), dev->base_addr); timeout = jiffies + timeoutfactor; while( inb(dev->base_addr+PAR_STATUS) & 0x80 ) if ( timeout < jiffies ) { @@ -626,7 +585,6 @@ plip_send_packet(struct device *dev, unsigned char *buf, int length) { int error = 0; - int plip_type; struct netstats *localstats; PRINTK2(("%s: plip_send_packet(%d) %02x %02x %02x %02x %02x...", @@ -663,44 +621,22 @@ if (plip_send_start(dev, (struct ethhdr *)buf) < 0) return 1; - /* select plip type */ - { - /* Use stripped ethernet header if each first 5 octet of eth - * address is same. - */ - int i; - struct ethhdr *eth = (struct ethhdr *)buf; - - plip_type = PLIP_HEADER_TYPE2; - for ( i = 0; i < ETH_ALEN - 1; i++) - if (eth->h_dest[i] != eth->h_source[i]) - plip_type = PLIP_HEADER_TYPE1; - } - - send_byte(dev, plip_type); /* send header octet */ - { - /* send packet's length */ - /* - * in original plip (before v0.1), it was sent with little endian. - * but in internet, network byteorder is big endian, - * so changed to use big endian. - * maybe using 'ntos()' is better. + /* send packet's length + the byte order has changed now and then. Today it's sent as in + the original crynwr-plip ... + Gruss PB */ - send_byte(dev, length >> 8); send_byte(dev, length); + send_byte(dev, length); + send_byte(dev, length >> 8); } { /* phase of sending data */ int i; int checksum = 0; - if (plip_type == PLIP_HEADER_TYPE2) { - plip_send_enethdr(dev, (struct ethhdr*)buf); - } for ( i = 0; i < sizeof(struct ethhdr); i++ ) { - if (plip_type == PLIP_HEADER_TYPE1) { - send_byte(dev, *buf); - } + send_byte(dev, *buf); checksum += *buf++; } @@ -772,29 +708,6 @@ PRINTK2(("h_dest = %08x%04x h_source = %08x%04x\n", *(long*)ð->h_dest[2],*(short*)ð->h_dest[0], *(long*)ð->h_source[2],*(short*)ð->h_source[0])); - return 0; -} - -static int -plip_send_enethdr(struct device *dev, struct ethhdr *eth) -{ - send_byte(dev, eth->h_dest[ETH_ALEN-1]); - send_byte(dev, eth->h_source[ETH_ALEN-1]); - send_byte(dev, eth->h_proto >> 8); - send_byte(dev, eth->h_proto); - return 0; -} - -static int -plip_rebuild_enethdr(struct device *dev, struct ethhdr *eth, - unsigned char dest, unsigned char source, - unsigned short type) -{ - eth->h_proto = type; - memcpy(eth->h_dest, dev->dev_addr, ETH_ALEN-1); - eth->h_dest[ETH_ALEN-1] = dest; - memcpy(eth->h_source, dev->dev_addr, ETH_ALEN-1); - eth->h_source[ETH_ALEN-1] = source; return 0; } diff -u --recursive --new-file v1.1.3/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v1.1.3/linux/drivers/net/skeleton.c Wed Feb 2 17:30:05 1994 +++ linux/drivers/net/skeleton.c Wed Apr 13 12:52:19 1994 @@ -56,10 +56,9 @@ #include #include -#include "dev.h" -#include "eth.h" -#include "skbuff.h" -#include "arp.h" +#include +#include +#include #ifndef HAVE_AUTOIRQ /* From auto_irq.c, in ioport.h for later versions. */ @@ -70,11 +69,6 @@ extern struct device *irq2dev_map[16]; #endif -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(addr, size) kfree_s(addr,size); -#endif - #ifndef HAVE_PORTRESERVE #define check_region(ioaddr, size) 0 #define snarf_region(ioaddr, size); do ; while (0) @@ -111,9 +105,7 @@ static void net_rx(struct device *dev); static int net_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif /* Example routines you must write ;->. */ #define tx_done(dev) 1 @@ -213,36 +205,11 @@ dev->stop = net_close; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif - /* Fill in the fields of the device structure with ethernet-generic values. - This should be in a common file instead of per-driver. */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; - - dev->hard_header = eth_header; - dev->add_arp = eth_add_arp; - dev->queue_xmit = dev_queue_xmit; - 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; - } - - /* 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); + /* Fill in the fields of the device structure with ethernet-generic values. */ + + ether_setup(dev); return 0; } @@ -314,15 +281,6 @@ return 0; } - /* For ethernet, fill in the header. This should really be done by a - higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { - skb->dev = dev; - arp_queue (skb); - return 0; - } - skb->arp=1; - /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) @@ -406,17 +364,14 @@ if (status & 0x04) lp->stats.rx_fifo_errors++; } else { /* Malloc up new buffer. */ - int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; - skb = alloc_skb(sksize, GFP_ATOMIC); + skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } - skb->mem_len = sksize; - skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; @@ -426,16 +381,7 @@ /* or */ insw(ioaddr, skb->data, (pkt_len + 1) >> 1); -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { - kfree_s(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif lp->stats.rx_packets++; } } while (--boguscount); @@ -492,7 +438,6 @@ return &lp->stats; } -#ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list @@ -508,7 +453,6 @@ } else outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */ } -#endif /* * Local variables: diff -u --recursive --new-file v1.1.3/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.1.3/linux/drivers/net/slhc.c Fri Dec 10 16:29:01 1993 +++ linux/drivers/net/slhc.c Wed Apr 13 12:52:19 1994 @@ -36,8 +36,15 @@ * allow zero or one slots * separate routines * status display + * + * + * This module is a difficult issue. Its clearly inet code but its also clearly + * driver code belonging close to PPP and SLIP */ +#include +#ifdef CONFIG_INET +/* Entire module is for IP only */ #include #include #include @@ -47,15 +54,14 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" #include "icmp.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" -#include "arp.h" #include #include #include @@ -723,3 +729,4 @@ } } +#endif /* CONFIG_INET */ diff -u --recursive --new-file v1.1.3/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.1.3/linux/drivers/net/slip.c Mon Mar 21 16:16:10 1994 +++ linux/drivers/net/slip.c Wed Apr 13 12:52:19 1994 @@ -21,6 +21,10 @@ * Michael Riepe : Automatic CSLIP recognition added * Charles Hedrick : CSLIP header length problem fix. * Alan Cox : Corrected non-IP cases of the above. + * + * + * FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without + * CONFIG_INET defined. */ #include @@ -39,21 +43,24 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #ifdef CONFIG_AX25 #include "ax25.h" #endif -#include "eth.h" +#include +#ifdef CONFIG_INET #include "ip.h" #include "route.h" #include "protocol.h" #include "tcp.h" -#include "skbuff.h" +#endif +#include #include "sock.h" -#include "arp.h" #include "slip.h" +#ifdef CONFIG_INET #include "slhc.h" +#endif #define SLIP_VERSION "0.7.5" @@ -363,6 +370,7 @@ int count; count = sl->rcount; +#ifdef CONFIG_INET if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) { #if 1 @@ -408,7 +416,7 @@ DPRINTF((DBG_SLIP, "<< \"%s\" recv:\r\n", sl->dev->name)); ip_dump(sl->rbuff, sl->rcount); - +#endif /* Bump the datagram to the upper layers... */ do { DPRINTF((DBG_SLIP, "SLIP: packet is %d at 0x%X\n", @@ -454,49 +462,14 @@ } p = icp; +#ifdef CONFIG_INET if(sl->mode & SL_MODE_CSLIP) len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); - -#ifdef OLD - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - bp = sl->xbuff; - *bp++ = END; - count = 1; - - /* - * For each byte in the packet, send the appropriate - * character sequence, according to the SLIP protocol. - */ - while(len-- > 0) { - c = *p++; - switch(c) { - case END: - *bp++ = ESC; - *bp++ = ESC_END; - count += 2; - break; - case ESC: - *bp++ = ESC; - *bp++ = ESC_ESC; - count += 2; - break; - default: - *bp++ = c; - count++; - } - } - *bp++ = END; - count++; -#else +#endif if(sl->mode & SL_MODE_SLIP6) count=slip_esc6(p, (unsigned char *)sl->xbuff,len); else count=slip_esc(p, (unsigned char *)sl->xbuff,len); -#endif sl->spacket++; bp = sl->xbuff; @@ -552,36 +525,45 @@ /* We were not, so we are now... :-) */ if (skb != NULL) { -#ifdef CONFIG_AX25 - if(sl->mode & SL_MODE_AX25) - { - if(!skb->arp && dev->rebuild_header(skb->data,dev)) - { - skb->dev=dev; - arp_queue(skb); - return 0; - } - skb->arp=1; - } +#if 0 +#ifdef CONFIG_AX25 + if(sl->mode & SL_MODE_AX25) + { + if(!skb->arp && dev->rebuild_header(skb->data,dev)) + { + skb->dev=dev; + arp_queue(skb); + return 0; + } + skb->arp=1; + } #endif +#endif sl_lock(sl); - size = skb->len; - if (!(sl->mode & SL_MODE_AX25)) { - if (size < sizeof(struct iphdr)) { + + size=skb->len; + + if(!(sl->mode&SL_MODE_AX25)) + { + if(sizedata))->tot_len; - size = ntohs(size); + } + else + { + size=((struct iphdr *)(skb->data))->tot_len; + size=ntohs(size); + /* sl_hex_dump(skb->data,skb->len);*/ } } - /* sl_hex_dump(skb->data,skb->len);*/ sl_encaps(sl, skb->data, size); - if (skb->free) + if (skb->free) kfree_skb(skb, FREE_WRITE); } return(0); } + /* Return the frame type ID. This is normally IP but maybe be AX.25. */ static unsigned short sl_type_trans (struct sk_buff *skb, struct device *dev) @@ -589,49 +571,37 @@ #ifdef CONFIG_AX25 struct slip *sl=&sl_ctrl[dev->base_addr]; if(sl->mode&SL_MODE_AX25) - return(NET16(ETH_P_AX25)); + return htons(ETH_P_AX25); #endif - return(NET16(ETH_P_IP)); + return htons(ETH_P_IP); } /* Fill in the MAC-level header. Not used by SLIP. */ static int sl_header(unsigned char *buff, struct device *dev, unsigned short type, - unsigned long daddr, unsigned long saddr, unsigned len) + void *daddr, void *saddr, unsigned len, struct sk_buff *skb) { #ifdef CONFIG_AX25 struct slip *sl=&sl_ctrl[dev->base_addr]; - if((sl->mode&SL_MODE_AX25) && type!=NET16(ETH_P_AX25)) - return ax25_encapsulate_ip(buff,dev,type,daddr,saddr,len); + if((sl->mode&SL_MODE_AX25) && type!=htons(ETH_P_AX25)) + return ax25_encapsulate(buff,dev,type,daddr,saddr,len,skb); #endif return(0); } -/* Add an ARP-entry for this device's broadcast address. Not used. */ -static void -sl_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev) -{ -#ifdef CONFIG_AX25 - struct slip *sl=&sl_ctrl[dev->base_addr]; - - if(sl->mode&SL_MODE_AX25) - arp_add(addr,((char *) skb->data)+8,dev); -#endif -} - - /* Rebuild the MAC-level header. Not used by SLIP. */ static int -sl_rebuild_header(void *buff, struct device *dev) +sl_rebuild_header(void *buff, struct device *dev, unsigned long raddr, + struct sk_buff *skb) { #ifdef CONFIG_AX25 struct slip *sl=&sl_ctrl[dev->base_addr]; if(sl->mode&SL_MODE_AX25) - return ax25_rebuild_header(buff,dev); + return ax25_rebuild_header(buff,dev,raddr, skb); #endif return(0); } @@ -779,33 +749,10 @@ break; } p = buff; -#ifdef OLD - while (count--) { - c = *p++; - if (sl->escape) { - if (c == ESC_ESC) - sl_enqueue(sl, ESC); - else if (c == ESC_END) - sl_enqueue(sl, END); - else - printk ("SLIP: received wrong character\n"); - sl->escape = 0; - } else { - if (c == ESC) - sl->escape = 1; - else if (c == END) { - if (sl->rcount > 2) sl_bump(sl); - sl_dequeue(sl, sl->rcount); - sl->rcount = 0; - } else sl_enqueue(sl, c); - } - } -#else if(sl->mode & SL_MODE_SLIP6) slip_unesc6(sl,buff,count,error); else slip_unesc(sl,buff,count,error); -#endif } while(1); } @@ -1102,9 +1049,9 @@ DPRINTF((DBG_SLIP, "SLIP: ioctl(%d, 0x%X, 0x%X)\n", tty->line, cmd, arg)); switch(cmd) { case SIOCGIFNAME: - err=verify_area(VERIFY_WRITE, arg, strlen(sl->dev->name) + 1); + err=verify_area(VERIFY_WRITE, arg, 16); if(err) - return err; + return -err; memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1); return(0); case SIOCGIFENCAP: @@ -1156,7 +1103,9 @@ if (already++ == 0) { printk("SLIP: version %s (%d channels)\n", SLIP_VERSION, SL_NRUNIT); +#ifdef CONFIG_INET printk("CSLIP: code copyright 1989 Regents of the University of California\n"); +#endif #ifdef CONFIG_AX25 printk("AX25: KISS encapsulation enabled\n"); #endif @@ -1191,7 +1140,6 @@ dev->open = sl_open; dev->stop = sl_close; dev->hard_header = sl_header; - dev->add_arp = sl_add_arp; dev->type_trans = sl_type_trans; dev->get_stats = sl_get_stats; #ifdef HAVE_SET_MAC_ADDR @@ -1206,10 +1154,9 @@ memcpy(dev->broadcast,ax25_bcast,7); /* Only activated in AX.25 mode */ memcpy(dev->dev_addr,ax25_test,7); /* "" "" "" "" */ #endif - dev->queue_xmit = dev_queue_xmit; dev->rebuild_header = sl_rebuild_header; for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; + skb_queue_head_init(&dev->buffs[i]); /* New-style flags. */ dev->flags = 0; diff -u --recursive --new-file v1.1.3/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v1.1.3/linux/drivers/net/smc-ultra.c Tue Mar 1 19:29:05 1994 +++ linux/drivers/net/smc-ultra.c Wed Apr 13 12:52:19 1994 @@ -24,7 +24,7 @@ #include #include -#include "dev.h" +#include #include "8390.h" /* Compatibility definitions for earlier kernel versions. */ diff -u --recursive --new-file v1.1.3/linux/drivers/net/wd.c linux/drivers/net/wd.c --- v1.1.3/linux/drivers/net/wd.c Fri Dec 17 11:38:47 1993 +++ linux/drivers/net/wd.c Wed Apr 13 12:52:19 1994 @@ -25,7 +25,7 @@ #include #include -#include "dev.h" +#include #include "8390.h" /* Compatibility definitions for earlier kernel versions. */ diff -u --recursive --new-file v1.1.3/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.1.3/linux/drivers/scsi/sd.c Wed Apr 13 11:33:52 1994 +++ linux/drivers/scsi/sd.c Wed Apr 13 10:47:04 1994 @@ -632,12 +632,12 @@ printk("Use sg, count %d %x %d\n", SCpnt->use_sg, count, dma_free_sectors); printk("maxsg = %x, counted = %d this_count = %d\n", max_sg, counted, this_count); while(bh){ - printk("[%8.8x %x] ", bh->b_data, bh->b_size); + printk("[%p %lx] ", bh->b_data, bh->b_size); bh = bh->b_reqnext; }; if(SCpnt->use_sg < 16) for(count=0; countuse_sg; count++) - printk("{%d:%8.8x %8.8x %d} ", count, + printk("{%d:%p %p %d} ", count, sgpnt[count].address, sgpnt[count].alt_address, sgpnt[count].length); diff -u --recursive --new-file v1.1.3/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.3/linux/fs/buffer.c Wed Apr 13 18:37:57 1994 +++ linux/fs/buffer.c Wed Apr 13 10:44:23 1994 @@ -193,10 +193,9 @@ /* If an unlocked buffer is not uptodate, there has been an IO error. Skip it. */ if (wait && bh->b_req && !bh->b_lock && - !bh->b_dirt && !bh->b_uptodate) - { + !bh->b_dirt && !bh->b_uptodate) { err = 1; - printk("Weird - unlocked, clean and not uptodate buffer on %d list %d\n", nlist); + printk("Weird - unlocked, clean and not uptodate buffer on list %d\n", nlist); continue; } /* Don't write clean buffers. Don't write ANY buffers @@ -208,7 +207,7 @@ ll_rw_block(WRITE, 1, &bh); if(nlist != BUF_DIRTY) { - printk("[%d %x %d] ", nlist, bh->b_dev, bh->b_blocknr); + printk("[%d %x %ld] ", nlist, bh->b_dev, bh->b_blocknr); ncount++; }; bh->b_count--; @@ -596,7 +595,8 @@ to request some blocks in a filesystem that we know that we will be needing ahead of time. */ - if(nr_free[isize] > 100) return 0; + if (nr_free[isize] > 100) + return; /* If there are too many dirty buffers, we wake up the update process now so as to ensure that there are still clean buffers available diff -u --recursive --new-file v1.1.3/linux/fs/proc/net.c linux/fs/proc/net.c --- v1.1.3/linux/fs/proc/net.c Tue Mar 22 08:54:43 1994 +++ linux/fs/proc/net.c Wed Apr 13 12:52:20 1994 @@ -15,6 +15,8 @@ * quite a bit, modularized the code. * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen) * Renamed "route_get_info()" to "rt_get_info()" for consistency. + * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94 + * Dusted off the code and added IPX. Fixed the 4K limit. * * proc net directory handling functions */ @@ -36,17 +38,20 @@ /* the get_*_info() functions are in the net code, and are configured in via the standard mechanism... */ -extern int unix_get_info(char *); +extern int unix_get_info(char *, char **, off_t, int); #ifdef CONFIG_INET -extern int tcp_get_info(char *); -extern int udp_get_info(char *); -extern int raw_get_info(char *); -extern int arp_get_info(char *); -extern int dev_get_info(char *); -extern int rt_get_info(char *); +extern int tcp_get_info(char *, char **, off_t, int); +extern int udp_get_info(char *, char **, off_t, int); +extern int raw_get_info(char *, char **, off_t, int); +extern int arp_get_info(char *, char **, off_t, int); +extern int dev_get_info(char *, char **, off_t, int); +extern int rt_get_info(char *, char **, off_t, int); #endif /* CONFIG_INET */ +#ifdef CONFIG_IPX +extern int ipx_get_info(char *, char **, off_t, int); +extern int ipx_rt_get_info(char *, char **, off_t, int); +#endif /* CONFIG_IPX */ - static struct file_operations proc_net_operations = { NULL, /* lseek - default */ proc_readnet, /* read - bad */ @@ -93,6 +98,10 @@ { 133,3,"tcp" }, { 134,3,"udp" } #endif /* CONFIG_INET */ +#ifdef CONFIG_IPX + ,{ 135,9,"ipx_route" }, + { 136,3,"ipx" } +#endif /* CONFIG_IPX */ }; #define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0]))) @@ -154,57 +163,86 @@ } +#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ + static int proc_readnet(struct inode * inode, struct file * file, char * buf, int count) { char * page; int length; - int end; unsigned int ino; + int bytes=count; + int thistime; + int copied=0; + char *start; if (count < 0) return -EINVAL; if (!(page = (char*) __get_free_page(GFP_KERNEL))) return -ENOMEM; ino = inode->i_ino; - switch (ino) { - case 128: - length = unix_get_info(page); - break; + + while(bytes>0) + { + thistime=bytes; + if(bytes>PROC_BLOCK_SIZE) + thistime=PROC_BLOCK_SIZE; + + switch (ino) + { + case 128: + length = unix_get_info(page,&start,file->f_pos,thistime); + break; #ifdef CONFIG_INET - case 129: - length = arp_get_info(page); - break; - case 130: - length = rt_get_info(page); - break; - case 131: - length = dev_get_info(page); - break; - case 132: - length = raw_get_info(page); - break; - case 133: - length = tcp_get_info(page); - break; - case 134: - length = udp_get_info(page); - break; + case 129: + length = arp_get_info(page,&start,file->f_pos,thistime); + break; + case 130: + length = rt_get_info(page,&start,file->f_pos,thistime); + break; + case 131: + length = dev_get_info(page,&start,file->f_pos,thistime); + break; + case 132: + length = raw_get_info(page,&start,file->f_pos,thistime); + break; + case 133: + length = tcp_get_info(page,&start,file->f_pos,thistime); + break; + case 134: + length = udp_get_info(page,&start,file->f_pos,thistime); + break; #endif /* CONFIG_INET */ - default: - free_page((unsigned long) page); - return -EBADF; - } - if (file->f_pos >= length) { - free_page((unsigned long) page); - return 0; +#ifdef CONFIG_IPX + case 135: + length = ipx_rt_get_info(page,&start,file->f_pos,thistime); + break; + case 136: + length = ipx_get_info(page,&start,file->f_pos,thistime); + break; +#endif /* CONFIG_IPX */ + default: + free_page((unsigned long) page); + return -EBADF; + } + + /* + * We have been given a non page aligned block of + * the data we asked for + a bit. We have been given + * the start pointer and we know the length.. + */ + + /* + * Copy the bytes + */ + memcpy_tofs(buf+copied, start, length); + file->f_pos+=length; /* Move down the file */ + bytes-=length; + copied+=length; + if(lengthf_pos > length) - count = length - file->f_pos; - end = count + file->f_pos; - memcpy_tofs(buf, page + file->f_pos, count); free_page((unsigned long) page); - file->f_pos = end; - return count; + return copied; } diff -u --recursive --new-file v1.1.3/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h --- v1.1.3/linux/include/linux/etherdevice.h +++ linux/include/linux/etherdevice.h Wed Apr 13 12:52:20 1994 @@ -0,0 +1,41 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the Ethernet handlers. + * + * Version: @(#)eth.h 1.0.4 05/13/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * Relocated to include/linux where it belongs by Alan Cox + * + * + * 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. + * + * WARNING: This move may well be temporary. This file will get merged with others RSN. + * + */ +#ifndef _LINUX_ETHERDEVICE_H +#define _LINUX_ETHERDEVICE_H + + +#include + +#ifdef __KERNEL__ +extern int eth_header(unsigned char *buff, struct device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len, + struct sk_buff *skb); +extern int eth_rebuild_header(void *buff, struct device *dev, + unsigned long raddr, struct sk_buff *skb); +extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev); + +#endif + +#endif /* _LINUX_ETHERDEVICE_H */ diff -u --recursive --new-file v1.1.3/linux/include/linux/if.h linux/include/linux/if.h --- v1.1.3/linux/include/linux/if.h Tue Apr 5 08:14:29 1994 +++ linux/include/linux/if.h Wed Apr 13 12:52:20 1994 @@ -22,44 +22,6 @@ #include /* for "caddr_t" et al */ #include /* for "struct sockaddr" et al */ - -/* Structure defining a queue for a network interface. */ -#ifdef not_yet_in_linux -struct ifnet { - char *if_name; /* name, e.g. ``en'' or ``lo'' */ - short if_unit; /* sub-unit for device driver */ - short if_mtu; /* maximum transmission unit */ - short if_flags; /* up/down, broadcast, etc. */ - short if_timer; /* time 'til if_watchdog called */ - int if_metric; /* routing metric (not used) */ - struct ifaddr *if_addrlist; /* linked list of addrs per if */ - struct ifqueue { - struct mbuf *ifq_head; - struct mbuf *ifq_tail; - int ifq_len; - int ifq_maxlen; - int ifq_drops; - } if_snd; /* output queue */ - - /* Procedure handles. */ - int (*if_init)(); /* init routine */ - int (*if_output)(); /* output routine */ - int (*if_ioctl)(); /* ioctl routine */ - int (*if_reset)(); /* bus reset routine */ - int (*if_watchdog)(); /* timer routine */ - - /* Generic interface statistics. */ - int if_ipackets; /* packets recv'd on interface */ - int if_ierrors; /* input errors on interface */ - int if_opackets; /* packets sent on interface */ - int if_oerrors; /* output errors on interface */ - int if_collisions; /* collisions on CSMA i'faces */ - - /* Linked list: pointer to next interface. */ - struct ifnet *if_next; -}; -#endif - /* Standard interface flags. */ #define IFF_UP 0x1 /* interface is up */ #define IFF_BROADCAST 0x2 /* broadcast address valid */ @@ -106,7 +68,7 @@ union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - char ifrn_hwaddr[IFHWADDRLEN]; + char ifrn_hwaddr[IFHWADDRLEN]; /* Obsolete */ } ifr_ifrn; union { @@ -114,6 +76,7 @@ struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; short ifru_flags; int ifru_metric; int ifru_mtu; @@ -122,7 +85,8 @@ }; #define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */ +#define old_ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ diff -u --recursive --new-file v1.1.3/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v1.1.3/linux/include/linux/if_arp.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/if_arp.h Wed Apr 13 12:52:20 1994 @@ -38,33 +38,6 @@ #define ARPOP_RREPLY 4 /* RARP reply */ -/* - * Address Resolution Protocol. - * - * See RFC 826 for protocol description. ARP packets are variable - * in size; the arphdr structure defines the fixed-length portion. - * Protocol type values are the same as those for 10 Mb/s Ethernet. - * It is followed by the variable-sized fields ar_sha, arp_spa, - * arp_tha and arp_tpa in that order, according to the lengths - * specified. Field names used correspond to RFC 826. - */ -struct arphdr { - unsigned short ar_hrd; /* format of hardware address */ - unsigned short ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - unsigned short ar_op; /* ARP opcode (command) */ - - /* The rest is variable in size, according to the sizes above. */ -#if 0 - unsigned char ar_sha[]; /* sender hardware address */ - unsigned char ar_spa[]; /* sender protocol address */ - unsigned char ar_tha[]; /* target hardware address */ - unsigned char ar_tpa[]; /* target protocol address */ -#endif /* not actually included! */ -}; - - /* ARP ioctl request. */ struct arpreq { struct sockaddr arp_pa; /* protocol address */ @@ -73,7 +46,6 @@ }; /* ARP Flag values. */ -#define ATF_INUSE 0x01 /* entry in use */ #define ATF_COM 0x02 /* completed entry (ha valid) */ #define ATF_PERM 0x04 /* permanent entry */ #define ATF_PUBL 0x08 /* publish entry */ diff -u --recursive --new-file v1.1.3/linux/include/linux/inet.h linux/include/linux/inet.h --- v1.1.3/linux/include/linux/inet.h +++ linux/include/linux/inet.h Wed Apr 13 12:52:20 1994 @@ -0,0 +1,90 @@ +/* + * Swansea University Computer Society NET3 + * + * This work is derived from NET2Debugged, which is in turn derived + * from NET2D which was written by: + * Fred N. van Kempen, + * + * This work was derived friom Ross Biro's inspirational work + * for the LINUX operating system. His version numbers were: + * + * $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ + * $Id: arp.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ + * $Id: arp.h,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ + * $Id: dev.c,v 0.8.4.13 1993/01/23 18:00:11 bir7 Exp $ + * $Id: dev.h,v 0.8.4.7 1993/01/23 18:00:11 bir7 Exp $ + * $Id: eth.c,v 0.8.4.4 1993/01/22 23:21:38 bir7 Exp $ + * $Id: eth.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ + * $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $ + * $Id: icmp.h,v 0.8.4.2 1992/11/15 14:55:30 bir7 Exp $ + * $Id: ip.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $ + * $Id: ip.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ + * $Id: loopback.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ + * $Id: packet.c,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ + * $Id: protocols.c,v 0.8.4.3 1992/11/15 14:55:30 bir7 Exp $ + * $Id: raw.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ + * $Id: sock.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ + * $Id: sock.h,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ + * $Id: tcp.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $ + * $Id: tcp.h,v 0.8.4.7 1993/01/22 22:58:08 bir7 Exp $ + * $Id: timer.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ + * $Id: timer.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ + * $Id: udp.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ + * $Id: udp.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ + * $Id: we.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $ + * $Id: wereg.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ + * + * 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. + */ +#ifndef _LINUX_INET_H +#define _LINUX_INET_H + + +#include + + +#undef INET_DEBUG +#ifdef INET_DEBUG +# define DPRINTF(x) dprintf x +#else +# define DPRINTF(x) do ; while (0) +#endif + +/* Debug levels. One per module. */ +#define DBG_OFF 0 /* no debugging */ +#define DBG_INET 1 /* sock.c */ +#define DBG_RT 2 /* route.c */ +#define DBG_DEV 3 /* dev.c */ +#define DBG_ETH 4 /* eth.c */ +#define DBG_PROTO 5 /* protocol.c */ +#define DBG_TMR 6 /* timer.c */ +#define DBG_PKT 7 /* packet.c */ +#define DBG_RAW 8 /* raw.c */ + +#define DBG_LOOPB 10 /* loopback.c */ +#define DBG_SLIP 11 /* slip.c */ + +#define DBG_ARP 20 /* arp.c */ +#define DBG_IP 21 /* ip.c */ +#define DBG_ICMP 22 /* icmp.c */ +#define DBG_TCP 23 /* tcp.c */ +#define DBG_UDP 24 /* udp.c */ + +#ifdef __KERNEL__ + +extern int inet_debug; + + +extern void inet_proto_init(struct ddi_proto *pro); +extern char *in_ntoa(unsigned long in); +extern unsigned long in_aton(char *str); + +extern void dprintf(int level, char *fmt, ...); + +extern int dbg_ioctl(void *arg, int level); + +#endif +#endif /* _LINUX_INET_H */ diff -u --recursive --new-file v1.1.3/linux/include/linux/ipx.h linux/include/linux/ipx.h --- v1.1.3/linux/include/linux/ipx.h +++ linux/include/linux/ipx.h Wed Apr 13 12:52:20 1994 @@ -0,0 +1,23 @@ +struct sockaddr_ipx +{ + short sipx_family; + unsigned long sipx_network; + unsigned char sipx_node[6]; + short sipx_port; +}; + +struct ipx_route_def +{ + unsigned long ipx_network; + unsigned long ipx_router_network; +#define IPX_ROUTE_NO_ROUTER 0 + unsigned char ipx_router_node[6]; + unsigned char ipx_device[16]; + unsigned short ipx_flags; +#define IPX_RT_BLUEBOOK 2 +#define IPX_RT_ROUTED 1 +}; + +#define IPX_MTU 576 + + diff -u --recursive --new-file v1.1.3/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v1.1.3/linux/include/linux/netdevice.h +++ linux/include/linux/netdevice.h Wed Apr 13 12:52:20 1994 @@ -0,0 +1,195 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the Interfaces handler. + * + * Version: @(#)dev.h 1.0.10 08/12/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Corey Minyard + * Donald J. Becker, + * + * 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. + * + * Moved to /usr/include/linux for NET3 + */ +#ifndef _LINUX_NETDEVICE_H +#define _LINUX_NETDEVICE_H + +#include +#include +#include + +/* for future expansion when we will have different priorities. */ +#define DEV_NUMBUFFS 3 +#define MAX_ADDR_LEN 7 +#define MAX_HEADER 18 + +#define IS_MYADDR 1 /* address is (one of) our own */ +#define IS_LOOPBACK 2 /* address is for LOOPBACK */ +#define IS_BROADCAST 3 /* address is a valid broadcast */ +#define IS_INVBCAST 4 /* Wrong netmask bcast not for us */ + +/* + * The DEVICE structure. + * Actually, this whole structure is a big mistake. It mixes I/O + * data with strictly "high-level" data, and it has to know about + * almost every data structure used in the INET module. + */ +struct device +{ + + /* + * This is the first field of the "visible" part of this structure + * (i.e. as seen by users in the "Space.c" file). It is the name + * the interface. + */ + char *name; + + /* I/O specific fields. These will be moved to DDI soon. */ + unsigned long rmem_end; /* shmem "recv" end */ + unsigned long rmem_start; /* shmem "recv" start */ + unsigned long mem_end; /* sahared mem end */ + unsigned long mem_start; /* shared mem start */ + unsigned short base_addr; /* device I/O address */ + unsigned char irq; /* device IRQ number */ + + /* Low-level status flags. */ + volatile unsigned char start, /* start an operation */ + tbusy, /* transmitter busy */ + interrupt; /* interrupt arrived */ + + /* + * Another mistake. + * This points to the next device in the "dev" chain. It will + * be moved to the "invisible" part of the structure as soon as + * it has been cleaned up. -FvK + */ + struct device *next; + + /* The device initialization function. Called only once. */ + int (*init)(struct device *dev); + + /* Some hardware also needs these fields, but they are not part of the + usual set specified in Space.c. */ + unsigned char if_port; /* Selectable AUI, TP,..*/ + unsigned char dma; /* DMA channel */ + + struct enet_statistics* (*get_stats)(struct device *dev); + + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at + * will (read: may be cleaned up at will). + */ + + /* These may be needed for future network-power-down code. */ + unsigned long trans_start; /* Time (in jiffies) of last Tx */ + unsigned long last_rx; /* Time of last Rx */ + + unsigned short flags; /* interface flags (a la BSD) */ + unsigned short family; /* address family ID (AF_INET) */ + unsigned short metric; /* routing metric (not used) */ + unsigned short mtu; /* interface MTU value */ + unsigned short type; /* interface hardware type */ + unsigned short hard_header_len; /* hardware hdr length */ + void *priv; /* pointer to private data */ + + /* Interface address info. */ + unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ + unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ + unsigned char addr_len; /* harfware address length */ + unsigned long pa_addr; /* protocol address */ + unsigned long pa_brdaddr; /* protocol broadcast addr */ + unsigned long pa_dstaddr; /* protocol P-P other side addr */ + unsigned long pa_mask; /* protocol netmask */ + unsigned short pa_alen; /* protocol address length */ + + /* Pointer to the interface buffers. */ + struct sk_buff_head buffs[DEV_NUMBUFFS]; + + /* Pointers to interface service routines. */ + int (*open)(struct device *dev); + int (*stop)(struct device *dev); + int (*hard_start_xmit) (struct sk_buff *skb, + struct device *dev); + int (*hard_header) (unsigned char *buff, + struct device *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len, + struct sk_buff *skb); + int (*rebuild_header)(void *eth, struct device *dev, + unsigned long raddr, struct sk_buff *skb); + unsigned short (*type_trans) (struct sk_buff *skb, + struct device *dev); +#define HAVE_MULTICAST + void (*set_multicast_list)(struct device *dev, + int num_addrs, void *addrs); +#define HAVE_SET_MAC_ADDR + int (*set_mac_address)(struct device *dev, void *addr); +}; + + +struct packet_type { + unsigned short type; /* This is really htons(ether_type). */ + unsigned short copy:1; + int (*func) (struct sk_buff *, struct device *, + struct packet_type *); + void *data; + struct packet_type *next; +}; + + +#ifdef __KERNEL__ + +/* Used by dev_rint */ +#define IN_SKBUFF 1 + +extern volatile char in_bh; + +extern struct device *dev_base; +extern struct packet_type *ptype_base; + + +extern int ip_addr_match(unsigned long addr1, unsigned long addr2); +extern int ip_chk_addr(unsigned long addr); +extern struct device *ip_dev_check(unsigned long daddr); +extern unsigned long ip_my_addr(void); +extern unsigned long ip_get_mask(unsigned long addr); + +extern void dev_add_pack(struct packet_type *pt); +extern void dev_remove_pack(struct packet_type *pt); +extern struct device *dev_get(char *name); +extern int dev_open(struct device *dev); +extern int dev_close(struct device *dev); +extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev, + int pri); +#define HAVE_NETIF_RX 1 +extern void netif_rx(struct sk_buff *skb); +/* The old interface to netif_rx(). */ +extern int dev_rint(unsigned char *buff, long len, int flags, + struct device * dev); +extern void dev_transmit(void); +extern int in_inet_bh(void); +extern void inet_bh(void *tmp); +extern void dev_tint(struct device *dev); +extern int dev_get_info(char *buffer, char **start, off_t offset, int length); +extern int dev_ioctl(unsigned int cmd, void *); + +extern void dev_init(void); + +/* This function lives elsewhere (drivers/net/net_init.c but is related) */ + +extern void ether_setup(struct device *dev); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_DEV_H */ diff -u --recursive --new-file v1.1.3/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.1.3/linux/include/linux/sched.h Wed Mar 30 08:42:03 1994 +++ linux/include/linux/sched.h Wed Apr 13 17:08:41 1994 @@ -23,6 +23,12 @@ extern unsigned long intr_count; +#define start_bh_atomic() \ +__asm__ __volatile__("incl _intr_count") + +#define end_bh_atomic() \ +__asm__ __volatile__("decl _intr_count") + /* * Bus types (default is ISA, but people can check others with these..) * MCA_bus hardcoded to 0 for now. diff -u --recursive --new-file v1.1.3/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.1.3/linux/include/linux/skbuff.h +++ linux/include/linux/skbuff.h Wed Apr 13 13:09:49 1994 @@ -0,0 +1,137 @@ +/* + * Definitions for the 'struct sk_buff' memory handlers. + * + * Authors: + * Alan Cox, + * Florian La Roche, + * + * 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. + */ + +#ifndef _LINUX_SKBUFF_H +#define _LINUX_SKBUFF_H +#include +#include +#include + +#define CONFIG_SKB_CHECK 1 + +#define HAVE_ALLOC_SKB /* For the drivers to know */ + + +#define FREE_READ 1 +#define FREE_WRITE 0 + + +struct sk_buff_head { + struct sk_buff * volatile next; + struct sk_buff * volatile prev; +#if CONFIG_SKB_CHECK + int magic_debug_cookie; +#endif +}; + + +struct sk_buff { + struct sk_buff * volatile next; + struct sk_buff * volatile prev; +#if CONFIG_SKB_CHECK + int magic_debug_cookie; +#endif + struct sk_buff * volatile link3; + struct sock *sk; + volatile unsigned long when; /* used to compute rtt's */ + struct timeval stamp; + struct device *dev; + void *mem_addr; + union { + struct tcphdr *th; + struct ethhdr *eth; + struct iphdr *iph; + struct udphdr *uh; + unsigned char *raw; + unsigned long seq; + } h; + struct iphdr *ip_hdr; /* For IPPROTO_RAW */ + unsigned long mem_len; + unsigned long len; + unsigned long fraglen; + struct sk_buff *fraglist; /* Fragment list */ + unsigned long truesize; + unsigned long saddr; + unsigned long daddr; + unsigned long raddr; /* next hop addr */ + volatile char acked, + used, + free, + arp; + unsigned char tries,lock; + unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ + unsigned long padding[0]; + unsigned char data[0]; +}; + +#define SK_WMEM_MAX 32767 +#define SK_RMEM_MAX 32767 + +#ifdef CONFIG_SKB_CHECK +#define SK_FREED_SKB 0x0DE2C0DE +#define SK_GOOD_SKB 0xDEC0DED1 +#define SK_HEAD_SKB 0x12231298 +#endif + +#ifdef __KERNEL__ +/* + * Handling routines are only of interest to the kernel + */ + +#if 0 +extern void print_skb(struct sk_buff *); +#endif +extern void kfree_skb(struct sk_buff *skb, int rw); +extern void skb_queue_head_init(struct sk_buff_head *list); +extern void skb_queue_head(struct sk_buff_head *list,struct sk_buff *buf); +extern void skb_queue_tail(struct sk_buff_head *list,struct sk_buff *buf); +extern struct sk_buff * skb_dequeue(struct sk_buff_head *list); +extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk); +extern void skb_append(struct sk_buff *old,struct sk_buff *newsk); +extern void skb_unlink(struct sk_buff *buf); +extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list); +extern struct sk_buff * alloc_skb(unsigned int size, int priority); +extern void kfree_skbmem(void *mem, unsigned size); +extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); +extern void skb_kept_by_device(struct sk_buff *skb); +extern void skb_device_release(struct sk_buff *skb, + int mode); +extern int skb_device_locked(struct sk_buff *skb); +/* + * Peek an sk_buff. Unlike most other operations you _MUST_ + * be careful with this one. A peek leaves the buffer on the + * list and someone else may run off with it. For an interrupt + * type system cli() peek the buffer copy the data and sti(); + */ +static __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_) +{ + struct sk_buff *list = (struct sk_buff *)list_; + return (list->next != list)? list->next : NULL; +} + +#if CONFIG_SKB_CHECK +extern int skb_check(struct sk_buff *skb,int,int, char *); +#define IS_SKB(skb) skb_check((skb), 0, __LINE__,__FILE__) +#define IS_SKB_HEAD(skb) skb_check((skb), 1, __LINE__,__FILE__) +#else +#define IS_SKB(skb) 0 +#define IS_SKB_HEAD(skb) 0 +#endif + +extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); +extern int datagram_select(struct sock *sk, int sel_type, select_table *wait); +extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); +extern void skb_free_datagram(struct sk_buff *skb); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SKBUFF_H */ diff -u --recursive --new-file v1.1.3/linux/include/linux/sockios.h linux/include/linux/sockios.h --- v1.1.3/linux/include/linux/sockios.h Sat Apr 2 20:05:43 1994 +++ linux/include/linux/sockios.h Wed Apr 13 12:52:20 1994 @@ -19,25 +19,14 @@ #define _LINUX_SOCKIOS_H /* This section will go away soon! */ -#if 1 /* FIXME: */ -#define MAX_IP_NAME 20 -#define IP_SET_DEV 0x2401 -struct ip_config { - char name[MAX_IP_NAME]; - unsigned long paddr; - unsigned long router; - unsigned long net; - unsigned up:1,destroy:1; -}; -#endif /* FIXME: */ - /* Socket-level I/O control calls. */ #define FIOSETOWN 0x8901 #define SIOCSPGRP 0x8902 #define FIOGETOWN 0x8903 #define SIOCGPGRP 0x8904 #define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8096 /* Get stamp */ /* Routing table calls. */ #define SIOCADDRT 0x890B /* add routing table entry */ @@ -63,10 +52,11 @@ #define SIOCSIFMEM 0x8920 /* set memory address (BSD) */ #define SIOCGIFMTU 0x8921 /* get MTU size */ #define SIOCSIFMTU 0x8922 /* set MTU size */ -#define SIOCGIFHWADDR 0x8923 /* get hardware address */ +#define OLD_SIOCGIFHWADDR 0x8923 /* get hardware address */ #define SIOCSIFHWADDR 0x8924 /* set hardware address (NI) */ #define SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */ #define SIOCSIFENCAP 0x8926 +#define SIOCGIFHWADDR 0x8927 /* Get hardware address */ /* Routing table calls (oldrtent - don't use) */ #define SIOCADDRTOLD 0x8940 /* add routing table entry */ diff -u --recursive --new-file v1.1.3/linux/net/Space.c linux/net/Space.c --- v1.1.3/linux/net/Space.c Tue Dec 14 12:12:06 1993 +++ linux/net/Space.c Wed Apr 13 12:52:20 1994 @@ -7,7 +7,11 @@ * Version: @(#)Space.c 1.0.2 04/22/93 * * Author: Fred N. van Kempen, + * + * Please see the comments in ddi.c - Alan + * */ + #include #include #include @@ -27,7 +31,7 @@ # include "unix/unix.h" #endif #ifdef CONFIG_INET -# include "inet/inet.h" +# include #endif #ifdef CONFIG_IPX #include "inet/ipxcall.h" @@ -53,43 +57,3 @@ }; -/* - * Section B: Device Driver Modules. - * This section defines which network device drivers - * get linked into the Linux kernel. It is currently - * only used by the INET protocol. Any takers for the - * other protocols like XNS or Novell? - * - * WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!! - */ -/*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */ -/*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */ -/*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */ - - -struct ddi_device devices[] = { -#if CONF_WE8003 - { "WD80x3[EBT]", - "", 0, 1, we8003_init, NULL, - 19, 0, DDI_FCHRDEV, - { 0x280, 0, 15, 0, 32768, 0xD0000 } }, -#endif -#if CONF_DP8390 - { "DP8390/WD80x3", - "", 0, 1, dpwd8003_init, NULL, - 20, 0, DDI_FCHRDEV, - { 0, 0, 0, 0, 0, 0, } }, - { "DP8390/NE-x000", - "", 0, 1, dpne2000_init, NULL, - 20, 8, DDI_FCHRDEV, - { 0, 0, 0, 0, 0, 0, } }, - { "DP8390/3C50x", - "", 0, 1, dpec503_init, NULL, - 20, 16, DDI_FCHRDEV, - { 0, 0, 0, 0, 0, 0, } }, -#endif - { NULL, - "", 0, 0, NULL, NULL, - 0, 0, 0, - { 0, 0, 0, 0, 0, 0 } } -}; diff -u --recursive --new-file v1.1.3/linux/net/ddi.c linux/net/ddi.c --- v1.1.3/linux/net/ddi.c Wed Dec 1 14:44:15 1993 +++ linux/net/ddi.c Wed Apr 13 12:52:20 1994 @@ -7,6 +7,14 @@ * Version: @(#)ddi.c 1.0.5 04/22/93 * * Author: Fred N. van Kempen, + * + * + * For the moment I'm classifying DDI as 'dead'. However if/when Fred + * produces a masterpiece of design DDI may get resurrected. With the + * current kernel as modules work by Peter MacDonald they might be + * redundant anyway. Thus I've removed all but the protocol initialise. + * + * We will end up with protocol initialisers and socket family initialisers. */ #include #include @@ -28,39 +36,10 @@ #endif -extern struct ddi_device devices[]; /* device driver map */ extern struct ddi_proto protocols[]; /* network protocols */ /* - * This function gets called with an ASCII string representing the - * ID of some DDI driver. We loop through the DDI Devices table - * and return the address of the control block that has a matching - * "name" field. It is used by upper-level layers that want to - * dynamically bind some UNIX-domain "/dev/XXXX" file name to a - * DDI device driver. The "iflink(8)" program is an example of - * this behaviour. - */ -struct ddi_device * -ddi_map(const char *id) -{ - register struct ddi_device *dev; - - PRINTK (("DDI: MAP: looking for \"%s\": ", id)); - dev = devices; - while (dev->title != NULL) { - if (strncmp(dev->name, id, DDI_MAXNAME) == 0) { - PRINTK (("OK at 0x%X\n", dev)); - return(dev); - } - dev++; - } - PRINTK (("NOT FOUND\n")); - return(NULL); -} - - -/* * This is the function that is called by a kernel routine during * system startup. Its purpose is to walk trough the "devices" * table (defined above), and to call all moduled defined in it. @@ -68,24 +47,16 @@ void ddi_init(void) { - struct ddi_proto *pro; - struct ddi_device *dev; + struct ddi_proto *pro; - PRINTK (("DDI: Starting up!\n")); + PRINTK (("DDI: Starting up!\n")); - /* First off, kick all configured protocols. */ - pro = protocols; - while (pro->name != NULL) { - (*pro->init)(pro); - pro++; - } - - /* Done. Now kick all configured device drivers. */ - dev = devices; - while (dev->title != NULL) { - (*dev->init)(dev); - dev++; - } - - /* We're all done... */ + /* Kick all configured protocols. */ + pro = protocols; + while (pro->name != NULL) + { + (*pro->init)(pro); + pro++; + } + /* We're all done... */ } diff -u --recursive --new-file v1.1.3/linux/net/inet/Makefile linux/net/inet/Makefile --- v1.1.3/linux/net/inet/Makefile Tue Dec 14 12:14:18 1993 +++ linux/net/inet/Makefile Wed Apr 13 12:52:21 1994 @@ -15,10 +15,21 @@ $(CC) $(CFLAGS) -S -o $*.s $< -OBJS = sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \ +OBJS = sock.o utils.o route.o proc.o timer.o protocol.o \ eth.o packet.o arp.o dev.o ip.o raw.o icmp.o tcp.o udp.o \ - datagram.o skbuff.o -# ipx.o ax25.o ax25_in.o ax25_out.o ax25_subr.o ax25_timer.o + datagram.o skbuff.o devinet.o + +ifdef CONFIG_AX25 + +OBJS := $(OBJS) ax25.o ax25_in.o ax25_out.o ax25_subr.o ax25_timer.o + +endif + +ifdef CONFIG_IPX + +OBJS := $(OBJS) ipx.o + +endif ifdef CONFIG_INET diff -u --recursive --new-file v1.1.3/linux/net/inet/README linux/net/inet/README --- v1.1.3/linux/net/inet/README Wed Dec 1 14:44:15 1993 +++ linux/net/inet/README Wed Apr 13 12:52:21 1994 @@ -1,44 +1,92 @@ -NET2Debugged 1.24 README ------------------------- +This is snapshot 010 -Major Changes - -o PLIP driver sort of works -o UDP and RAW have been partially rewritten for speed -o Internals heavily cleaned up, and memory monitoring of network - memory is now done. (On shift-scroll-lock) -o ARP should now not generate garbage -o Using MSG_PEEK can't cause race conditions and crashes -o Support for bootp clients. -o Supports RFC931 TAP authd -o NFS problems with certain types of network configuration are - fixed. -o Doesn't forward packets for other subnet (can cause packet storms) -o TCP won't ack rst frames causing packet storms (especially with - Lan workplace for DOS). -o Numerous fixes for solidity -o Verify_area used properly. -o MSG_PEEK is faster again -o Minor TCP fixes. Hopefully no more TCP lockups (ha!) -o Donald's promiscuous mode. Go forth and write protocol analysers... -------------------------------------------------------------------------- -NOTE: - Drivers for this stack set must be using alloc_skb() not just -kmalloc. If you get millions of 'non sk_buff...' errors please check the -driver you are using. All Donald's drivers know about this. If you have -a problem driver replace all cases of - - .. =(struct sk_buff *)kmalloc(sizeof(struct sk_buff)+... - -With - ..=alloc_skb(sizeof(struct sk_buff)+... - -And if it uses kfree_s on the packet change that to use kfree_skbmem(). - -------------------------------------------------------------------------- -Bug fixes and improvements for this section of the code should be mailed to -iiitac@pyr.swan.ac.uk. - - -Alan +Notes: +ARP + As of snapshot 006, ARP should compile and work correctly + for any protocol that has the right build_header support. + +AX25 + This is an ALPHA release. It will not be a standard part + of the real release module. Please read the copyrights on + the AX.25 code carefully. When AX.25 is finished it will + be part of a seperatly available amateur radio add on. Also + please rememeber this is ALPHA code. It works well for a lot + of people but I know for a fact it is currently buggy. + +IPX + The IPX module in here is fairly complete, and certainly + usable for things. The IPX user code isn't yet very useful + (nobody has written a RIP/SAP daemon!). + +NetROM + I'm slowly doing bits of this code, but its not even fit + to include here. + + +Status: + +Done: + Replaced ARP with Florian la Roche's ARP. + Replaced/improved sk_buff handlers (again from Florian) + Removed surplus DDI code. + Reformatted most modules. + Fixed ICMP handling bugs (ICMP error to ICMP error). + Fixed fragmentation bugs (both memory and mtu). + Moved some includes. + Drivers now build correctly with no IP layer. + Merged Linus 1.0.1 diffs and my patches 1-3. + Further fixups on clean driver build. + Loopback driver now lives where it belongs. + UDP verified against specification (passes). + IP verified against specification (two errors: Incorrect forwarding and + no mandatory option handling). + ARP verified against specification (passes: recommendation that ARP + rejects MAC broadcast/multicast addresses - this needs + driver changes doing). + All surplus skb->sk assignment and skb->mem_len skb->mem_addr removed. + eth.h became linux/etherdevice.h. + alloc_skb nows adds the sizeof(struct sk_buff) itself. + Now relative to Linux 1.0.4. + All IP wakeups are now callbacks. + IPX and AX.25 callbacks now use wake_up_interruptible correctly. + ICMP,IP and UDP collect snmp statistics. + Removed the 4K limit from the /proc/net/* files. + Routing bugs. + Cleaned up skb duplication. + IPX /proc from Mark Evans. + Driver packet ordering now enforced. + AX.25 unused SSID bits now set. + +In Progress: + Module by module validation against specifications. + TCP delayed ACK [RFC1122 requires this]. + Byte-order fixes. + Core code restructure to enable a working non IP build + Trying to fix /proc to do >4K correctly, as well as dynamic addition + of /proc/ and /proc/net/ objects (for module protocol layers). + Adding the extra NET2E driver ioctl() support. + SNMP MIB statistic capture - finish TCP and add device layer when + Donald is ready. + Donald Beckers latest driver mods. + Adding the ICMP_TIMESTAMP support patch. + Routing bugs. + Packet level time stamping. + Merging in support for the I^2IT 'TICK' time synchronisation chip. + Crynwyr compliant PLIP driver. + +To Do: + Merge in sk_buff data handling module. + Socket family/protocol seperation. + Additional BSD options (SO_LOWAT etc). + IP option handling, especially on ip forwards. + AX.25 /proc support. + SNMP /proc support. + TCP MSS/Window and route metrics in the routing table. + TCP mtu discovery support. + NetROM. + TCP closing side state machine bug fixes. + NetBEUI (Lan Manager) [ie IEE802.3/IEE802.2/NetBIOS]. + Make drivers record type and addressing category(Multicast/Broadcast..) + Speed it up. + Unix domain cleanup/rewrite. diff -u --recursive --new-file v1.1.3/linux/net/inet/arp.c linux/net/inet/arp.c --- v1.1.3/linux/net/inet/arp.c Wed Mar 2 10:03:40 1994 +++ linux/net/inet/arp.c Wed Apr 13 12:52:21 1994 @@ -1,59 +1,32 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * This file implements the Address Resolution Protocol (ARP), - * which is used by TCP/IP to map the IP addresses from a host - * to a low-level hardware address (like an Ethernet address) - * which it can use to talk to that host. +/* linux/net/inet/arp.c * - * NOTE: This module will be rewritten completely in the near future, - * because I want it to become a multi-address-family address - * resolver, like it should be. It will be put in a separate - * directory under 'net', being a protocol of its own. -FvK + * Copyright (C) 1994 by Florian La Roche * - * Version: @(#)arp.c 1.0.15 05/25/93 + * This module implements the Address Resolution Protocol ARP (RFC 826), + * which is used to convert IP addresses (or in the future maybe other + * high-level addresses into a low-level hardware address (like an Ethernet + * address). * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Arnt Gulbrandsen, + * FIXME: + * Experiment with better retransmit timers + * Clean up the timer deletions + * If you create a proxy entry set your interface address to the address + * and then delete it, proxies may get out of sync with reality - check this * - * Fixes: - * Stephen A. Wood : arp problems - * 'Mr Linux' : arp problems. - * Alan Cox : arp_ioctl now checks memory areas with verify_area. - * Alan Cox : Non IP arp message now only appears with debugging on. - * Alan Cox : arp queue is volatile (may be altered by arp messages while doing sends) - * Generic queue code is urgently needed! - * Alan Cox : Deleting your own ip addr now gives EINVAL not a printk message. - * Alan Cox : Fix to arp linked list error - * Alan Cox : Ignore broadcast arp (Linus' idea 8-)) - * Alan Cox : arp_send memory leak removed - * Alan Cox : generic skbuff code fixes. - * Alan Cox : 'Bad Packet' only reported on debugging - * Alan Cox : Proxy arp. - * Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet. - * Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet - * one. - * Dominik Kubla : Better checking - * Tegge : Assorted corrections on cross port stuff - * Alan Cox : ATF_PERM was backwards! - might be useful now (sigh) - * Alan Cox : Arp timer added. + * 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. * - * To Fix: - * : arp response allocates an skbuff to send. However there is a perfectly - * good spare skbuff the right size about to be freed (the query). Use the - * query for the reply. This avoids an out of memory case _and_ speeds arp - * up. - * : FREE_READ v FREE_WRITE errors. Not critical as loopback arps don't occur * + * Fixes: + * Alan Cox : Removed the ethernet assumptions in Florians code + * Alan Cox : Fixed some small errors in the ARP logic + * Alan Cox : Allow >4K in /proc + * Alan Cox : Make ARP add its own protocol entry * - * 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 #include #include @@ -61,917 +34,999 @@ #include #include #include -#include #include #include #include #include #include #include -#include "inet.h" -#include "dev.h" -#include "eth.h" +#include +#include +#include #include "ip.h" #include "route.h" #include "protocol.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include "arp.h" - +#ifdef CONFIG_AX25 +#include "ax25.h" +#endif -#define ARP_MAX_TRIES 3 - +/* + * This structure defines the ARP mapping cache. As long as we make changes + * in this structure, we keep interrupts of. But normally we can copy the + * hardware address and the device pointer in a local variable and then make + * any "long calls" to send a packet out. + */ + +struct arp_table +{ + struct arp_table *next; /* Linked entry list */ + unsigned long last_used; /* For expiry */ + unsigned int flags; /* Control status */ + unsigned long ip; /* ip address of entry */ + unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ + unsigned char hlen; /* Length of hardware address */ + unsigned char htype; /* Type of hardware in use */ + struct device *dev; /* Device the entry is tied to */ -static char *unk_print(unsigned char *, int); -static char *eth_aprint(unsigned char *, int); + /* + * The following entries are only used for unresolved hw addresses. + */ + + struct timer_list timer; /* expire timer */ + int retries; /* remaining retries */ + struct sk_buff_head skb; /* list of queued packets */ +}; +/* + * This structure defines an ethernet arp header. + */ + +struct arphdr +{ + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + +#if 0 + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +#endif -static char *arp_cmds[] = { - "0x%04X", - "REQUEST", - "REPLY", - "REVERSE REQUEST", - "REVERSE REPLY", - NULL }; -#define ARP_MAX_CMDS (sizeof(arp_cmds) / sizeof(arp_cmds[0])) -static struct { - char *name; - char *(*print)(unsigned char *ptr, int len); -} arp_types[] = { - { "0x%04X", unk_print }, - { "10 Mbps Ethernet", eth_aprint }, - { "3 Mbps Ethernet", eth_aprint }, - { "AX.25", unk_print }, - { "Pronet", unk_print }, - { "Chaos", unk_print }, - { "IEEE 802.2 Ethernet (?)", eth_aprint }, - { "Arcnet", unk_print }, - { "AppleTalk", unk_print }, - { NULL, NULL } -}; -#define ARP_MAX_TYPE (sizeof(arp_types) / sizeof(arp_types[0])) +/* + * Configurable Parameters (don't touch unless you know what you are doing + */ + +/* + * If an arp request is send, ARP_RES_TIME is the timeout value until the + * next request is send. + */ + +#define ARP_RES_TIME (250*(HZ/10)) +/* + * The number of times an arp request is send, until the host is + * considered unreachable. + */ + +#define ARP_MAX_TRIES 3 -struct arp_table *arp_tables[ARP_TABLE_SIZE] = { - NULL, -}; +/* + * After that time, an unused entry is deleted from the arp table. + */ + +#define ARP_TIMEOUT (600*HZ) -static int arp_proxies=0; /* So we can avoid the proxy arp - overhead with the usual case of - no proxy arps */ +/* + * How often is the function 'arp_check_retries' called. + * An entry is invalidated in the time between ARP_TIMEOUT and + * (ARP_TIMEOUT+ARP_CHECK_INTERVAL). + */ -struct sk_buff * volatile arp_q = NULL; +#define ARP_CHECK_INTERVAL (60 * HZ) -static struct arp_table *arp_lookup(unsigned long addr); -static struct arp_table *arp_lookup_proxy(unsigned long addr); -/* Dump the ADDRESS bytes of an unknown hardware type. */ -static char * -unk_print(unsigned char *ptr, int len) -{ - static char buff[32]; - char *bufp = buff; - int i; +static void arp_check_expire (unsigned long); /* Forward declaration. */ - for (i = 0; i < len; i++) - bufp += sprintf(bufp, "%02X ", (*ptr++ & 0377)); - return(buff); -} +static struct timer_list arp_timer = + { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire }; -/* Dump the ADDRESS bytes of an Ethernet hardware type. */ -static char * -eth_aprint(unsigned char *ptr, int len) -{ - if (len != ETH_ALEN) return(""); - return(eth_print(ptr)); -} +/* + * The size of the hash table. Must be a power of two. + * Maybe we should remove hashing in the future for arp and concentrate + * on Patrick Schaaf's Host-Cache-Lookup... + */ +#define ARP_TABLE_SIZE 16 -/* Dump an ARP packet. Not complete yet for non-Ethernet packets. */ -static void -arp_print(struct arphdr *arp) +struct arp_table *arp_tables[ARP_TABLE_SIZE] = { - int len, idx; - unsigned char *ptr; - - if (inet_debug != DBG_ARP) return; - - printk("ARP: "); - if (arp == NULL) { - printk("(null)\n"); - return; - } + NULL, +}; - /* Print the opcode name. */ - len = htons(arp->ar_op); - if (len < ARP_MAX_CMDS) idx = len; - else idx = 0; - printk("op "); - printk(arp_cmds[idx], len); - - /* Print the ARP header. */ - len = htons(arp->ar_hrd); - if (len < ARP_MAX_TYPE) idx = len; - else idx = 0; - printk(" hrd = "); printk(arp_types[idx].name, len); - printk(" pro = 0x%04X\n", htons(arp->ar_pro)); - printk(" hlen = %d plen = %d\n", arp->ar_hln, arp->ar_pln); - - /* - * Print the variable data. - * When ARP gets redone (after the formal introduction of NET-2), - * this part will be redone. ARP will then be a multi-family address - * resolver, and the code below will be made more general. -FvK - */ - ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); - printk(" sender HA = %s ", arp_types[idx].print(ptr, arp->ar_hln)); - ptr += arp->ar_hln; - printk(" PA = %s\n", in_ntoa(*(unsigned long *) ptr)); - ptr += arp->ar_pln; - printk(" target HA = %s ", arp_types[idx].print(ptr, arp->ar_hln)); - ptr += arp->ar_hln; - printk(" PA = %s\n", in_ntoa(*(unsigned long *) ptr)); -} +/* + * The last bits in the IP address are used for the cache lookup. + */ + +#define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1)) +/* + * Number of proxy arp entries. This is normally zero and we use it to do + * some optimizing for normal uses + */ + +static int proxies = 0; -/* This will try to retransmit everything on the queue. */ -static void -arp_send_q(void) -{ - struct sk_buff *skb; - struct sk_buff *volatile work_q; - cli(); - work_q = arp_q; - skb_new_list_head(&work_q); - arp_q = NULL; - sti(); - while((skb=skb_dequeue(&work_q))!=NULL) - { - IS_SKB(skb); - skb->magic = 0; - skb->next = NULL; - skb->prev = NULL; - /* Decrement the 'tries' counter. */ +/* + * Check if there are too old entries and remove them. If the ATF_PERM + * flag is set, they are always left in the arp cache (permanent entry). + * Note: Only fully resolved entries, which don't have any packets in + * the queue, can be deleted, since ARP_TIMEOUT is much greater than + * ARP_MAX_TRIES*ARP_RES_TIME. + */ + +static void arp_check_expire(unsigned long dummy) +{ + int i; + unsigned long now = jiffies; + unsigned long flags; + save_flags(flags); cli(); - skb->tries--; - if (skb->tries == 0) { - /* - * Grmpf. - * We have tried ARP_MAX_TRIES to resolve the IP address - * from this datagram. This means that the machine does - * not listen to our ARP requests. Perhaps someone tur- - * ned off the thing? - * In any case, trying further is useless. So, we kill - * this packet from the queue. (grinnik) -FvK - */ - skb->sk = NULL; - if(skb->free) - kfree_skb(skb, FREE_WRITE); - /* If free was 0, magic is now 0, next is 0 and - the write queue will notice and kill */ - sti(); - continue; - } - - /* Can we now complete this packet? */ - sti(); - if (skb->arp || !skb->dev->rebuild_header(skb->data, skb->dev)) { - skb->arp = 1; - skb->dev->queue_xmit(skb, skb->dev, 0); - } else { - /* Alas. Re-queue it... */ - skb->magic = ARP_QUEUE_MAGIC; - skb_queue_head(&arp_q,skb); + + for (i = 0; i < ARP_TABLE_SIZE; i++) + { + struct arp_table *entry; + struct arp_table **pentry = &arp_tables[i]; + + while ((entry = *pentry) != NULL) + { + if ((now - entry->last_used) > ARP_TIMEOUT + && !(entry->flags & ATF_PERM)) + { + *pentry = entry->next; /* remove from list */ + if (entry->flags & ATF_PUBL) + proxies--; + del_timer(&entry->timer); /* Paranoia */ + kfree_s(entry, sizeof(struct arp_table)); + } + else + pentry = &entry->next; /* go to next entry */ + } } - } -} - - -static struct timer_list arp_timer; + restore_flags(flags); -static void arp_queue_ticker(unsigned long data); + /* + * Set the timer again. + */ -static void arp_queue_kick(void) -{ - arp_timer.expires = 500; /* 5 seconds */ - arp_timer.data = 0; - arp_timer.function = arp_queue_ticker; del_timer(&arp_timer); + arp_timer.expires = ARP_CHECK_INTERVAL; add_timer(&arp_timer); } -static void arp_queue_ticker(unsigned long data/*UNUSED*/) + +/* + * Release all linked skb's and the memory for this entry. + */ + +static void arp_release_entry(struct arp_table *entry) { - arp_send_q(); - if (skb_peek(&arp_q)) - arp_queue_kick(); -} - - - -/* Create and send our response to an ARP request. */ -static int -arp_response(struct arphdr *arp1, struct device *dev, int addrtype) -{ - struct arphdr *arp2; - struct sk_buff *skb; - unsigned long src, dst; - unsigned char *ptr1, *ptr2; - int hlen; - struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */ - - /* Decode the source (REQUEST) message. */ - ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short); - src = *((unsigned long *) (ptr1 + arp1->ar_hln)); - dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln)); - - if(addrtype!=IS_MYADDR) - { - apt=arp_lookup_proxy(dst); - if(apt==NULL) - return(1); - } - - /* Get some mem and initialize it for the return trip. */ - skb = alloc_skb(sizeof(struct sk_buff) + - sizeof(struct arphdr) + - (2 * arp1->ar_hln) + (2 * arp1->ar_pln) + - dev->hard_header_len, GFP_ATOMIC); - if (skb == NULL) { - printk("ARP: no memory available for ARP REPLY!\n"); - return(1); - } - - skb->mem_addr = skb; - skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) + - (2 * arp1->ar_pln) + dev->hard_header_len; - skb->mem_len = sizeof(struct sk_buff) + skb->len; - hlen = dev->hard_header(skb->data, dev, ETH_P_ARP, src, dst, skb->len); - if (hlen < 0) { - printk("ARP: cannot create HW frame header for REPLY !\n"); - kfree_skb(skb, FREE_WRITE); - return(1); - } - - /* - * Fill in the ARP REPLY packet. - * This looks ugly, but we have to deal with the variable-length - * ARP packets and such. It is not as bad as it looks- FvK - */ - arp2 = (struct arphdr *) (skb->data + hlen); - ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short); - arp2->ar_hrd = arp1->ar_hrd; - arp2->ar_pro = arp1->ar_pro; - arp2->ar_hln = arp1->ar_hln; - arp2->ar_pln = arp1->ar_pln; - arp2->ar_op = htons(ARPOP_REPLY); - if(addrtype==IS_MYADDR) - memcpy(ptr2, dev->dev_addr, arp2->ar_hln); - else /* Proxy arp, so pull from the table */ - memcpy(ptr2, apt->ha, arp2->ar_hln); - ptr2 += arp2->ar_hln; - memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln); - ptr2 += arp2->ar_pln; - memcpy(ptr2, ptr1, arp2->ar_hln); - ptr2 += arp2->ar_hln; - memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln); - - skb->free = 1; - skb->arp = 1; - skb->sk = NULL; - skb->next = NULL; - - DPRINTF((DBG_ARP, ">>")); - arp_print(arp2); - - /* Queue the packet for transmission. */ - dev->queue_xmit(skb, dev, 0); - return(0); -} - - -/* This will find an entry in the ARP table by looking at the IP address. */ -static struct arp_table * -arp_lookup(unsigned long paddr) -{ - struct arp_table *apt; - unsigned long hash; - - DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr))); - - /* We don't want to ARP ourselves. */ - if (chk_addr(paddr) == IS_MYADDR) { - printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr)); - return(NULL); - } - - /* Loop through the table for the desired address. */ - hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); - cli(); - apt = arp_tables[hash]; - while(apt != NULL) { - if (apt->ip == paddr) { - sti(); - return(apt); + struct sk_buff *skb; + + if (entry->flags & ATF_PUBL) + proxies--; + /* Release the list of `skb' pointers. */ + while ((skb = skb_dequeue(&entry->skb)) != NULL) + { + if (skb->free) + kfree_skb(skb, FREE_WRITE); } - apt = apt->next; - } - sti(); - return(NULL); + del_timer(&entry->timer); + kfree_s(entry, sizeof(struct arp_table)); + return; } -/* This will find a proxy in the ARP table by looking at the IP address. */ -static struct arp_table *arp_lookup_proxy(unsigned long paddr) -{ - struct arp_table *apt; - unsigned long hash; - - DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr))); +/* + * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast + * message. + */ + +static void arp_send(int type, unsigned long dest_ip, struct device *dev, + unsigned long src_ip, unsigned char *dest_hw, unsigned char *src_hw) +{ + struct sk_buff *skb; + struct arphdr *arp; + unsigned char *arp_ptr; - /* Loop through the table for the desired address. */ - hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); - cli(); - apt = arp_tables[hash]; - while(apt != NULL) { - if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) { - sti(); - return(apt); + /* + * No arp on this interface. + */ + + if(dev->flags&IFF_NOARP) + return; + + /* + * Allocate a buffer + */ + + skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + + dev->hard_header_len, GFP_ATOMIC); + if (skb == NULL) + { + printk("ARP: no memory to send an arp packet\n"); + return; } - apt = apt->next; - } - sti(); - return(NULL); -} + skb->len = sizeof(struct arphdr) + dev->hard_header_len + 2*(dev->addr_len+4); + skb->arp = 1; + skb->dev = dev; + skb->free = 1; + /* + * Fill the device header for the ARP frame + */ -/* Delete an ARP mapping entry in the cache. */ -void -arp_destructor(unsigned long paddr, int force) -{ - struct arp_table *apt; - struct arp_table **lapt; - unsigned long hash; + dev->hard_header(skb->data,dev,ETH_P_ARP,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb); - DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr))); + /* Fill out the arp protocol part. */ + arp = (struct arphdr *) (skb->data + dev->hard_header_len); + arp->ar_hrd = htons(dev->type); +#ifdef CONFIG_AX25 + arp->ar_pro = (dev->type != ARPHRD_AX25)? htons(ETH_P_IP) : htons(AX25_P_IP); +#else + arp->ar_pro = htons(ETH_P_IP); +#endif + arp->ar_hln = dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr=(unsigned char *)(arp+1); + + memcpy(arp_ptr, src_hw, dev->addr_len); + arp_ptr+=dev->addr_len; + memcpy(arp_ptr, &src_ip,4); + arp_ptr+=4; + if (dest_hw != NULL) + memcpy(arp_ptr, dest_hw, dev->addr_len); + else + memset(arp_ptr, 0, dev->addr_len); + arp_ptr+=dev->addr_len; + memcpy(arp_ptr, &dest_ip, 4); + + dev_queue_xmit(skb, dev, 0); +} - /* We cannot destroy our own ARP entry. */ - if (chk_addr(paddr) == IS_MYADDR) { - DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n", - in_ntoa(paddr))); - return; - } - hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); - cli(); - lapt = &arp_tables[hash]; - while ((apt = *lapt) != NULL) { - if (apt->ip == paddr) { - if((apt->flags&ATF_PERM) && !force) - return; - *lapt = apt->next; - if(apt->flags&ATF_PUBL) - arp_proxies--; - kfree_s(apt, sizeof(struct arp_table)); - sti(); +/* + * This function is called, if an entry is not resolved in ARP_RES_TIME. + * Either resend a request, or give it up and free the entry. + */ + +static void arp_expire_request (unsigned long arg) +{ + struct arp_table *entry = (struct arp_table *) arg; + struct arp_table **pentry; + unsigned long hash; + unsigned long flags; + + save_flags(flags); + cli(); + + /* + * Since all timeouts are handled with interrupts enabled, there is a + * small chance, that this entry has just been resolved by an incoming + * packet. This is the only race condition, but it is handled... + */ + + if (entry->flags & ATF_COM) + { + restore_flags(flags); + return; + } + + if (--entry->retries > 0) + { + unsigned long ip = entry->ip; + struct device *dev = entry->dev; + + /* Set new timer. */ + del_timer(&entry->timer); + entry->timer.expires = ARP_RES_TIME; + add_timer(&entry->timer); + restore_flags(flags); + arp_send(ARPOP_REQUEST, ip, dev, dev->pa_addr, NULL, + dev->dev_addr); return; } - lapt = &apt->next; - } - sti(); + + /* + * Arp request timed out. Delete entry and all waiting packets. + * If we give each entry a pointer to itself, we don't have to + * loop through everything again. Maybe hash is good enough, but + * I will look at it later. + */ + + hash = HASH(entry->ip); + pentry = &arp_tables[hash]; + while (*pentry != NULL) + { + if (*pentry == entry) + { + *pentry = entry->next; /* delete from linked list */ + del_timer(&entry->timer); + restore_flags(flags); + arp_release_entry(entry); + return; + } + pentry = &(*pentry)->next; + } + restore_flags(flags); + printk("Possible ARP queue corruption.\n"); + /* + * We should never arrive here. + */ } -/* - * Kill an entry - eg for ioctl() - */ - -void arp_destroy(unsigned long paddr) -{ - arp_destructor(paddr,1); -} /* - * Delete a possibly invalid entry (see timer.c) + * This will try to retransmit everything on the queue. */ - -void arp_destroy_maybe(unsigned long paddr) + +static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest) { - arp_destructor(paddr,0); + struct sk_buff *skb; + + + /* + * Empty the entire queue, building its data up ready to send + */ + + if(!(entry->flags&ATF_COM)) + { + printk("arp_send_q: incomplete entry for %s\n", + in_ntoa(entry->ip)); + return; + } + + while((skb = skb_dequeue(&entry->skb)) != NULL) + { + IS_SKB(skb); + if(!skb->dev->rebuild_header(skb->data,skb->dev,skb->raddr,skb)) + { + skb->arp = 1; + if(skb->sk==NULL) + dev_queue_xmit(skb, skb->dev, 0); + else + dev_queue_xmit(skb,skb->dev,skb->sk->priority); + } + else + { + /* This routine is only ever called when 'entry' is + complete. Thus this can't fail (but does) */ + printk("arp_send_q: The impossible occurred. Please notify Alan.\n"); + printk("arp_send_q: active entity %s\n",in_ntoa(entry->ip)); + printk("arp_send_q: failed to find %s\n",in_ntoa(skb->raddr)); + } + } } -/* Create an ARP entry. The caller should check for duplicates! */ -static struct arp_table * -arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype) -{ - struct arp_table *apt; - unsigned long hash; - - DPRINTF((DBG_ARP, "ARP: create(%s, ", in_ntoa(paddr))); - DPRINTF((DBG_ARP, "%s, ", eth_print(addr))); - DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype)); - apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC); - if (apt == NULL) { - printk("ARP: no memory available for new ARP entry!\n"); - return(NULL); - } +/* + * Delete an ARP mapping entry in the cache. + */ + +void arp_destroy(unsigned long ip_addr, int force) +{ + struct arp_table *entry; + struct arp_table **pentry; + unsigned long hash = HASH(ip_addr); - /* Fill in the allocated ARP cache entry. */ - hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); - apt->ip = paddr; - apt->hlen = hlen; - apt->htype = htype; - apt->flags = (ATF_INUSE | ATF_COM); /* USED and COMPLETED entry */ - memcpy(apt->ha, addr, hlen); - apt->last_used = jiffies; - cli(); - apt->next = arp_tables[hash]; - arp_tables[hash] = apt; - sti(); - return(apt); + cli(); + pentry = &arp_tables[hash]; + while ((entry = *pentry) != NULL) + { + if (entry->ip == ip_addr) + { + if ((entry->flags & ATF_PERM) && !force) + return; + *pentry = entry->next; + sti(); + del_timer(&entry->timer); + arp_release_entry(entry); + return; + } + pentry = &entry->next; + } + sti(); } -/* - * An ARP REQUEST packet has arrived. - * We try to be smart here, and fetch the data of the sender of the - * packet- we might need it later, so fetching it now can save us a - * broadcast later. - * Then, if the packet was meant for us (i.e. the TARGET address was - * one of our own IP addresses), we set up and send out an ARP REPLY - * packet to the sender. +/* + * Receive an arp request by the device layer. Maybe I rewrite it, to + * use the incoming packet for the reply. The time for the current + * "overhead" isn't that high... */ -int -arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) + +int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { - struct arphdr *arp; - struct arp_table *tbl; - unsigned long src, dst; - unsigned char *ptr; - int ret; - int addr_hint; + /* + * We shouldn't use this type conversion. Check later. + */ + + struct arphdr *arp = (struct arphdr *)skb->h.raw; + unsigned char *arp_ptr= (unsigned char *)(arp+1); + struct arp_table *entry; + struct arp_table *proxy_entry; + int addr_hint; + unsigned long hash; + unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */ + long sip,tip; + unsigned char *sha,*tha; - DPRINTF((DBG_ARP, "<<\n")); - arp = skb->h.arp; - arp_print(arp); + /* + * If this test doesn't pass, its not IP, or we should ignore it anyway + */ + + if (arp->ar_hln != dev->addr_len || dev->type != ntohs(arp->ar_hrd) || dev->flags&IFF_NOARP) + { + kfree_skb(skb, FREE_READ); + return 0; + } - /* If this test doesn't pass, its not IP. Might be DECNET or friends */ - if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd)) - { - DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name)); - kfree_skb(skb, FREE_READ); - return(0); - } + /* + * For now we will only deal with IP addresses. + */ + if ( +#ifdef CONFIG_AX25 + (arp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) || +#endif + (arp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) + || arp->ar_pln != 4) + { + /* This packet is not for us. Remove it. */ + kfree_skb(skb, FREE_READ); + return 0; + } - /* For now we will only deal with IP addresses. */ - if (((arp->ar_pro != NET16(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4) - { - if (arp->ar_op != NET16(ARPOP_REQUEST)) - DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name)); - kfree_skb(skb, FREE_READ); - return(0); - } + /* + * Extract variable width fields + */ - /* - * As said before, we try to be smart by using the - * info already present in the packet: the sender's - * IP and hardware address. - */ - ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); - memcpy(&src, ptr + arp->ar_hln, arp->ar_pln); - tbl = arp_lookup(src); - if (tbl != NULL) { - DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src))); - memcpy(tbl->ha, ptr, arp->ar_hln); - tbl->hlen = arp->ar_hln; - tbl->flags |= ATF_COM; - tbl->last_used = jiffies; - } else { - memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); - if (chk_addr(dst) != IS_MYADDR && arp_proxies == 0) { - kfree_skb(skb, FREE_READ); - return(0); - } else { - tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd); - if (tbl == NULL) { + sha=arp_ptr; + arp_ptr+=dev->addr_len; + memcpy(&sip,arp_ptr,4); + arp_ptr+=4; + tha=arp_ptr; + arp_ptr+=dev->addr_len; + memcpy(&tip,arp_ptr,4); + + /* + * Process entry + */ + + addr_hint = ip_chk_addr(tip); + + hash = HASH(sip); + proxy_entry = NULL; + if (proxies != 0 && addr_hint != IS_MYADDR) + { + unsigned long dest_hash = HASH(tip); + cli(); + proxy_entry = arp_tables[dest_hash]; + while (proxy_entry != NULL) + { + if (proxy_entry->ip == tip && proxy_entry->htype==arp->ar_hrd) + break; + proxy_entry = proxy_entry->next; + } + if (proxy_entry && (proxy_entry->flags & ATF_PUBL)) + memcpy(ha, proxy_entry->ha, dev->addr_len); + else + proxy_entry = NULL; + } + else + cli(); + + for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) + if (entry->ip == sip) + break; + + if (entry != NULL) + { + int old_flags = entry->flags; + memcpy(entry->ha, sha, arp->ar_hln); + entry->hlen = arp->ar_hln; + /* This seems sensible but not everyone gets it right ! */ + entry->htype = ntohs(arp->ar_hrd); + if(entry->htype==0) + entry->htype = dev->type; /* Not good but we have no choice */ + entry->last_used = jiffies; + if (!(entry->flags & ATF_COM)) + { + del_timer(&entry->timer); + entry->flags |= ATF_COM; + } + sti(); + if (!(old_flags & ATF_COM)) + { + /* Send out waiting packets. We might have problems, + if someone is manually removing entries right now. + I will fix this one. */ + arp_send_q(entry, sha); + } + if (addr_hint != IS_MYADDR && proxy_entry == NULL) + { + kfree_skb(skb, FREE_READ); + return 0; + } + } + else + { + if (addr_hint != IS_MYADDR && proxy_entry == NULL) + { + /* We don't do "smart arp" and cache all possible + entries. That just makes us more work. */ + sti(); kfree_skb(skb, FREE_READ); - return(0); + return 0; } + entry = (struct arp_table *)kmalloc(sizeof(struct arp_table), + GFP_ATOMIC); + if (entry == NULL) + { + sti(); + kfree_skb(skb, FREE_READ); + printk("ARP: no memory for new arp entry\n"); + return 0; + } + entry->ip = sip; + entry->hlen = arp->ar_hln; + entry->htype = arp->ar_hrd; + entry->flags = ATF_COM; + memcpy(entry->ha, sha, arp->ar_hln); + entry->last_used = jiffies; + entry->next = arp_tables[hash]; + arp_tables[hash] = entry; + entry->dev = skb->dev; + skb_queue_head_init(&entry->skb); + sti(); } - } - /* - * Since we updated the ARP cache, we might have enough - * information to send out some previously queued IP - * datagrams.... - */ - arp_send_q(); - - /* - * OK, we used that part of the info. Now check if the - * request was an ARP REQUEST for one of our own addresses.. - */ - if (arp->ar_op != NET16(ARPOP_REQUEST)) { - kfree_skb(skb, FREE_READ); - return(0); - } + /* From here on, interrupts are enabled. Never touch entry->.. + any more. */ -/* - * A broadcast arp, ignore it - */ + if (arp->ar_op != htons(ARPOP_REQUEST) + || tip == INADDR_LOOPBACK) + { + /* This wasn't a request, or some bad request for 127.0.0.1 + has made its way to the net, so delete it. */ + kfree_skb(skb, FREE_READ); + return 0; + } + + /* Either we respond with our own hw address, or we do proxy arp for + another machine. */ + arp_send(ARPOP_REPLY, sip, dev, tip, sha, + (addr_hint == IS_MYADDR)? dev->dev_addr : ha); - if(chk_addr(dst)==IS_BROADCAST) - { kfree_skb(skb, FREE_READ); return 0; - } - - memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); - if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) { - DPRINTF((DBG_ARP, "ARP: request was not for me!\n")); - kfree_skb(skb, FREE_READ); - return(0); - } - - /* - * Yes, it is for us. - * Allocate, fill in and send an ARP REPLY packet. - */ - ret = arp_response(arp, dev, addr_hint); - kfree_skb(skb, FREE_READ); - return(ret); } -/* Create and send an ARP REQUEST packet. */ -void -arp_send(unsigned long paddr, struct device *dev, unsigned long saddr) -{ - struct sk_buff *skb; - struct arphdr *arp; - unsigned char *ptr; - int tmp; - - DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr))); - DPRINTF((DBG_ARP, "dev=%s, ", dev->name)); - DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr))); - - skb = alloc_skb(sizeof(struct sk_buff) + - sizeof(struct arphdr) + (2 * dev->addr_len) + - dev->hard_header_len + - (2 * 4 /* arp->plen */), GFP_ATOMIC); - if (skb == NULL) { - printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr)); - return; - } - - /* Fill in the request. */ - skb->sk = NULL; - skb->mem_addr = skb; - skb->len = sizeof(struct arphdr) + - dev->hard_header_len + (2 * dev->addr_len) + 8; - skb->mem_len = sizeof(struct sk_buff) + skb->len; - skb->arp = 1; - skb->dev = dev; - skb->next = NULL; - skb->free = 1; - tmp = dev->hard_header(skb->data, dev, ETH_P_ARP, 0, saddr, skb->len); - if (tmp < 0) { - kfree_skb(skb,FREE_WRITE); - return; - } - arp = (struct arphdr *) (skb->data + tmp); - arp->ar_hrd = htons(dev->type); - if(dev->type!=3) /* AX.25 */ - arp->ar_pro = htons(ETH_P_IP); - else - arp->ar_pro = htons(0xCC); - arp->ar_hln = dev->addr_len; - arp->ar_pln = 4; - arp->ar_op = htons(ARPOP_REQUEST); - - ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); - memcpy(ptr, dev->dev_addr, arp->ar_hln); - ptr += arp->ar_hln; - memcpy(ptr, &saddr, arp->ar_pln); - ptr += arp->ar_pln; - /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/ - memset(ptr,0,arp->ar_hln); - ptr += arp->ar_hln; - memcpy(ptr, &paddr, arp->ar_pln); - - DPRINTF((DBG_ARP, ">>\n")); - arp_print(arp); - dev->queue_xmit(skb, dev, 0); -} - +/* + * Find an arp mapping in the cache. If not found, post a request. + */ + +int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, + unsigned long saddr, struct sk_buff *skb) +{ + struct arp_table *entry; + unsigned long hash; + + switch (ip_chk_addr(paddr)) + { + case IS_MYADDR: + printk("ARP: arp called for own IP address\n"); + memcpy(haddr, dev->dev_addr, dev->addr_len); + skb->arp = 1; + return 0; + case IS_BROADCAST: + memcpy(haddr, dev->broadcast, dev->addr_len); + skb->arp = 1; + return 0; + } -/* Find an ARP mapping in the cache. If not found, post a REQUEST. */ -int -arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, - unsigned long saddr) -{ - struct arp_table *apt; - - DPRINTF((DBG_ARP, "ARP: find(haddr=%s, ", eth_print(haddr))); - DPRINTF((DBG_ARP, "paddr=%s, ", in_ntoa(paddr))); - DPRINTF((DBG_ARP, "dev=%s, saddr=%s)\n", dev->name, in_ntoa(saddr))); - - switch(chk_addr(paddr)) { - case IS_MYADDR: - memcpy(haddr, dev->dev_addr, dev->addr_len); - return(0); - case IS_BROADCAST: - memcpy(haddr, dev->broadcast, dev->addr_len); - return(0); - } - - apt = arp_lookup(paddr); - if (apt != NULL) { + hash = HASH(paddr); + cli(); + /* - * Make sure it's not too old. If it is too old, we will - * just pretend we did not find it, and then arp_send will - * verify the address for us. + * Find an entry */ - if ((apt->flags & ATF_PERM) || - (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) { - apt->last_used = jiffies; - memcpy(haddr, apt->ha, dev->addr_len); - return(0); - } else { - DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n", - in_ntoa(apt->ip))); + for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) + if (entry->ip == paddr) + break; + + + if (entry != NULL) /* It exists */ + { + if (!(entry->flags & ATF_COM)) + { + /* + * A request was already send, but no reply yet. Thus + * queue the packet with the previous attempt + */ + + if (skb != NULL) + skb_queue_tail(&entry->skb, skb); + sti(); + return 1; + } + + /* + * Update the record + */ + + entry->last_used = jiffies; + memcpy(haddr, entry->ha, dev->addr_len); + if (skb) + skb->arp = 1; + sti(); + return 0; } - } - /* - * This assume haddr are at least 4 bytes. - * If this isn't true we can use a lookup table, one for every dev. - * NOTE: this bit of code still looks fishy to me- FvK - */ - *(unsigned long *)haddr = paddr; + /* + * Create a new unresolved entry. + */ + + entry = (struct arp_table *) kmalloc(sizeof(struct arp_table), + GFP_ATOMIC); + if (entry != NULL) + { + entry->ip = paddr; + entry->hlen = dev->addr_len; + entry->htype = dev->type; + entry->flags = 0; + memset(entry->ha, 0, dev->addr_len); + entry->last_used = jiffies; + entry->next = arp_tables[hash]; + entry->dev = dev; + arp_tables[hash] = entry; + entry->timer.function = arp_expire_request; + entry->timer.data = (unsigned long)entry; + entry->timer.expires = ARP_RES_TIME; + add_timer(&entry->timer); + entry->retries = ARP_MAX_TRIES; + skb_queue_head_init(&entry->skb); + if (skb != NULL) + skb_queue_tail(&entry->skb, skb); + } + else + { + if (skb != NULL && skb->free) + kfree_skb(skb, FREE_WRITE); + } + sti(); - /* If we didn't find an entry, we will try to send an ARP packet. */ - arp_send(paddr, dev, saddr); + /* + * If we didn't find an entry, we will try to send an ARP packet. + */ + + arp_send(ARPOP_REQUEST, paddr, dev, saddr, NULL, dev->dev_addr); - return(1); + return 1; } -/* Add an entry to the ARP cache. Check for dupes! */ -void -arp_add(unsigned long addr, unsigned char *haddr, struct device *dev) +/* + * Write the contents of the ARP cache to a PROCfs file. + * + * Will change soon to ASCII format + */ + +int arp_get_info(char *buffer, char **start, off_t offset, int length) { - struct arp_table *apt; + struct arp_table *entry; + struct arpreq *req = (struct arpreq *) buffer; + int i; + off_t pos=0; + off_t begin=0; + int len=0; - DPRINTF((DBG_ARP, "ARP: add(%s, ", in_ntoa(addr))); - DPRINTF((DBG_ARP, "%s, ", eth_print(haddr))); - DPRINTF((DBG_ARP, "%d, %d)\n", dev->hard_header_len, dev->type)); + cli(); + /* Loop over the ARP table and copy structures to the buffer. */ + for (i = 0; i < ARP_TABLE_SIZE; i++) + { + for (entry = arp_tables[i]; entry; entry = entry->next) + { + memset(req, 0, sizeof(struct arpreq)); + req->arp_pa.sa_family = AF_INET; + memcpy(req->arp_pa.sa_data, &entry->ip, 4); + req->arp_ha.sa_family = entry->htype; + memcpy(req->arp_ha.sa_data, &entry->ha, MAX_ADDR_LEN); + req->arp_flags = entry->flags; + req++; + len+=sizeof(struct arpreq); + pos+=sizeof(struct arpreq); + if(posoffset+length) + break; + } + if(pos>offset+length) + break; + } + sti(); + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; +} - /* This is probably a good check... */ - if (addr == 0) { - printk("ARP: add: will not add entry for 0.0.0.0 !\n"); - return; - } - /* First see if the address is already in the table. */ - apt = arp_lookup(addr); - if (apt != NULL) { - DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr))); - apt->last_used = jiffies; - memcpy(apt->ha, haddr , dev->addr_len); - return; - } - arp_create(addr, haddr, dev->addr_len, dev->type); +/* + * This will find an entry in the ARP table by looking at the IP address. + * Be careful, interrupts are turned off on exit!!! + */ + +static struct arp_table *arp_lookup(unsigned long paddr) +{ + struct arp_table *entry; + unsigned long hash = HASH(paddr); + + cli(); + for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) + if (entry->ip == paddr) break; + return entry; } -/* Create an ARP entry for a device's broadcast address. */ -void -arp_add_broad(unsigned long addr, struct device *dev) +/* + * Set (create) an ARP cache entry. + */ + +static int arp_req_set(struct arpreq *req) { - struct arp_table *apt; + struct arpreq r; + struct arp_table *entry; + struct sockaddr_in *si; + int htype, hlen; + unsigned long ip, hash; + struct rtable *rt; + + memcpy_fromfs(&r, req, sizeof(r)); + + /* We only understand about IP addresses... */ + if (r.arp_pa.sa_family != AF_INET) + return -EPFNOSUPPORT; + + /* + * Find out about the hardware type. + * We have to be compatible with BSD UNIX, so we have to + * assume that a "not set" value (i.e. 0) means Ethernet. + */ + + switch (r.arp_ha.sa_family) { + case 0: + /* Moan about this. ARP family 0 is NetROM and _will_ be needed */ + printk("Application using old BSD convention for arp set. Please recompile it.\n"); + case ARPHRD_ETHER: + htype = ARPHRD_ETHER; + hlen = ETH_ALEN; + break; +#ifdef CONFIG_AX25 + case ARPHRD_AX25: + htype = ARPHRD_AX25; + hlen = 7; + break; +#endif + default: + return -EPFNOSUPPORT; + } + + si = (struct sockaddr_in *) &r.arp_pa; + ip = si->sin_addr.s_addr; + if (ip == 0) + { + printk("ARP: SETARP: requested PA is 0.0.0.0 !\n"); + return -EINVAL; + } + + /* + * Is it reachable directly ? + */ + + rt = ip_rt_route(ip, NULL, NULL); + if (rt == NULL) + return -ENETUNREACH; + + /* + * Is there an existing entry for this address? + */ + + hash = HASH(ip); + cli(); + + /* + * Find the entry + */ + for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) + if (entry->ip == ip) + break; + + /* + * Do we need to create a new entry + */ + + if (entry == NULL) + { + entry = (struct arp_table *) kmalloc(sizeof(struct arp_table), + GFP_ATOMIC); + if (entry == NULL) + { + sti(); + return -ENOMEM; + } + entry->ip = ip; + entry->hlen = hlen; + entry->htype = htype; + entry->next = arp_tables[hash]; + arp_tables[hash] = entry; + skb_queue_head_init(&entry->skb); + } + else + if (entry->flags & ATF_PUBL) + proxies--; + /* + * We now have a pointer to an ARP entry. Update it! + */ + + memcpy(&entry->ha, &r.arp_ha.sa_data, hlen); + entry->last_used = jiffies; + entry->flags = r.arp_flags | ATF_COM; + if (entry->flags & ATF_PUBL) + proxies++; + entry->dev = rt->rt_dev; + sti(); - arp_add(addr, dev->broadcast, dev); - apt = arp_lookup(addr); - if (apt != NULL) { - apt->flags |= ATF_PERM; - } + return 0; } -/* Queue an IP packet, while waiting for the ARP reply packet. */ -void -arp_queue(struct sk_buff *skb) +/* + * Get an ARP cache entry. + */ + +static int arp_req_get(struct arpreq *req) { - cli(); - skb->tries = ARP_MAX_TRIES; + struct arpreq r; + struct arp_table *entry; + struct sockaddr_in *si; + + /* + * We only understand about IP addresses... + */ + + memcpy_fromfs(&r, req, sizeof(r)); + + if (r.arp_pa.sa_family != AF_INET) + return -EPFNOSUPPORT; + + /* + * Is there an existing entry for this address? + */ + + si = (struct sockaddr_in *) &r.arp_pa; + entry = arp_lookup(si->sin_addr.s_addr); + + if (entry == NULL) + { + sti(); + return -ENXIO; + } - if (skb->next != NULL) { + /* + * We found it; copy into structure. + */ + + memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen); + r.arp_ha.sa_family = entry->htype; + r.arp_flags = entry->flags; sti(); - printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic); - return; - } - if(arp_q==NULL) - arp_queue_kick(); - skb_queue_tail(&arp_q,skb); - skb->magic = ARP_QUEUE_MAGIC; - sti(); + + /* + * Copy the information back + */ + + memcpy_tofs(req, &r, sizeof(r)); + return 0; } /* - * Write the contents of the ARP cache to a PROCfs file. - * This is not by long perfect, as the internal ARP table doesn't - * have all the info we would like to have. Oh well, it works for - * now, eh? - FvK - * Also note, that due to space limits, we cannot generate more than - * 4Kbyte worth of data. This usually is enough, but I have seen - * machines die from under me because of a *very* large ARP cache. - * This can be simply tested by doing: - * - * # ping 255.255.255.255 - * # arp -a - * - * Perhaps we should redo PROCfs to handle larger buffers? Michael? + * Handle an ARP layer I/O control request. */ -int -arp_get_info(char *buffer) + +int arp_ioctl(unsigned int cmd, void *arg) { - struct arpreq *req; - struct arp_table *apt; - int i; - char *pos; - - /* Loop over the ARP table and copy structures to the buffer. */ - pos = buffer; - i = 0; - for (i = 0; i < ARP_TABLE_SIZE; i++) { - cli(); - apt = arp_tables[i]; - sti(); - while (apt != NULL) { - if (pos < (buffer + 4000)) { - req = (struct arpreq *) pos; - memset((char *) req, 0, sizeof(struct arpreq)); - req->arp_pa.sa_family = AF_INET; - memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4); - req->arp_ha.sa_family = apt->htype; - memcpy((char *) req->arp_ha.sa_data, - (char *) &apt->ha, apt->hlen); - req->arp_flags = apt->flags; - } - pos += sizeof(struct arpreq); - cli(); - apt = apt->next; - sti(); + struct arpreq r; + struct sockaddr_in *si; + int err; + + switch(cmd) + { + case DDIOCSDBG: + return dbg_ioctl(arg, DBG_ARP); + case SIOCDARP: + if (!suser()) + return -EPERM; + err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); + if(err) + return err; + memcpy_fromfs(&r, arg, sizeof(r)); + if (r.arp_pa.sa_family != AF_INET) + return -EPFNOSUPPORT; + si = (struct sockaddr_in *) &r.arp_pa; + arp_destroy(si->sin_addr.s_addr, 1); + return 0; + case SIOCGARP: + err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); + if(err) + return err; + return arp_req_get((struct arpreq *)arg); + case SIOCSARP: + if (!suser()) + return -EPERM; + err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); + if(err) + return err; + return arp_req_set((struct arpreq *)arg); + default: + return -EINVAL; } - } - return(pos - buffer); + /*NOTREACHED*/ + return 0; } -/* Set (create) an ARP cache entry. */ -static int -arp_req_set(struct arpreq *req) -{ - struct arpreq r; - struct arp_table *apt; - struct sockaddr_in *si; - int htype, hlen; - - /* We only understand about IP addresses... */ - memcpy_fromfs(&r, req, sizeof(r)); - if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT); - - /* - * Find out about the hardware type. - * We have to be compatible with BSD UNIX, so we have to - * assume that a "not set" value (i.e. 0) means Ethernet. - */ - si = (struct sockaddr_in *) &r.arp_pa; - switch(r.arp_ha.sa_family) { - case 0: - case ARPHRD_ETHER: - htype = ARPHRD_ETHER; - hlen = ETH_ALEN; - break; - case ARPHRD_AX25: - htype = ARPHRD_AX25; - hlen = 7; - break; - - default: - return(-EPFNOSUPPORT); - } - - /* Is there an existing entry for this address? */ - if (si->sin_addr.s_addr == 0) { - printk("ARP: SETARP: requested PA is 0.0.0.0 !\n"); - return(-EINVAL); - } - apt = arp_lookup(si->sin_addr.s_addr); - if (apt == NULL) { - apt = arp_create(si->sin_addr.s_addr, - (unsigned char *) r.arp_ha.sa_data, hlen, htype); - if (apt == NULL) return(-ENOMEM); - } - - /* We now have a pointer to an ARP entry. Update it! */ - memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen); - apt->last_used = jiffies; - apt->flags = r.arp_flags; - if(apt->flags&ATF_PUBL) - arp_proxies++; /* Count proxy arps so we know if to use it */ - - return(0); -} - - -/* Get an ARP cache entry. */ -static int -arp_req_get(struct arpreq *req) -{ - struct arpreq r; - struct arp_table *apt; - struct sockaddr_in *si; - - /* We only understand about IP addresses... */ - memcpy_fromfs(&r, req, sizeof(r)); - if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT); - - /* Is there an existing entry for this address? */ - si = (struct sockaddr_in *) &r.arp_pa; - apt = arp_lookup(si->sin_addr.s_addr); - if (apt == NULL) return(-ENXIO); - - /* We found it; copy into structure. */ - memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen); - r.arp_ha.sa_family = apt->htype; - - /* Copy the information back */ - memcpy_tofs(req, &r, sizeof(r)); - return(0); -} - - -/* Delete an ARP cache entry. */ -static int -arp_req_del(struct arpreq *req) -{ - struct arpreq r; - struct sockaddr_in *si; - - /* We only understand about IP addresses... */ - memcpy_fromfs(&r, req, sizeof(r)); - if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT); - - si = (struct sockaddr_in *) &r.arp_pa; - - /* The system cope with this but splats up a nasty kernel message - We trap it beforehand and tell the user off */ - if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR) - return -EINVAL; - - arp_destroy(si->sin_addr.s_addr); - - return(0); -} - - -/* Handle an ARP layer I/O control request. */ -int -arp_ioctl(unsigned int cmd, void *arg) -{ - int err; - switch(cmd) { - case DDIOCSDBG: - return(dbg_ioctl(arg, DBG_ARP)); - case SIOCDARP: - if (!suser()) return(-EPERM); - err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq)); - if(err) - return err; - return(arp_req_del((struct arpreq *)arg)); - case SIOCGARP: - err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq)); - if(err) - return err; - return(arp_req_get((struct arpreq *)arg)); - case SIOCSARP: - if (!suser()) return(-EPERM); - err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq)); - if(err) - return err; - return(arp_req_set((struct arpreq *)arg)); - default: - return(-EINVAL); - } - /*NOTREACHED*/ - return(0); +/* + * Called once on startup. + */ + +static struct packet_type arp_packet_type = +{ + 0, /* Should be: __constant_htons(ETH_P_ARP) - but this _doesn't_ come out constant! */ + 0, /* copy */ + arp_rcv, + NULL, + NULL +}; + +void arp_init (void) +{ + /* Register the packet type */ + arp_packet_type.type=htons(ETH_P_ARP); + dev_add_pack(&arp_packet_type); + /* Start with the regular checks for expired arp entries. */ + add_timer(&arp_timer); } + diff -u --recursive --new-file v1.1.3/linux/net/inet/arp.h linux/net/inet/arp.h --- v1.1.3/linux/net/inet/arp.h Thu Jan 13 20:51:25 1994 +++ linux/net/inet/arp.h Wed Apr 13 12:52:21 1994 @@ -1,64 +1,14 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ARP protocol module. - * - * Version: @(#)arp.h 1.0.6 05/21/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * 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. - */ +/* linux/net/inet/arp.h */ #ifndef _ARP_H #define _ARP_H -#define ARP_TABLE_SIZE 16 /* size of ARP table */ -#define ARP_TIMEOUT 30000 /* five minutes */ -#define ARP_RES_TIME 250 /* 2.5 seconds */ - -#define ARP_MAX_TRIES 3 /* max # of tries to send ARP */ -#define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */ - - -/* This structure defines the ARP mapping cache. */ -struct arp_table { - struct arp_table *next; - volatile unsigned long last_used; - unsigned int flags; -#if 1 - unsigned long ip; -#else - unsigned char pa[MAX_ADDR_LEN]; - unsigned char plen; - unsigned char ptype; -#endif - unsigned char ha[MAX_ADDR_LEN]; - unsigned char hlen; - unsigned char htype; -}; - - -/* This is also used in "sock.c" and "tcp.c" - YUCK! - FvK */ -extern struct sk_buff *arp_q; - - -extern void arp_destroy(unsigned long paddr); +extern void arp_init(void); +extern void arp_destroy(unsigned long paddr, int force); extern int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); extern int arp_find(unsigned char *haddr, unsigned long paddr, - struct device *dev, unsigned long saddr); -extern void arp_add(unsigned long addr, unsigned char *haddr, - struct device *dev); -extern void arp_add_broad(unsigned long addr, struct device *dev); -extern void arp_queue(struct sk_buff *skb); -extern int arp_get_info(char *buffer); + struct device *dev, unsigned long saddr, struct sk_buff *skb); +extern int arp_get_info(char *buffer, char **start, off_t origin, int length); extern int arp_ioctl(unsigned int cmd, void *arg); -extern void arp_destroy_maybe(unsigned long paddr); #endif /* _ARP_H */ diff -u --recursive --new-file v1.1.3/linux/net/inet/datagram.c linux/net/inet/datagram.c --- v1.1.3/linux/net/inet/datagram.c Fri Feb 11 09:14:40 1994 +++ linux/net/inet/datagram.c Wed Apr 13 12:52:21 1994 @@ -1,5 +1,5 @@ /* - * SUCS NET2 Debugged. + * SUCS NET3: * * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top * of these would make sense. Not tonight however 8-). @@ -14,6 +14,11 @@ * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but * AX.25 now works right, and SPX is feasible. * Alan Cox : Fixed write select of non IP protocol crash. + * Florian La Roche: Changed for my new skbuff handling. + * + * Note: + * A lot of this will change when the protocol/socket seperation + * occurs. Using this will make things reasonably clean. */ #include @@ -26,15 +31,14 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" -#include "arp.h" #include "route.h" #include "tcp.h" #include "udp.h" -#include "skbuff.h" +#include #include "sock.h" @@ -53,7 +57,7 @@ /* Socket is inuse - so the timer doesn't attack it */ restart: sk->inuse = 1; - while(sk->rqueue == NULL) /* No data */ + while(skb_peek(&sk->receive_queue) == NULL) /* No data */ { /* If we are shutdown then no more data is going to appear. We are done */ if (sk->shutdown & RCV_SHUTDOWN) @@ -91,7 +95,7 @@ /* Interrupts off so that no packet arrives before we begin sleeping. Otherwise we might miss our wake up */ cli(); - if (sk->rqueue == NULL) + if (skb_peek(&sk->receive_queue) == NULL) { interruptible_sleep_on(sk->sleep); /* Signals may need a restart of the syscall */ @@ -115,10 +119,10 @@ sti(); } /* Again only user level code calls this function, so nothing interrupt level - will suddenely eat the rqueue */ + will suddenely eat the receive_queue */ if (!(flags & MSG_PEEK)) { - skb=skb_dequeue(&sk->rqueue); + skb=skb_dequeue(&sk->receive_queue); if(skb!=NULL) skb->users++; else @@ -127,7 +131,7 @@ else { cli(); - skb=skb_peek(&sk->rqueue); + skb=skb_peek(&sk->receive_queue); if(skb!=NULL) skb->users++; sti(); @@ -150,7 +154,7 @@ return; } /* See if it needs destroying */ - if(skb->list == NULL) /* Been dequeued by someone - ie its read */ + if(!skb->next && !skb->prev) /* Been dequeued by someone - ie its read */ kfree_skb(skb,FREE_READ); restore_flags(flags); } @@ -178,7 +182,7 @@ /* Connection closed: Wake up */ return(1); } - if (sk->rqueue != NULL || sk->err != 0) + if (skb_peek(&sk->receive_queue) != NULL || sk->err != 0) { /* This appears to be consistent with other stacks */ return(1); diff -u --recursive --new-file v1.1.3/linux/net/inet/dev.c linux/net/inet/dev.c --- v1.1.3/linux/net/inet/dev.c Mon Mar 21 16:13:14 1994 +++ linux/net/inet/dev.c Wed Apr 13 17:09:46 1994 @@ -1,41 +1,28 @@ /* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. + * NET3 Protocol independant device support routines. * - * Interface (streams) handling functions. - * - * Version: @(#)dev.c 1.0.19 05/31/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Mark Evans, - * - * Fixes: - * Alan Cox: check_addr returns a value for a wrong subnet - * ie not us but don't forward this! - * Alan Cox: block timer if the inet_bh handler is running - * Alan Cox: generic queue code added. A lot neater now - * C.E.Hawkins: SIOCGIFCONF only reports 'upped' interfaces - * C.E.Hawkins: IFF_PROMISC support - * Alan Cox: Supports Donald Beckers new hardware - * multicast layer, but not yet multicast lists. - * Alan Cox: ip_addr_match problems with class A/B nets. - * C.E.Hawkins IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT] - * Alan Cox: Removed bogus subnet check now the subnet code - * a) actually works for all A/B nets - * b) doesn't forward off the same interface. - * Alan Cox: Multiple extra protocols - * Alan Cox: Fixed ifconfig up of dud device setting the up flag - * Alan Cox: Fixed verify_area errors - * Alan Cox: Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give - * anything away 8) - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * Derived from the non IP parts of dev.c 1.0.19 + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * + * Additional Authors: + * Florian la Roche + * Alan Cox + * + * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have + * the rest as well commented in the end. + */ + +/* + * A lot of these includes will be going walkies very soon */ + #include #include #include @@ -51,544 +38,547 @@ #include #include #include -#include "inet.h" -#include "dev.h" -#include "eth.h" +#include +#include +#include #include "ip.h" #include "route.h" -#include "protocol.h" -#include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include "arp.h" -#ifdef CONFIG_AX25 -#include "ax25.h" -#endif - - -#ifdef CONFIG_IPX - -static struct packet_type ipx_8023_type = { - NET16(ETH_P_802_3), - 0, - ipx_rcv, - NULL, - NULL -}; - -static struct packet_type ipx_packet_type = { - NET16(ETH_P_IPX), - 0, - ipx_rcv, - NULL, - &ipx_8023_type -}; -#endif -#ifdef CONFIG_AX25 +/* + * The list of packet types we will receive (as opposed to discard) + * and the routines to invoke. + */ -static struct packet_type ax25_packet_type = { - NET16(ETH_P_AX25), - 0, - ax25_rcv, - NULL, -#ifdef CONFIG_IPX - &ipx_packet_type -#else - NULL -#endif -}; -#endif +struct packet_type *ptype_base = NULL; +/* + * Device drivers call our routines to queue packets here. We empty the + * queue in the bottom half handler. + */ -static struct packet_type arp_packet_type = { - NET16(ETH_P_ARP), - 0, /* copy */ - arp_rcv, - NULL, -#ifdef CONFIG_IPX -#ifndef CONFIG_AX25 - &ipx_packet_type -#else - &ax25_packet_type -#endif -#else -#ifdef CONFIG_AX25 - &ax25_packet_type -#else - NULL /* next */ -#endif +static struct sk_buff_head backlog = +{ + (struct sk_buff *)&backlog, (struct sk_buff *)&backlog +#ifdef CONFIG_SKB_CHECK + ,SK_HEAD_SKB #endif }; - -static struct packet_type ip_packet_type = { - NET16(ETH_P_IP), - 0, /* copy */ - ip_rcv, - NULL, - &arp_packet_type -}; - - -struct packet_type *ptype_base = &ip_packet_type; -static struct sk_buff *volatile backlog = NULL; +/* + * We don't overdo the queue or we will thrash memory badly. + */ + static int backlog_size = 0; -static unsigned long ip_bcast = 0; +/* + * The number of sockets open for 'all' protocol use. We have to + * know this to copy a buffer the correct number of times. + */ + +static int dev_nit=0; -/* Return the lesser of the two values. */ -static unsigned long -min(unsigned long a, unsigned long b) +/* + * Return the lesser of the two values. + */ + +static __inline__ unsigned long min(unsigned long a, unsigned long b) { - if (a < b) return(a); - return(b); + return (a < b)? a : b; } -/* Determine a default network mask, based on the IP address. */ -static unsigned long -get_mask(unsigned long addr) -{ - unsigned long dst; - - if (addr == 0L) - return(0L); /* special case */ - - dst = ntohl(addr); - if (IN_CLASSA(dst)) - return(htonl(IN_CLASSA_NET)); - if (IN_CLASSB(dst)) - return(htonl(IN_CLASSB_NET)); - if (IN_CLASSC(dst)) - return(htonl(IN_CLASSC_NET)); - - /* Something else, probably a subnet. */ - return(0); -} +/****************************************************************************************** + Protocol management and registration routines -int -ip_addr_match(unsigned long me, unsigned long him) -{ - int i; - unsigned long mask=0xFFFFFFFF; - DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me))); - DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him))); - - if (me == him) - return(1); - for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8) { - if ((me & 0xFF) != (him & 0xFF)) { - /* - * The only way this could be a match is for - * the rest of addr1 to be 0 or 255. - */ - if (me != 0 && me != mask) return(0); - return(1); - } - } - return(1); -} +*******************************************************************************************/ -/* Check the address for our address, broadcasts, etc. */ -int chk_addr(unsigned long addr) +/* + * Add a protocol ID to the list. + */ + +void dev_add_pack(struct packet_type *pt) { - struct device *dev; - unsigned long mask; + struct packet_type *p1; + pt->next = ptype_base; - /* Accept both `all ones' and `all zeros' as BROADCAST. */ - if (addr == INADDR_ANY || addr == INADDR_BROADCAST) - return IS_BROADCAST; - - mask = get_mask(addr); - - /* Accept all of the `loopback' class A net. */ - if ((addr & mask) == htonl(0x7F000000L)) - return IS_MYADDR; - - /* OK, now check the interface addresses. */ - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (!(dev->flags & IFF_UP)) - continue; - if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/) - return IS_MYADDR; - /* Is it the exact IP address? */ - if (addr == dev->pa_addr) - return IS_MYADDR; - /* Is it our broadcast address? */ - if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr) - return IS_BROADCAST; - /* Nope. Check for a subnetwork broadcast. */ - if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) { - if ((addr & ~dev->pa_mask) == 0) - return IS_BROADCAST; - if ((addr & ~dev->pa_mask) == ~dev->pa_mask) - return IS_BROADCAST; - } - /* Nope. Check for Network broadcast. */ - if (((addr ^ dev->pa_addr) & mask) == 0) { - if ((addr & ~mask) == 0) - return IS_BROADCAST; - if ((addr & ~mask) == ~mask) - return IS_BROADCAST; - } + /* + * Don't use copy counts on ETH_P_ALL. Instead keep a global + * count of number of these and use it and pt->copy to decide + * copies + */ + + pt->copy=0; /* Assume we will not be copying the buffer before + * this routine gets it + */ + + if(pt->type == htons(ETH_P_ALL)) + dev_nit++; /* I'd like a /dev/nit too one day 8) */ + else + { + /* + * See if we need to copy it - that is another process also + * wishes to receive this type of packet. + */ + for (p1 = ptype_base; p1 != NULL; p1 = p1->next) + { + if (p1->type == pt->type) + { + pt->copy = 1; /* We will need to copy */ + break; + } + } } - return 0; /* no match at all */ -} - - -/* - * Retrieve our own address. - * Because the loopback address (127.0.0.1) is already recognized - * automatically, we can use the loopback interface's address as - * our "primary" interface. This is the addressed used by IP et - * al when it doesn't know which address to use (i.e. it does not - * yet know from or to which interface to go...). - */ -unsigned long -my_addr(void) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (dev->flags & IFF_LOOPBACK) return(dev->pa_addr); - } - return(0); -} - - -static int dev_nit=0; /* Number of network taps running */ - -/* Add a protocol ID to the list. This will change soon. */ -void -dev_add_pack(struct packet_type *pt) -{ - struct packet_type *p1; - pt->next = ptype_base; - - /* Don't use copy counts on ETH_P_ALL. Instead keep a global - count of number of these and use it and pt->copy to decide - copies */ - pt->copy=0; - if(pt->type==NET16(ETH_P_ALL)) - dev_nit++; /* I'd like a /dev/nit too one day 8) */ - else - { - /* See if we need to copy it. */ - for (p1 = ptype_base; p1 != NULL; p1 = p1->next) { - if (p1->type == pt->type) { - pt->copy = 1; - break; - } - } - } /* * NIT taps must go at the end or inet_bh will leak! */ - if(pt->type==NET16(ETH_P_ALL)) - { - pt->next=NULL; - if(ptype_base==NULL) - ptype_base=pt; - else + if (pt->type == htons(ETH_P_ALL)) { - for(p1=ptype_base;p1->next!=NULL;p1=p1->next); - p1->next=pt; - } - } - else - ptype_base = pt; + pt->next=NULL; + if(ptype_base==NULL) + ptype_base=pt; + else + { + /* + * Move to the end of the list + */ + for(p1=ptype_base;p1->next!=NULL;p1=p1->next); + /* + * Hook on the end + */ + p1->next=pt; + } + } + else +/* + * It goes on the start + */ + ptype_base = pt; } -/* Remove a protocol ID from the list. This will change soon. */ -void -dev_remove_pack(struct packet_type *pt) -{ - struct packet_type *lpt, *pt1; - - if (pt->type == NET16(ETH_P_ALL)) - dev_nit--; - if (pt == ptype_base) { - ptype_base = pt->next; - return; - } +/* + * Remove a protocol ID from the list. + */ + +void dev_remove_pack(struct packet_type *pt) +{ + struct packet_type *lpt, *pt1; - lpt = NULL; - for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next) { - if (pt1->next == pt ) { - cli(); - if (!pt->copy && lpt) - lpt->copy = 0; - pt1->next = pt->next; - sti(); + /* + * Keep the count of nit (Network Interface Tap) sockets correct. + */ + + if (pt->type == htons(ETH_P_ALL)) + dev_nit--; + + /* + * If we are first, just unhook us. + */ + + if (pt == ptype_base) + { + ptype_base = pt->next; return; } - if (pt1->next -> type == pt ->type && pt->type != NET16(ETH_P_ALL)) { - lpt = pt1->next; + lpt = NULL; + + /* + * This is harder. What we do is to walk the list of sockets + * for this type. We unhook the entry, and if there is a previous + * entry that is copying _and_ we are not copying, (ie we are the + * last entry for this type) then the previous one is set to + * non-copying as it is now the last. + */ + for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next) + { + if (pt1->next == pt ) + { + cli(); + if (!pt->copy && lpt) + lpt->copy = 0; + pt1->next = pt->next; + sti(); + return; + } + if (pt1->next->type == pt->type && pt->type != htons(ETH_P_ALL)) + lpt = pt1->next; } - } } +/***************************************************************************************** -/* Find an interface in the list. This will change soon. */ -struct device * -dev_get(char *name) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (strcmp(dev->name, name) == 0) - return(dev); - } - return(NULL); -} + Device Inteface Subroutines +******************************************************************************************/ -/* Find an interface that can handle addresses for a certain address. */ -struct device * dev_check(unsigned long addr) +/* + * Find an interface by name. + */ + +struct device *dev_get(char *name) { struct device *dev; - for (dev = dev_base; dev; dev = dev->next) { - if (!(dev->flags & IFF_UP)) - continue; - if (!(dev->flags & IFF_POINTOPOINT)) - continue; - if (addr != dev->pa_dstaddr) - continue; - return dev; - } - for (dev = dev_base; dev; dev = dev->next) { - if (!(dev->flags & IFF_UP)) - continue; - if (dev->flags & IFF_POINTOPOINT) - continue; - if (dev->pa_mask & (addr ^ dev->pa_addr)) - continue; - return dev; + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (strcmp(dev->name, name) == 0) + return(dev); } - return NULL; + return(NULL); } -/* Prepare an interface for use. */ -int -dev_open(struct device *dev) -{ - int ret = 0; - - if (dev->open) - ret = dev->open(dev); - if (ret == 0) - dev->flags |= (IFF_UP | IFF_RUNNING); +/* + * Prepare an interface for use. + */ + +int dev_open(struct device *dev) +{ + int ret = 0; + + /* + * Call device private open method + */ + if (dev->open) + ret = dev->open(dev); - return(ret); + /* + * If it went open OK then set the flags + */ + + if (ret == 0) + dev->flags |= (IFF_UP | IFF_RUNNING); + + return(ret); } -/* Completely shutdown an interface. */ -int -dev_close(struct device *dev) -{ - if (dev->flags != 0) { - int ct=0; - dev->flags = 0; - if (dev->stop) - dev->stop(dev); - rt_flush(dev); - dev->pa_addr = 0; - dev->pa_dstaddr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - /* Purge any queued packets when we down the link */ - while(ctbuffs[ct]))!=NULL) - if(skb->free) - kfree_skb(skb,FREE_WRITE); - ct++; +/* + * Completely shutdown an interface. + * + * WARNING: Both because of the way the upper layers work (that can be fixed) + * and because of races during a close (that can't be fixed any other way) + * a device may be given things to transmit EVEN WHEN IT IS DOWN. The driver + * MUST cope with this (eg by freeing and dumping the frame). + */ + +int dev_close(struct device *dev) +{ + /* + * Only close a device if it is up. + */ + + if (dev->flags != 0) + { + int ct=0; + dev->flags = 0; + /* + * Call the device specific close. This cannot fail. + */ + if (dev->stop) + dev->stop(dev); + /* + * Delete the route to the device. + */ + ip_rt_flush(dev); + /* + * Blank the IP addresses + */ + dev->pa_addr = 0; + dev->pa_dstaddr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + /* + * Purge any queued packets when we down the link + */ + while(ctbuffs[ct]))!=NULL) + if(skb->free) + kfree_skb(skb,FREE_WRITE); + ct++; + } } - } - - return(0); + return(0); } -/* Send (or queue for sending) a packet. */ -void -dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) +/* + * Send (or queue for sending) a packet. + */ + +void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) { - int where = 0; /* used to say if the packet should go */ + int where = 0; /* used to say if the packet should go */ /* at the front or the back of the */ /* queue. */ - DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n", + DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n", skb, dev, pri)); - if (dev == NULL) { - printk("dev.c: dev_queue_xmit: dev = NULL\n"); - return; - } + if (dev == NULL) + { + printk("dev.c: dev_queue_xmit: dev = NULL\n"); + return; + } - IS_SKB(skb); + IS_SKB(skb); - skb->dev = dev; - if (skb->next != NULL) { - /* Make sure we haven't missed an interrupt. */ - dev->hard_start_xmit(NULL, dev); - return; - } + skb->dev = dev; + start_bh_atomic(); - if (pri < 0) { - pri = -pri-1; - where = 1; - } - - if (pri >= DEV_NUMBUFFS) { - printk("bad priority in dev_queue_xmit.\n"); - pri = 1; - } + /* + * This just eliminates some race conditions, but not all... + */ - if (dev->hard_start_xmit(skb, dev) == 0) { - return; - } + if (skb->next != NULL) + { + /* + * Make sure we haven't missed an interrupt. + */ + printk("dev_queue_xmit: worked around a missed interrupt\n"); + dev->hard_start_xmit(NULL, dev); + end_bh_atomic(); + return; + } + + /* + * Negative priority is used to flag a frame that is being pulled from the + * queue front as a retransmit attempt. It therefore goes back on the queue + * start on a failure. + */ + + if (pri < 0) + { + pri = -pri-1; + where = 1; + } + + if (pri >= DEV_NUMBUFFS) + { + printk("bad priority in dev_queue_xmit.\n"); + pri = 1; + } + + /* + * If the address has not been resolved called the device header rebuilder. + * This can cover all protocols and technically no just ARP either. + */ + + if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { + end_bh_atomic(); + return; + } + + /* + * This is vitally important. We _MUST_ keep packets in order. While tcp/ip + * suffers only a slow down some IPX apps, and all the AX.25 code will break + * if it occurs out of order. + * + * This is commented out while I fix a few 'side effects' + */ + + if ((where==1 || skb_peek(&dev->buffs[pri])==NULL) && dev->hard_start_xmit(skb, dev) == 0) + { + end_bh_atomic(); + return; + } + + /* + * Transmission failed, put skb back into a list. + */ - /* Put skb into a bidirectional circular linked list. */ - DPRINTF((DBG_DEV, "dev_queue_xmit dev->buffs[%d]=%X\n", - pri, dev->buffs[pri])); - - /* Interrupts should already be cleared by hard_start_xmit. */ - cli(); - skb->magic = DEV_QUEUE_MAGIC; - if(where) - skb_queue_head(&dev->buffs[pri],skb); - else - skb_queue_tail(&dev->buffs[pri],skb); - skb->magic = DEV_QUEUE_MAGIC; - sti(); + if(where) + skb_queue_head(&dev->buffs[pri],skb); + else + skb_queue_tail(&dev->buffs[pri],skb); + end_bh_atomic(); } /* - * Receive a packet from a device driver and queue it for the upper - * (protocol) levels. It always succeeds. + * Receive a packet from a device driver and queue it for the upper + * (protocol) levels. It always succeeds. This is the recommended + * interface to use. */ -void -netif_rx(struct sk_buff *skb) + +void netif_rx(struct sk_buff *skb) { - static int dropping = 0; - /* Set any necessary flags. */ - skb->sk = NULL; - skb->free = 1; - - /* check that we aren't oevrdoing things.. */ - if (!backlog_size) - dropping = 0; - else if (backlog_size > 100) - dropping = 1; - if (dropping) { - kfree_skb(skb, FREE_READ); - return; - } - /* and add it to the "backlog" queue. */ - IS_SKB(skb); - skb_queue_tail(&backlog,skb); - backlog_size++; + static int dropping = 0; + extern struct timeval xtime; + + /* + * Any received buffers are un-owned and should be discarded + * when freed. These will be updated later as the frames get + * owners. + */ + skb->sk = NULL; + skb->free = 1; + if(skb->stamp.tv_sec==0) + skb->stamp = xtime; + + /* + * Check that we aren't oevrdoing things. + */ + + if (!backlog_size) + dropping = 0; + else if (backlog_size > 100) + dropping = 1; + + if (dropping) + { + kfree_skb(skb, FREE_READ); + return; + } + + /* + * Add it to the "backlog" queue. + */ + + IS_SKB(skb); + skb_queue_tail(&backlog,skb); + backlog_size++; - /* If any packet arrived, mark it for processing. */ - if (backlog != NULL) mark_bh(INET_BH); + /* + * If any packet arrived, mark it for processing after the + * hardware interrupt returns. + */ - return; + mark_bh(INET_BH); + return; } /* - * The old interface to fetch a packet from a device driver. - * This function is the base level entry point for all drivers that - * want to send a packet to the upper (protocol) levels. It takes - * care of de-multiplexing the packet to the various modules based - * on their protocol ID. + * The old interface to fetch a packet from a device driver. + * This function is the base level entry point for all drivers that + * want to send a packet to the upper (protocol) levels. It takes + * care of de-multiplexing the packet to the various modules based + * on their protocol ID. * - * Return values: 1 <- exit I can't do any more + * Return values: 1 <- exit I can't do any more * 0 <- feed me more (i.e. "done", "OK"). + * + * This function is OBSOLETE and should not be used by any new + * device. */ -int -dev_rint(unsigned char *buff, long len, int flags, struct device *dev) + +int dev_rint(unsigned char *buff, long len, int flags, struct device *dev) { - static int dropping = 0; - struct sk_buff *skb = NULL; - unsigned char *to; - int amount, left; - int len2; - - if (dev == NULL || buff == NULL || len <= 0) return(1); - if (flags & IN_SKBUFF) { - skb = (struct sk_buff *) buff; - } else { - if (dropping) { - if (backlog != NULL) - return(1); - printk("INET: dev_rint: no longer dropping packets.\n"); - dropping = 0; - } + static int dropping = 0; + struct sk_buff *skb = NULL; + unsigned char *to; + int amount, left; + int len2; - skb = alloc_skb(sizeof(*skb) + len, GFP_ATOMIC); - if (skb == NULL) { - printk("dev_rint: packet dropped on %s (no memory) !\n", - dev->name); - dropping = 1; + if (dev == NULL || buff == NULL || len <= 0) return(1); + + if (flags & IN_SKBUFF) + { + skb = (struct sk_buff *) buff; } - skb->mem_len = sizeof(*skb) + len; - skb->mem_addr = (struct sk_buff *) skb; + else + { + if (dropping) + { + if (skb_peek(&backlog) != NULL) + return(1); + printk("INET: dev_rint: no longer dropping packets.\n"); + dropping = 0; + } + + skb = alloc_skb(len, GFP_ATOMIC); + if (skb == NULL) + { + printk("dev_rint: packet dropped on %s (no memory) !\n", + dev->name); + dropping = 1; + return(1); + } + + /* + * First we copy the packet into a buffer, and save it for later. We + * in effect handle the incoming data as if it were from a circular buffer + */ - /* First we copy the packet into a buffer, and save it for later. */ - to = skb->data; - left = len; - len2 = len; - while (len2 > 0) { - amount = min(len2, (unsigned long) dev->rmem_end - + to = skb->data; + left = len; + + len2 = len; + while (len2 > 0) + { + amount = min(len2, (unsigned long) dev->rmem_end - (unsigned long) buff); - memcpy(to, buff, amount); - len2 -= amount; - left -= amount; - buff += amount; - to += amount; - if ((unsigned long) buff == dev->rmem_end) - buff = (unsigned char *) dev->rmem_start; + memcpy(to, buff, amount); + len2 -= amount; + left -= amount; + buff += amount; + to += amount; + if ((unsigned long) buff == dev->rmem_end) + buff = (unsigned char *) dev->rmem_start; + } } - } - skb->len = len; - skb->dev = dev; - skb->free = 1; - - netif_rx(skb); - /* OK, all done. */ - return(0); + + /* + * Tag the frame and kick it to the proper receive routine + */ + + skb->len = len; + skb->dev = dev; + skb->free = 1; + + netif_rx(skb); + /* + * OK, all done. + */ + return(0); } -/* This routine causes all interfaces to try to send some data. */ -void -dev_transmit(void) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (!dev->tbusy) { - dev_tint(dev); +/* + * This routine causes all interfaces to try to send some data. + */ + +void dev_transmit(void) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (!dev->tbusy) { + /* + * Kick the device + */ + dev_tint(dev); + } } - } } -static volatile char in_bh = 0; + +/********************************************************************************** + + Receive Queue Processor + +***********************************************************************************/ + +/* + * This is a single non-rentrant routine which takes the received packet + * queue and throws it at the networking layers in the hope that something + * useful will emerge. + */ + +volatile char in_bh = 0; /* Non-rentrant remember */ int in_inet_bh() /* Used by timer.c */ { @@ -596,116 +586,181 @@ } /* - * This function gets called periodically, to see if we can - * process any data that came in from some interface. - * + * When we are called the queue is ready to grab, the interrupts are + * on and hardware can interrupt and queue to the receive queue a we + * run with no problems. + * This is run as a bottom half after an interrupt handler that does + * mark_bh(INET_BH); */ -void -inet_bh(void *tmp) + +void inet_bh(void *tmp) { - struct sk_buff *skb; - struct packet_type *ptype; - unsigned short type; - unsigned char flag = 0; - int nitcount; - - /* Atomically check and mark our BUSY state. */ - if (set_bit(1, (void*)&in_bh)) - return; + struct sk_buff *skb; + struct packet_type *ptype; + unsigned short type; + unsigned char flag = 0; + int nitcount; + + /* + * Atomically check and mark our BUSY state. + */ + + if (set_bit(1, (void*)&in_bh)) + return; + + /* + * Can we send anything now? We want to clear the + * decks for any more sends that get done as we + * process the input. + */ - /* Can we send anything now? */ - dev_transmit(); + dev_transmit(); - /* Any data left to process? */ - while((skb=skb_dequeue(&backlog))!=NULL) - { - backlog_size--; - nitcount=dev_nit; - flag=0; - sti(); - /* - * Bump the pointer to the next structure. - * This assumes that the basic 'skb' pointer points to - * the MAC header, if any (as indicated by its "length" - * field). Take care now! - */ - skb->h.raw = skb->data + skb->dev->hard_header_len; - skb->len -= skb->dev->hard_header_len; - - /* - * Fetch the packet protocol ID. This is also quite ugly, as - * it depends on the protocol driver (the interface itself) to - * know what the type is, or where to get it from. The Ethernet - * interfaces fetch the ID from the two bytes in the Ethernet MAC - * header (the h_proto field in struct ethhdr), but drivers like - * SLIP and PLIP have no alternative but to force the type to be - * IP or something like that. Sigh- FvK - */ - type = skb->dev->type_trans(skb, skb->dev); - - /* - * We got a packet ID. Now loop over the "known protocols" - * table (which is actually a linked list, but this will - * change soon if I get my way- FvK), and forward the packet - * to anyone who wants it. - */ - for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) { - if (ptype->type == type || ptype->type == NET16(ETH_P_ALL)) { - struct sk_buff *skb2; - - if (ptype->type==NET16(ETH_P_ALL)) - nitcount--; - if (ptype->copy || nitcount) { /* copy if we need to */ - skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); - if (skb2 == NULL) - continue; - memcpy(skb2, (const void *) skb, skb->mem_len); - skb2->mem_addr = skb2; - skb2->h.raw = (unsigned char *)( - (unsigned long) skb2 + - (unsigned long) skb->h.raw - - (unsigned long) skb - ); - skb2->free = 1; - } else { - skb2 = skb; - } + /* + * Any data left to process. This may occur because a + * mark_bh() is done after we empty the queue including + * that from the device which does a mark_bh() just after + */ - /* This used to be in the 'else' part, but then - * we don't have this flag set when we get a - * protocol that *does* require copying... -FvK - */ - flag = 1; + cli(); + + /* + * While the queue is not empty + */ + + while((skb=skb_dequeue(&backlog))!=NULL) + { + /* + * We have a packet. Therefore the queue has shrunk + */ + backlog_size--; + + nitcount=dev_nit; + flag=0; + sti(); + + /* + * Bump the pointer to the next structure. + * This assumes that the basic 'skb' pointer points to + * the MAC header, if any (as indicated by its "length" + * field). Take care now! + */ + + skb->h.raw = skb->data + skb->dev->hard_header_len; + skb->len -= skb->dev->hard_header_len; + + /* + * Fetch the packet protocol ID. This is also quite ugly, as + * it depends on the protocol driver (the interface itself) to + * know what the type is, or where to get it from. The Ethernet + * interfaces fetch the ID from the two bytes in the Ethernet MAC + * header (the h_proto field in struct ethhdr), but other drivers + * may either use the ethernet ID's or extra ones that do not + * clash (eg ETH_P_AX25). We could set this before we queue the + * frame. In fact I may change this when I have time. + */ + + type = skb->dev->type_trans(skb, skb->dev); - /* Kick the protocol handler. */ - ptype->func(skb2, skb->dev, ptype); + /* + * We got a packet ID. Now loop over the "known protocols" + * table (which is actually a linked list, but this will + * change soon if I get my way- FvK), and forward the packet + * to anyone who wants it. + * + * [FvK didn't get his way but he is right this ought to be + * hashed so we typically get a single hit. The speed cost + * here is minimal but no doubt adds up at the 4,000+ pkts/second + * rate we can hit flat out] + */ + + for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) + { + if (ptype->type == type || ptype->type == htons(ETH_P_ALL)) + { + struct sk_buff *skb2; + + if (ptype->type == htons(ETH_P_ALL)) + nitcount--; + if (ptype->copy || nitcount) + { + /* + * copy if we need to + */ +#ifdef OLD + skb2 = alloc_skb(skb->len, GFP_ATOMIC); + if (skb2 == NULL) + continue; + memcpy(skb2, skb, skb2->mem_len); + skb2->mem_addr = skb2; + skb2->h.raw = (unsigned char *)( + (unsigned long) skb2 + + (unsigned long) skb->h.raw - + (unsigned long) skb + ); + skb2->free = 1; +#else + skb2=skb_clone(skb, GFP_ATOMIC); + if(skb2==NULL) + continue; +#endif + } + else + { + skb2 = skb; + } + + /* + * Protocol located. + */ + + flag = 1; + + /* + * Kick the protocol handler. This should be fast + * and efficient code. + */ + + ptype->func(skb2, skb->dev, ptype); + } + } /* End of protocol list loop */ + + /* + * Has an unknown packet has been received ? + */ + + if (!flag) + { + DPRINTF((DBG_DEV,"INET: unknown packet type 0x%04X (ignored)\n", type)); + kfree_skb(skb, FREE_WRITE); } - } + + /* + * Again, see if we can transmit anything now. + */ + dev_transmit(); + cli(); + } /* End of queue loop */ + + /* + * We have emptied the queue + */ + + in_bh = 0; + sti(); + /* - * That's odd. We got an unknown packet. Who's using - * stuff like Novell or Amoeba on this network?? + * One last output flush. */ - if (!flag) { - DPRINTF((DBG_DEV, - "INET: unknown packet type 0x%04X (ignored)\n", type)); - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - } - - /* Again, see if we can transmit anything now. */ + dev_transmit(); - cli(); - } - in_bh = 0; - sti(); - dev_transmit(); } /* - * This routine is called when an device driver (i.e. an - * interface) is * ready to transmit a packet. + * This routine is called when an device driver (i.e. an + * interface) is ready to transmit a packet. */ void dev_tint(struct device *dev) @@ -713,13 +768,26 @@ int i; struct sk_buff *skb; - for(i = 0;i < DEV_NUMBUFFS; i++) { + /* + * Work the queues in priority order + */ + + for(i = 0;i < DEV_NUMBUFFS; i++) + { + /* + * Pull packets from the queue + */ + while((skb=skb_dequeue(&dev->buffs[i]))!=NULL) { - skb->magic = 0; - skb->next = NULL; - skb->prev = NULL; - dev->queue_xmit(skb,dev,-i - 1); + /* + * Feed them to the output stage and if it fails + * indicate they re-queue at the front. + */ + dev_queue_xmit(skb,dev,-i - 1); + /* + * If we can take no more then stop here. + */ if (dev->tbusy) return; } @@ -727,59 +795,98 @@ } -/* Perform a SIOCGIFCONF call. */ -static int -dev_ifconf(char *arg) -{ - struct ifconf ifc; - struct ifreq ifr; - struct device *dev; - char *pos; - int len; - int err; - - /* Fetch the caller's info block. */ - err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); - if(err) - return err; - memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); - len = ifc.ifc_len; - pos = ifc.ifc_buf; - err=verify_area(VERIFY_WRITE, pos, len); - if(err) - return err; - - /* Loop over the interfaces, and write an info block for each. */ - for (dev = dev_base; dev != NULL; dev = dev->next) { - if(!(dev->flags & IFF_UP)) - continue; - memset(&ifr, 0, sizeof(struct ifreq)); - strcpy(ifr.ifr_name, dev->name); - (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - - /* Write this block to the caller's space. */ - memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); - pos += sizeof(struct ifreq); - len -= sizeof(struct ifreq); - if (len < sizeof(struct ifreq)) break; - } - - /* All done. Write the updated control block back to the caller. */ - ifc.ifc_len = (pos - ifc.ifc_buf); - ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; - memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); - return(pos - arg); -} +/* + * Perform a SIOCGIFCONF call. This structure will change + * size shortly, and there is nothing I can do about it. + * Thus we will need a 'compatibility mode'. + */ -/* Print device statistics. */ -char *sprintf_stats(char *buffer, struct device *dev) +static int dev_ifconf(char *arg) { - char *pos = buffer; - struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); + struct ifconf ifc; + struct ifreq ifr; + struct device *dev; + char *pos; + int len; + int err; + + /* + * Fetch the caller's info block. + */ + + err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); + if(err) + return err; + memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); + len = ifc.ifc_len; + pos = ifc.ifc_buf; + + /* + * We now walk the device list filling each active device + * into the array. + */ + + err=verify_area(VERIFY_WRITE,pos,len); + if(err) + return err; + + /* + * Loop over the interfaces, and write an info block for each. + */ + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if(!(dev->flags & IFF_UP)) /* Downed devices don't count */ + continue; + memset(&ifr, 0, sizeof(struct ifreq)); + strcpy(ifr.ifr_name, dev->name); + (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; + (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; + + /* + * Write this block to the caller's space. + */ + + memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); + pos += sizeof(struct ifreq); + len -= sizeof(struct ifreq); + + /* + * Have we run out of space here ? + */ + + if (len < sizeof(struct ifreq)) + break; + } + + /* + * All done. Write the updated control block back to the caller. + */ + + ifc.ifc_len = (pos - ifc.ifc_buf); + ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; + memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); + + /* + * Report how much was filled in + */ + + return(pos - arg); +} + + +/* + * This is invoked by the /proc filesystem handler to display a device + * in detail. + */ - if (stats) - pos += sprintf(pos, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", +static int sprintf_stats(char *buffer, struct device *dev) +{ + struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); + int size; + + if (stats) + size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", dev->name, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, @@ -790,29 +897,61 @@ stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors + stats->tx_window_errors + stats->tx_heartbeat_errors); - else - pos += sprintf(pos, "%6s: No statistics available.\n", dev->name); + else + size = sprintf(buffer, "%6s: No statistics available.\n", dev->name); - return pos; + return size; } -/* Called from the PROCfs module. */ -int -dev_get_info(char *buffer) -{ - char *pos = buffer; - struct device *dev; - - pos += - sprintf(pos, - "Inter-| Receive | Transmit\n" - " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); - for (dev = dev_base; dev != NULL; dev = dev->next) { - pos = sprintf_stats(pos, dev); - } - return pos - buffer; +/* + * Called from the PROCfs module. This now uses the new arbitary sized /proc/net interface + * to create /proc/net/dev + */ + +int dev_get_info(char *buffer, char **start, off_t offset, int length) +{ + int len=0; + off_t begin=0; + off_t pos=0; + int size; + + struct device *dev; + + + size = sprintf(buffer, "Inter-| Receive | Transmit\n" + " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); + + pos+=size; + len+=size; + + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + size = sprintf_stats(buffer+len, dev); + len+=size; + pos=begin+len; + + if(posoffset+length) + break; + } + + *start=buffer+(offset-begin); /* Start of wanted data */ + len-=(offset-begin); /* Start slop */ + if(len>length) + len=length; /* Ending slop */ + return len; } + +/* + * This checks bitmasks for the ioctl calls for devices. + */ + static inline int bad_mask(unsigned long mask, unsigned long addr) { if (addr & (mask = ~mask)) @@ -823,238 +962,344 @@ return 0; } +/* + * Perform the SIOCxIFxxx calls. + * + * The socket layer has seen an ioctl the address family thinks is + * for the device. At this point we get invoked to make a decision + */ + +static int dev_ifsioc(void *arg, unsigned int getset) +{ + struct ifreq ifr; + struct device *dev; + int ret; + + /* + * Fetch the caller's info block into kernel space + */ -/* Perform the SIOCxIFxxx calls. */ -static int -dev_ifsioc(void *arg, unsigned int getset) -{ - struct ifreq ifr; - struct device *dev; - int ret; - - /* Fetch the caller's info block. */ - int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); - if(err) - return err; - memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); - - /* See which interface the caller is talking about. */ - if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-EINVAL); - - switch(getset) { - case SIOCGIFFLAGS: - ifr.ifr_flags = dev->flags; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFFLAGS: - { - int old_flags = dev->flags; - dev->flags = ifr.ifr_flags & ( - IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | - IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | - IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI); - - if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0)) - dev->set_multicast_list(dev,0,NULL); - if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0)) - dev->set_multicast_list(dev,-1,NULL); - if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) { - ret = dev_close(dev); - } else - { - ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) - ? dev_open(dev) : 0; - if(ret<0) - dev->flags&=~IFF_UP; /* Didnt open so down the if */ - } - } - break; - case SIOCGIFADDR: - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFADDR: - dev->pa_addr = (*(struct sockaddr_in *) + int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); + if(err) + return err; + + memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); + + /* + * See which interface the caller is talking about. + */ + + if ((dev = dev_get(ifr.ifr_name)) == NULL) + return(-ENODEV); + + switch(getset) + { + case SIOCGIFFLAGS: /* Get interface flags */ + ifr.ifr_flags = dev->flags; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFFLAGS: /* Set interface flags */ + { + int old_flags = dev->flags; + dev->flags = ifr.ifr_flags & ( + IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | + IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | + IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI); + + /* + * Has promiscuous mode been turned off + */ + if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0)) + dev->set_multicast_list(dev,0,NULL); + + /* + * Has it been turned on + */ + + if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0)) + dev->set_multicast_list(dev,-1,NULL); + + /* + * Have we downed the interface + */ + + if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) + { + ret = dev_close(dev); + } + else + { + /* + * Have we upped the interface + */ + + ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) + ? dev_open(dev) : 0; + /* + * Check the flags. + */ + if(ret<0) + dev->flags&=~IFF_UP; /* Didnt open so down the if */ + } + } + break; + + case SIOCGIFADDR: /* Get interface address (and family) */ + (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; + (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + + case SIOCSIFADDR: /* Set interface address (and family) */ + dev->pa_addr = (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr; - dev->family = ifr.ifr_addr.sa_family; - dev->pa_mask = get_mask(dev->pa_addr); - dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; - ret = 0; - break; - case SIOCGIFBRDADDR: - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFBRDADDR: - dev->pa_brdaddr = (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr; - ret = 0; - break; - case SIOCGIFDSTADDR: - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFDSTADDR: - dev->pa_dstaddr = (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr; - ret = 0; - break; - case SIOCGIFNETMASK: - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFNETMASK: { - unsigned long mask = (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr; - ret = -EINVAL; - if (bad_mask(mask,0)) - break; - dev->pa_mask = mask; - ret = 0; - break; + dev->family = ifr.ifr_addr.sa_family; + dev->pa_mask = ip_get_mask(dev->pa_addr); + dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; + ret = 0; + break; + + case SIOCGIFBRDADDR: /* Get the broadcast address */ + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + + case SIOCSIFBRDADDR: /* Set the broadcast address */ + dev->pa_brdaddr = (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_addr.s_addr; + ret = 0; + break; + + case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ + (*(struct sockaddr_in *) + &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + + case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ + dev->pa_dstaddr = (*(struct sockaddr_in *) + &ifr.ifr_dstaddr).sin_addr.s_addr; + ret = 0; + break; + + case SIOCGIFNETMASK: /* Get the netmask for the interface */ + (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; + (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + + case SIOCSIFNETMASK: /* Set the netmask for the interface */ + { + unsigned long mask = (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_addr.s_addr; + ret = -EINVAL; + /* + * The mask we set must be legal. + */ + if (bad_mask(mask,0)) + break; + dev->pa_mask = mask; + ret = 0; + } + break; + + case SIOCGIFMETRIC: /* Get the metric on the inteface (currently unused) */ + + ifr.ifr_metric = dev->metric; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + + case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ + dev->metric = ifr.ifr_metric; + ret = 0; + break; + + case SIOCGIFMTU: /* Get the MTU of a device */ + ifr.ifr_mtu = dev->mtu; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + + case SIOCSIFMTU: /* Set the MTU of a device */ + + /* + * MTU must be positive and under the page size problem + */ + + if(ifr.ifr_mtu<1 || ifr.ifr_mtu>3800) + return -EINVAL; + dev->mtu = ifr.ifr_mtu; + ret = 0; + break; + + case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently + do not support it */ + printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg); + ret = -EINVAL; + break; + + case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ + printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg); + ret = -EINVAL; + break; + + case OLD_SIOCGIFHWADDR: /* Get the hardware address. This will change and SIFHWADDR will be added */ + memcpy(ifr.old_ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN); + memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); + ret=0; + break; + + case SIOCGIFHWADDR: + memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); + ifr.ifr_hwaddr.sa_family=dev->type; + memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); + ret=0; + break; + + case SIOCSIFHWADDR: + if(dev->set_mac_address==NULL) + return -EOPNOTSUPP; + if(ifr.ifr_hwaddr.sa_family!=dev->type) + return -EINVAL; + ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data); + break; + + /* + * Unknown ioctl + */ + + default: + ret = -EINVAL; } - case SIOCGIFMETRIC: - ifr.ifr_metric = dev->metric; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFMETRIC: - dev->metric = ifr.ifr_metric; - ret = 0; - break; - case SIOCGIFMTU: - ifr.ifr_mtu = dev->mtu; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFMTU: - dev->mtu = ifr.ifr_mtu; - ret = 0; - break; - case SIOCGIFMEM: - printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg); - ret = -EINVAL; - break; - case SIOCSIFMEM: - printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg); - ret = -EINVAL; - break; - case SIOCGIFHWADDR: - memcpy(ifr.ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN); - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - ret=0; - break; - default: - ret = -EINVAL; - } - return(ret); + return(ret); } -/* This function handles all "interface"-type I/O control requests. */ -int -dev_ioctl(unsigned int cmd, void *arg) -{ - struct iflink iflink; - struct ddi_device *dev; - - switch(cmd) { - case IP_SET_DEV: - printk("Your network configuration program needs upgrading.\n"); - return -EINVAL; - - case SIOCGIFCONF: - (void) dev_ifconf((char *) arg); - return 0; - - case SIOCGIFFLAGS: - case SIOCGIFADDR: - case SIOCGIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - return dev_ifsioc(arg, cmd); - - case SIOCSIFFLAGS: - case SIOCSIFADDR: - case SIOCSIFDSTADDR: - case SIOCSIFBRDADDR: - case SIOCSIFNETMASK: - case SIOCSIFMETRIC: - case SIOCSIFMTU: - case SIOCSIFMEM: - if (!suser()) - return -EPERM; - return dev_ifsioc(arg, cmd); - - case SIOCSIFLINK: - if (!suser()) - return -EPERM; - memcpy_fromfs(&iflink, arg, sizeof(iflink)); - dev = ddi_map(iflink.id); - if (dev == NULL) +/* + * This function handles all "interface"-type I/O control requests. The actual + * 'doing' part of this is dev_ifsioc above. + */ + +int dev_ioctl(unsigned int cmd, void *arg) +{ + switch(cmd) + { + /* + * The old old setup ioctl. Even its name and this entry will soon be + * just so much ionization on a backup tape. + */ + + case SIOCGIFCONF: + (void) dev_ifconf((char *) arg); + return 0; + + /* + * Ioctl calls that can be done by all. + */ + + case SIOCGIFFLAGS: + case SIOCGIFADDR: + case SIOCGIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + case SIOCGIFMEM: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case OLD_SIOCGIFHWADDR: + return dev_ifsioc(arg, cmd); + + /* + * Ioctl calls requiring the power of a superuser + */ + + case SIOCSIFFLAGS: + case SIOCSIFADDR: + case SIOCSIFDSTADDR: + case SIOCSIFBRDADDR: + case SIOCSIFNETMASK: + case SIOCSIFMETRIC: + case SIOCSIFMTU: + case SIOCSIFMEM: + if (!suser()) + return -EPERM; + return dev_ifsioc(arg, cmd); + + case SIOCSIFLINK: return -EINVAL; - /* Now allocate an interface and connect it. */ - printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n", - dev->name, iflink.stream); - return 0; - - default: - return -EINVAL; - } + /* + * Unknown ioctl. + */ + + default: + return -EINVAL; + } } -/* Initialize the DEV module. */ -void -dev_init(void) -{ - struct device *dev, *dev2; - - /* Add the devices. - * If the call to dev->init fails, the dev is removed - * from the chain disconnecting the device until the - * next reboot. - */ - dev2 = NULL; - for (dev = dev_base; dev != NULL; dev=dev->next) { - if (dev->init && dev->init(dev)) { - if (dev2 == NULL) dev_base = dev->next; - else dev2->next = dev->next; - } else { - dev2 = dev; - } - } +/* + * Initialize the DEV module. At boot time this walks the device list and + * unhooks any devices that fail to initialise (normally hardware not + * present) and leaves us with a valid list of present and active devices. + * + * The PCMICA code may need to change this a little, and add a pair + * of register_inet_device() unregister_inet_device() calls. This will be + * needed for ethernet as modules support. + */ + +void dev_init(void) +{ + struct device *dev, *dev2; - /* Set up some IP addresses. */ - ip_bcast = in_aton("255.255.255.255"); + /* + * Add the devices. + * If the call to dev->init fails, the dev is removed + * from the chain disconnecting the device until the + * next reboot. + */ + + dev2 = NULL; + for (dev = dev_base; dev != NULL; dev=dev->next) + { + if (dev->init && dev->init(dev)) + { + /* + * It failed to come up. Unhook it. + */ + + if (dev2 == NULL) + dev_base = dev->next; + else + dev2->next = dev->next; + } + else + { + dev2 = dev; + } + } } diff -u --recursive --new-file v1.1.3/linux/net/inet/devinet.c linux/net/inet/devinet.c --- v1.1.3/linux/net/inet/devinet.c +++ linux/net/inet/devinet.c Wed Apr 13 12:52:22 1994 @@ -0,0 +1,248 @@ +/* + * NET3 IP device support routines. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Derived from the IP parts of dev.c 1.0.19 + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * + * Additional Authors: + * Alan Cox, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ip.h" +#include "route.h" +#include "protocol.h" +#include "tcp.h" +#include +#include "sock.h" +#include "arp.h" + +/* + * Determine a default network mask, based on the IP address. + */ + +unsigned long ip_get_mask(unsigned long addr) +{ + unsigned long dst; + + if (addr == 0L) + return(0L); /* special case */ + + dst = ntohl(addr); + if (IN_CLASSA(dst)) + return(htonl(IN_CLASSA_NET)); + if (IN_CLASSB(dst)) + return(htonl(IN_CLASSB_NET)); + if (IN_CLASSC(dst)) + return(htonl(IN_CLASSC_NET)); + + /* + * Something else, probably a multicast. + */ + + return(0); +} + +/* + * Perform an IP address matching operation + */ + +int ip_addr_match(unsigned long me, unsigned long him) +{ + int i; + unsigned long mask=0xFFFFFFFF; + DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me))); + DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him))); + + /* + * Simple case + */ + if (me == him) + return(1); + + /* + * Look for a match ending in all 1's + */ + + for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8) + { + if ((me & 0xFF) != (him & 0xFF)) + { + /* + * The only way this could be a match is for + * the rest of addr1 to be 0 or 255. + */ + if (me != 0 && me != mask) + return(0); + return(1); + } + } + return(1); +} + + +/* + * Check the address for our address, broadcasts, etc. + * + * I intend to fix this to at the very least cache the last + * resolved entry. + */ + +int ip_chk_addr(unsigned long addr) +{ + struct device *dev; + unsigned long mask; + + /* + * Accept both `all ones' and `all zeros' as BROADCAST. + * (Support old BSD in other words). This old BSD + * support will go very soon as it messes other things + * up. + */ + + if (addr == INADDR_ANY || addr == INADDR_BROADCAST) + return IS_BROADCAST; + + mask = ip_get_mask(addr); + + /* + * Accept all of the `loopback' class A net. + */ + + if ((addr & mask) == htonl(0x7F000000L)) + return IS_MYADDR; + + /* + * OK, now check the interface addresses. + */ + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (!(dev->flags & IFF_UP)) + continue; + /* + * If the protocol address of the device is 0 this is special + * and means we are address hunting (eg bootp). + */ + + if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/) + return IS_MYADDR; + /* + * Is it the exact IP address? + */ + + if (addr == dev->pa_addr) + return IS_MYADDR; + /* + * Is it our broadcast address? + */ + + if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr) + return IS_BROADCAST; + /* + * Nope. Check for a subnetwork broadcast. + */ + + if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) + { + if ((addr & ~dev->pa_mask) == 0) + return IS_BROADCAST; + if ((addr & ~dev->pa_mask) == ~dev->pa_mask) + return IS_BROADCAST; + } + + /* + * Nope. Check for Network broadcast. + */ + + if (((addr ^ dev->pa_addr) & mask) == 0) + { + if ((addr & ~mask) == 0) + return IS_BROADCAST; + if ((addr & ~mask) == ~mask) + return IS_BROADCAST; + } + } + return 0; /* no match at all */ +} + + +/* + * Retrieve our own address. + * + * Because the loopback address (127.0.0.1) is already recognized + * automatically, we can use the loopback interface's address as + * our "primary" interface. This is the addressed used by IP et + * al when it doesn't know which address to use (i.e. it does not + * yet know from or to which interface to go...). + */ + +unsigned long ip_my_addr(void) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (dev->flags & IFF_LOOPBACK) + return(dev->pa_addr); + } + return(0); +} + +/* + * Find an interface that can handle addresses for a certain address. + * + * This needs optimising, since its relatively trivial to collapse + * the two loops into one. + */ + +struct device * ip_dev_check(unsigned long addr) +{ + struct device *dev; + + for (dev = dev_base; dev; dev = dev->next) + { + if (!(dev->flags & IFF_UP)) + continue; + if (!(dev->flags & IFF_POINTOPOINT)) + continue; + if (addr != dev->pa_dstaddr) + continue; + return dev; + } + for (dev = dev_base; dev; dev = dev->next) + { + if (!(dev->flags & IFF_UP)) + continue; + if (dev->flags & IFF_POINTOPOINT) + continue; + if (dev->pa_mask & (addr ^ dev->pa_addr)) + continue; + return dev; + } + return NULL; +} diff -u --recursive --new-file v1.1.3/linux/net/inet/eth.c linux/net/inet/eth.c --- v1.1.3/linux/net/inet/eth.c Wed Jan 19 13:24:38 1994 +++ linux/net/inet/eth.c Wed Apr 13 12:52:22 1994 @@ -10,6 +10,8 @@ * Authors: Ross Biro, * Fred N. van Kempen, * Mark Evans, + * Florian La Roche, + * Alan Cox, * * Fixes: * Mr Linux : Arp problems @@ -18,6 +20,9 @@ * Alan Cox : eth_rebuild_header missing an htons and * minor other things. * Tegge : Arp bug fixes. + * Florian : Removed many unnecessary functions, code cleanup + * and changes for new arp and skbuff. + * Alan Cox : Redid header building to reflect new format. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,40 +38,23 @@ #include #include #include -#include "inet.h" -#include "dev.h" -#include "eth.h" -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "tcp.h" -#include "skbuff.h" -#include "sock.h" +#include +#include +#include +#include #include #include "arp.h" - -/* Display an Ethernet address in readable format. */ -char *eth_print(unsigned char *ptr) -{ - static char buff[64]; - - if (ptr == NULL) return("[NONE]"); - sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", - (ptr[0] & 255), (ptr[1] & 255), (ptr[2] & 255), - (ptr[3] & 255), (ptr[4] & 255), (ptr[5] & 255) - ); - return(buff); -} - void eth_setup(char *str, int *ints) { struct device *d = dev_base; if (!str || !*str) return; - while (d) { - if (!strcmp(str,d->name)) { + while (d) + { + if (!strcmp(str,d->name)) + { if (ints[0] > 0) d->irq=ints[1]; if (ints[0] > 1) @@ -81,107 +69,102 @@ } } -/* Display the contents of the Ethernet MAC header. */ -void -eth_dump(struct ethhdr *eth) -{ - if (inet_debug != DBG_ETH) return; - - printk("eth: SRC = %s ", eth_print(eth->h_source)); - printk("DST = %s ", eth_print(eth->h_dest)); - printk("TYPE = %04X\n", ntohs(eth->h_proto)); -} - - -/* Create the Ethernet MAC header. */ -int -eth_header(unsigned char *buff, struct device *dev, unsigned short type, - unsigned long daddr, unsigned long saddr, unsigned len) -{ - struct ethhdr *eth; - - DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr))); - DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type)); - - /* Fill in the basic Ethernet MAC header. */ - eth = (struct ethhdr *) buff; - eth->h_proto = htons(type); - - /* We don't ARP for the LOOPBACK device... */ - if (dev->flags & IFF_LOOPBACK) { - DPRINTF((DBG_DEV, "ETH: No header for loopback\n")); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - memset(eth->h_dest, 0, dev->addr_len); - return(dev->hard_header_len); - } - - /* Check if we can use the MAC BROADCAST address. */ - if (chk_addr(daddr) == IS_BROADCAST) { - DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n")); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - memcpy(eth->h_dest, dev->broadcast, dev->addr_len); - return(dev->hard_header_len); - } - cli(); - memcpy(eth->h_source, &saddr, 4); - /* No. Ask ARP to resolve the Ethernet address. */ - if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr)) - { - sti(); - if(type!=ETH_P_IP) - printk("Erk: protocol %X got into an arp request state!\n",type); - return(-dev->hard_header_len); - } - else - { - memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the - header built correctly! */ - sti(); - return(dev->hard_header_len); - } -} - -/* Rebuild the Ethernet MAC header. */ -int -eth_rebuild_header(void *buff, struct device *dev) -{ - struct ethhdr *eth; - unsigned long src, dst; +/* + * Create the Ethernet MAC header for an arbitary protocol layer + * + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp) + */ - DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n")); - eth = (struct ethhdr *) buff; - src = *(unsigned long *) eth->h_source; - dst = *(unsigned long *) eth->h_dest; - DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src))); - DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst))); - if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */ - if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */)) return(1); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - return(0); +int eth_header(unsigned char *buff, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len, + struct sk_buff *skb) +{ + struct ethhdr *eth = (struct ethhdr *)buff; + + /* + * Set the protocol type. For a packet of type ETH_P_802_3 we put the length + * in here instead. It is up to the 802.2 layer to carry protocol information. + */ + + if(type!=ETH_P_802_3) + eth->h_proto = htons(type); + else + eth->h_proto = htons(len); + + /* + * Set the source hardware address. + */ + + if(saddr) + memcpy(eth->h_source,saddr,dev->addr_len); + else + memcpy(eth->h_source,dev->dev_addr,dev->addr_len); + + /* + * Anyway, the loopback-device should never use this function... + */ + + if (dev->flags & IFF_LOOPBACK) + { + memset(eth->h_dest, 0, dev->addr_len); + return(dev->hard_header_len); + } + + if(daddr) + { + memcpy(eth->h_dest,daddr,dev->addr_len); + return dev->hard_header_len; + } + + return -dev->hard_header_len; } -/* Add an ARP entry for a host on this interface. */ -void -eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev) -{ - struct ethhdr *eth; +/* + * Rebuild the Ethernet MAC header. This is called after an ARP + * (or in future other address resolution) has completed on this + * sk_buff. We now let ARP fill in the other fields. + */ + +int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst, + struct sk_buff *skb) +{ + struct ethhdr *eth = (struct ethhdr *)buff; + + /* + * Only ARP/IP is currently supported + */ + + if(eth->h_proto != htons(ETH_P_IP)) + { + printk("eth_rebuild_header: Don't know how to resolve type %d addreses?\n",(int)eth->h_proto); + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + return 0; + } - eth = (struct ethhdr *) skb->data; - arp_add(addr, eth->h_source, dev); + /* + * Try and get ARP to resolve the header. + */ + + return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; } -/* Determine the packet's protocol ID. */ -unsigned short -eth_type_trans(struct sk_buff *skb, struct device *dev) +/* + * Determine the packet's protocol ID. The rule here is that we + * assume 802.3 if the type field is short enough to be a length. + * This is normal practice and works for any 'now in use' protocol. + */ + +unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) { - struct ethhdr *eth; + struct ethhdr *eth = (struct ethhdr *) skb->data; - eth = (struct ethhdr *) skb->data; + if (ntohs(eth->h_proto) < 1536) + return htons(ETH_P_802_3); - if(ntohs(eth->h_proto)<1536) - return(htons(ETH_P_802_3)); - return(eth->h_proto); + return eth->h_proto; } + diff -u --recursive --new-file v1.1.3/linux/net/inet/icmp.c linux/net/inet/icmp.c --- v1.1.3/linux/net/inet/icmp.c Wed Apr 13 11:33:58 1994 +++ linux/net/inet/icmp.c Wed Apr 13 12:52:23 1994 @@ -10,16 +10,25 @@ * Authors: Ross Biro, * Fred N. van Kempen, * Mark Evans, + * Alan Cox, * * Fixes: * Alan Cox : Generic queue usage. * Gerhard Koerting: ICMP addressing corrected * Alan Cox : Use tos/ttl settings + * Alan Cox : Protocol violations + * Alan Cox : SNMP Statistics + * Alan Cox : Routing errors * + * + * FIXME: + * When 1.0.6 is out merge in the NET channel diffs for TIMESTAMP * + * * 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 +#include * 2 of the License, or (at your option) any later version. */ #include @@ -28,15 +37,16 @@ #include #include #include -#include -#include "inet.h" -#include "dev.h" +#include +#include +#include "snmp.h" #include "ip.h" #include "route.h" #include "protocol.h" #include "icmp.h" #include "tcp.h" -#include "skbuff.h" +#include "snmp.h" +#include #include "sock.h" #include #include @@ -47,6 +57,13 @@ #define min(a,b) ((a)<(b)?(a):(b)) +/* + * Statistics + */ + +struct icmp_mib icmp_statistics={0,}; + + /* An array of errno for error messages from dest unreach. */ struct icmp_err icmp_err_convert[] = { { ENETUNREACH, 1 }, /* ICMP_NET_UNREACH */ @@ -65,446 +82,646 @@ }; -/* Display the contents of an ICMP header. */ -static void -print_icmp(struct icmphdr *icmph) +/* + * Display the contents of an ICMP header. + */ + +static void print_icmp(struct icmphdr *icmph) { - if (inet_debug != DBG_ICMP) return; + if (inet_debug != DBG_ICMP) + return; - printk("ICMP: type = %d, code = %d, checksum = %X\n", + printk("ICMP: type = %d, code = %d, checksum = %X\n", icmph->type, icmph->code, icmph->checksum); - printk(" gateway = %s\n", in_ntoa(icmph->un.gateway)); + printk(" gateway = %s\n", in_ntoa(icmph->un.gateway)); } -/* Send an ICMP message. */ -void -icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) +/* + * Send an ICMP message in response to a situation + * + * Fixme: Fragment handling is wrong really. + */ + +void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) { - struct sk_buff *skb; - struct iphdr *iph; - int offset; - struct icmphdr *icmph; - int len; + struct sk_buff *skb; + struct iphdr *iph; + int offset; + struct icmphdr *icmph; + int len; + struct device *ndev=NULL; /* Make this =dev to force replies on the same interface */ - DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n", + DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n", skb_in, type, code, dev)); - /* Get some memory for the reply. */ - len = sizeof(struct sk_buff) + dev->hard_header_len + - sizeof(struct iphdr) + sizeof(struct icmphdr) + - sizeof(struct iphdr) + 8; /* amount of header to return */ + /* + * Find the original IP header. + */ + + iph = (struct iphdr *) (skb_in->data + dev->hard_header_len); + + /* + * We must NEVER NEVER send an ICMP error to an ICMP error message + */ + + if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED) + { + if(iph->protocol==IPPROTO_ICMP) + return; + + } + icmp_statistics.IcmpOutMsgs++; + + /* + * This needs a tidy. + */ + + switch(type) + { + case ICMP_DEST_UNREACH: + icmp_statistics.IcmpOutDestUnreachs++; + break; + case ICMP_SOURCE_QUENCH: + icmp_statistics.IcmpOutSrcQuenchs++; + break; + case ICMP_REDIRECT: + icmp_statistics.IcmpOutRedirects++; + break; + case ICMP_ECHO: + icmp_statistics.IcmpOutEchos++; + break; + case ICMP_ECHOREPLY: + icmp_statistics.IcmpOutEchoReps++; + break; + case ICMP_TIME_EXCEEDED: + icmp_statistics.IcmpOutTimeExcds++; + break; + case ICMP_PARAMETERPROB: + icmp_statistics.IcmpOutParmProbs++; + break; + case ICMP_TIMESTAMP: + icmp_statistics.IcmpOutTimestamps++; + break; + case ICMP_TIMESTAMPREPLY: + icmp_statistics.IcmpOutTimestampReps++; + break; + case ICMP_ADDRESS: + icmp_statistics.IcmpOutAddrMasks++; + break; + case ICMP_ADDRESSREPLY: + icmp_statistics.IcmpOutAddrMaskReps++; + break; + } + /* + * Get some memory for the reply. + */ + + len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) + + sizeof(struct iphdr) + 8; /* amount of header to return */ - skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC); - if (skb == NULL) - return; - - skb->sk = NULL; - skb->mem_addr = skb; - skb->mem_len = len; - len -= sizeof(struct sk_buff); - - /* Find the IP header. */ - iph = (struct iphdr *) (skb_in->data + dev->hard_header_len); - - /* Build Layer 2-3 headers for message back to source. */ - offset = ip_build_header(skb, dev->pa_addr, iph->saddr, - &dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255); - if (offset < 0) { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } + skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC); + if (skb == NULL) + { + icmp_statistics.IcmpOutErrors++; + return; + } + + /* + * Build Layer 2-3 headers for message back to source. + */ + + offset = ip_build_header(skb, dev->pa_addr, iph->saddr, + &ndev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255); + + if (offset < 0) + { + icmp_statistics.IcmpOutErrors++; + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return; + } - /* Re-adjust length according to actual IP header size. */ - skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8; - icmph = (struct icmphdr *) (skb->data + offset); - icmph->type = type; - icmph->code = code; - icmph->checksum = 0; - icmph->un.gateway = 0; - memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8); + /* + * Re-adjust length according to actual IP header size. + */ + + skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8; + + /* + * Fill in the frame + */ + + icmph = (struct icmphdr *) (skb->data + offset); + icmph->type = type; + icmph->code = code; + icmph->checksum = 0; + icmph->un.gateway = 0; + memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8); - icmph->checksum = ip_compute_csum((unsigned char *)icmph, + icmph->checksum = ip_compute_csum((unsigned char *)icmph, sizeof(struct icmphdr) + sizeof(struct iphdr) + 8); - DPRINTF((DBG_ICMP, ">>\n")); - print_icmp(icmph); + DPRINTF((DBG_ICMP, ">>\n")); + print_icmp(icmph); - /* Send it and free it. */ - ip_queue_xmit(NULL, dev, skb, 1); + /* + * Send it and free it once sent. + */ + ip_queue_xmit(NULL, dev, skb, 1); } -/* Handle ICMP_UNREACH and ICMP_QUENCH. */ -static void -icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) +/* + * Handle ICMP_UNREACH and ICMP_QUENCH. + */ + +static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) { - struct inet_protocol *ipprot; - struct iphdr *iph; - unsigned char hash; - int err; - - err = (icmph->type << 8) | icmph->code; - iph = (struct iphdr *) (icmph + 1); - switch(icmph->code & 7) { - case ICMP_NET_UNREACH: - DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n", + struct inet_protocol *ipprot; + struct iphdr *iph; + unsigned char hash; + int err; + + err = (icmph->type << 8) | icmph->code; + iph = (struct iphdr *) (icmph + 1); + + switch(icmph->code & 7) + { + case ICMP_NET_UNREACH: + DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n", + in_ntoa(iph->daddr))); + break; + case ICMP_HOST_UNREACH: + DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n", in_ntoa(iph->daddr))); - break; - case ICMP_HOST_UNREACH: - DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n", - in_ntoa(iph->daddr))); - break; - case ICMP_PROT_UNREACH: - printk("ICMP: %s:%d: protocol unreachable.\n", - in_ntoa(iph->daddr), ntohs(iph->protocol)); - break; - case ICMP_PORT_UNREACH: - DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n", - in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */)); - break; - case ICMP_FRAG_NEEDED: - printk("ICMP: %s: fragmentation needed and DF set.\n", - in_ntoa(iph->daddr)); - break; - case ICMP_SR_FAILED: - printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)); - break; - default: - DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n", - (icmph->code & 7), in_ntoa(iph->daddr))); - break; - } - - /* Get the protocol(s). */ - hash = iph->protocol & (MAX_INET_PROTOS -1); - - /* This can change while we are doing it. */ - ipprot = (struct inet_protocol *) inet_protos[hash]; - while(ipprot != NULL) { - struct inet_protocol *nextip; - - nextip = (struct inet_protocol *) ipprot->next; - - /* Pass it off to everyone who wants it. */ - if (iph->protocol == ipprot->protocol && ipprot->err_handler) { - ipprot->err_handler(err, (unsigned char *)(icmph + 1), - iph->daddr, iph->saddr, ipprot); + break; + case ICMP_PROT_UNREACH: + printk("ICMP: %s:%d: protocol unreachable.\n", + in_ntoa(iph->daddr), ntohs(iph->protocol)); + break; + case ICMP_PORT_UNREACH: + DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n", + in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */)); + break; + case ICMP_FRAG_NEEDED: + printk("ICMP: %s: fragmentation needed and DF set.\n", + in_ntoa(iph->daddr)); + break; + case ICMP_SR_FAILED: + printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)); + break; + default: + DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n", + (icmph->code & 7), in_ntoa(iph->daddr))); + break; } - ipprot = nextip; - } - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + /* + * Get the protocol(s). + */ + + hash = iph->protocol & (MAX_INET_PROTOS -1); + + /* + * This can't change while we are doing it. + */ + + ipprot = (struct inet_protocol *) inet_protos[hash]; + while(ipprot != NULL) + { + struct inet_protocol *nextip; + + nextip = (struct inet_protocol *) ipprot->next; + + /* + * Pass it off to everyone who wants it. + */ + if (iph->protocol == ipprot->protocol && ipprot->err_handler) + { + ipprot->err_handler(err, (unsigned char *)(icmph + 1), + iph->daddr, iph->saddr, ipprot); + } + + ipprot = nextip; + } + kfree_skb(skb, FREE_READ); } -/* Handle ICMP_REDIRECT. */ -static void -icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev) +/* + * Handle ICMP_REDIRECT. + */ + +static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev) { - struct iphdr *iph; - unsigned long ip; + struct iphdr *iph; + unsigned long ip; - iph = (struct iphdr *) (icmph + 1); - ip = iph->daddr; - switch(icmph->code & 7) { - case ICMP_REDIR_NET: + /* + * Get the copied header of the packet that caused the redirect + */ + + iph = (struct iphdr *) (icmph + 1); + ip = iph->daddr; + + switch(icmph->code & 7) + { + case ICMP_REDIR_NET: + /* + * This causes a problem with subnetted networks. What we should do + * is use ICMP_ADDRESS to get the subnet mask of the problem route + * and set both. But we don't.. + */ #ifdef not_a_good_idea - rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev); - break; + ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), + ip, 0, icmph->un.gateway, dev); + break; #endif - case ICMP_REDIR_HOST: - rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev); - break; - case ICMP_REDIR_NETTOS: - case ICMP_REDIR_HOSTTOS: - printk("ICMP: cannot handle TOS redirects yet!\n"); - break; - default: - DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n", + case ICMP_REDIR_HOST: + /* + * Add better route to host + */ + ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), + ip, 0, icmph->un.gateway, dev); + break; + case ICMP_REDIR_NETTOS: + case ICMP_REDIR_HOSTTOS: + printk("ICMP: cannot handle TOS redirects yet!\n"); + break; + default: + DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n", (icmph->code & 7))); break; - } - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + } + + /* + * Discard the original packet + */ + + kfree_skb(skb, FREE_READ); } -/* Handle ICMP_ECHO ("ping") requests. */ -static void -icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, +/* + * Handle ICMP_ECHO ("ping") requests. + */ + +static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, unsigned long saddr, unsigned long daddr, int len, struct options *opt) { - struct icmphdr *icmphr; - struct sk_buff *skb2; - int size, offset; - - size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; - skb2 = alloc_skb(size, GFP_ATOMIC); - if (skb2 == NULL) { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - skb2->sk = NULL; - skb2->mem_addr = skb2; - skb2->mem_len = size; - skb2->free = 1; - - /* Build Layer 2-3 headers for message back to source */ - offset = ip_build_header(skb2, daddr, saddr, &dev, - IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); - if (offset < 0) { - printk("ICMP: Could not build IP Header for ICMP ECHO Response\n"); - kfree_skb(skb2,FREE_WRITE); - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - - /* Re-adjust length according to actual IP header size. */ - skb2->len = offset + len; - - /* Build ICMP_ECHO Response message. */ - icmphr = (struct icmphdr *) (skb2->data + offset); - memcpy((char *) icmphr, (char *) icmph, len); - icmphr->type = ICMP_ECHOREPLY; - icmphr->code = 0; - icmphr->checksum = 0; - icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len); + struct icmphdr *icmphr; + struct sk_buff *skb2; + struct device *ndev=NULL; + int size, offset; + + icmp_statistics.IcmpOutEchoReps++; + icmp_statistics.IcmpOutMsgs++; + + size = dev->hard_header_len + 64 + len; + skb2 = alloc_skb(size, GFP_ATOMIC); + + if (skb2 == NULL) + { + icmp_statistics.IcmpOutErrors++; + kfree_skb(skb, FREE_READ); + return; + } + skb2->free = 1; - /* Ship it out - free it when done */ - ip_queue_xmit((struct sock *)NULL, dev, skb2, 1); + /* Build Layer 2-3 headers for message back to source */ + offset = ip_build_header(skb2, daddr, saddr, &ndev, + IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); + if (offset < 0) + { + icmp_statistics.IcmpOutErrors++; + printk("ICMP: Could not build IP Header for ICMP ECHO Response\n"); + kfree_skb(skb2,FREE_WRITE); + kfree_skb(skb, FREE_READ); + return; + } - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + /* + * Re-adjust length according to actual IP header size. + */ + + skb2->len = offset + len; + + /* + * Build ICMP_ECHO Response message. + */ + icmphr = (struct icmphdr *) (skb2->data + offset); + memcpy((char *) icmphr, (char *) icmph, len); + icmphr->type = ICMP_ECHOREPLY; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len); + + /* + * Ship it out - free it when done + */ + ip_queue_xmit((struct sock *)NULL, dev, skb2, 1); + + /* + * Free the received frame + */ + + kfree_skb(skb, FREE_READ); } - -/* Handle ICMP Timestamp requests. */ -static void -icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, +/* + * Handle ICMP Timestamp requests. + */ + +static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, unsigned long saddr, unsigned long daddr, int len, struct options *opt) { - struct icmphdr *icmphr; - struct sk_buff *skb2; - int size, offset; - unsigned long *timeptr, midtime; - extern struct timeval xtime; /* kernel/time.c */ - - size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; - if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - skb2->sk = NULL; - skb2->mem_addr = skb2; - skb2->mem_len = size; - skb2->free = 1; - - /* Build Layer 2-3 headers for message back to source */ - offset = ip_build_header(skb2, daddr, saddr, &dev, IPPROTO_ICMP, opt, len, + struct icmphdr *icmphr; + struct sk_buff *skb2; + int size, offset; + unsigned long *timeptr, midtime; + extern struct timeval xtime; /* kernel/time.c */ + struct device *ndev=NULL; + + size = dev->hard_header_len + 64 + len; + + if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) + { + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + icmp_statistics.IcmpOutErrors++; + return; + } + skb2->free = 1; + +/* + * Build Layer 2-3 headers for message back to source + */ + + offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, skb->ip_hdr->tos, 255); - if (offset < 0) { - printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n"); - kfree_skb(skb2, FREE_WRITE); - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - - /* Re-adjust length according to actual IP header size. */ - skb2->len = offset + len; - - /* Build ICMP_TIMESTAMP Response message. */ - icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset); - memcpy((char *) icmphr, (char *) icmph, len); - icmphr->type = ICMP_TIMESTAMPREPLY; - icmphr->code = icmphr->checksum = 0; - - /* fill in the current time as ms since midnight UT: */ - midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000; - timeptr = (unsigned long *) (icmphr + 1); - /* the originate timestamp (timeptr [0]) is still in the copy: */ - timeptr [1] = timeptr [2] = htonl(midtime); - - icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, len); - - /* Ship it out - free it when done */ - ip_queue_xmit((struct sock *) NULL, dev, skb2, 1); + if (offset < 0) + { + printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n"); + kfree_skb(skb2, FREE_WRITE); + kfree_skb(skb, FREE_READ); + icmp_statistics.IcmpOutErrors++; + return; + } + + /* + * Re-adjust length according to actual IP header size. + */ + skb2->len = offset + len; + + /* + * Build ICMP_TIMESTAMP Response message. + */ + + icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset); + memcpy((char *) icmphr, (char *) icmph, len); + icmphr->type = ICMP_TIMESTAMPREPLY; + icmphr->code = icmphr->checksum = 0; + + /* fill in the current time as ms since midnight UT: */ + midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000; + timeptr = (unsigned long *) (icmphr + 1); + /* + * the originate timestamp (timeptr [0]) is still in the copy: + */ + timeptr [1] = timeptr [2] = htonl(midtime); + + icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, len); + + /* + * Ship it out - free it when done + */ - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + ip_queue_xmit((struct sock *) NULL, dev, skb2, 1); + icmp_statistics.IcmpOutTimestampReps++; + kfree_skb(skb, FREE_READ); } + + -/* Handle the ICMP INFORMATION REQUEST. */ -static void -icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, +/* + * Handle the ICMP INFORMATION REQUEST. + */ + +static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, unsigned long saddr, unsigned long daddr, int len, struct options *opt) { - /* NOT YET */ - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + /* Obsolete */ + kfree_skb(skb, FREE_READ); } -/* Handle ICMP_ADRESS_MASK requests. */ -static void -icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, +/* + * Handle ICMP_ADRESS_MASK requests. + */ + +static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, unsigned long saddr, unsigned long daddr, int len, struct options *opt) { - struct icmphdr *icmphr; - struct sk_buff *skb2; - int size, offset; - - size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; - skb2 = alloc_skb(size, GFP_ATOMIC); - if (skb2 == NULL) { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - skb2->sk = NULL; - skb2->mem_addr = skb2; - skb2->mem_len = size; - skb2->free = 1; - - /* Build Layer 2-3 headers for message back to source */ - offset = ip_build_header(skb2, daddr, saddr, &dev, - IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); - if (offset < 0) { - printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n"); - kfree_skb(skb2,FREE_WRITE); - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - - /* Re-adjust length according to actual IP header size. */ - skb2->len = offset + len; + struct icmphdr *icmphr; + struct sk_buff *skb2; + int size, offset; + struct device *ndev=NULL; + + icmp_statistics.IcmpOutMsgs++; + icmp_statistics.IcmpOutAddrMaskReps++; + + size = dev->hard_header_len + 64 + len; + skb2 = alloc_skb(size, GFP_ATOMIC); + if (skb2 == NULL) + { + icmp_statistics.IcmpOutErrors++; + kfree_skb(skb, FREE_READ); + return; + } + skb2->free = 1; + + /* + * Build Layer 2-3 headers for message back to source + */ + + offset = ip_build_header(skb2, daddr, saddr, &ndev, + IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); + if (offset < 0) + { + icmp_statistics.IcmpOutErrors++; + printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n"); + kfree_skb(skb2,FREE_WRITE); + kfree_skb(skb, FREE_READ); + return; + } - /* Build ICMP ADDRESS MASK Response message. */ - icmphr = (struct icmphdr *) (skb2->data + offset); - icmphr->type = ICMP_ADDRESSREPLY; - icmphr->code = 0; - icmphr->checksum = 0; - icmphr->un.echo.id = icmph->un.echo.id; - icmphr->un.echo.sequence = icmph->un.echo.sequence; - memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask)); + /* + * Re-adjust length according to actual IP header size. + */ + + skb2->len = offset + len; + + /* + * Build ICMP ADDRESS MASK Response message. + */ + + icmphr = (struct icmphdr *) (skb2->data + offset); + icmphr->type = ICMP_ADDRESSREPLY; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->un.echo.id = icmph->un.echo.id; + icmphr->un.echo.sequence = icmph->un.echo.sequence; + memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask)); - icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len); + icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len); - /* Ship it out - free it when done */ - ip_queue_xmit((struct sock *)NULL, dev, skb2, 1); + /* Ship it out - free it when done */ + ip_queue_xmit((struct sock *)NULL, dev, skb2, 1); - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + skb->sk = NULL; + kfree_skb(skb, FREE_READ); } -/* Deal with incoming ICMP packets. */ -int -icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, +/* + * Deal with incoming ICMP packets. + */ + +int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, unsigned long daddr, unsigned short len, unsigned long saddr, int redo, struct inet_protocol *protocol) { - struct icmphdr *icmph; - unsigned char *buff; + struct icmphdr *icmph; + unsigned char *buff; - /* Drop broadcast packets. */ - if (chk_addr(daddr) == IS_BROADCAST) { - DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n", + /* + * Drop broadcast packets. IP has done a broadcast check and ought one day + * to pass on that information. + */ + + icmp_statistics.IcmpInMsgs++; + + if (ip_chk_addr(daddr) == IS_BROADCAST) + { + DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n", in_ntoa(saddr))); - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(0); - } - - buff = skb1->h.raw; - icmph = (struct icmphdr *) buff; - - /* Validate the packet first */ - if (ip_compute_csum((unsigned char *) icmph, len)) { - /* Failed checksum! */ - printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr)); - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(0); - } - print_icmp(icmph); - - /* Parse the ICMP message */ - switch(icmph->type) { - case ICMP_TIME_EXCEEDED: - case ICMP_DEST_UNREACH: - case ICMP_SOURCE_QUENCH: - icmp_unreach(icmph, skb1); - return(0); - case ICMP_REDIRECT: - icmp_redirect(icmph, skb1, dev); - return(0); - case ICMP_ECHO: - icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_ECHOREPLY: - skb1->sk = NULL; + icmp_statistics.IcmpInErrors++; kfree_skb(skb1, FREE_READ); return(0); - case ICMP_TIMESTAMP: - icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_TIMESTAMPREPLY: - skb1->sk = NULL; + } + + /* + * Grab the packet as an icmp object + */ + + buff = skb1->h.raw; + icmph = (struct icmphdr *) buff; + + /* + * Validate the packet first + */ + + if (ip_compute_csum((unsigned char *) icmph, len)) + { + /* Failed checksum! */ + icmp_statistics.IcmpInErrors++; + printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr)); kfree_skb(skb1, FREE_READ); return(0); - case ICMP_INFO_REQUEST: - icmp_info(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_INFO_REPLY: - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(0); - case ICMP_ADDRESS: - icmp_address(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_ADDRESSREPLY: - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(0); - default: - DPRINTF((DBG_ICMP, - "ICMP: Unsupported ICMP from %s, type = 0x%X\n", - in_ntoa(saddr), icmph->type)); - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(0); - } + } + print_icmp(icmph); + + /* + * Parse the ICMP message + */ + + switch(icmph->type) + { + case ICMP_TIME_EXCEEDED: + icmp_statistics.IcmpInTimeExcds++; + icmp_unreach(icmph, skb1); + return 0; + case ICMP_DEST_UNREACH: + icmp_statistics.IcmpInDestUnreachs++; + icmp_unreach(icmph, skb1); + return 0; + case ICMP_SOURCE_QUENCH: + icmp_statistics.IcmpInSrcQuenchs++; + icmp_unreach(icmph, skb1); + return(0); + case ICMP_REDIRECT: + icmp_statistics.IcmpInRedirects++; + icmp_redirect(icmph, skb1, dev); + return(0); + case ICMP_ECHO: + icmp_statistics.IcmpInEchos++; + icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_ECHOREPLY: + icmp_statistics.IcmpInEchoReps++; + kfree_skb(skb1, FREE_READ); + return(0); + case ICMP_TIMESTAMP: + icmp_statistics.IcmpInTimestamps++; + icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_TIMESTAMPREPLY: + icmp_statistics.IcmpInTimestampReps++; + kfree_skb(skb1,FREE_READ); + return 0; + /* INFO is obsolete and doesn't even feature in the SNMP stats */ + case ICMP_INFO_REQUEST: + icmp_info(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_INFO_REPLY: + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(0); + case ICMP_ADDRESS: + icmp_statistics.IcmpInAddrMasks++; + icmp_address(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_ADDRESSREPLY: + /* + * We ought to set our netmask on receiving this, but + * experience shows its a waste of effort. + */ + icmp_statistics.IcmpInAddrMaskReps++; + kfree_skb(skb1, FREE_READ); + return(0); + default: + icmp_statistics.IcmpInErrors++; + DPRINTF((DBG_ICMP, + "ICMP: Unsupported ICMP from %s, type = 0x%X\n", + in_ntoa(saddr), icmph->type)); + kfree_skb(skb1, FREE_READ); + return(0); + } /*NOTREACHED*/ - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(-1); + kfree_skb(skb1, FREE_READ); + return(-1); } -/* Perform any ICMP-related I/O control requests. */ -int -icmp_ioctl(struct sock *sk, int cmd, unsigned long arg) +/* + * Perform any ICMP-related I/O control requests. + * [to vanish soon] + */ + +int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - switch(cmd) { - case DDIOCSDBG: - return(dbg_ioctl((void *) arg, DBG_ICMP)); - default: - return(-EINVAL); - } - return(0); + switch(cmd) + { + case DDIOCSDBG: + return(dbg_ioctl((void *) arg, DBG_ICMP)); + default: + return(-EINVAL); + } + return(0); } diff -u --recursive --new-file v1.1.3/linux/net/inet/icmp.h linux/net/inet/icmp.h --- v1.1.3/linux/net/inet/icmp.h Wed Dec 1 14:44:15 1993 +++ linux/net/inet/icmp.h Wed Apr 13 12:52:23 1994 @@ -22,6 +22,8 @@ extern struct icmp_err icmp_err_convert[]; +extern struct icmp_mib icmp_statistics; + extern void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev); diff -u --recursive --new-file v1.1.3/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.3/linux/net/inet/ip.c Wed Apr 13 11:33:59 1994 +++ linux/net/inet/ip.c Wed Apr 13 12:52:24 1994 @@ -45,6 +45,11 @@ * Alan Cox : handling. * Gerhard Koerting: Forwarding uses IP priority hints * Teemu Rantanen : Fragment problems. + * Alan Cox : General cleanup, comments and reformat + * Alan Cox : SNMP statistics + * Alan Cox : BSD address rule semantics. Also see + * UDP as there is a nasty checksum issue + * if you do things the wrong way. * * To Fix: * IP option processing is mostly not needed. ip_forward needs to know about routing rules @@ -65,14 +70,15 @@ #include #include #include -#include "inet.h" -#include "dev.h" -#include "eth.h" +#include +#include +#include +#include "snmp.h" #include "ip.h" #include "protocol.h" #include "route.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include "arp.h" #include "icmp.h" @@ -85,63 +91,93 @@ #define min(a,b) ((a)<(b)?(a):(b)) -void -ip_print(struct iphdr *ip) +/* + * SNMP management statistics + */ + +struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */ + +/* + * Print an IP packet for debugging purposes. + * + * This function is exported for the IP + * upper layers to use also. + */ + +void ip_print(const struct iphdr *ip) { - unsigned char buff[32]; - unsigned char *ptr; - int addr, len, i; + unsigned char buff[32]; + unsigned char *ptr; + int addr; + int len; + int i; - if (inet_debug != DBG_IP) return; + /* Are we debugging IP frames */ + + if (inet_debug != DBG_IP) + return; - /* Dump the IP header. */ - printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n", - ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len)); - printk(" id=%X, ttl=%d, prot=%d, check=%X\n", - ip->id, ip->ttl, ip->protocol, ip->check); - printk(" frag_off=%d\n", ip->frag_off); - printk(" soucre=%s ", in_ntoa(ip->saddr)); - printk("dest=%s\n", in_ntoa(ip->daddr)); - printk(" ----\n"); - - /* Dump the data. */ - ptr = (unsigned char *)(ip + 1); - addr = 0; - len = ntohs(ip->tot_len) - (4 * ip->ihl); - while (len > 0) { - printk(" %04X: ", addr); - for(i = 0; i < 16; i++) { - if (len > 0) { - printk("%02X ", (*ptr & 0xFF)); - buff[i] = *ptr++; - if (buff[i] < 32 || buff[i] > 126) buff[i] = '.'; - } else { - printk(" "); - buff[i] = ' '; - } - addr++; - len--; - }; - buff[i] = '\0'; - printk(" \"%s\"\n", buff); - } - printk(" ----\n\n"); + /* Dump the IP header. */ + printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n", + ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len)); + printk(" id=%X, ttl=%d, prot=%d, check=%X\n", + ip->id, ip->ttl, ip->protocol, ip->check); + printk(" frag_off=%d\n", ip->frag_off); + printk(" soucre=%s ", in_ntoa(ip->saddr)); + printk("dest=%s\n", in_ntoa(ip->daddr)); + printk(" ----\n"); + + /* Dump the data. */ + ptr = (unsigned char *)(ip + 1); + addr = 0; + len = ntohs(ip->tot_len) - (4 * ip->ihl); + + while (len > 0) + { + printk(" %04X: ", addr); + for(i = 0; i < 16; i++) + { + if (len > 0) + { + printk("%02X ", (*ptr & 0xFF)); + buff[i] = *ptr++; + if (buff[i] < 32 || buff[i] > 126) + buff[i] = '.'; + } + else + { + printk(" "); + buff[i] = ' '; + } + addr++; + len--; + }; + buff[i] = '\0'; + printk(" \"%s\"\n", buff); + } + printk(" ----\n\n"); } +/* + * Handle the issuing of an ioctl() request + * for the ip device. This is scheduled to + * disappear + */ -int -ip_ioctl(struct sock *sk, int cmd, unsigned long arg) +int ip_ioctl(struct sock *sk, int cmd, unsigned long arg) { - switch(cmd) { - case DDIOCSDBG: - return(dbg_ioctl((void *) arg, DBG_IP)); - default: - return(-EINVAL); - } + switch(cmd) + { + case DDIOCSDBG: + return(dbg_ioctl((void *) arg, DBG_IP)); + default: + return(-EINVAL); + } } -/* these two routines will do routining. */ +/* these two routines will do routing. */ + static void strict_route(struct iphdr *iph, struct options *opt) { @@ -183,26 +219,31 @@ #endif -/* Take an skb, and fill in the MAC header. */ -static int -ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, - unsigned long saddr) +/* + * Take an skb, and fill in the MAC header. + */ + +static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr) { - unsigned char *ptr; - int mac; + int mac = 0; - ptr = skb->data; - mac = 0; - skb->arp = 1; - if (dev->hard_header) { - mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len); - } - if (mac < 0) { - mac = -mac; - skb->arp = 0; - } - skb->dev = dev; - return(mac); + skb->dev = dev; + skb->arp = 1; + if (dev->hard_header) + { + /* + * Build a hardware header. Source address is our mac, destination unknown + * (rebuild header will sort this out) + */ + mac = dev->hard_header(skb->data, dev, ETH_P_IP, NULL, NULL, len, skb); + if (mac < 0) + { + mac = -mac; + skb->arp = 0; + skb->raddr = daddr; /* next routing address */ + } + } + return mac; } @@ -212,81 +253,124 @@ * protocol knows what it's doing, otherwise it uses the * routing/ARP tables to select a device struct. */ -int -ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, +int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, struct device **dev, int type, struct options *opt, int len, int tos, int ttl) { - static struct options optmem; - struct iphdr *iph; - struct rtable *rt; - unsigned char *buff; - unsigned long raddr; - static int count = 0; - int tmp; + static struct options optmem; + struct iphdr *iph; + struct rtable *rt; + unsigned char *buff; + unsigned long raddr; + static int count = 0; + int tmp; + unsigned long src; - if (saddr == 0) - saddr = my_addr(); - - DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n" - " type=%d, opt=%X, len = %d)\n", - skb, saddr, daddr, *dev, type, opt, len)); + /* + * If there is no 'from' address as yet, then make it our loopback + */ + + if (saddr == 0) + saddr = ip_my_addr(); + + DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n" + " type=%d, opt=%X, len = %d)\n", + skb, saddr, daddr, *dev, type, opt, len)); - buff = skb->data; + buff = skb->data; - /* See if we need to look up the device. */ - if (*dev == NULL) { - rt = rt_route(daddr, &optmem); - if (rt == NULL) - return(-ENETUNREACH); + /* + * See if we need to look up the device. + */ + + if (*dev == NULL) + { + rt = ip_rt_route(daddr, &optmem, &src); + if (rt == NULL) + { + ip_statistics.IpOutNoRoutes++; + return(-ENETUNREACH); + } + + *dev = rt->rt_dev; + /* + * 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) + saddr = src;/*rt->rt_dev->pa_addr;*/ + raddr = rt->rt_gateway; - *dev = rt->rt_dev; - if (saddr == 0x0100007FL && daddr != 0x0100007FL) - saddr = rt->rt_dev->pa_addr; - raddr = rt->rt_gateway; + DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr))); + opt = &optmem; + } + else + { + /* + * We still need the address of the first hop. + */ + rt = ip_rt_route(daddr, &optmem, &src); + /* + * 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) + saddr = src;/*rt->rt_dev->pa_addr;*/ - DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr))); - opt = &optmem; - } else { - /* We still need the address of the first hop. */ - rt = rt_route(daddr, &optmem); - raddr = (rt == NULL) ? 0 : rt->rt_gateway; - } - if (raddr == 0) - raddr = daddr; + raddr = (rt == NULL) ? 0 : rt->rt_gateway; + } + + /* + * No gateway so aim at the real destination + */ + if (raddr == 0) + raddr = daddr; + + /* + * Now build the MAC header. + */ + + tmp = ip_send(skb, raddr, len, *dev, saddr); + buff += tmp; + len -= tmp; + + /* + * Book keeping + */ + + skb->dev = *dev; + skb->saddr = saddr; + if (skb->sk) + skb->sk->saddr = saddr; + + /* + * Now build the IP header. + */ - /* Now build the MAC header. */ - tmp = ip_send(skb, raddr, len, *dev, saddr); - buff += tmp; - len -= tmp; - - skb->dev = *dev; - skb->saddr = saddr; - if (skb->sk) skb->sk->saddr = saddr; - - /* Now build the IP header. */ - - /* If we are using IPPROTO_RAW, then we don't need an IP header, since - one is being supplied to us by the user */ - - if(type == IPPROTO_RAW) return (tmp); - - iph = (struct iphdr *)buff; - iph->version = 4; - iph->tos = tos; - iph->frag_off = 0; - iph->ttl = ttl; - iph->daddr = daddr; - iph->saddr = saddr; - iph->protocol = type; - iph->ihl = 5; - iph->id = htons(count++); + /* + * If we are using IPPROTO_RAW, then we don't need an IP header, since + * one is being supplied to us by the user + */ + + if(type == IPPROTO_RAW) + return (tmp); + + iph = (struct iphdr *)buff; + iph->version = 4; + iph->tos = tos; + iph->frag_off = 0; + iph->ttl = ttl; + iph->daddr = daddr; + iph->saddr = saddr; + iph->protocol = type; + iph->ihl = 5; + iph->id = htons(count++); - /* Setup the IP options. */ + /* Setup the IP options. */ #ifdef Not_Yet_Avail - build_options(iph, opt); + build_options(iph, opt); #endif - return(20 + tmp); /* IP header plus MAC header size */ + return(20 + tmp); /* IP header plus MAC header size */ } @@ -437,14 +521,17 @@ return(0); } -/* This is a version of ip_compute_csum() optimized for IP headers, which - always checksum on 4 octet boundaries. */ -static inline unsigned short -ip_fast_csum(unsigned char * buff, int wlen) +/* + * This is a version of ip_compute_csum() optimized for IP headers, which + * always checksum on 4 octet boundaries. + */ + +static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen) { - unsigned long sum = 0; + unsigned long sum = 0; - if (wlen) { + if (wlen) + { unsigned long bogus; __asm__("clc\n" "1:\t" @@ -459,22 +546,23 @@ "adcw $0, %w0" : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus) : "0" (sum), "1" (buff), "2" (wlen)); - } - return (~sum) & 0xffff; + } + return (~sum) & 0xffff; } /* * This routine does all the checksum computations that don't * require anything special (like copying or special headers). */ -unsigned short -ip_compute_csum(unsigned char * buff, int len) + +unsigned short ip_compute_csum(unsigned char * buff, int len) { - unsigned long sum = 0; + unsigned long sum = 0; - /* Do the first multiple of 4 bytes and convert to 16 bits. */ - if (len > 3) { - __asm__("clc\n" + /* Do the first multiple of 4 bytes and convert to 16 bits. */ + if (len > 3) + { + __asm__("clc\n" "1:\t" "lodsl\n\t" "adcl %%eax, %%ebx\n\t" @@ -487,47 +575,63 @@ : "=b" (sum) , "=S" (buff) : "0" (sum), "c" (len >> 2) ,"1" (buff) : "ax", "cx", "si", "bx" ); - } - if (len & 2) { - __asm__("lodsw\n\t" + } + if (len & 2) + { + __asm__("lodsw\n\t" "addw %%ax, %%bx\n\t" "adcw $0, %%bx" : "=b" (sum), "=S" (buff) : "0" (sum), "1" (buff) : "bx", "ax", "si"); - } - if (len & 1) { - __asm__("lodsb\n\t" + } + if (len & 1) + { + __asm__("lodsb\n\t" "movb $0, %%ah\n\t" "addw %%ax, %%bx\n\t" "adcw $0, %%bx" : "=b" (sum), "=S" (buff) : "0" (sum), "1" (buff) : "bx", "ax", "si"); - } - sum =~sum; - return(sum & 0xffff); + } + sum =~sum; + return(sum & 0xffff); } -/* Check the header of an incoming IP datagram. This version is still used in slhc.c. */ -int -ip_csum(struct iphdr *iph) +/* + * Check the header of an incoming IP datagram. This version is still used in slhc.c. + */ + +int ip_csum(struct iphdr *iph) { - return ip_fast_csum((unsigned char *)iph, iph->ihl); + return ip_fast_csum((unsigned char *)iph, iph->ihl); } -/* Generate a checksym for an outgoing IP datagram. */ -static void -ip_send_check(struct iphdr *iph) +/* + * Generate a checksym for an outgoing IP datagram. + */ + +static void ip_send_check(struct iphdr *iph) { - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } /************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/ + +/* + * This fragment handler is a bit of a heap. On the other hand it works quite + * happily and handles things quite well. + */ + static struct ipq *ipqueue = NULL; /* IP fragment queue */ - /* Create a new fragment entry. */ + +/* + * Create a new fragment entry. + */ + static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr) { struct ipfrag *fp; @@ -552,9 +656,10 @@ /* - * Find the correct entry in the "incomplete datagrams" queue for - * this IP datagram, and return the queue entry address if found. + * Find the correct entry in the "incomplete datagrams" queue for + * this IP datagram, and return the queue entry address if found. */ + static struct ipq *ip_find(struct iphdr *iph) { struct ipq *qp; @@ -567,7 +672,7 @@ if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr && iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol) { - del_timer(&qp->timer); /* So it doesnt vanish on us. The timer will be reset anyway */ + del_timer(&qp->timer); /* So it doesn't vanish on us. The timer will be reset anyway */ sti(); return(qp); } @@ -578,9 +683,9 @@ /* - * Remove an entry from the "incomplete datagrams" queue, either - * because we completed, reassembled and processed it, or because - * it timed out. + * Remove an entry from the "incomplete datagrams" queue, either + * because we completed, reassembled and processed it, or because + * it timed out. */ static void ip_free(struct ipq *qp) @@ -588,8 +693,10 @@ struct ipfrag *fp; struct ipfrag *xp; - /* Stop the timer for this entry. */ -/* printk("ip_free\n");*/ + /* + * Stop the timer for this entry. + */ + del_timer(&qp->timer); /* Remove this entry from the "incomplete datagrams" queue. */ @@ -608,7 +715,7 @@ } /* Release all fragment data. */ -/* printk("ip_free: kill frag data\n");*/ + fp = qp->fragments; while (fp != NULL) { @@ -619,8 +726,6 @@ fp = xp; } -/* printk("ip_free: cleanup\n");*/ - /* Release the MAC header. */ kfree_s(qp->mac, qp->maclen); @@ -634,7 +739,9 @@ } - /* Oops- a fragment queue timed out. Kill it and send an ICMP reply. */ +/* + * Oops- a fragment queue timed out. Kill it and send an ICMP reply. + */ static void ip_expire(unsigned long arg) { @@ -643,25 +750,29 @@ qp = (struct ipq *)arg; DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp)); - /* Send an ICMP "Fragment Reassembly Timeout" message. */ -#if 0 - icmp_send(qp->iph->ip_src.s_addr, ICMP_TIME_EXCEEDED, - ICMP_EXC_FRAGTIME, qp->iph); -#endif + /* + * Send an ICMP "Fragment Reassembly Timeout" message. + */ + + ip_statistics.IpReasmTimeout++; + ip_statistics.IpReasmFails++; + /* This if is always true... shrug */ if(qp->fragments!=NULL) icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, qp->dev); - /* Nuke the fragment queue. */ + /* + * Nuke the fragment queue. + */ ip_free(qp); } /* - * Add an entry to the 'ipq' queue for a newly received IP datagram. - * We will (hopefully :-) receive all other fragments of this datagram - * in time, so we just create a queue for this datagram, in which we - * will insert the received fragments at their respective positions. + * Add an entry to the 'ipq' queue for a newly received IP datagram. + * We will (hopefully :-) receive all other fragments of this datagram + * in time, so we just create a queue for this datagram, in which we + * will insert the received fragments at their respective positions. */ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev) @@ -675,10 +786,17 @@ { printk("IP: create: no memory left !\n"); return(NULL); + skb->dev = qp->dev; } memset(qp, 0, sizeof(struct ipq)); - /* Allocate memory for the MAC header. */ + /* + * Allocate memory for the MAC header. + * + * FIXME: We have a maximum MAC address size limit and define + * elsewhere. We should use it here and avoid the 3 kmalloc() calls + */ + maclen = ((unsigned long) iph) - ((unsigned long) skb->data); qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC); if (qp->mac == NULL) @@ -688,7 +806,10 @@ return(NULL); } - /* Allocate memory for the IP header (plus 8 octects for ICMP). */ + /* + * Allocate memory for the IP header (plus 8 octects for ICMP). + */ + ihlen = (iph->ihl * sizeof(unsigned long)); qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC); if (qp->iph == NULL) @@ -707,7 +828,6 @@ qp->maclen = maclen; qp->fragments = NULL; qp->dev = dev; -/* printk("Protocol = %d\n",qp->iph->protocol);*/ /* Start a timer for this entry. */ qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ @@ -727,7 +847,10 @@ } - /* See if a fragment queue is complete. */ +/* + * See if a fragment queue is complete. + */ + static int ip_done(struct ipq *qp) { struct ipfrag *fp; @@ -753,7 +876,15 @@ } -/* Build a new IP datagram from all its fragments. */ +/* + * Build a new IP datagram from all its fragments. + * + * FIXME: We copy here because we lack an effective way of handling lists + * of bits on input. Until the new skb data handling is in I'm not going + * to touch this with a bargepole. This also causes a 4Kish limit on + * packet sizes. + */ + static struct sk_buff *ip_glue(struct ipq *qp) { struct sk_buff *skb; @@ -762,10 +893,15 @@ unsigned char *ptr; int count, len; - /* Allocate a new buffer for the datagram. */ - len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len; + /* + * Allocate a new buffer for the datagram. + */ + + len = qp->maclen + qp->ihlen + qp->len; + if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL) { + ip_statistics.IpReasmFails++; printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp); ip_free(qp); return(NULL); @@ -775,19 +911,15 @@ skb->len = (len - qp->maclen); skb->h.raw = skb->data; skb->free = 1; - skb->dev = qp->dev; /* Copy the original MAC and IP headers into the new buffer. */ ptr = (unsigned char *) skb->h.raw; memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen); -/* printk("Copied %d bytes of mac header.\n",qp->maclen);*/ ptr += qp->maclen; memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen); -/* printk("Copied %d byte of ip header.\n",qp->ihlen);*/ ptr += qp->ihlen; skb->h.raw += qp->maclen; -/* printk("Protocol = %d\n",skb->h.iph->protocol);*/ count = 0; /* Copy the data portions of all fragments into the new buffer. */ @@ -799,9 +931,9 @@ printk("Invalid fragment list: Fragment over size.\n"); ip_free(qp); kfree_skb(skb,FREE_WRITE); + ip_statistics.IpReasmFails++; return NULL; } -/* printk("Fragment %d size %d\n",fp->offset,fp->len);*/ memcpy((ptr + fp->offset), fp->ptr, fp->len); count += fp->len; fp = fp->next; @@ -815,11 +947,16 @@ iph->frag_off = 0; iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count); skb->ip_hdr = iph; + + ip_statistics.IpReasmOKs++; return(skb); } -/* Process an incoming IP datagram fragment. */ +/* + * Process an incoming IP datagram fragment. + */ + static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev) { struct ipfrag *prev, *next; @@ -830,6 +967,8 @@ int flags, offset; int i, ihl, end; + ip_statistics.IpReasmReqds++; + /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */ qp = ip_find(iph); @@ -837,11 +976,13 @@ offset = ntohs(iph->frag_off); flags = offset & ~IP_OFFSET; offset &= IP_OFFSET; - if (((flags & IP_MF) == 0) && (offset == 0)) { + if (((flags & IP_MF) == 0) && (offset == 0)) + { if (qp != NULL) ip_free(qp); /* Huh? How could this exist?? */ return(skb); } + offset <<= 3; /* offset is in 8-byte chunks */ /* @@ -849,36 +990,55 @@ * as we still are receiving fragments. Otherwise, create a fresh * queue entry. */ - if (qp != NULL) { + + if (qp != NULL) + { del_timer(&qp->timer); qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); - } else { - if ((qp = ip_create(skb, iph, dev)) == NULL) { + } + else + { + /* + * If we failed to create it, then discard the frame + */ + if ((qp = ip_create(skb, iph, dev)) == NULL) + { skb->sk = NULL; kfree_skb(skb, FREE_READ); + ip_statistics.IpReasmFails++; return NULL; } } - /* Determine the position of this fragment. */ + /* + * Determine the position of this fragment. + */ + ihl = (iph->ihl * sizeof(unsigned long)); end = offset + ntohs(iph->tot_len) - ihl; - /* Point into the IP datagram 'data' part. */ + /* + * Point into the IP datagram 'data' part. + */ + ptr = skb->data + dev->hard_header_len + ihl; - /* Is this the final fragment? */ + /* + * Is this the final fragment? + */ + if ((flags & IP_MF) == 0) qp->len = end; /* - * Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? + * Find out which fragments are in front and at the back of us + * in the chain of fragments so far. We must know where to put + * this fragment, right? */ + prev = NULL; for(next = qp->fragments; next != NULL; next = next->next) { @@ -888,9 +1048,9 @@ } /* - * We found where to put this one. - * Check for overlap with preceeding fragment, and, if needed, - * align things so that any overlaps are eliminated. + * We found where to put this one. + * Check for overlap with preceeding fragment, and, if needed, + * align things so that any overlaps are eliminated. */ if (prev != NULL && offset < prev->end) { @@ -916,7 +1076,10 @@ next->offset += i; /* next fragment */ next->ptr += i; - /* If we get a frag size of <= 0, remove it. */ + /* + * If we get a frag size of <= 0, remove it and the packet + * that it goes with. + */ if (next->len <= 0) { DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n", @@ -928,17 +1091,26 @@ if (tfp->next != NULL) next->next->prev = next->prev; - - kfree_skb(next->skb, FREE_READ); + + kfree_skb(next->skb,FREE_READ); kfree_s(next, sizeof(struct ipfrag)); } DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i)); } - /* Insert this fragment in the chain of fragments. */ + /* + * Insert this fragment in the chain of fragments. + */ + tfp = NULL; tfp = ip_frag_create(offset, end, skb, ptr); - if (!tfp) { + + /* + * No memory to save the fragment - so throw the lot + */ + + if (!tfp) + { skb->sk = NULL; kfree_skb(skb, FREE_READ); return NULL; @@ -954,9 +1126,9 @@ next->prev = tfp; /* - * OK, so we inserted this new fragment into the chain. - * Check if we now have a full IP datagram which we can - * bump up to the IP layer... + * OK, so we inserted this new fragment into the chain. + * Check if we now have a full IP datagram which we can + * bump up to the IP layer... */ if (ip_done(qp)) @@ -969,13 +1141,19 @@ /* - * This IP datagram is too large to be sent in one piece. Break it up into - * smaller pieces (each of size equal to the MAC header plus IP header plus - * a block of the data of the original IP data part) that will yet fit in a - * single device frame, and queue such a frame for sending by calling the - * ip_queue_xmit(). Note that this is recursion, and bad things will happen - * if this function causes a loop... + * This IP datagram is too large to be sent in one piece. Break it up into + * smaller pieces (each of size equal to the MAC header plus IP header plus + * a block of the data of the original IP data part) that will yet fit in a + * single device frame, and queue such a frame for sending by calling the + * ip_queue_xmit(). Note that this is recursion, and bad things will happen + * if this function causes a loop... + * + * Yes this is inefficient, feel free to submit a quicker one. + * + * **Protocol Violation** + * We copy all the options to each fragment. !FIXME! */ + void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag) { struct iphdr *iph; @@ -985,27 +1163,34 @@ int left, mtu, hlen, len; int offset; - /* Point into the IP datagram header. */ + /* + * Point into the IP datagram header. + */ + raw = skb->data; iph = (struct iphdr *) (raw + dev->hard_header_len); skb->ip_hdr = iph; - /* Setup starting values. */ + /* + * Setup starting values. + */ + hlen = (iph->ihl * sizeof(unsigned long)); - left = ntohs(iph->tot_len) - hlen; - hlen += dev->hard_header_len; - mtu = (dev->mtu - hlen); - ptr = (raw + hlen); + left = ntohs(iph->tot_len) - hlen; /* Space per frame */ + hlen += dev->hard_header_len; /* Total header size */ + mtu = (dev->mtu - hlen); /* Size of data space */ + ptr = (raw + hlen); /* Where to start from */ DPRINTF((DBG_IP, "IP: Fragmentation Desired\n")); DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s", dev->name, dev->mtu, left, in_ntoa(iph->saddr))); DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr))); - - if (mtu < 8) - return; - /* Check for any "DF" flag. */ + + /* + * Check for any "DF" flag. [DF means do not fragment] + */ + if (ntohs(iph->frag_off) & IP_DF) { DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n")); @@ -1013,15 +1198,44 @@ dev->name, dev->mtu, left, in_ntoa(iph->saddr))); DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr))); + ip_statistics.IpFragFails++; icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev); return; } - /* Fragment the datagram. */ + /* + * The protocol doesn't seem to say what to do in the case that the + * frame + options doesn't fit the mtu. As it used to fall down dead + * in this case we were fortunate it didn't happen + */ + + if(mtu<8) + { + /* It's wrong but its better than nothing */ + icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,dev); + ip_statistics.IpFragFails++; + return; + } + + /* + * Fragment the datagram. + */ + + /* + * The initial offset is 0 for a complete frame. When + * fragmenting fragments its wherever this one starts. + */ + if (is_frag & 2) - offset = (ntohs(iph->frag_off) & 0x1fff) << 3; + offset = (ntohs(iph->frag_off) & 0x1fff) << 3; else - offset = 0; + offset = 0; + + + /* + * Keep copying data until we run out. + */ + while(left > 0) { len = left; @@ -1038,332 +1252,496 @@ DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n", len, len + hlen)); - /* Allocate buffer. */ - if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_ATOMIC)) == NULL) + /* + * Allocate buffer. + */ + + if ((skb2 = alloc_skb(len + hlen,GFP_ATOMIC)) == NULL) { printk("IP: frag: no memory for new fragment!\n"); + ip_statistics.IpFragFails++; return; } + + /* + * Set up data on packet + */ + skb2->arp = skb->arp; skb2->free = skb->free; skb2->len = len + hlen; skb2->h.raw=(char *) skb2->data; + /* + * Charge the memory for the fragment to any owner + * it might posess + */ + if (sk) sk->wmem_alloc += skb2->mem_len; - /* Copy the packet header into the new buffer. */ + /* + * Copy the packet header into the new buffer. + */ + memcpy(skb2->h.raw, raw, hlen); - /* Copy a block of the IP datagram. */ + /* + * Copy a block of the IP datagram. + */ memcpy(skb2->h.raw + hlen, ptr, len); left -= len; skb2->h.raw+=dev->hard_header_len; - /* Fill in the new header fields. */ + + /* + * Fill in the new header fields. + */ iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/); iph->frag_off = htons((offset >> 3)); - /* Added AC : If we are fragmenting a fragment thats not the - last fragment then keep MF on each bit */ + /* + * Added AC : If we are fragmenting a fragment thats not the + * last fragment then keep MF on each bit + */ if (left > 0 || (is_frag & 1)) iph->frag_off |= htons(IP_MF); ptr += len; offset += len; -/* printk("Queue frag\n");*/ - /* Put this fragment into the sending queue. */ + /* + * Put this fragment into the sending queue. + */ + + ip_statistics.IpFragCreates++; + ip_queue_xmit(sk, dev, skb2, 1); -/* printk("Queued\n");*/ } - } + ip_statistics.IpFragOKs++; +} #ifdef CONFIG_IP_FORWARD -/* Forward an IP datagram to its next destination. */ -static void -ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) +/* + * Forward an IP datagram to its next destination. + */ + +static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) { - struct device *dev2; - struct iphdr *iph; - struct sk_buff *skb2; - struct rtable *rt; - unsigned char *ptr; - unsigned long raddr; + struct device *dev2; /* Output device */ + struct iphdr *iph; /* Our header */ + struct sk_buff *skb2; /* Output packet */ + struct rtable *rt; /* Route we use */ + unsigned char *ptr; /* Data pointer */ + unsigned long raddr; /* Router IP address */ - /* - * Only forward packets that were fired at us when we are in promiscuous - * mode. In standard mode we rely on the driver to filter for us. - */ + /* + * Only forward packets that were fired at us when we are in promiscuous + * mode. In standard mode we rely on the driver to filter for us. + */ - if(dev->flags&IFF_PROMISC) - { - if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len)) - return; - } - - /* - * According to the RFC, we must first decrease the TTL field. If - * that reaches zero, we must reply an ICMP control message telling - * that the packet's lifetime expired. - */ - iph = skb->h.iph; - iph->ttl--; - if (iph->ttl <= 0) { - DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n")); - DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); - - /* Tell the sender its packet died... */ - icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev); - return; - } + if(dev->flags&IFF_PROMISC) + { + if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len)) + return; + } + - /* Re-compute the IP header checksum. */ - ip_send_check(iph); + + /* + * According to the RFC, we must first decrease the TTL field. If + * that reaches zero, we must reply an ICMP control message telling + * that the packet's lifetime expired. + * + * Exception: + * We may not generate an ICMP for an ICMP. icmp_send does the + * enforcement of this so we can forget it here. It is however + * sometimes VERY important. + */ + + iph = skb->h.iph; + iph->ttl--; + if (iph->ttl <= 0) + { + DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n")); + DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); + + /* Tell the sender its packet died... */ + icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev); + return; + } - /* - * OK, the packet is still valid. Fetch its destination address, - * and give it to the IP sender for further processing. - */ - rt = rt_route(iph->daddr, NULL); - if (rt == NULL) { - DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n")); - - /* Tell the sender its packet cannot be delivered... */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev); - return; - } + /* + * Re-compute the IP header checksum. + * This is inefficient. We know what has happened to the header + * and could thus adjust the checksum as Phil Karn does in KA9Q + */ + + ip_send_check(iph); + /* + * OK, the packet is still valid. Fetch its destination address, + * and give it to the IP sender for further processing. + */ - /* - * Gosh. Not only is the packet valid; we even know how to - * forward it onto its final destination. Can we say this - * is being plain lucky? - * If the router told us that there is no GW, use the dest. - * IP address itself- we seem to be connected directly... - */ - raddr = rt->rt_gateway; - if (raddr != 0) { - rt = rt_route(raddr, NULL); - if (rt == NULL) { - DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n")); + rt = ip_rt_route(iph->daddr, NULL, NULL); + if (rt == NULL) + { + DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n")); - /* Tell the sender its packet cannot be delivered... */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev); + /* + * Tell the sender its packet cannot be delivered. Again + * ICMP is screened later. + */ + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev); return; } - if (rt->rt_gateway != 0) raddr = rt->rt_gateway; - } else raddr = iph->daddr; - dev2 = rt->rt_dev; - if (dev == dev2) - return; - /* - * We now allocate a new buffer, and copy the datagram into it. - * If the indicated interface is up and running, kick it. - */ - DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n", - in_ntoa(raddr), dev2->name, skb->len)); + /* + * Gosh. Not only is the packet valid; we even know how to + * forward it onto its final destination. Can we say this + * is being plain lucky? + * If the router told us that there is no GW, use the dest. + * IP address itself- we seem to be connected directly... + */ - if (dev2->flags & IFF_UP) { - skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) + - dev2->hard_header_len + skb->len, GFP_ATOMIC); - if (skb2 == NULL) { - printk("\nIP: No memory available for IP forward\n"); + raddr = rt->rt_gateway; + + if (raddr != 0) + { + /* + * There is a gateway so find the correct route for it. + * Gateways cannot in turn be gatewayed. + */ + rt = ip_rt_route(raddr, NULL, NULL); + if (rt == NULL) + { + DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n")); + + /* + * Tell the sender its packet cannot be delivered... + */ + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev); + return; + } + if (rt->rt_gateway != 0) + raddr = rt->rt_gateway; + } + else + raddr = iph->daddr; + + /* + * Having picked a route we can now send the frame out. + */ + + dev2 = rt->rt_dev; + + /* + * In IP you never forward a frame on the interface that it arrived + * upon. We should generate an ICMP HOST REDIRECT giving the route + * we calculated. + * For now just dropping the packet is an acceptable compromise. + */ + + if (dev == dev2) return; - } - ptr = skb2->data; - skb2->sk = NULL; - skb2->free = 1; - skb2->len = skb->len + dev2->hard_header_len; - skb2->mem_addr = skb2; - skb2->mem_len = sizeof(struct sk_buff) + skb2->len; - skb2->next = NULL; - skb2->h.raw = ptr; - /* Copy the packet data into the new buffer. */ - memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len); - - /* Now build the MAC header. */ - (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr); + /* + * We now allocate a new buffer, and copy the datagram into it. + * If the indicated interface is up and running, kick it. + */ - if(skb2->len > dev2->mtu) - { - ip_fragment(NULL,skb2,dev2, is_frag); - kfree_skb(skb2,FREE_WRITE); - } - else + DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n", + in_ntoa(raddr), dev2->name, skb->len)); + + if (dev2->flags & IFF_UP) { - if(iph->tos & IPTOS_LOWDELAY) - dev2->queue_xmit(skb2, dev2, SOPRI_INTERACTIVE); - else if(iph->tos & IPTOS_THROUGHPUT) - dev2->queue_xmit(skb2, dev2, SOPRI_BACKGROUND); + + /* + * Current design decrees we copy the packet. For identical header + * lengths we could avoid it. The new skb code will let us push + * data so the problem goes away then. + */ + + skb2 = alloc_skb(dev2->hard_header_len + skb->len, GFP_ATOMIC); + /* + * This is rare and since IP is tolerant of network failures + * quite harmless. + */ + if (skb2 == NULL) + { + printk("\nIP: No memory available for IP forward\n"); + return; + } + ptr = skb2->data; + skb2->free = 1; + skb2->len = skb->len + dev2->hard_header_len; + skb2->h.raw = ptr; + + /* + * Copy the packet data into the new buffer. + */ + memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len); + + /* Now build the MAC header. */ + (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr); + + ip_statistics.IpForwDatagrams++; + + /* + * See if it needs fragmenting. Note in ip_rcv we tagged + * the fragment type. This must be right so that + * the fragmenter does the right thing. + */ + + if(skb2->len > dev2->mtu) + { + ip_fragment(NULL,skb2,dev2, is_frag); + kfree_skb(skb2,FREE_WRITE); + } else - dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL); + { + /* + * Map service types to priority. We lie about + * throughput being low priority, but its a good + * choice to help improve general usage. + */ + if(iph->tos & IPTOS_LOWDELAY) + dev_queue_xmit(skb2, dev2, SOPRI_INTERACTIVE); + else if(iph->tos & IPTOS_THROUGHPUT) + dev_queue_xmit(skb2, dev2, SOPRI_BACKGROUND); + else + dev_queue_xmit(skb2, dev2, SOPRI_NORMAL); + } } - } } #endif -/* This function receives all incoming IP datagrams. */ -int -ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - struct iphdr *iph = skb->h.iph; - unsigned char hash; - unsigned char flag = 0; - unsigned char opts_p = 0; /* Set iff the packet has options. */ - struct inet_protocol *ipprot; - static struct options opt; /* since we don't use these yet, and they +/* + * This function receives all incoming IP datagrams. + */ + +int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct iphdr *iph = skb->h.iph; + unsigned char hash; + unsigned char flag = 0; + unsigned char opts_p = 0; /* Set iff the packet has options. */ + struct inet_protocol *ipprot; + static struct options opt; /* since we don't use these yet, and they take up stack space. */ - int brd; - int is_frag=0; + int brd; + int is_frag=0; - DPRINTF((DBG_IP, "<<\n")); - skb->ip_hdr = iph; /* Fragments can cause ICMP errors too! */ - /* Is the datagram acceptable? */ - if (skb->lenihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) { - DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n")); - DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - return(0); - } - - if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */ - ip_print(iph); /* Bogus, only for debugging. */ - memset((char *) &opt, 0, sizeof(opt)); - if (do_options(iph, &opt) != 0) - return 0; - opts_p = 1; - } + ip_statistics.IpInReceives++; + + DPRINTF((DBG_IP, "<<\n")); + + /* + * Tag the ip header of this packet so we can find it + */ + + skb->ip_hdr = iph; + + /* + * Is the datagram acceptable? + * + * 1. Length at least the size of an ip header + * 2. Version of 4 + * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] + * (4. We ought to check for IP multicast addresses and undefined types.. does this matter ?) + */ + + if (skb->lenihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) + { + ip_statistics.IpInHdrErrors++; + DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n")); + DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); + kfree_skb(skb, FREE_WRITE); + return(0); + } + + /* + * Our transport medium may have padded the buffer out. Now we know it + * is IP we can trim to the true length of the frame. + */ + + skb->len=ntohs(iph->tot_len); + + /* + * Next anaylse the packet for options. Studies show under one packet in + * a thousand have options.... + */ + + if (iph->ihl != 5) + { /* Fast path for the typical optionless IP packet. */ + ip_print(iph); /* Bogus, only for debugging. */ + memset((char *) &opt, 0, sizeof(opt)); + if (do_options(iph, &opt) != 0) + return 0; + opts_p = 1; + } + + /* + * Remember if the frame is fragmented. + */ - if (iph->frag_off & 0x0020) - is_frag|=1; - if (ntohs(iph->frag_off) & 0x1fff) - is_frag|=2; + if (iph->frag_off & 0x0020) + is_frag|=1; + + /* + * Last fragment ? + */ + + if (ntohs(iph->frag_off) & 0x1fff) + is_frag|=2; - /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */ - if ((brd = chk_addr(iph->daddr)) == 0) { + /* + * Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. + * + * This is inefficient. While finding out if it is for us we could also compute + * the routing table entry. This is where the great unified cache theory comes + * in as and when someone impliments it + */ + + if ((brd = ip_chk_addr(iph->daddr)) == 0) + { + + /* + * The packet is for another target. Forward the frame + */ + #ifdef CONFIG_IP_FORWARD - ip_forward(skb, dev, is_frag); + ip_forward(skb, dev, is_frag); #else - printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n", + printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n", iph->saddr,iph->daddr); + ip_statistics.IpInAddrErrors++; #endif - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - return(0); - } + /* + * The forwarder is inefficient and copies the packet. We + * free the original now. + */ + + kfree_skb(skb, FREE_WRITE); + return(0); + } - /* - * Reassemble IP fragments. - */ + /* + * Reassemble IP fragments. + */ - if(is_frag) - { + if(is_frag) + { #ifdef CONFIG_IP_DEFRAG - skb=ip_defrag(iph,skb,dev); - if(skb==NULL) - { - return 0; - } - iph=skb->h.iph; + /* Defragment. Obtain the complete packet if there is one */ + skb=ip_defrag(iph,skb,dev); + if(skb==NULL) + return 0; + iph=skb->h.iph; #else - printk("\nIP: *** datagram fragmentation not yet implemented ***\n"); - printk(" SRC = %s ", in_ntoa(iph->saddr)); - printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr)); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - return(0); + printk("\nIP: *** datagram fragmentation not yet implemented ***\n"); + printk(" SRC = %s ", in_ntoa(iph->saddr)); + printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr)); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); + kfree_skb(skb, FREE_WRITE); + return(0); #endif - } - + } + /* + * Point into the IP datagram, just past the header. + */ - if(brd==IS_INVBCAST) - { -/* printk("Invalid broadcast address from %x [target %x] (Probably they have a wrong netmask)\n", - iph->saddr,iph->daddr);*/ - skb->sk=NULL; - kfree_skb(skb,FREE_WRITE); - return(0); - } - - /* Point into the IP datagram, just past the header. */ + skb->ip_hdr = iph; + skb->h.raw += iph->ihl*4; + + /* + * skb->h.raw now points at the protocol beyond the IP header. + */ + + hash = iph->protocol & (MAX_INET_PROTOS -1); + for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next) + { + struct sk_buff *skb2; - skb->ip_hdr = iph; - skb->h.raw += iph->ihl*4; - hash = iph->protocol & (MAX_INET_PROTOS -1); - for (ipprot = (struct inet_protocol *)inet_protos[hash]; - ipprot != NULL; - ipprot=(struct inet_protocol *)ipprot->next) - { - struct sk_buff *skb2; - - if (ipprot->protocol != iph->protocol) continue; - DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot)); - print_ipprot(ipprot); + if (ipprot->protocol != iph->protocol) + continue; + DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot)); + print_ipprot(ipprot); /* - * See if we need to make a copy of it. This will - * only be set if more than one protocol wants it. - * and then not for the last one. + * See if we need to make a copy of it. This will + * only be set if more than one protocol wants it. + * and then not for the last one. + * + * This is an artifact of poor upper protocol design. + * Because the upper protocols damage the actual packet + * we must do copying. In actual fact it's even worse + * than this as TCP may hold on to the buffer. */ - if (ipprot->copy) { - skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); - if (skb2 == NULL) - continue; - memcpy(skb2, skb, skb->mem_len); - skb2->mem_addr = skb2; - skb2->ip_hdr = (struct iphdr *)( - (unsigned long)skb2 + - (unsigned long) skb->ip_hdr - - (unsigned long)skb); - skb2->h.raw = (unsigned char *)( - (unsigned long)skb2 + - (unsigned long) skb->h.raw - - (unsigned long)skb); - skb2->free=1; - } else { - skb2 = skb; - } - flag = 1; + if (ipprot->copy) + { +#if 0 + skb2 = alloc_skb(skb->mem_len-sizeof(struct sk_buff), GFP_ATOMIC); + if (skb2 == NULL) + continue; + memcpy(skb2, skb, skb2->mem_len); + skb2->ip_hdr = (struct iphdr *)( + (unsigned long)skb2 + + (unsigned long) skb->ip_hdr - + (unsigned long)skb); + skb2->h.raw = (unsigned char *)( + (unsigned long)skb2 + + (unsigned long) skb->h.raw - + (unsigned long)skb); + skb2->free=1; +#else + skb2 = skb_clone(skb, GFP_ATOMIC); + if(skb2==NULL) + continue; +#endif + } + else + { + skb2 = skb; + } + flag = 1; - /* - * Pass on the datagram to each protocol that wants it, - * based on the datagram protocol. We should really - * check the protocol handler's return values here... - */ - ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr, - (ntohs(iph->tot_len) - (iph->ihl * 4)), - iph->saddr, 0, ipprot); + /* + * Pass on the datagram to each protocol that wants it, + * based on the datagram protocol. We should really + * check the protocol handler's return values here... + */ + ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr, + (ntohs(iph->tot_len) - (iph->ihl * 4)), + iph->saddr, 0, ipprot); - } + } - /* - * All protocols checked. - * If this packet was a broadcast, we may *not* reply to it, since that - * causes (proven, grin) ARP storms and a leakage of memory (i.e. all - * ICMP reply messages get queued up for transmission...) - */ - if (!flag) { - if (brd != IS_BROADCAST) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - } + /* + * All protocols checked. + * If this packet was a broadcast, we may *not* reply to it, since that + * causes (proven, grin) ARP storms and a leakage of memory (i.e. all + * ICMP reply messages get queued up for transmission...) + */ - return(0); + if (!flag) + { + if (brd != IS_BROADCAST) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); + kfree_skb(skb, FREE_WRITE); + } + + return(0); } @@ -1371,178 +1749,287 @@ * 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. - * This routine also needs to put in the total length, and - * compute the checksum. + * This routine also needs to put in the total length, + * and compute the checksum */ -void -ip_queue_xmit(struct sock *sk, struct device *dev, + +void ip_queue_xmit(struct sock *sk, struct device *dev, struct sk_buff *skb, int free) { - struct iphdr *iph; - unsigned char *ptr; + struct iphdr *iph; + unsigned char *ptr; - if (sk == NULL) free = 1; - if (dev == NULL) { - printk("IP: ip_queue_xmit dev = NULL\n"); - return; - } - IS_SKB(skb); - skb->free = free; - skb->dev = dev; - skb->when = jiffies; + /* All buffers without an owner socket get freed */ + if (sk == NULL) + free = 1; + + /* Sanity check */ + if (dev == NULL) + { + printk("IP: ip_queue_xmit dev = NULL\n"); + return; + } - DPRINTF((DBG_IP, ">>\n")); - ptr = skb->data; - ptr += dev->hard_header_len; - iph = (struct iphdr *)ptr; - skb->ip_hdr = iph; - iph->tot_len = ntohs(skb->len-dev->hard_header_len); - - if(skb->len > dev->mtu) - { -/* printk("Fragment!\n");*/ - ip_fragment(sk,skb,dev,0); IS_SKB(skb); - kfree_skb(skb,FREE_WRITE); - return; - } + + /* + * Do some book-keeping in the packet for later + */ + + skb->free = free; + skb->dev = dev; + skb->when = jiffies; - ip_send_check(iph); - ip_print(iph); - skb->next = NULL; - - /* See if this is the one trashing our queue. Ross? */ - skb->magic = 1; - if (!free) { - skb->link3 = NULL; - sk->packets_out++; - cli(); - if (sk->send_head == NULL) { - sk->send_tail = skb; - sk->send_head = skb; - } else { - /* See if we've got a problem. */ - if (sk->send_tail == NULL) { - printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n"); - sort_send(sk); - } else { + DPRINTF((DBG_IP, ">>\n")); + + /* + * Find the IP header and set the length. This is bad + * but once we get the skb data handling code in the + * hardware will push its header sensibly and we will + * set skb->ip_hdr to avoid this mess and the fixed + * header length problem + */ + + ptr = skb->data; + ptr += dev->hard_header_len; + iph = (struct iphdr *)ptr; + skb->ip_hdr = iph; + iph->tot_len = ntohs(skb->len-dev->hard_header_len); + + /* + * Do we need to fragment. Again this is inefficient. + * We need to somehow lock the original buffer and use + * bits of it. + */ + + if(skb->len > dev->mtu) + { + ip_fragment(sk,skb,dev,0); + IS_SKB(skb); + kfree_skb(skb,FREE_WRITE); + return; + } + + /* + * Add an IP checksum + */ + + ip_send_check(iph); + + /* + * Print the frame when debugging + */ + ip_print(iph); + + /* + * More debugging. You cannot queue a packet already on a list + * Spot this and moan loudly. + */ + if (skb->next != NULL) + { + printk("ip_queue_xmit: next != NULL\n"); + skb_unlink(skb); + } + + /* + * If a sender wishes the packet to remain unfreed + * we add it to his send queue. This arguably belongs + * in the TCP level since nobody elses uses it. BUT + * remember IPng might change all the rules. + */ + + if (!free) + { + unsigned long flags; + /* The socket now has more outstanding blocks */ + + sk->packets_out++; + + /* Protect the list for a moment */ + save_flags(flags); + cli(); + + if (skb->link3 != NULL) + { + printk("ip.c: link3 != NULL\n"); + skb->link3 = NULL; + } + if (sk->send_head == NULL) + { + sk->send_tail = skb; + sk->send_head = skb; + } + else + { sk->send_tail->link3 = skb; sk->send_tail = skb; } - } - sti(); - reset_timer(sk, TIME_WRITE, sk->rto); - } else { - skb->sk = sk; - } + /* skb->link3 is NULL */ + + /* Interrupt restore */ + restore_flags(flags); + /* Set the IP write timeout to the round trip time for the packet. + If an acknowledge has not arrived by then we may wish to act */ + reset_timer(sk, TIME_WRITE, sk->rto); + } + else + /* Remember who owns the buffer */ + skb->sk = sk; - /* If the indicated interface is up and running, kick it. */ - if (dev->flags & IFF_UP) { - if (sk != NULL) { - dev->queue_xmit(skb, dev, sk->priority); + /* + * If the indicated interface is up and running, send the packet. + */ + ip_statistics.IpOutRequests++; + + if (dev->flags & IFF_UP) + { + /* + * If we have an owner use its priority setting, + * otherwise use NORMAL + */ + + if (sk != NULL) + { + dev_queue_xmit(skb, dev, sk->priority); + } + else + { + dev_queue_xmit(skb, dev, SOPRI_NORMAL); + } } - else { - dev->queue_xmit(skb, dev, SOPRI_NORMAL); + else + { + ip_statistics.IpOutDiscards++; + if (free) + kfree_skb(skb, FREE_WRITE); } - } else { - if (free) kfree_skb(skb, FREE_WRITE); - } } -void -ip_do_retransmit(struct sock *sk, int all) +/* + * A socket has timed out on its send queue and wants to do a + * little retransmitting. Currently this means TCP. + */ + +void ip_do_retransmit(struct sock *sk, int all) { - struct sk_buff * skb; - struct proto *prot; - struct device *dev; - int retransmits; - - prot = sk->prot; - skb = sk->send_head; - retransmits = sk->retransmits; - while (skb != NULL) { - dev = skb->dev; - /* I know this can't happen but as it does.. */ - if(dev==NULL) + struct sk_buff * skb; + struct proto *prot; + struct device *dev; + int retransmits; + + prot = sk->prot; + skb = sk->send_head; + retransmits = sk->retransmits; + + while (skb != NULL) { - printk("ip_retransmit: NULL device bug!\n"); - goto oops; - } + dev = skb->dev; + IS_SKB(skb); +#if 0 + /********** THIS IS NOW DONE BY THE DEVICE LAYER **********/ + /* + * The rebuild_header function sees if the ARP is done. + * If not it sends a new ARP request, and if so it builds + * the header. It isn't really needed here, and with the + * new ARP pretty much will not happen. + */ + + if (!skb->arp) + { + if (dev->rebuild_header(skb->data, dev, skb->raddr, NULL)) + { + if (!all) + break; + skb = skb->link3; + continue; + } + } +#endif + skb->when = jiffies; - IS_SKB(skb); - - /* - * The rebuild_header function sees if the ARP is done. - * If not it sends a new ARP request, and if so it builds - * the header. - */ - cli(); /* We might get interrupted by an arp reply here and fill - the frame in twice. Because of the technique used this - would be a little sad */ - if (!skb->arp) { - if (dev->rebuild_header(skb->data, dev)) { - sti(); /* Failed to rebuild - next */ - if (!all) break; - skb = (struct sk_buff *)skb->link3; - continue; + /* + * If the interface is (still) up and running, kick it. + */ + + if (dev->flags & IFF_UP) + { + /* + * If the packet is still being sent by the device/protocol + * below then don't retransmit. This is both needed, and good - + * especially with connected mode AX.25 where it stops resends + * occuring of an as yet unsent anyway frame! + * We still add up the counts as the round trip time wants + * adjusting. + */ + if (sk && !skb_device_locked(skb)) + { + /* Remove it from any existing driver queue first! */ + skb_unlink(skb); + /* Now queue it */ + ip_statistics.IpOutRequests++; + dev_queue_xmit(skb, dev, sk->priority); + } } - } - skb->arp = 1; - sti(); - skb->when = jiffies; + + /* + * Count retransmissions + */ + retransmits++; + sk->prot->retransmits ++; + + /* + * Only one retransmit requested. + */ + if (!all) + break; - /* If the interface is (still) up and running, kick it. */ - if (dev->flags & IFF_UP) { - if (sk && !skb_device_locked(skb)) - dev->queue_xmit(skb, dev, sk->priority); - /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */ + /* + * This should cut it off before we send too many packets. + */ + if (sk->retransmits > sk->cong_window) + break; + skb = skb->link3; } - -oops: retransmits++; - sk->prot->retransmits ++; - if (!all) break; - - /* This should cut it off before we send too many packets. */ - if (sk->retransmits > sk->cong_window) break; - skb = (struct sk_buff *)skb->link3; - } } /* - * This is the normal code called for timeouts. It does the retransmission - * and then does backoff. ip_do_retransmit is separated out because - * tcp_ack needs to send stuff from the retransmit queue without - * initiating a backoff. + * This is the normal code called for timeouts. It does the retransmission + * and then does backoff. ip_do_retransmit is separated out because + * tcp_ack needs to send stuff from the retransmit queue without + * initiating a backoff. */ -void -ip_retransmit(struct sock *sk, int all) +void ip_retransmit(struct sock *sk, int all) { - ip_do_retransmit(sk, all); + ip_do_retransmit(sk, all); + + /* + * Increase the timeout each time we retransmit. Note that + * we do not increase the rtt estimate. rto is initialized + * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests + * that doubling rto each time is the least we can get away with. + * In KA9Q, Karn uses this for the first few times, and then + * goes to quadratic. netBSD doubles, but only goes up to *64, + * and clamps at 1 to 64 sec afterwards. Note that 120 sec is + * defined in the protocol as the maximum possible RTT. I guess + * we'll have to use something other than TCP to talk to the + * University of Mars. + */ - /* - * Increase the timeout each time we retransmit. Note that - * we do not increase the rtt estimate. rto is initialized - * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests - * that doubling rto each time is the least we can get away with. - * In KA9Q, Karns uses this for the first few times, and then - * goes to quadratic. netBSD doubles, but only goes up to *64, - * and clamps at 1 to 64 sec afterwards. Note that 120 sec is - * defined in the protocol as the maximum possible RTT. I guess - * we'll have to use something other than TCP to talk to the - * University of Mars. - */ - - sk->retransmits++; - sk->backoff++; - sk->rto = min(sk->rto << 1, 120*HZ); - reset_timer(sk, TIME_WRITE, sk->rto); + sk->retransmits++; + sk->backoff++; + sk->rto = min(sk->rto << 1, 120*HZ); + reset_timer(sk, TIME_WRITE, sk->rto); } /* * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on * an IP socket. + * + * We impliment IP_TOS (type of service), IP_TTL (time to live). + * + * Next release we will sort out IP_OPTIONS since for some people are kind of important. */ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) @@ -1579,6 +2066,11 @@ } } +/* + * Get the options. Note for future reference. The GET of IP options gets the + * _received_ ones. The set sets the _sent_ ones. + */ + int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { int val,err; @@ -1608,4 +2100,32 @@ put_fs_long(val,(unsigned long *)optval); return(0); +} + +/* + * IP protocol layer initialiser + */ + +static struct packet_type ip_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_IP),*/ + 0, /* copy */ + ip_rcv, + NULL, + NULL, +}; + + +/* + * IP registers the packet type and then calls the subprotocol initialisers + */ + +void ip_init(void) +{ + ip_packet_type.type=htons(ETH_P_IP); + dev_add_pack(&ip_packet_type); +/* ip_raw_init(); + ip_packet_init(); + ip_tcp_init(); + ip_udp_init();*/ } diff -u --recursive --new-file v1.1.3/linux/net/inet/ip.h linux/net/inet/ip.h --- v1.1.3/linux/net/inet/ip.h Sun Feb 6 12:17:40 1994 +++ linux/net/inet/ip.h Wed Apr 13 12:52:24 1994 @@ -9,6 +9,7 @@ * * Authors: Ross Biro, * Fred N. van Kempen, + * Alan Cox, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,6 +22,9 @@ #include +#ifndef _SNMP_H +#include "snmp.h" +#endif #include "sock.h" /* struct sock */ @@ -61,7 +65,7 @@ extern int backoff(int n); -extern void ip_print(struct iphdr *ip); +extern void ip_print(const struct iphdr *ip); extern int ip_ioctl(struct sock *sk, int cmd, unsigned long arg); extern void ip_route_check(unsigned long daddr); @@ -81,5 +85,7 @@ extern void ip_do_retransmit(struct sock *sk, int all); extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen); extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen); +extern void ip_init(void); +extern struct ip_mib ip_statistics; #endif /* _IP_H */ diff -u --recursive --new-file v1.1.3/linux/net/inet/ipx.c linux/net/inet/ipx.c --- v1.1.3/linux/net/inet/ipx.c +++ linux/net/inet/ipx.c Wed Apr 13 12:52:25 1994 @@ -0,0 +1,1123 @@ +/* + * Implements an IPX socket layer (badly - but I'm working on it). + * + * This code is derived from work by + * Ross Biro : Writing the original IP stack + * Fred Van Kempen : Tidying up the TCP/IP + * + * Many thanks go to Keith Baker, Institute For Industrial Information + * Technology Ltd, Swansea University for allowing me to work on this + * in my own time even though it was in some ways related to commercial + * work I am currently employed to do there. + * + * All the material in this file is subject to the Gnu license version 2. + * Neither Alan Cox nor the Swansea University Computer Society admit liability + * nor provide warranty for any of this software. This material is provided + * as is and at no charge. + * + * Revision 0.21: Uses the new generic socket option code. + * Revision 0.22: Gcc clean ups and drop out device registration. Use the + * new multi-protocol edition of hard_header + * Revision 0.23: IPX /proc by Mark Evans. + * Adding a route will overwrite any existing route to the same + * network. + * Revision 0.24: Supports new /proc with no 4K limit + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sock.h" +#include +#include +#include +#include +#include + +#ifdef CONFIG_IPX +/***********************************************************************************************************************\ +* * +* Handlers for the socket list. * +* * +\***********************************************************************************************************************/ + +static ipx_socket *volatile ipx_socket_list=NULL; + +/* + * Note: Sockets may not be removed _during_ an interrupt or inet_bh + * handler using this technique. They can be added although we do not + * use this facility. + */ + +static void ipx_remove_socket(ipx_socket *sk) +{ + ipx_socket *s; + + cli(); + s=ipx_socket_list; + if(s==sk) + { + ipx_socket_list=s->next; + sti(); + return; + } + while(s && s->next) + { + if(s->next==sk) + { + s->next=sk->next; + sti(); + return; + } + s=s->next; + } + sti(); +} + +static void ipx_insert_socket(ipx_socket *sk) +{ + cli(); + sk->next=ipx_socket_list; + ipx_socket_list=sk; + sti(); +} + +static ipx_socket *ipx_find_socket(int port) +{ + ipx_socket *s; + s=ipx_socket_list; + while(s) + { + if(s->ipx_source_addr.sock==port) + { + return(s); + } + s=s->next; + } + return(NULL); +} + +/* + * This is only called from user mode. Thus it protects itself against + * interrupt users but doesn't worry about being called during work. + * Once it is removed from the queue no interrupt or bottom half will + * touch it and we are (fairly 8-) ) safe. + */ + +static void ipx_destroy_socket(ipx_socket *sk) +{ + struct sk_buff *skb; + ipx_remove_socket(sk); + + while((skb=skb_dequeue(&sk->receive_queue))!=NULL) + { + kfree_skb(skb,FREE_READ); + } + + kfree_s(sk,sizeof(*sk)); +} + + +/* Called from proc fs */ +int ipx_get_info(char *buffer, char **start, off_t offset, int length) +{ + ipx_socket *s; + int len=0; + off_t pos=0; + off_t begin=0; + + /* Theory.. Keep printing in the same place until we pass offset */ + + len += sprintf (buffer,"Type local_address rem_address tx_queue rx_queue st uid\n"); + for (s = ipx_socket_list; s != NULL; s = s->next) + { + len += sprintf (buffer+len,"%02X ", s->ipx_type); + len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_source_addr.net), + s->ipx_source_addr.node[0], s->ipx_source_addr.node[1], s->ipx_source_addr.node[2], + s->ipx_source_addr.node[3], s->ipx_source_addr.node[4], s->ipx_source_addr.node[5], + htons(s->ipx_source_addr.sock)); + len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_dest_addr.net), + s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1], s->ipx_dest_addr.node[2], + s->ipx_dest_addr.node[3], s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5], + htons(s->ipx_dest_addr.sock)); + len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc); + len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid); + + /* Are we still dumping unwanted data then discard the record */ + pos=begin+len; + + if(posoffset+length) /* We have dumped enough */ + break; + } + + /* The data in question runs from begin to begin+len */ + *start=buffer+(offset-begin); /* Start of wanted data */ + len-=(offset-begin); /* Remove unwanted header data from lenth */ + if(len>length) + len=length; /* Remove unwanted tail data from length */ + + return len; +} + +/*******************************************************************************************************************\ +* * +* Routing tables for the IPX socket layer * +* * +\*******************************************************************************************************************/ + + +static ipx_route *ipx_router_list=NULL; + +static ipx_route *ipxrtr_get_dev(long net) +{ + ipx_route *r; + unsigned long flags; + save_flags(flags); + cli(); + r=ipx_router_list; + while(r!=NULL) + { + if(r->net==net) + { + restore_flags(flags); + return r; + } + r=r->next; + } + restore_flags(flags); + return NULL; +} + +static int ipxrtr_create(struct ipx_route_def *r) +{ + ipx_route *rt=ipxrtr_get_dev(r->ipx_network); + struct device *dev; + + if(r->ipx_router_network!=0) + { + /* Adding an indirect route */ + ipx_route *rt1=ipxrtr_get_dev(r->ipx_router_network); + if(rt1==NULL) + return -ENETUNREACH; + if(rt1->flags&IPX_RT_ROUTED) + return -EMULTIHOP; + if (rt==NULL) + { + rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC); /* Because we are brave and don't lock the table! */ + if(rt==NULL) + return -EAGAIN; + rt->next=ipx_router_list; + ipx_router_list=rt; + } + rt->net=r->ipx_network; + rt->router_net=r->ipx_router_network; + memcpy(rt->router_node,r->ipx_router_node,sizeof(rt->router_node)); + rt->flags=(rt1->flags&IPX_RT_BLUEBOOK)|IPX_RT_ROUTED; + rt->dev=rt1->dev; + return 0; + } + /* Add a direct route */ + dev=dev_get(r->ipx_device); + if(dev==NULL) + return -ENODEV; + /* Check addresses are suitable */ + if(dev->addr_len>6) + return -EINVAL; + if(dev->addr_len<2) + return -EINVAL; + /* Ok now create */ + if (rt==NULL) + { + rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC); /* Because we are brave and don't lock the table! */ + if(rt==NULL) + return -EAGAIN; + rt->next=ipx_router_list; + ipx_router_list=rt; + } + rt->router_net=0; + memset(rt->router_node,0,sizeof(rt->router_node)); + rt->dev=dev; + rt->net=r->ipx_network; + rt->flags=r->ipx_flags&IPX_RT_BLUEBOOK; + return 0; +} + +static int ipxrtr_delete(long net) +{ + ipx_route *r=ipx_router_list; + if(r->net==net) + { + ipx_router_list=r->next; + return 0; + } + while(r->next!=NULL) + { + if(r->next->net==net) + { + ipx_route *d=r->next; + r->next=d->next; + kfree_s(d,sizeof(ipx_route)); + return 0; + } + r=r->next; + } + return -ENOENT; +} + +static int ipxrtr_ioctl(unsigned int cmd, void *arg) +{ + int err; + switch(cmd) + { + case SIOCDELRT: + err=verify_area(VERIFY_READ,arg,sizeof(long)); + if(err) + return err; + return ipxrtr_delete(get_fs_long(arg)); + case SIOCADDRT: + { + struct ipx_route_def f; + err=verify_area(VERIFY_READ,arg,sizeof(f)); + if(err) + return err; + memcpy_fromfs(&f,arg,sizeof(f)); + return ipxrtr_create(&f); + } + default: + return -EINVAL; + } +} + +/* Called from proc fs */ +int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length) +{ + ipx_route *rt; + int len=0; + off_t pos=0; + off_t begin=0; + + len += sprintf (buffer,"Net Router Flags Dev\n"); + for (rt = ipx_router_list; rt != NULL; rt = rt->next) + { + len += sprintf (buffer+len,"%08lX %08lX:%02X%02X%02X%02X%02X%02X %02X %s\n", ntohl(rt->net), + ntohl(rt->router_net), rt->router_node[0], rt->router_node[1], rt->router_node[2], + rt->router_node[3], rt->router_node[4], rt->router_node[5], rt->flags, rt->dev->name); + pos=begin+len; + if(posoffset+length) + break; + } + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; +} + +/*******************************************************************************************************************\ +* * +* Handling for system calls applied via the various interfaces to an IPX socket object * +* * +\*******************************************************************************************************************/ + +static int ipx_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + ipx_socket *sk; + + sk=(ipx_socket *)sock->data; + + if(sk==NULL) + { + printk("IPX:fcntl:passed sock->data=NULL\n"); + return(0); + } + + switch(cmd) + { + default: + return(-EINVAL); + } +} + +static int ipx_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + ipx_socket *sk; + int err,opt; + + sk=(ipx_socket *)sock->data; + + if(sk==NULL) + { + printk("IPX:setsockopt:passed sock->data=NULL\n"); + return 0; + } + + if(optval==NULL) + return(-EINVAL); + err=verify_area(VERIFY_READ,optval,sizeof(int)); + if(err) + return err; + opt=get_fs_long((unsigned long *)optval); + + switch(level) + { + case SOL_IPX: + switch(optname) + { + case IPX_TYPE: + if(!suser()) + return(-EPERM); + sk->ipx_type=opt; + return 0; + default: + return -EOPNOTSUPP; + } + break; + + case SOL_SOCKET: + return sock_setsockopt(sk,level,optname,optval,optlen); + + default: + return -EOPNOTSUPP; + } +} + +static int ipx_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + ipx_socket *sk; + int val=0; + int err; + + sk=(ipx_socket *)sock->data; + if(sk==NULL) + { + printk("IPX:getsockopt:passed NULL sock->data.\n"); + return 0; + } + + switch(level) + { + + case SOL_IPX: + switch(optname) + { + case IPX_TYPE: + val=sk->ipx_type; + break; + default: + return -ENOPROTOOPT; + } + break; + + case SOL_SOCKET: + return sock_getsockopt(sk,level,optname,optval,optlen); + + default: + return -EOPNOTSUPP; + } + err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); + if(err) + return err; + put_fs_long(sizeof(int),(unsigned long *)optlen); + err=verify_area(VERIFY_WRITE,optval,sizeof(int)); + put_fs_long(val,(unsigned long *)optval); + return(0); +} + +static int ipx_listen(struct socket *sock, int backlog) +{ + return -EOPNOTSUPP; +} + +static void def_callback1(struct sock *sk) +{ + if(!sk->dead) + wake_up_interruptible(sk->sleep); +} + +static void def_callback2(struct sock *sk, int len) +{ + if(!sk->dead) + wake_up_interruptible(sk->sleep); +} + +static int ipx_create(struct socket *sock, int protocol) +{ + ipx_socket *sk; + sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL); + if(sk==NULL) + return(-ENOMEM); + switch(sock->type) + { + case SOCK_DGRAM: + break; + default: + kfree_s((void *)sk,sizeof(*sk)); + return(-ESOCKTNOSUPPORT); + } + sk->stamp.tv_sec=0; + sk->rmem_alloc=0; + sk->dead=0; + sk->next=NULL; + sk->broadcast=0; + sk->rcvbuf=SK_RMEM_MAX; + sk->sndbuf=SK_WMEM_MAX; + sk->wmem_alloc=0; + sk->rmem_alloc=0; + sk->inuse=0; + sk->dead=0; + sk->prot=NULL; /* So we use default free mechanisms */ + sk->broadcast=0; + sk->err=0; + skb_queue_head_init(&sk->receive_queue); + skb_queue_head_init(&sk->write_queue); + sk->send_head=NULL; + skb_queue_head_init(&sk->back_log); + sk->mtu=512; + sk->state=TCP_CLOSE; + sk->socket=sock; + sk->type=sock->type; + sk->ipx_type=0; /* General user level IPX */ + sk->debug=0; + + memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr)); + memset(&sk->ipx_source_addr,'\0',sizeof(sk->ipx_source_addr)); + sk->mtu=IPX_MTU; + + if(sock!=NULL) + { + sock->data=(void *)sk; + sk->sleep=sock->wait; + } + + sk->state_change=def_callback1; + sk->data_ready=def_callback2; + sk->write_space=def_callback1; + sk->error_report=def_callback1; + + sk->zapped=1; + return(0); +} + +static int ipx_dup(struct socket *newsock,struct socket *oldsock) +{ + return(ipx_create(newsock,SOCK_DGRAM)); +} + +static int ipx_release(struct socket *sock, struct socket *peer) +{ + ipx_socket *sk=(ipx_socket *)sock->data; + if(sk==NULL) + return(0); + if(!sk->dead) + sk->state_change(sk); + sk->dead=1; + sock->data=NULL; + ipx_destroy_socket(sk); + return(0); +} + +static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) +{ + ipx_socket *sk; + int err; + struct sockaddr_ipx addr; + struct ipx_route *rt; + + sk=(ipx_socket *)sock->data; + if(sk==NULL) + { + printk("IPX:bind:sock->data=NULL\n"); + return 0; + } + + if(sk->zapped==0) + return(-EIO); + + err=verify_area(VERIFY_READ,uaddr,addr_len); + if(err) + return err; + if(addr_len!=sizeof(addr)) + return -EINVAL; + memcpy_fromfs(&addr,uaddr,addr_len); + + if(ntohs(addr.sipx_port)<0x4000 && !suser()) + return(-EPERM); /* protect IPX system stuff like routing/sap */ + + /* Source addresses are easy. It must be our network:node pair for + an interface routed to IPX with the ipx routing ioctl() */ + + if(ipx_find_socket(addr.sipx_port)!=NULL) + { + if(sk->debug) + printk("IPX: bind failed because port %X in use.\n", + (int)addr.sipx_port); + return(-EADDRINUSE); + } + sk->ipx_source_addr.sock=addr.sipx_port; + memcpy(sk->ipx_source_addr.node,addr.sipx_node,sizeof(sk->ipx_source_addr.node)); + sk->ipx_source_addr.net=addr.sipx_network; + if((rt=ipxrtr_get_dev(sk->ipx_source_addr.net))==NULL) + { + if(sk->debug) + printk("IPX: bind failed (no device for net %lX)\n", + sk->ipx_source_addr.net); + return(-EADDRNOTAVAIL); + } + memset(sk->ipx_source_addr.node,'\0',6); + memcpy(sk->ipx_source_addr.node,rt->dev->dev_addr,rt->dev->addr_len); + ipx_insert_socket(sk); + sk->zapped=0; + if(sk->debug) + printk("IPX: socket is bound.\n"); + return(0); +} + +static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) +{ + ipx_socket *sk=(ipx_socket *)sock->data; + struct sockaddr_ipx addr; + int err; + + if(sk==NULL) + { + printk("IPX:connect:sock->data=NULL!\n"); + return 0; + } + + sk->state = TCP_CLOSE; + sock->state = SS_UNCONNECTED; + + if(addr_len!=sizeof(addr)) + return(-EINVAL); + err=verify_area(VERIFY_READ,uaddr,addr_len); + if(err) + return err; + memcpy_fromfs(&addr,uaddr,sizeof(addr)); + + if(ntohs(addr.sipx_port)<0x4000 && !suser()) + return -EPERM; + if(sk->ipx_source_addr.net==0) /* Must bind first - no autobinding in this */ + return -EINVAL; + + + sk->ipx_dest_addr.net=addr.sipx_network; + sk->ipx_dest_addr.sock=addr.sipx_port; + memcpy(sk->ipx_dest_addr.node,addr.sipx_node,sizeof(sk->ipx_source_addr.node)); + if(ipxrtr_get_dev(sk->ipx_dest_addr.net)==NULL) + return -ENETUNREACH; + sock->state = SS_CONNECTED; + sk->state=TCP_ESTABLISHED; + return(0); +} + +static int ipx_socketpair(struct socket *sock1, struct socket *sock2) +{ + return(-EOPNOTSUPP); +} + +static int ipx_accept(struct socket *sock, struct socket *newsock, int flags) +{ + if(newsock->data) + kfree_s(newsock->data,sizeof(ipx_socket)); + return -EOPNOTSUPP; +} + +static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + ipx_address *addr; + struct sockaddr_ipx sipx; + ipx_socket *sk; + int len; + int err; + + sk=(ipx_socket *)sock->data; + + err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long)); + if(err) + return err; + + len = get_fs_long(uaddr_len); + + err = verify_area(VERIFY_WRITE, uaddr, len); + if(err) + return err; + + if(lenstate!=TCP_ESTABLISHED) + return -ENOTCONN; + addr=&sk->ipx_dest_addr; + } + else + addr=&sk->ipx_source_addr; + + sipx.sipx_family = AF_IPX; + sipx.sipx_port = addr->sock; + sipx.sipx_network = addr->net; + memcpy(sipx.sipx_node,addr->node,sizeof(sipx.sipx_node)); + memcpy_tofs(uaddr,&sipx,sizeof(sipx)); + put_fs_long(len,uaddr_len); + return(0); +} + + +int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + /* NULL here for pt means the packet was looped back */ + ipx_socket *sock; + unsigned char *buff; + ipx_packet *ipx; + ipx_route *rt; + + buff=skb->data; + buff+=dev->hard_header_len; + ipx=(ipx_packet *)buff; + + if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) + { + /* We don't do checksum options. We can't really. Novell don't seem to have documented them. + If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be + the same... */ + kfree_skb(skb,FREE_READ); + return(0); + } + + /* Too small */ + if(htons(ipx->ipx_pktsize)hard_header_len) + { + kfree_skb(skb,FREE_READ); + return(0); + } + + /* Too many hops */ + if(ipx->ipx_tctrl>16) + { + kfree_skb(skb,FREE_READ); + return(0); + } + + /* Not us/broadcast */ + if(memcmp(dev->dev_addr,ipx->ipx_dest.node,dev->addr_len)!=0 + && memcmp(ipx_broadcast_node,ipx->ipx_dest.node,dev->addr_len)!=0) + { + /********************************************************************************************** + + IPX router. Roughly as per the Novell spec. This doesn't handle netbios flood fill + broadcast frames. See the Novell IPX router specification for more details + (for ftp from ftp.novell.com) + + ***********************************************************************************************/ + + struct sk_buff *skb2; + int free_it=0; + + /* Rule: Don't forward packets that have exceeded the hop limit. This is fixed at 16 in IPX */ + if(ipx->ipx_tctrl==16) + { + kfree_skb(skb,FREE_READ); + return(0); + } + + /* Don't forward if we don't have a route. We ought to go off and start hunting out routes but + if someone needs this _THEY_ can add it */ + rt=ipxrtr_get_dev(ipx->ipx_dest.net); + if(rt==NULL) /* Unlike IP we can send on the interface we received. Eg doing DIX/802.3 conversion */ + { + kfree_skb(skb,FREE_READ); + return(0); + } + if(rt->dev->hard_header_len!=dev->hard_header_len) + { + /* A different header length causes a copy. Awkward to avoid with the current + sk_buff stuff. */ + skb2=alloc_skb(skb->len,GFP_ATOMIC); + if(skb2==NULL) + { + kfree_skb(skb,FREE_READ); + return 0; + } + free_it=1; + skb2->free=1; + skb2->len=skb->len; + memcpy((char *)(skb2+1),(char *)(skb+1),skb->len); + buff=(char *)(skb2+1); + ipx=(ipx_packet *)(buff+dev->hard_header_len); + } + else + { + skb2=skb; + buff=(char *)(skb+1); + } + /* Now operate on the buffer */ + /* Increase hop count */ + ipx->ipx_tctrl++; + /* If the route is a gateway then forward to it */ + + dev->hard_header(buff, dev, + (rt->flags&IPX_RT_BLUEBOOK)?ntohs(ETH_P_IPX):ntohs(skb2->len), + (rt->flags&IPX_RT_ROUTED)?rt->router_node:ipx->ipx_dest.node, + NULL, /* Our source */ + skb2->len, + skb2); + + dev_queue_xmit(skb2,dev,SOPRI_NORMAL); + + if(free_it) + kfree_skb(skb,FREE_READ); + return(0); + } + /************ End of router: Now sanity check stuff for us ***************/ + + /* Ok its for us ! */ + + sock=ipx_find_socket(ipx->ipx_dest.sock); + if(sock==NULL) /* But not one of our sockets */ + { + kfree_skb(skb,FREE_READ); + return(0); + } + + if(sock->rmem_alloc>=sock->rcvbuf) + { + kfree_skb(skb,FREE_READ); /* Socket is full */ + return(0); + } + + sock->rmem_alloc+=skb->mem_len; + skb_queue_tail(&sock->receive_queue,skb); + if(!sock->dead) + sock->data_ready(sock,skb->len); + return(0); +} + + + + +static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, + unsigned flags, struct sockaddr *usip, int addr_len) +{ + ipx_socket *sk=(ipx_socket *)sock->data; + struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip; + int err; + struct sockaddr_ipx sipx; + struct sk_buff *skb; + struct device *dev; + struct ipx_packet *ipx; + int size; + ipx_route *rt; + + if(flags) + return -EINVAL; + if(len<0) + return -EINVAL; + if(len == 0) + return 0; + + if(usipx) + { + if(addr_len state!=TCP_ESTABLISHED) + return -ENOTCONN; + sipx.sipx_family=AF_IPX; + sipx.sipx_port=sk->ipx_dest_addr.sock; + sipx.sipx_network=sk->ipx_dest_addr.net; + memcpy(sipx.sipx_node,sk->ipx_dest_addr.node,sizeof(sipx.sipx_node)); + } + + if(sk->debug) + printk("IPX: sendto: Addresses built.\n"); + if(!sk->broadcast && memcmp(&sipx.sipx_node,&ipx_broadcast_node,6)==0) + return -ENETUNREACH; + /* Build a packet */ + + if(sk->debug) + printk("IPX: sendto: building packet.\n"); + err=verify_area(VERIFY_READ,ubuf,len); + if(err) + return err; + + size=sizeof(ipx_packet)+len; /* For mac headers */ + + /* Find out where this has to go */ + rt=ipxrtr_get_dev(sipx.sipx_network); + if(rt==NULL) + { + return -ENETUNREACH; + } + + dev=rt->dev; + + size+=dev->hard_header_len; + + if(sk->debug) + printk("IPX: sendto: allocating buffer (%d)\n",size-sizeof(struct sk_buff)); + + if(size+sk->wmem_alloc>sk->sndbuf) + return -EAGAIN; + + skb=alloc_skb(size,GFP_KERNEL); + if(skb==NULL) + return -ENOMEM; + if(skb->mem_len+sk->wmem_alloc>sk->sndbuf) + { + kfree_skb(skb,FREE_WRITE); + return -EAGAIN; + } + + sk->wmem_alloc+=skb->mem_len; + skb->sk=sk; + skb->free=1; + skb->arp=1; + skb->len=size-sizeof(struct sk_buff); + + if(sk->debug) + printk("Building MAC header.\n"); + skb->dev=rt->dev; + + dev->hard_header(skb->data,skb->dev, + (rt->flags&IPX_RT_BLUEBOOK)?ntohs(ETH_P_IPX):ntohs(len+sizeof(ipx_packet)), + (rt->flags&IPX_RT_ROUTED)?rt->router_node:sipx.sipx_node, + NULL, + len+sizeof(ipx_packet), + skb); + + /* Now the IPX */ + if(sk->debug) + printk("Building IPX Header.\n"); + ipx=(ipx_packet *)skb->data+skb->dev->hard_header_len; + ipx->ipx_checksum=0xFFFF; + ipx->ipx_pktsize=htons(len+sizeof(ipx_packet)); + ipx->ipx_tctrl=0; + ipx->ipx_type=sk->ipx_type; + memcpy(&ipx->ipx_source,&sk->ipx_source_addr,sizeof(ipx->ipx_source)); + ipx->ipx_dest.net=sipx.sipx_network; + memcpy(ipx->ipx_dest.node,sipx.sipx_node,sizeof(ipx->ipx_dest.node)); + ipx->ipx_dest.sock=sipx.sipx_port; + if(sk->debug) + printk("IPX: Appending user data.\n"); + /* User data follows immediately after the IPX data */ + memcpy_fromfs((char *)(ipx+1),ubuf,len); + if(sk->debug) + printk("IPX: Transmitting buffer\n"); + if(dev->flags&IFF_LOOPBACK) + /* loop back */ + ipx_rcv(skb,dev,NULL); + else + dev_queue_xmit(skb,dev,SOPRI_NORMAL); + return len; +} + +static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags) +{ + return ipx_sendto(sock,ubuf,size,noblock,flags,NULL,0); +} + +static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock) +{ + return ipx_send(sock,ubuf,size,noblock,0); +} + +static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags, struct sockaddr *sip, int *addr_len) +{ + ipx_socket *sk=(ipx_socket *)sock->data; + struct sockaddr_ipx *sipx=(struct sockaddr_ipx *)sip; + /* FILL ME IN */ + int copied = 0; + struct sk_buff *skb; + int er; + + if(sk->err) + { + er= -sk->err; + sk->err=0; + return er; + } + + if(size==0) + return 0; + if(size<0) + return -EINVAL; + if(addr_len) + { + er=verify_area(VERIFY_WRITE,addr_len,sizeof(*addr_len)); + if(er) + return er; + put_fs_long(sizeof(*sipx),addr_len); + } + if(sipx) + { + er=verify_area(VERIFY_WRITE,sipx,sizeof(*sipx)); + if(er) + return er; + } + er=verify_area(VERIFY_WRITE,ubuf,size); + if(er) + return er; + skb=skb_recv_datagram(sk,flags,noblock,&er); + if(skb==NULL) + return er; + copied=(sizelen)?size:skb->len; + skb_copy_datagram(skb,sizeof(struct ipx_packet),ubuf,copied); + sk->stamp=skb->stamp; + + if(sipx) + { + struct sockaddr_ipx addr; + + addr.sipx_family=AF_IPX; + addr.sipx_port=((ipx_packet*)skb->h.raw)->ipx_source.sock; + memcpy(addr.sipx_node,((ipx_packet*)skb->h.raw)->ipx_source.node,sizeof(addr.sipx_node)); + addr.sipx_network=((ipx_packet*)skb->h.raw)->ipx_source.net; + memcpy_tofs(sipx,&addr,sizeof(*sipx)); + } + skb_free_datagram(skb); + return(copied); +} + +static int ipx_recv(struct socket *sock, void *ubuf, int size , int noblock, + unsigned flags) +{ + ipx_socket *sk=(ipx_socket *)sock->data; + if(sk->zapped) + return -ENOTCONN; + return ipx_recvfrom(sock,ubuf,size,noblock,flags,NULL, NULL); +} + +static int ipx_read(struct socket *sock, char *ubuf, int size, int noblock) +{ + return ipx_recv(sock,ubuf,size,noblock,0); +} + + +static int ipx_shutdown(struct socket *sk,int how) +{ + return -EOPNOTSUPP; +} + +static int ipx_select(struct socket *sock , int sel_type, select_table *wait) +{ + ipx_socket *sk=(ipx_socket *)sock->data; + + return datagram_select(sk,sel_type,wait); +} + +static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) +{ + + switch(cmd) + { + case SIOCADDRT: + case SIOCDELRT: + if(!suser()) + return -EPERM; + return(ipxrtr_ioctl(cmd,(void *)arg)); + default: + return -EINVAL; + } + /*NOTREACHED*/ + return(0); +} + +static struct proto_ops ipx_proto_ops = { + AF_IPX, + + ipx_create, + ipx_dup, + ipx_release, + ipx_bind, + ipx_connect, + ipx_socketpair, + ipx_accept, + ipx_getname, + ipx_read, + ipx_write, + ipx_select, + ipx_ioctl, + ipx_listen, + ipx_send, + ipx_recv, + ipx_sendto, + ipx_recvfrom, + ipx_shutdown, + ipx_setsockopt, + ipx_getsockopt, + ipx_fcntl, +}; + +/* Called by ddi.c on kernel start up */ + +static struct packet_type ipx_8023_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_8023),*/ + 0, /* copy */ + ipx_rcv, + NULL, + NULL, +}; + +static struct packet_type ipx_dix_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_IPX),*/ + 0, /* copy */ + ipx_rcv, + NULL, + NULL, +}; + + +void ipx_proto_init(struct ddi_proto *pro) +{ + (void) sock_register(ipx_proto_ops.family, &ipx_proto_ops); + ipx_dix_packet_type.type=htons(ETH_P_IPX); + dev_add_pack(&ipx_dix_packet_type); + ipx_8023_packet_type.type=htons(ETH_P_802_3); + dev_add_pack(&ipx_8023_packet_type); + + printk("Swansea University Computer Society IPX 0.24 BETA for NET3 ALPHA.008\n"); + +} + +#endif diff -u --recursive --new-file v1.1.3/linux/net/inet/ipx.h linux/net/inet/ipx.h --- v1.1.3/linux/net/inet/ipx.h +++ linux/net/inet/ipx.h Wed Apr 13 12:52:25 1994 @@ -0,0 +1,64 @@ + +/* + * The following information is in its entirety obtained from: + * + * Novell 'IPX Router Specification' Version 1.10 + * Part No. 107-000029-001 + * + * Which is available from ftp.novell.com + */ + +#ifndef _IPX_H +#define _IPX_H + +#include + +typedef struct +{ + unsigned long net; + unsigned char node[6]; + unsigned short sock; +} ipx_address; + +#define ipx_broadcast_node "\377\377\377\377\377\377" + +typedef struct ipx_packet +{ + unsigned short ipx_checksum; +#define IPX_NO_CHECKSUM 0xFFFF + unsigned short ipx_pktsize; + unsigned char ipx_tctrl; + unsigned char ipx_type; +#define IPX_TYPE_UNKNOWN 0x00 +#define IPX_TYPE_RIP 0x01 /* may also be 0 */ +#define IPX_TYPE_SAP 0x04 /* may also be 0 */ +#define IPX_TYPE_SPX 0x05 /* Not yet implemented */ +#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */ +#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */ + ipx_address ipx_dest __attribute__ ((packed)); + ipx_address ipx_source __attribute__ ((packed)); +} ipx_packet; + + +typedef struct ipx_route +{ + unsigned long net; + unsigned char router_node[6]; + unsigned long router_net; + unsigned short flags; + struct device *dev; +#define IPX_RT_ROUTED 1 /* This isn't a direct route. Send via this if to node router_node */ +#define IPX_RT_BLUEBOOK 2 /* Use DIX 8137 frames not IEE802.3 */ + struct ipx_route *next; +} ipx_route; + + +typedef struct sock ipx_socket; + + +#include "ipxcall.h" +extern int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); + + + +#endif diff -u --recursive --new-file v1.1.3/linux/net/inet/ipxcall.h linux/net/inet/ipxcall.h --- v1.1.3/linux/net/inet/ipxcall.h +++ linux/net/inet/ipxcall.h Wed Apr 13 12:52:25 1994 @@ -0,0 +1,2 @@ +/* Seperate to keep compilation of Space.c simpler */ +extern void ipx_proto_init(struct ddi_proto *pro); diff -u --recursive --new-file v1.1.3/linux/net/inet/loopback.c linux/net/inet/loopback.c --- v1.1.3/linux/net/inet/loopback.c Wed Jan 19 13:27:09 1994 +++ linux/net/inet/loopback.c @@ -1,137 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Pseudo-driver for the loopback interface. - * - * Version: @(#)loopback.c 1.0.4b 08/16/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Donald Becker, - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For the statistics structure. */ - -#include -#include -#include - -#include "inet.h" -#include "dev.h" -#include "eth.h" -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include "skbuff.h" -#include "sock.h" -#include "arp.h" - - -static int -loopback_xmit(struct sk_buff *skb, struct device *dev) -{ - struct enet_statistics *stats = (struct enet_statistics *)dev->priv; - int done; - - DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb)); - if (skb == NULL || dev == NULL) return(0); - - cli(); - if (dev->tbusy != 0) { - sti(); - stats->tx_errors++; - return(1); - } - dev->tbusy = 1; - sti(); - - done = dev_rint(skb->data, skb->len, 0, dev); - if (skb->free) kfree_skb(skb, FREE_WRITE); - - while (done != 1) { - done = dev_rint(NULL, 0, 0, dev); - } - stats->tx_packets++; - - dev->tbusy = 0; - -#if 1 - __asm__("cmpl $0,_intr_count\n\t" - "jne 1f\n\t" - "movl _bh_active,%%eax\n\t" - "testl _bh_mask,%%eax\n\t" - "je 1f\n\t" - "incl _intr_count\n\t" - "call _do_bottom_half\n\t" - "decl _intr_count\n" - "1:" - : - : - : "ax", "dx", "cx"); -#endif - - return(0); -} - -static struct enet_statistics * -get_stats(struct device *dev) -{ - return (struct enet_statistics *)dev->priv; -} - -/* Initialize the rest of the LOOPBACK device. */ -int -loopback_init(struct device *dev) -{ - dev->mtu = 2000; /* MTU */ - dev->tbusy = 0; - dev->hard_start_xmit = loopback_xmit; - dev->open = NULL; -#if 1 - dev->hard_header = eth_header; - dev->add_arp = NULL; - dev->hard_header_len = ETH_HLEN; /* 14 */ - dev->addr_len = ETH_ALEN; /* 6 */ - dev->type = ARPHRD_ETHER; /* 0x0001 */ - dev->type_trans = eth_type_trans; - dev->rebuild_header = eth_rebuild_header; -#else - dev->hard_header_length = 0; - dev->add_arp = NULL; - dev->addr_len = 0; - dev->type = 0; /* loopback_type (0) */ - dev->hard_header = NULL; - dev->type_trans = NULL; - dev->rebuild_header = NULL; -#endif - dev->queue_xmit = dev_queue_xmit; - - /* New-style flags. */ - dev->flags = IFF_LOOPBACK; - dev->family = AF_INET; - dev->pa_addr = in_aton("127.0.0.1"); - dev->pa_brdaddr = in_aton("127.255.255.255"); - dev->pa_mask = in_aton("255.0.0.0"); - dev->pa_alen = sizeof(unsigned long); - dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); - memset(dev->priv, 0, sizeof(struct enet_statistics)); - dev->get_stats = get_stats; - - return(0); -}; diff -u --recursive --new-file v1.1.3/linux/net/inet/packet.c linux/net/inet/packet.c --- v1.1.3/linux/net/inet/packet.c Mon Jan 31 16:35:36 1994 +++ linux/net/inet/packet.c Wed Apr 13 12:52:26 1994 @@ -9,6 +9,7 @@ * * Authors: Ross Biro, * Fred N. van Kempen, + * Alan Cox, * * Fixes: * Alan Cox : verify_area() now used correctly @@ -19,257 +20,416 @@ * from all old Linux datagram code. * Alan Cox : Uses the improved datagram code. * Alan Cox : Added NULL's for socket options. + * Alan Cox : Re-commented the code. * * * 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 #include #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" -#include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include #include #include #include -#include "udp.h" -#include "raw.h" +/* + * We really ought to have a single public _inline_ min function! + */ -static unsigned long -min(unsigned long a, unsigned long b) +static unsigned long min(unsigned long a, unsigned long b) { - if (a < b) return(a); - return(b); + if (a < b) + return(a); + return(b); } -/* This should be the easiest of all, all we do is copy it into a buffer. */ -int -packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +/* + * This should be the easiest of all, all we do is copy it into a buffer. + */ + +int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { - struct sock *sk; - - sk = (struct sock *) pt->data; - skb->dev = dev; - skb->len += dev->hard_header_len; - - skb->sk = sk; - - /* Charge it too the socket. */ - if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); + struct sock *sk; + + /* + * When we registered the protcol we saved the socket in the data + * field for just this event. + */ + + sk = (struct sock *) pt->data; + + /* + * The SOCK_PACKET socket receives _all_ frames, and as such + * therefore needs to put the header back onto the buffer. + * (it was removed by inet_bh()). + */ + + skb->dev = dev; + skb->len += dev->hard_header_len; + + skb->sk = sk; + + /* + * Charge the memory to the socket. This is done specificially + * to prevent sockets using all the memory up. + */ + + if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) + { + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return(0); + } + sk->rmem_alloc += skb->mem_len; + + /* + * Queue the packet up, and wake anyone waiting for it. + */ + + skb_queue_tail(&sk->receive_queue,skb); + wake_up_interruptible(sk->sleep); + + /* + * Processing complete. + */ + + release_sock(sk); /* This is now effectively surplus in this layer */ return(0); - } - sk->rmem_alloc += skb->mem_len; - skb_queue_tail(&sk->rqueue,skb); - wake_up_interruptible(sk->sleep); - release_sock(sk); - return(0); } -/* This will do terrible things if len + ipheader + devheader > dev->mtu */ -static int -packet_sendto(struct sock *sk, unsigned char *from, int len, +/* + * Output a raw packet to a device layer. This bypasses all the other + * protocol layers and you must therefore supply it with a complete frame + */ + +static int packet_sendto(struct sock *sk, unsigned char *from, int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) { - struct sk_buff *skb; - struct device *dev; - struct sockaddr saddr; - int err; - - /* Check the flags. */ - if (flags) return(-EINVAL); - if (len < 0) return(-EINVAL); - - /* Get and verify the address. */ - if (usin) { - if (addr_len < sizeof(saddr)) return(-EINVAL); - err=verify_area(VERIFY_READ, usin, sizeof(saddr)); + struct sk_buff *skb; + struct device *dev; + struct sockaddr saddr; + int err; + + /* + * Check the flags. + */ + + if (flags) + return(-EINVAL); + if (len < 0) + return(-EINVAL); + + /* + * Get and verify the address. + */ + + if (usin) + { + if (addr_len < sizeof(saddr)) + return(-EINVAL); + err=verify_area(VERIFY_READ, usin, sizeof(saddr)); + if(err) + return err; + memcpy_fromfs(&saddr, usin, sizeof(saddr)); + } + else + return(-EINVAL); /* SOCK_PACKET must be sent giving an address */ + + + /* + * Check the buffer is readable. + */ + + err=verify_area(VERIFY_READ,from,len); if(err) - return err; - memcpy_fromfs(&saddr, usin, sizeof(saddr)); - } else - return(-EINVAL); + return(err); + + /* + * Find the device first to size check it + */ + + saddr.sa_data[13] = 0; + dev = dev_get(saddr.sa_data); + if (dev == NULL) + { + return(-ENXIO); + } - err=verify_area(VERIFY_READ,from,len); - if(err) - return(err); -/* Find the device first to size check it */ - - saddr.sa_data[13] = 0; - dev = dev_get(saddr.sa_data); - if (dev == NULL) { - return(-ENXIO); - } - if(len>dev->mtu) - return -EMSGSIZE; - -/* Now allocate the buffer, knowing 4K pagelimits wont break this line */ - skb = sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL); - - /* This shouldn't happen, but it could. */ - if (skb == NULL) { - DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n")); - return(-ENOMEM); - } - /* Fill it in */ - skb->mem_addr = skb; - skb->mem_len = len + sizeof(*skb); - skb->sk = sk; - skb->free = 1; - memcpy_fromfs(skb->data, from, len); - skb->len = len; - skb->next = NULL; - skb->arp = 1; - if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority); - else kfree_skb(skb, FREE_WRITE); - return(len); + /* + * You may not queue a frame bigger than the mtu. This is the lowest level + * raw protocol and you must do your own fragmentation at this level. + */ + + if(len>dev->mtu) + return -EMSGSIZE; + + /* + * Now allocate the buffer, knowing 4K pagelimits wont break this line. + */ + + skb = sk->prot->wmalloc(sk, len, 0, GFP_KERNEL); + + /* + * If the write buffer is full, then tough. At this level the user gets to + * deal with the problem. + */ + + if (skb == NULL) + { + DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n")); + return(-ENOMEM); + } + + /* + * Fill it in + */ + + skb->sk = sk; + skb->free = 1; + memcpy_fromfs(skb->data, from, len); + skb->len = len; + skb->arp = 1; /* No ARP needs doing on this (complete) frame */ + + /* + * Now send it + */ + + if (dev->flags & IFF_UP) + dev_queue_xmit(skb, dev, sk->priority); + else + kfree_skb(skb, FREE_WRITE); + return(len); } +/* + * A write to a SOCK_PACKET can't actually do anything useful and will + * always fail but we include it for completeness and future expansion. + */ -static int -packet_write(struct sock *sk, unsigned char *buff, +static int packet_write(struct sock *sk, unsigned char *buff, int len, int noblock, unsigned flags) { - return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0)); + return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0)); } +/* + * Close a SOCK_PACKET socket. This is fairly simple. We immediately go + * to 'closed' state and remove our protocol entry in the device list. + * The release_sock() will destroy the socket if a user has closed the + * file side of the object. + */ -static void -packet_close(struct sock *sk, int timeout) +static void packet_close(struct sock *sk, int timeout) { - sk->inuse = 1; - sk->state = TCP_CLOSE; - dev_remove_pack((struct packet_type *)sk->pair); - kfree_s((void *)sk->pair, sizeof(struct packet_type)); - sk->pair = NULL; - release_sock(sk); + sk->inuse = 1; + sk->state = TCP_CLOSE; + dev_remove_pack((struct packet_type *)sk->pair); + kfree_s((void *)sk->pair, sizeof(struct packet_type)); + sk->pair = NULL; + release_sock(sk); } +/* + * Create a packet of type SOCK_PACKET. We do one slightly irregular + * thing here that wants tidying up. We borrow the 'pair' pointer in + * the socket object so we can find the packet_type entry in the + * device list. The reverse is easy as we use the data field of the + * packet type to point to our socket. + */ -static int -packet_init(struct sock *sk) +static int packet_init(struct sock *sk) { - struct packet_type *p; - - p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) return(-ENOMEM); + struct packet_type *p; - p->func = packet_rcv; - p->type = sk->num; - p->data = (void *)sk; - dev_add_pack(p); + p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) + return(-ENOMEM); + + p->func = packet_rcv; + p->type = sk->num; + p->data = (void *)sk; + dev_add_pack(p); + + /* + * We need to remember this somewhere. + */ - /* We need to remember this somewhere. */ - sk->pair = (struct sock *)p; + sk->pair = (struct sock *)p; - return(0); + return(0); } /* - * This should be easy, if there is something there - * we return it, otherwise we block. + * Pull a packet from our receive queue and hand it to the user. + * If neccessary we block. */ -int -packet_recvfrom(struct sock *sk, unsigned char *to, int len, + +int packet_recvfrom(struct sock *sk, unsigned char *to, int len, int noblock, unsigned flags, struct sockaddr_in *sin, int *addr_len) { - int copied=0; - struct sk_buff *skb; - struct sockaddr *saddr; - int err; - - saddr = (struct sockaddr *)sin; - if (len == 0) return(0); - if (len < 0) return(-EINVAL); - - if (sk->shutdown & RCV_SHUTDOWN) return(0); - if (addr_len) { - err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); - if(err) - return err; - put_fs_long(sizeof(*saddr), addr_len); - } - - err=verify_area(VERIFY_WRITE,to,len); - if(err) - return err; - skb=skb_recv_datagram(sk,flags,noblock,&err); - if(skb==NULL) - return err; - copied = min(len, skb->len); - - memcpy_tofs(to, skb->data, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */ - - /* Copy the address. */ - if (saddr) { - struct sockaddr addr; - - addr.sa_family = skb->dev->type; - memcpy(addr.sa_data,skb->dev->name, 14); - verify_area(VERIFY_WRITE, saddr, sizeof(*saddr)); - memcpy_tofs(saddr, &addr, sizeof(*saddr)); - } - - skb_free_datagram(skb); /* Its either been used up, or its a peek_copy anyway */ - - release_sock(sk); - return(copied); + int copied=0; + struct sk_buff *skb; + struct sockaddr *saddr; + int err; + + saddr = (struct sockaddr *)sin; + if (len == 0) + return(0); + if (len < 0) + return(-EINVAL); + + if (sk->shutdown & RCV_SHUTDOWN) + return(0); + + /* + * If the address length field is there to be filled in, we fill + * it in now. + */ + + if (addr_len) + { + err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); + if(err) + return err; + put_fs_long(sizeof(*saddr), addr_len); + } + + if(saddr) + { + err=verify_area(VERIFY_WRITE, saddr, sizeof(*saddr)); + if(err) + return err; + } + + /* + * Check the user given area can be written to. + */ + + err=verify_area(VERIFY_WRITE,to,len); + if(err) + return err; + + /* + * Call the generic datagram receiver. This handles all sorts + * of horrible races and re-entrancy so we can forget about it + * in the protocol layers. + */ + + skb=skb_recv_datagram(sk,flags,noblock,&err); + + /* + * An error occured so return it. Because skb_recv_datagram() + * handles the blocking we don't see and worry about blocking + * retries. + */ + + if(skb==NULL) + return err; + + /* + * You lose any data beyond the buffer you gave. If it worries a + * user program they can ask the device for its MTU anyway. + */ + + copied = min(len, skb->len); + + memcpy_tofs(to, skb->data, copied); /* We can't use skb_copy_datagram here */ + + /* + * Copy the address. + */ + + if (saddr) + { + struct sockaddr addr; + + addr.sa_family = skb->dev->type; + memcpy(addr.sa_data,skb->dev->name, 14); + memcpy_tofs(saddr, &addr, sizeof(*saddr)); + } + + /* + * Free or return the buffer as appropriate. Again this hides all the + * races and re-entrancy issues from us. + */ + + skb_free_datagram(skb); + + /* + * We are done. + */ + + release_sock(sk); + return(copied); } -int -packet_read(struct sock *sk, unsigned char *buff, +/* + * A packet read can succeed and is just the same as a recvfrom but without the + * addresses being recorded. + */ + +int packet_read(struct sock *sk, unsigned char *buff, int len, int noblock, unsigned flags) { - return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); + return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); } -struct proto packet_prot = { - sock_wmalloc, - sock_rmalloc, - sock_wfree, - sock_rfree, - sock_rspace, - sock_wspace, - packet_close, - packet_read, - packet_write, - packet_sendto, - packet_recvfrom, - ip_build_header, - udp_connect, - NULL, - ip_queue_xmit, - ip_retransmit, - NULL, - NULL, - NULL, - datagram_select, - NULL, - packet_init, - NULL, - NULL, /* No set/get socket options */ - NULL, - 128, - 0, - {NULL,}, - "PACKET" +/* + * This structure declares to the lower layer socket subsystem currently + * incorrectly embedded in the IP code how to behave. This interface needs + * a lot of work and will change. + */ + +struct proto packet_prot = +{ + sock_wmalloc, + sock_rmalloc, + sock_wfree, + sock_rfree, + sock_rspace, + sock_wspace, + packet_close, + packet_read, + packet_write, + packet_sendto, + packet_recvfrom, + ip_build_header, /* Not actually used */ + NULL, + NULL, + ip_queue_xmit, /* These two are not actually used */ + ip_retransmit, + NULL, + NULL, + NULL, + datagram_select, + NULL, + packet_init, + NULL, + NULL, /* No set/get socket options */ + NULL, + 128, + 0, + {NULL,}, + "PACKET" }; diff -u --recursive --new-file v1.1.3/linux/net/inet/proc.c linux/net/inet/proc.c --- v1.1.3/linux/net/inet/proc.c Mon Apr 4 09:23:07 1994 +++ linux/net/inet/proc.c Wed Apr 13 12:52:26 1994 @@ -36,13 +36,13 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" #include "tcp.h" #include "udp.h" -#include "skbuff.h" +#include #include "sock.h" #include "raw.h" @@ -54,18 +54,21 @@ * happens, get__netinfo returns only part of the available infos. */ static int -get__netinfo(struct proto *pro, char *buffer, int format) +get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length) { struct sock **s_array; struct sock *sp; - char *pos=buffer; int i; int timer_active; unsigned long dest, src; unsigned short destp, srcp; + int len=0; + off_t pos=0; + off_t begin=0; + s_array = pro->sock_array; - pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n"); + len+=sprintf(buffer, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n"); /* * This was very pretty but didn't work when a socket is destroyed at the wrong moment * (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing @@ -86,7 +89,7 @@ timer_active = del_timer(&sp->timer); if (!timer_active) sp->timer.expires = 0; - pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n", + len+=sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n", i, src, srcp, dest, destp, sp->state, format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, @@ -94,40 +97,47 @@ SOCK_INODE(sp->socket)->i_uid); if (timer_active) add_timer(&sp->timer); - /* Is place in buffer too rare? then abort. */ - if (pos > buffer+PAGE_SIZE-90) { - printk("oops, too many %s sockets for netinfo.\n", - pro->name); - return(strlen(buffer)); - } - /* * All sockets with (port mod SOCK_ARRAY_SIZE) = i * are kept in sock_array[i], so we must follow the * 'next' link to get them all. */ sp = sp->next; + pos=begin+len; + if(posoffset+length) + break; } sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up before this will clear before we jump back and cli, so its not as bad as it looks */ + if(pos>offset+length) + break; } - return(strlen(buffer)); + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; } -int tcp_get_info(char *buffer) +int tcp_get_info(char *buffer, char **start, off_t offset, int length) { - return get__netinfo(&tcp_prot, buffer,0); + return get__netinfo(&tcp_prot, buffer,0, start, offset, length); } -int udp_get_info(char *buffer) +int udp_get_info(char *buffer, char **start, off_t offset, int length) { - return get__netinfo(&udp_prot, buffer,1); + return get__netinfo(&udp_prot, buffer,1, start, offset, length); } -int raw_get_info(char *buffer) +int raw_get_info(char *buffer, char **start, off_t offset, int length) { - return get__netinfo(&raw_prot, buffer,1); + return get__netinfo(&raw_prot, buffer,1, start, offset, length); } diff -u --recursive --new-file v1.1.3/linux/net/inet/protocol.c linux/net/inet/protocol.c --- v1.1.3/linux/net/inet/protocol.c Wed Dec 1 14:44:15 1993 +++ linux/net/inet/protocol.c Wed Apr 13 12:52:26 1994 @@ -29,12 +29,12 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include "icmp.h" #include "udp.h" diff -u --recursive --new-file v1.1.3/linux/net/inet/raw.c linux/net/inet/raw.c --- v1.1.3/linux/net/inet/raw.c Tue Apr 5 10:17:16 1994 +++ linux/net/inet/raw.c Wed Apr 13 12:52:26 1994 @@ -40,12 +40,14 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" +#if 0 #include "tcp.h" -#include "skbuff.h" +#endif +#include #include "sock.h" #include "icmp.h" #include "udp.h" @@ -101,13 +103,18 @@ " len=%d, saddr=%X, redo=%d, protocol=%X)\n", skb, dev, opt, daddr, len, saddr, redo, protocol)); - if (skb == NULL) return(0); - if (protocol == NULL) { + if (skb == NULL) + return(0); + + if (protocol == NULL) + { kfree_skb(skb, FREE_READ); return(0); } + sk = (struct sock *) protocol->data; - if (sk == NULL) { + if (sk == NULL) + { kfree_skb(skb, FREE_READ); return(0); } @@ -122,12 +129,14 @@ /* Charge it too the socket. */ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) { - skb->sk = NULL; + ip_statistics.IpInDiscards++; + skb->sk=NULL; kfree_skb(skb, FREE_READ); return(0); } sk->rmem_alloc += skb->mem_len; - skb_queue_tail(&sk->rqueue,skb); + ip_statistics.IpInDelivers++; + skb_queue_tail(&sk->receive_queue,skb); sk->data_ready(sk,skb->len); release_sock(sk); return(0); @@ -173,7 +182,7 @@ } if (sin.sin_port == 0) sin.sin_port = sk->protocol; - if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) return -EACCES; sk->inuse = 1; @@ -188,7 +197,7 @@ } skb = sk->prot->wmalloc(sk, - len+sizeof(*skb) + sk->prot->max_header, + len + sk->prot->max_header, 0, GFP_KERNEL); if (skb == NULL) { int tmp; @@ -210,12 +219,9 @@ sti(); } } - skb->mem_addr = skb; - skb->mem_len = len + sizeof(*skb) +sk->prot->max_header; skb->sk = sk; - skb->free = 1; /* these two should be unecessary. */ - skb->arp = 0; + skb->free = 1; tmp = sk->prot->build_header(skb, sk->saddr, sin.sin_addr.s_addr, &dev, @@ -244,6 +250,7 @@ } skb->len = tmp + len; + sk->prot->queue_xmit(sk, dev, skb, 1); release_sock(sk); return(len); @@ -345,6 +352,7 @@ copied = min(len, skb->len); skb_copy_datagram(skb, 0, to, copied); + sk->stamp=skb->stamp; /* Copy the address. */ if (sin) { diff -u --recursive --new-file v1.1.3/linux/net/inet/route.c linux/net/inet/route.c --- v1.1.3/linux/net/inet/route.c Sun Mar 13 16:20:59 1994 +++ linux/net/inet/route.c Wed Apr 13 12:52:27 1994 @@ -9,6 +9,8 @@ * * Authors: Ross Biro, * Fred N. van Kempen, + * Alan Cox, + * Linus Torvalds, * * Fixes: * Alan Cox : Verify area fixes. @@ -16,12 +18,15 @@ * Rui Oliveira : ICMP routing table updates * (rco@di.uminho.pt) Routing table insertion and update * Linus Torvalds : Rewrote bits to be sensible + * Alan Cox : Added BSD route gw semantics + * Alan Cox : Super /proc >4K * * 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 #include #include @@ -32,40 +37,52 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" #include "route.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" -#include "arp.h" #include "icmp.h" +/* + * The routing table list + */ static struct rtable *rt_base = NULL; + +/* + * Pointer to the loopback route + */ + static struct rtable *rt_loopback = NULL; -/* Dump the contents of a routing table entry. */ -static void -rt_print(struct rtable *rt) +/* + * Dump the contents of a routing table entry. + */ + +static void rt_print(struct rtable *rt) { - if (rt == NULL || inet_debug != DBG_RT) return; + + if (rt == NULL || inet_debug != DBG_RT) + return; - printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n", + printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n", (long) rt, (long) rt->rt_next, rt->rt_flags); - printk(" TARGET=%s ", in_ntoa(rt->rt_dst)); - printk("GW=%s ", in_ntoa(rt->rt_gateway)); - printk(" DEV=%s USE=%ld REF=%d\n", - (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name, - rt->rt_use, rt->rt_refcnt); + printk(" TARGET=%s ", in_ntoa(rt->rt_dst)); + printk("GW=%s ", in_ntoa(rt->rt_gateway)); + printk(" DEV=%s USE=%ld REF=%d\n", + (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name, + rt->rt_use, rt->rt_refcnt); } /* - * Remove a routing table entry. + * Remove a routing table entry. */ + static void rt_del(unsigned long dst) { struct rtable *r, **rp; @@ -73,14 +90,27 @@ DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst))); rp = &rt_base; + + /* + * This must be done with interrupts off because we could take + * an ICMP_REDIRECT. + */ + save_flags(flags); cli(); - while((r = *rp) != NULL) { - if (r->rt_dst != dst) { + while((r = *rp) != NULL) + { + if (r->rt_dst != dst) + { rp = &r->rt_next; continue; } *rp = r->rt_next; + + /* + * If we delete the loopback route update its pointer. + */ + if (rt_loopback == r) rt_loopback = NULL; kfree_s(r, sizeof(struct rtable)); @@ -90,9 +120,11 @@ /* - * Remove all routing table entries for a device. + * Remove all routing table entries for a device. This is called when + * a device is downed. */ -void rt_flush(struct device *dev) + +void ip_rt_flush(struct device *dev) { struct rtable *r; struct rtable **rp; @@ -116,12 +148,13 @@ } /* - * Used by 'rt_add()' when we can't get the netmask any other way.. + * Used by 'rt_add()' when we can't get the netmask any other way.. * - * If the lower byte or two are zero, we guess the mask based on the - * number of zero 8-bit net numbers, otherwise we use the "default" - * masks judging by the destination address and our device netmask. + * If the lower byte or two are zero, we guess the mask based on the + * number of zero 8-bit net numbers, otherwise we use the "default" + * masks judging by the destination address and our device netmask. */ + static inline unsigned long default_mask(unsigned long dst) { dst = ntohl(dst); @@ -132,6 +165,11 @@ return htonl(IN_CLASSC_NET); } + +/* + * If no mask is specified then generate a default entry. + */ + static unsigned long guess_mask(unsigned long dst, struct device * dev) { unsigned long mask; @@ -144,16 +182,25 @@ return dev->pa_mask; } + +/* + * Find the route entry through which our gateway will be reached + */ + static inline struct device * get_gw_dev(unsigned long gw) { struct rtable * rt; - for (rt = rt_base ; ; rt = rt->rt_next) { + for (rt = rt_base ; ; rt = rt->rt_next) + { if (!rt) return NULL; if ((gw ^ rt->rt_dst) & rt->rt_mask) continue; - /* gateways behind gateways are a no-no */ + /* + * Gateways behind gateways are a no-no + */ + if (rt->rt_flags & RTF_GATEWAY) return NULL; return rt->rt_dev; @@ -161,41 +208,78 @@ } /* - * rewrote rt_add(), as the old one was weird. Linus + * Rewrote rt_add(), as the old one was weird - Linus + * + * This routine is used to update the IP routing table, either + * from the kernel (ICMP_REDIRECT) or via an ioctl call issued + * by the superuser. */ -void rt_add(short flags, unsigned long dst, unsigned long mask, + +void ip_rt_add(short flags, unsigned long dst, unsigned long mask, unsigned long gw, struct device *dev) { struct rtable *r, *rt; struct rtable **rp; unsigned long cpuflags; - if (flags & RTF_HOST) { + /* + * A host is a unique machine and has no network bits. + */ + + if (flags & RTF_HOST) + { mask = 0xffffffff; - } else if (!mask) { - if (!((dst ^ dev->pa_addr) & dev->pa_mask)) { + } + + /* + * Calculate the network mask + */ + + else if (!mask) + { + if (!((dst ^ dev->pa_addr) & dev->pa_mask)) + { mask = dev->pa_mask; flags &= ~RTF_GATEWAY; - if (flags & RTF_DYNAMIC) { + if (flags & RTF_DYNAMIC) + { /*printk("Dynamic route to my own net rejected\n");*/ return; } - } else + } + else mask = guess_mask(dst, dev); dst &= mask; } + + /* + * A gateway must be reachable and not a local address + */ + if (gw == dev->pa_addr) flags &= ~RTF_GATEWAY; - if (flags & RTF_GATEWAY) { - /* don't try to add a gateway we can't reach.. */ + + if (flags & RTF_GATEWAY) + { + /* + * Don't try to add a gateway we can't reach.. + */ + if (dev != get_gw_dev(gw)) return; + flags |= RTF_GATEWAY; - } else + } + else gw = 0; - /* Allocate an entry. */ + + /* + * Allocate an entry and fill it in. + */ + rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC); - if (rt == NULL) { + if (rt == NULL) + { DPRINTF((DBG_RT, "RT: no memory for new route!\n")); return; } @@ -207,17 +291,26 @@ rt->rt_mask = mask; rt->rt_mtu = dev->mtu; rt_print(rt); + /* - * What we have to do is loop though this until we have - * found the first address which has a higher generality than - * the one in rt. Then we can put rt in right before it. + * What we have to do is loop though this until we have + * found the first address which has a higher generality than + * the one in rt. Then we can put rt in right before it. + * The interrupts must be off for this process. */ + save_flags(cpuflags); cli(); - /* remove old route if we are getting a duplicate. */ + + /* + * Remove old route if we are getting a duplicate. + */ + rp = &rt_base; - while ((r = *rp) != NULL) { - if (r->rt_dst != dst) { + while ((r = *rp) != NULL) + { + if (r->rt_dst != dst) + { rp = &r->rt_next; continue; } @@ -226,7 +319,11 @@ rt_loopback = NULL; kfree_s(r, sizeof(struct rtable)); } - /* add the new route */ + + /* + * Add the new route + */ + rp = &rt_base; while ((r = *rp) != NULL) { if ((r->rt_mask & mask) != mask) @@ -235,12 +332,27 @@ } rt->rt_next = r; *rp = rt; + + /* + * Update the loopback route + */ + if (rt->rt_dev->flags & IFF_LOOPBACK) rt_loopback = rt; + + /* + * Restore the interrupts and return + */ + restore_flags(cpuflags); return; } + +/* + * Check if a mask is acceptable. + */ + static inline int bad_mask(unsigned long mask, unsigned long addr) { if (addr & (mask = ~mask)) @@ -251,6 +363,10 @@ return 0; } +/* + * Process a route add request from the user + */ + static int rt_new(struct rtentry *r) { int err; @@ -258,7 +374,12 @@ struct device * dev = NULL; unsigned long flags, daddr, mask, gw; - if ((devname = r->rt_dev) != NULL) { + /* + * If a device is specified find it. + */ + + if ((devname = r->rt_dev) != NULL) + { err = getname(devname, &devname); if (err) return err; @@ -267,22 +388,37 @@ if (!dev) return -EINVAL; } + + /* + * If the device isn't INET, don't allow it + */ if (r->rt_dst.sa_family != AF_INET) return -EAFNOSUPPORT; + /* + * Make local copies of the important bits + */ + flags = r->rt_flags; daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr; mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr; gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr; -/* BSD emulation: Permits route add someroute gw one-of-my-addresses - to indicate which iface. Not as clean as the nice Linux dev technique - but people keep using it... */ - if (!dev && (flags & RTF_GATEWAY)) { + + /* + * BSD emulation: Permits route add someroute gw one-of-my-addresses + * to indicate which iface. Not as clean as the nice Linux dev technique + * but people keep using it... + */ + + if (!dev && (flags & RTF_GATEWAY)) + { struct device *dev2; - for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) { - if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) { + for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) + { + if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) + { flags &= ~RTF_GATEWAY; dev = dev2; break; @@ -290,30 +426,56 @@ } } + /* + * Ignore faulty masks + */ + if (bad_mask(mask, daddr)) mask = 0; + /* + * Set the mask to nothing for host routes. + */ + if (flags & RTF_HOST) mask = 0xffffffff; else if (mask && r->rt_genmask.sa_family != AF_INET) return -EAFNOSUPPORT; - if (flags & RTF_GATEWAY) { + /* + * You can only gateway IP via IP.. + */ + + if (flags & RTF_GATEWAY) + { if (r->rt_gateway.sa_family != AF_INET) return -EAFNOSUPPORT; if (!dev) dev = get_gw_dev(gw); - } else if (!dev) - dev = dev_check(daddr); + } + else if (!dev) + dev = ip_dev_check(daddr); + /* + * Unknown device. + */ + if (dev == NULL) return -ENETUNREACH; - rt_add(flags, daddr, mask, gw, dev); + /* + * Add the route + */ + + ip_rt_add(flags, daddr, mask, gw, dev); return 0; } +/* + * Remove a route, as requested by the user. + */ + static int rt_kill(struct rtentry *r) { struct sockaddr_in *trg; @@ -324,45 +486,83 @@ } -/* Called from the PROCfs module. */ -int -rt_get_info(char *buffer) +/* + * Called from the PROCfs module. This outputs /proc/net/route. + */ + +int rt_get_info(char *buffer, char **start, off_t offset, int length) { - struct rtable *r; - char *pos; - - pos = buffer; + struct rtable *r; + int len=0; + off_t pos=0; + off_t begin=0; + int size; - pos += sprintf(pos, + len += sprintf(buffer, "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n"); + pos=len; - /* This isn't quite right -- r->rt_dst is a struct! */ - for (r = rt_base; r != NULL; r = r->rt_next) { - pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n", - r->rt_dev->name, r->rt_dst, r->rt_gateway, - r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, - r->rt_mask); - } - return(pos - buffer); + /* + * This isn't quite right -- r->rt_dst is a struct! + */ + + for (r = rt_base; r != NULL; r = r->rt_next) + { + size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n", + r->rt_dev->name, r->rt_dst, r->rt_gateway, + r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, + r->rt_mask); + len+=size; + pos+=size; + if(posoffset+length) + break; + } + + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; } /* - * This is hackish, but results in better code. Use "-S" to see why. + * This is hackish, but results in better code. Use "-S" to see why. */ + #define early_out ({ goto no_route; 1; }) -struct rtable * rt_route(unsigned long daddr, struct options *opt) +/* + * Route a packet. This needs to be fairly quick. Florian & Co. + * suggested a unified ARP and IP routing cache. Done right its + * probably a brilliant idea. I'd actually suggest a unified + * ARP/IP routing/Socket pointer cache. Volunteers welcome + */ + +struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr) { struct rtable *rt; - for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) { + for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) + { if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) break; - /* broadcast addresses can be special cases.. */ + /* + * broadcast addresses can be special cases.. + */ + if ((rt->rt_dev->flags & IFF_BROADCAST) && rt->rt_dev->pa_brdaddr == daddr) break; } + + if(src_addr!=NULL) + *src_addr= rt->rt_dev->pa_addr; + if (daddr == rt->rt_dev->pa_addr) { if ((rt = rt_loopback) == NULL) goto no_route; @@ -373,7 +573,11 @@ return NULL; } -static int get_old_rtent(struct old_rtentry * src, struct rtentry * rt) +/* + * Backwards compatibility + */ + +static int ip_get_old_rtent(struct old_rtentry * src, struct rtentry * rt) { int err; struct old_rtentry tmp; @@ -389,34 +593,42 @@ ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask; rt->rt_flags = tmp.rt_flags; rt->rt_dev = tmp.rt_dev; + printk("Warning: obsolete routing request made.\n"); return 0; } -int rt_ioctl(unsigned int cmd, void *arg) +/* + * Handle IP routing ioctl calls. These are used to manipulate the routing tables + */ + +int ip_rt_ioctl(unsigned int cmd, void *arg) { int err; struct rtentry rt; - switch(cmd) { - case DDIOCSDBG: - return dbg_ioctl(arg, DBG_RT); - case SIOCADDRTOLD: - case SIOCDELRTOLD: - if (!suser()) - return -EPERM; - err = get_old_rtent((struct old_rtentry *) arg, &rt); - if (err) - return err; - return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt); - case SIOCADDRT: - case SIOCDELRT: - if (!suser()) - return -EPERM; - err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry)); - if (err) - return err; - memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); - return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); + switch(cmd) + { + case DDIOCSDBG: /* Control debugging */ + return dbg_ioctl(arg, DBG_RT); + + case SIOCADDRTOLD: /* Old style add route */ + case SIOCDELRTOLD: /* Old style delete route */ + if (!suser()) + return -EPERM; + err = ip_get_old_rtent((struct old_rtentry *) arg, &rt); + if (err) + return err; + return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt); + + case SIOCADDRT: /* Add a route */ + case SIOCDELRT: /* Delete a route */ + if (!suser()) + return -EPERM; + err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry)); + if (err) + return err; + memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); + return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); } return -EINVAL; diff -u --recursive --new-file v1.1.3/linux/net/inet/route.h linux/net/inet/route.h --- v1.1.3/linux/net/inet/route.h Tue Jan 25 08:30:29 1994 +++ linux/net/inet/route.h Wed Apr 13 12:52:27 1994 @@ -37,11 +37,11 @@ }; -extern void rt_flush(struct device *dev); -extern void rt_add(short flags, unsigned long addr, unsigned long mask, +extern void ip_rt_flush(struct device *dev); +extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask, unsigned long gw, struct device *dev); -extern struct rtable *rt_route(unsigned long daddr, struct options *opt); -extern int rt_get_info(char * buffer); -extern int rt_ioctl(unsigned int cmd, void *arg); +extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr); +extern int rt_get_info(char * buffer, char **start, off_t offset, int length); +extern int ip_rt_ioctl(unsigned int cmd, void *arg); #endif /* _ROUTE_H */ diff -u --recursive --new-file v1.1.3/linux/net/inet/skbuff.c linux/net/inet/skbuff.c --- v1.1.3/linux/net/inet/skbuff.c Wed Apr 13 11:33:59 1994 +++ linux/net/inet/skbuff.c Wed Apr 13 16:48:10 1994 @@ -1,19 +1,15 @@ /* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. + * Routines having to do with the 'struct sk_buff' memory handlers. * - * A saner implementation of the skbuff stuff scattered everywhere - * in the old NET2D code. - * * Authors: Alan Cox + * Florian La Roche * - * Fixes: - * Alan Cox : Tracks memory and number of buffers for kernel memory report - * and memory leak hunting. - * Alan Cox : More generic kfree handler + * 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 #include #include @@ -23,124 +19,178 @@ #include #include #include -#include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" -#include "arp.h" +#include #include "route.h" #include "tcp.h" #include "udp.h" -#include "skbuff.h" +#include #include "sock.h" -/* Socket buffer operations. Ideally much of this list swap stuff ought to be using - exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic - slow C version. No doubt when Linus sees this comment he'll do horrible things - to this code 8-) -*/ - /* * Resource tracking variables */ + +volatile unsigned long net_memory = 0; +volatile unsigned long net_skbcount = 0; -volatile unsigned long net_memory=0; -volatile unsigned long net_skbcount=0; +#if CONFIG_SKB_CHECK + /* * Debugging paranoia. Can go later when this crud stack works - */ + */ +int skb_check(struct sk_buff *skb, int head, int line, char *file) +{ + if (head) { + if (skb->magic_debug_cookie != SK_HEAD_SKB) { + printk("File: %s Line %d, found a bad skb-head\n", + file,line); + return -1; + } + if (!skb->next || !skb->prev) { + printk("skb_check: head without next or prev\n"); + return -1; + } + if (skb->next->magic_debug_cookie != SK_HEAD_SKB + && skb->next->magic_debug_cookie != SK_GOOD_SKB) { + printk("File: %s Line %d, bad next head-skb member\n", + file,line); + return -1; + } + if (skb->prev->magic_debug_cookie != SK_HEAD_SKB + && skb->prev->magic_debug_cookie != SK_GOOD_SKB) { + printk("File: %s Line %d, bad prev head-skb member\n", + file,line); + return -1; + } +#if 0 + { + struct sk_buff *skb2 = skb->next; + int i = 0; + while (skb2 != skb && i < 5) { + if (skb_check(skb2, 0, line, file) < 0) { + printk("bad queue element in whole queue\n"); + return -1; + } + i++; + skb2 = skb2->next; + } + } +#endif + return 0; + } + if (skb->next != NULL && skb->next->magic_debug_cookie != SK_HEAD_SKB + && skb->next->magic_debug_cookie != SK_GOOD_SKB) { + printk("File: %s Line %d, bad next skb member\n", + file,line); + return -1; + } + if (skb->prev != NULL && skb->prev->magic_debug_cookie != SK_HEAD_SKB + && skb->prev->magic_debug_cookie != SK_GOOD_SKB) { + printk("File: %s Line %d, bad prev skb member\n", + file,line); + return -1; + } -void skb_check(struct sk_buff *skb, int line, char *file) -{ if(skb->magic_debug_cookie==SK_FREED_SKB) { printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n", file,line); - printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n", - skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free); + printk("skb=%p, real size=%ld, claimed size=%ld, free=%d\n", + skb,skb->truesize,skb->mem_len,skb->free); + return -1; } if(skb->magic_debug_cookie!=SK_GOOD_SKB) { printk("File: %s Line %d, passed a non skb!\n", file,line); - printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n", - skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free); + printk("skb=%p, real size=%ld, claimed size=%ld, free=%d\n", + skb,skb->truesize,skb->mem_len,skb->free); + return -1; } if(skb->mem_len!=skb->truesize) { printk("File: %s Line %d, Dubious size setting!\n",file,line); - printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n", - skb,skb->truesize,skb->mem_len,skb->magic,skb->list); + printk("skb=%p, real size=%ld, claimed size=%ld\n", + skb,skb->truesize,skb->mem_len); + return -1; } /* Guess it might be acceptable then */ + return 0; +} +#endif + + +void skb_queue_head_init(struct sk_buff_head *list) +{ + list->prev = (struct sk_buff *)list; + list->next = (struct sk_buff *)list; +#if CONFIG_SKB_CHECK + list->magic_debug_cookie = SK_HEAD_SKB; +#endif } + /* * Insert an sk_buff at the start of a list. */ - -void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk) + +void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk) { unsigned long flags; + struct sk_buff *list = (struct sk_buff *)list_; - IS_SKB(newsk); - if(newsk->list) - printk("Suspicious queue head: sk_buff on list!\n"); save_flags(flags); cli(); - newsk->list=list; + +#if CONFIG_SKB_CHECK + IS_SKB(newsk); + IS_SKB_HEAD(list); + if (newsk->next || newsk->prev) + printk("Suspicious queue head: sk_buff on list!\n"); +#endif - newsk->next=*list; + newsk->next = list->next; + newsk->prev = list; - if(*list) - newsk->prev=(*list)->prev; - else - newsk->prev=newsk; - newsk->prev->next=newsk; - newsk->next->prev=newsk; - IS_SKB(newsk->prev); - IS_SKB(newsk->next); - *list=newsk; + newsk->next->prev = newsk; + newsk->prev->next = newsk; + restore_flags(flags); } /* * Insert an sk_buff at the end of a list. */ - -void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk) + +void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) { unsigned long flags; - - if(newsk->list) - printk("Suspicious queue tail: sk_buff on list!\n"); + struct sk_buff *list = (struct sk_buff *)list_; - IS_SKB(newsk); save_flags(flags); cli(); - newsk->list=list; - if(*list) - { - (*list)->prev->next=newsk; - newsk->prev=(*list)->prev; - newsk->next=*list; - (*list)->prev=newsk; - } - else - { - newsk->next=newsk; - newsk->prev=newsk; - *list=newsk; - } - IS_SKB(newsk->prev); - IS_SKB(newsk->next); - restore_flags(flags); +#if CONFIG_SKB_CHECK + if (newsk->next || newsk->prev) + printk("Suspicious queue tail: sk_buff on list!\n"); + IS_SKB(newsk); + IS_SKB_HEAD(list); +#endif + newsk->next = list; + newsk->prev = list->prev; + + newsk->next->prev = newsk; + newsk->prev->next = newsk; + + restore_flags(flags); } /* @@ -148,93 +198,88 @@ * so you can grab read and free buffers as another process adds them. */ -struct sk_buff *skb_dequeue(struct sk_buff *volatile* list) +struct sk_buff *skb_dequeue(struct sk_buff_head *list_) { long flags; struct sk_buff *result; + struct sk_buff *list = (struct sk_buff *)list_; save_flags(flags); cli(); - if(*list==NULL) - { + IS_SKB_HEAD(list); + + result = list->next; + if (result == list) { restore_flags(flags); - return(NULL); + return NULL; } + + result->next->prev = list; + list->next = result->next; - result=*list; - if(result->next==result) - *list=NULL; - else - { - result->next->prev=result->prev; - result->prev->next=result->next; - *list=result->next; - } + result->next = NULL; + result->prev = NULL; - IS_SKB(result); restore_flags(flags); - - if(result->list!=list) - printk("Dequeued packet has invalid list pointer\n"); - - result->list=0; - result->next=0; - result->prev=0; - return(result); + + return result; } /* * Insert a packet before another one in a list. */ - + void skb_insert(struct sk_buff *old, struct sk_buff *newsk) { unsigned long flags; +#if CONFIG_SKB_CHECK IS_SKB(old); IS_SKB(newsk); - if(!old->list) + if(!old->next || !old->prev) printk("insert before unlisted item!\n"); - if(newsk->list) + if(newsk->next || newsk->prev) printk("inserted item is already on a list.\n"); +#endif save_flags(flags); cli(); - newsk->list=old->list; - newsk->next=old; - newsk->prev=old->prev; - newsk->next->prev=newsk; - newsk->prev->next=newsk; - + newsk->next = old; + newsk->prev = old->prev; + old->prev = newsk; + newsk->prev->next = newsk; + restore_flags(flags); } /* * Place a packet after a given packet in a list. */ - + void skb_append(struct sk_buff *old, struct sk_buff *newsk) { unsigned long flags; +#if CONFIG_SKB_CHECK IS_SKB(old); IS_SKB(newsk); - if(!old->list) + if(!old->next || !old->prev) printk("append before unlisted item!\n"); - if(newsk->list) + if(newsk->next || newsk->prev) printk("append item is already on a list.\n"); +#endif save_flags(flags); cli(); - newsk->list=old->list; - newsk->prev=old; - newsk->next=old->next; - newsk->next->prev=newsk; - newsk->prev->next=newsk; + newsk->prev = old; + newsk->next = old->next; + newsk->next->prev = newsk; + old->next = newsk; + restore_flags(flags); } @@ -244,131 +289,94 @@ * MUST EXIST when you unlink. Thus a list must have its contents unlinked * _FIRST_. */ - + void skb_unlink(struct sk_buff *skb) { unsigned long flags; + save_flags(flags); cli(); IS_SKB(skb); - if(skb->list) + if(skb->prev && skb->next) { - skb->next->prev=skb->prev; - skb->prev->next=skb->next; - if(*skb->list==skb) - { - if(skb->next==skb) - *skb->list=NULL; - else - *skb->list=skb->next; - } - skb->next=0; - skb->prev=0; - skb->list=0; + skb->next->prev = skb->prev; + skb->prev->next = skb->next; + skb->next = NULL; + skb->prev = NULL; } +#ifdef PARANOID_BUGHUNT_MODE /* This is legal but we sometimes want to watch it */ + else + printk("skb_unlink: not a linked element\n"); +#endif restore_flags(flags); } /* - * An skbuff list has had its head reassigned. Move all the list - * pointers. Must be called with ints off during the whole head - * shifting - */ - -void skb_new_list_head(struct sk_buff *volatile* list) -{ - struct sk_buff *skb=skb_peek(list); - if(skb!=NULL) - { - do - { - IS_SKB(skb); - skb->list=list; - skb=skb->next; - } - while(skb!=*list); - } -} - -/* - * Peek an sk_buff. Unlike most other operations you _MUST_ - * be careful with this one. A peek leaves the buffer on the - * list and someone else may run off with it. For an interrupt - * type system cli() peek the buffer copy the data and sti(); - */ - -struct sk_buff *skb_peek(struct sk_buff *volatile* list) -{ - return *list; -} - -/* * Get a clone of an sk_buff. This is the safe way to peek at * a socket queue without accidents. Its a bit long but most * of it acutally ends up as tiny bits of inline assembler * anyway. Only the memcpy of upto 4K with ints off is not * as nice as I'd like. */ - -struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list) + +struct sk_buff *skb_peek_copy(struct sk_buff_head *list_) { + struct sk_buff *list = (struct sk_buff *)list_; struct sk_buff *orig,*newsk; unsigned long flags; unsigned int len; /* Now for some games to avoid races */ + IS_SKB_HEAD(list); do { save_flags(flags); cli(); - orig=skb_peek(list); - if(orig==NULL) - { + orig = list->next; + if (orig == list) { restore_flags(flags); return NULL; } IS_SKB(orig); - len=orig->truesize; + len = orig->truesize; restore_flags(flags); - newsk=alloc_skb(len,GFP_KERNEL); /* May sleep */ + newsk = alloc_skb(len,GFP_KERNEL); /* May sleep */ - if(newsk==NULL) /* Oh dear... not to worry */ + if (newsk == NULL) /* Oh dear... not to worry */ return NULL; - + save_flags(flags); cli(); - if(skb_peek(list)!=orig) /* List changed go around another time */ + if (list->next != orig) /* List changed go around another time */ { restore_flags(flags); - newsk->sk=NULL; - newsk->free=1; - newsk->mem_addr=newsk; - newsk->mem_len=len; + newsk->sk = NULL; + newsk->free = 1; + newsk->mem_addr = newsk; + newsk->mem_len = len; kfree_skb(newsk, FREE_WRITE); continue; } - + IS_SKB(orig); IS_SKB(newsk); memcpy(newsk,orig,len); - newsk->list=NULL; - newsk->magic=0; - newsk->next=NULL; - newsk->prev=NULL; - newsk->mem_addr=newsk; - newsk->h.raw+=((char *)newsk-(char *)orig); - newsk->link3=NULL; - newsk->sk=NULL; - newsk->free=1; + newsk->next = NULL; + newsk->prev = NULL; + newsk->mem_addr = newsk; + newsk->h.raw += ((char *)newsk - (char *)orig); + newsk->link3 = NULL; + newsk->sk = NULL; + newsk->free = 1; } while(0); - + restore_flags(flags); - return(newsk); -} + return newsk; +} /* * Free an sk_buff. This still knows about things it should @@ -377,30 +385,29 @@ void kfree_skb(struct sk_buff *skb, int rw) { - if (skb == NULL) { + if (skb == NULL) + { printk("kfree_skb: skb = NULL\n"); return; - } + } IS_SKB(skb); - if(skb->lock) + if (skb->lock) { - skb->free=1; /* Free when unlocked */ + skb->free = 1; /* Free when unlocked */ return; - } - - if(skb->free == 2) + } + if (skb->free == 2) printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n"); - if(skb->list) - printk("Warning: kfree_skb passed an skb still on a list.\n"); - skb->magic = 0; - if (skb->sk) + if (skb->next) + printk("Warning: kfree_skb passed an skb still on a list.\n"); + if (skb->sk) { - if(skb->sk->prot!=NULL) + if(skb->sk->prot!=NULL) { if (rw) - skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len); - else - skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len); + skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len); + else + skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len); } else @@ -411,11 +418,11 @@ else skb->sk->wmem_alloc-=skb->mem_len; if(!skb->sk->dead) - wake_up_interruptible(skb->sk->sleep); + wake_up_interruptible(skb->sk->sleep); kfree_skbmem(skb->mem_addr,skb->mem_len); } - } - else + } + else kfree_skbmem(skb->mem_addr, skb->mem_len); } @@ -423,57 +430,111 @@ * Allocate a new skbuff. We do this ourselves so we can fill in a few 'private' * fields and also do memory statistics to find all the [BEEP] leaks. */ - -struct sk_buff *alloc_skb(unsigned int size,int priority) -{ - struct sk_buff *skb; - - if (intr_count && priority != GFP_ATOMIC) { + + struct sk_buff *alloc_skb(unsigned int size,int priority) + { + struct sk_buff *skb; + + if (intr_count && priority!=GFP_ATOMIC) { static int count = 0; if (++count < 5) { printk("alloc_skb called nonatomically from interrupt %08lx\n", ((unsigned long *)&size)[-1]); priority = GFP_ATOMIC; } - } - skb=(struct sk_buff *)kmalloc(size,priority); - if(skb==NULL) - return NULL; - skb->free= 2; /* Invalid so we pick up forgetful users */ - skb->list= 0; /* Not on a list */ - skb->lock= 0; - skb->truesize=size; - skb->mem_len=size; - skb->mem_addr=skb; - skb->fraglist=NULL; - net_memory+=size; - net_skbcount++; - skb->magic_debug_cookie=SK_GOOD_SKB; - skb->users=0; - return skb; + } + + size+=sizeof(struct sk_buff); + skb=(struct sk_buff *)kmalloc(size,priority); + if (skb == NULL) + return NULL; + + skb->free = 2; /* Invalid so we pick up forgetful users */ + skb->lock = 0; + skb->truesize = size; + skb->mem_len = size; + skb->mem_addr = skb; + skb->fraglist = NULL; + skb->prev = skb->next = NULL; + skb->link3 = NULL; + skb->sk = NULL; + skb->stamp.tv_sec=0; /* No idea about time */ + net_memory += size; + net_skbcount++; +#if CONFIG_SKB_CHECK + skb->magic_debug_cookie = SK_GOOD_SKB; +#endif + skb->users = 0; + return skb; } /* * Free an skbuff by memory - */ + */ void kfree_skbmem(void *mem,unsigned size) { - struct sk_buff *x=(struct sk_buff *) mem; +#if CONFIG_SKB_CHECK + struct sk_buff *x = mem; IS_SKB(x); - if(x->magic_debug_cookie==SK_GOOD_SKB) + if(x->magic_debug_cookie == SK_GOOD_SKB) { - x->magic_debug_cookie=SK_FREED_SKB; + x->magic_debug_cookie = SK_FREED_SKB; kfree_s(mem,size); net_skbcount--; - net_memory-=size; + net_memory -= size; } + else + printk("kfree_skbmem: bad magic cookie\n"); +#else + kfree_s(mem, size); +#endif } /* - * Skbuff device locking + * Duplicate an sk_buff. The new one is not owned by a socket or locked + * and will be freed on deletion. */ - + +struct sk_buff *skb_clone(struct sk_buff *skb, int priority) +{ + struct sk_buff *n; + unsigned long offset; + + n=alloc_skb(skb->mem_len-sizeof(struct sk_buff),priority); + if(n==NULL) + return NULL; + + offset=((char *)n)-((char *)skb); + + memcpy(n->data,skb->data,skb->mem_len-sizeof(struct sk_buff)); + n->len=skb->len; + n->link3=NULL; + n->sk=NULL; + n->when=skb->when; + n->dev=skb->dev; + n->h.raw=skb->h.raw+offset; + n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset); + n->fraglen=skb->fraglen; + n->fraglist=skb->fraglist; + n->saddr=skb->saddr; + n->daddr=skb->daddr; + n->raddr=skb->raddr; + n->acked=skb->acked; + n->used=skb->used; + n->free=1; + n->arp=skb->arp; + n->tries=0; + n->lock=0; + n->users=0; + return n; +} + + +/* + * Skbuff device locking + */ + void skb_kept_by_device(struct sk_buff *skb) { skb->lock++; @@ -485,16 +546,13 @@ save_flags(flags); cli(); - if (!--skb->lock) { - if (skb->free==1) - kfree_skb(skb,mode); - } + if (!--skb->lock && skb->free == 1) + kfree_skb(skb,mode); restore_flags(flags); } int skb_device_locked(struct sk_buff *skb) { - if(skb->lock) - return 1; - return 0; + return skb->lock? 1 : 0; } + diff -u --recursive --new-file v1.1.3/linux/net/inet/skbuff.h linux/net/inet/skbuff.h --- v1.1.3/linux/net/inet/skbuff.h Tue Apr 5 07:30:48 1994 +++ linux/net/inet/skbuff.h @@ -1,111 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the 'struct sk_buff' memory handlers. - * - * Version: @(#)skbuff.h 1.0.4 05/20/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Corey Minyard - * - * Fixes: - * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff) - * Alan Cox : Declaration for new primitives - * Alan Cox : Fraglist support (idea by Donald Becker) - * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy - * being used. - * - * 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. - */ -#ifndef _SKBUFF_H -#define _SKBUFF_H -#include - -#ifdef CONFIG_IPX -#include "ipx.h" -#endif - -#define HAVE_ALLOC_SKB /* For the drivers to know */ - - -#define FREE_READ 1 -#define FREE_WRITE 0 - - -struct sk_buff { - unsigned long magic_debug_cookie; - struct sk_buff *volatile next; - struct sk_buff *volatile prev; - struct sk_buff *volatile link3; - struct sk_buff *volatile* list; - struct sock *sk; - volatile unsigned long when; /* used to compute rtt's */ - struct device *dev; - void *mem_addr; - union { - struct tcphdr *th; - struct ethhdr *eth; - struct iphdr *iph; - struct udphdr *uh; - struct arphdr *arp; - unsigned char *raw; - unsigned long seq; -#ifdef CONFIG_IPX - ipx_packet *ipx; -#endif - } h; - struct iphdr *ip_hdr; /* For IPPROTO_RAW */ - unsigned long mem_len; - unsigned long len; - unsigned long fraglen; - struct sk_buff *fraglist; /* Fragment list */ - unsigned long truesize; - unsigned long saddr; - unsigned long daddr; - int magic; - volatile char acked, - used, - free, - arp; - unsigned char tries,lock; /* Lock is now unused */ - unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ - unsigned long padding[0]; - unsigned char data[0]; -}; - -#define SK_WMEM_MAX 32767 -#define SK_RMEM_MAX 32767 - -#define SK_FREED_SKB 0x0DE2C0DE -#define SK_GOOD_SKB 0xDEC0DED1 - -extern void print_skb(struct sk_buff *); -extern void kfree_skb(struct sk_buff *skb, int rw); -extern void skb_queue_head(struct sk_buff * volatile *list,struct sk_buff *buf); -extern void skb_queue_tail(struct sk_buff * volatile *list,struct sk_buff *buf); -extern struct sk_buff * skb_dequeue(struct sk_buff * volatile *list); -extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk); -extern void skb_append(struct sk_buff *old,struct sk_buff *newsk); -extern void skb_unlink(struct sk_buff *buf); -extern void skb_new_list_head(struct sk_buff *volatile* list); -extern struct sk_buff * skb_peek(struct sk_buff * volatile *list); -extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list); -extern struct sk_buff * alloc_skb(unsigned int size, int priority); -extern void kfree_skbmem(void *mem, unsigned size); -extern void skb_kept_by_device(struct sk_buff *skb); -extern void skb_device_release(struct sk_buff *skb, int mode); -extern int skb_device_locked(struct sk_buff *skb); -extern void skb_check(struct sk_buff *skb,int, char *); -#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__) - -extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); -extern int datagram_select(struct sock *sk, int sel_type, select_table *wait); -extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); -extern void skb_free_datagram(struct sk_buff *skb); -#endif /* _SKBUFF_H */ diff -u --recursive --new-file v1.1.3/linux/net/inet/snmp.h linux/net/inet/snmp.h --- v1.1.3/linux/net/inet/snmp.h +++ linux/net/inet/snmp.h Wed Apr 13 12:52:27 1994 @@ -0,0 +1,107 @@ +/* + * + * SNMP MIB entries for the IP subsystem. + * + * Alan Cox + * + * We don't chose to implement SNMP in the kernel (this would + * be silly as SNMP is a pain in the backside in places). We do + * however need to collect the MIB statistics and export them + * out of /proc (eventually) + * + * 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. + * + */ + +#ifndef _SNMP_H +#define _SNMP_H + +/* + * We use all unsigned longs. Linux will soon be so reliable that even these + * will rapidly get too small 8-). Seriously consider the IpInReceives count + * on the 20Gb/s + networks people expect in a few years time! + */ + +struct ip_mib +{ + unsigned long IpForwarding; + unsigned long IpDefaultTTL; + unsigned long IpInReceives; + unsigned long IpInHdrErrors; + unsigned long IpInAddrErrors; + unsigned long IpForwDatagrams; + unsigned long IpInUnknownProtos; + unsigned long IpInDiscards; + unsigned long IpInDelivers; + unsigned long IpOutRequests; + unsigned long IpOutDiscards; + unsigned long IpOutNoRoutes; + unsigned long IpReasmTimeout; + unsigned long IpReasmReqds; + unsigned long IpReasmOKs; + unsigned long IpReasmFails; + unsigned long IpFragOKs; + unsigned long IpFragFails; + unsigned long IpFragCreates; +}; + + +struct icmp_mib +{ + unsigned long IcmpInMsgs; + unsigned long IcmpInErrors; + unsigned long IcmpInDestUnreachs; + unsigned long IcmpInTimeExcds; + unsigned long IcmpInParmProbs; + unsigned long IcmpInSrcQuenchs; + unsigned long IcmpInRedirects; + unsigned long IcmpInEchos; + unsigned long IcmpInEchoReps; + unsigned long IcmpInTimestamps; + unsigned long IcmpInTimestampReps; + unsigned long IcmpInAddrMasks; + unsigned long IcmpInAddrMaskReps; + unsigned long IcmpOutMsgs; + unsigned long IcmpOutErrors; + unsigned long IcmpOutDestUnreachs; + unsigned long IcmpOutTimeExcds; + unsigned long IcmpOutParmProbs; + unsigned long IcmpOutSrcQuenchs; + unsigned long IcmpOutRedirects; + unsigned long IcmpOutEchos; + unsigned long IcmpOutEchoReps; + unsigned long IcmpOutTimestamps; + unsigned long IcmpOutTimestampReps; + unsigned long IcmpOutAddrMasks; + unsigned long IcmpOutAddrMaskReps; +}; + +struct tcp_mib +{ + unsigned long TcpRtoAlgorithm; + unsigned long TcpRtoMin; + unsigned long TcpRtoMax; + unsigned long TcpMaxConn; + unsigned long TcpActiveOpens; + unsigned long TcpPassiveOpens; + unsigned long TcpAttemptFails; + unsigned long TcpEstabResets; + unsigned long TcpCurrEstab; + unsigned long TcpInSegs; + unsigned long TcpOutSegs; + unsigned long TcpRetransSegs; +}; + +struct udp_mib +{ + unsigned long UdpInDatagrams; + unsigned long UdpNoPorts; + unsigned long UdpInErrors; + unsigned long UdpOutDatagrams; +}; + + +#endif diff -u --recursive --new-file v1.1.3/linux/net/inet/sock.c linux/net/inet/sock.c --- v1.1.3/linux/net/inet/sock.c Tue Apr 5 07:37:25 1994 +++ linux/net/inet/sock.c Wed Apr 13 12:52:28 1994 @@ -81,15 +81,15 @@ #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" #include "arp.h" #include "route.h" #include "tcp.h" #include "udp.h" -#include "skbuff.h" +#include #include "sock.h" #include "raw.h" #include "icmp.h" @@ -112,10 +112,7 @@ } printk(" wmem_alloc = %lu\n", sk->wmem_alloc); printk(" rmem_alloc = %lu\n", sk->rmem_alloc); - printk(" send_head = %p\n", sk->send_head); printk(" state = %d\n",sk->state); - printk(" wback = %p, rqueue = %p\n", sk->wback, sk->rqueue); - printk(" wfront = %p\n", sk->wfront); printk(" daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr); printk(" num = %d", sk->num); printk(" next = %p\n", sk->next); @@ -124,7 +121,7 @@ printk(" rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n", sk->rcv_ack_seq, sk->window_seq, sk->fin_seq); printk(" prot = %p\n", sk->prot); - printk(" pair = %p, back_log = %p\n", sk->pair,sk->back_log); + printk(" pair = %p\n", sk->pair); printk(" inuse = %d , blog = %d\n", sk->inuse, sk->blog); printk(" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks); printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout); @@ -134,6 +131,7 @@ } +#if 0 void print_skb(struct sk_buff *skb) { @@ -146,6 +144,7 @@ printk(" mem_addr = %p, mem_len = %lu\n", skb->mem_addr, skb->mem_len); printk(" used = %d free = %d\n", skb->used,skb->free); } +#endif @@ -272,10 +271,6 @@ struct sock *sk2; DPRINTF((DBG_INET, "remove_sock(sk1=%X)\n", sk1)); - if (!sk1) { - printk("sock.c: remove_sock: sk1 == NULL\n"); - return; - } if (!sk1->prot) { printk("sock.c: remove_sock: sk1->prot == NULL\n"); @@ -323,97 +318,61 @@ /* Now we can no longer get new packets. */ delete_timer(sk); - - while ((skb = tcp_dequeue_partial(sk)) != NULL) - { - IS_SKB(skb); - kfree_skb(skb, FREE_WRITE); - } - - /* Cleanup up the write buffer. */ - for(skb = sk->wfront; skb != NULL; ) - { - struct sk_buff *skb2; + while ((skb = tcp_dequeue_partial(sk)) != NULL) { + IS_SKB(skb); + kfree_skb(skb, FREE_WRITE); + } - skb2=(struct sk_buff *)skb->next; - if (skb->magic != TCP_WRITE_QUEUE_MAGIC) { - printk("sock.c:destroy_sock write queue with bad magic(%X)\n", - skb->magic); - break; - } + /* Cleanup up the write buffer. */ + while((skb = skb_dequeue(&sk->write_queue)) != NULL) { IS_SKB(skb); kfree_skb(skb, FREE_WRITE); - skb = skb2; } - sk->wfront = NULL; - sk->wback = NULL; - - if (sk->rqueue != NULL) - { - while((skb=skb_dequeue(&sk->rqueue))!=NULL) - { - /* - * This will take care of closing sockets that were - * listening and didn't accept everything. - */ - if (skb->sk != NULL && skb->sk != sk) - { - IS_SKB(skb); - skb->sk->dead = 1; - skb->sk->prot->close(skb->sk, 0); - } + while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { + /* + * This will take care of closing sockets that were + * listening and didn't accept everything. + */ + if (skb->sk != NULL && skb->sk != sk) + { IS_SKB(skb); - kfree_skb(skb, FREE_READ); + skb->sk->dead = 1; + skb->sk->prot->close(skb->sk, 0); } - } - sk->rqueue = NULL; + IS_SKB(skb); + kfree_skb(skb, FREE_READ); + } /* Now we need to clean up the send head. */ - for(skb = sk->send_head; skb != NULL; ) - { + cli(); + for(skb = sk->send_head; skb != NULL; ) + { struct sk_buff *skb2; /* * We need to remove skb from the transmit queue, * or maybe the arp queue. */ - cli(); - /* see if it's in a transmit queue. */ - /* this can be simplified quite a bit. Look */ - /* at tcp.c:tcp_ack to see how. */ - if (skb->next != NULL) - { + if (skb->next && skb->prev) { + printk("destroy_sock: unlinked skb\n"); IS_SKB(skb); skb_unlink(skb); } skb->dev = NULL; - sti(); - skb2 = (struct sk_buff *)skb->link3; + skb2 = skb->link3; kfree_skb(skb, FREE_WRITE); skb = skb2; - } - sk->send_head = NULL; + } + sk->send_head = NULL; + sti(); /* And now the backlog. */ - if (sk->back_log != NULL) - { + while((skb=skb_dequeue(&sk->back_log))!=NULL) { /* this should never happen. */ - printk("cleaning back_log. \n"); - cli(); - skb = (struct sk_buff *)sk->back_log; - do - { - struct sk_buff *skb2; - - skb2 = (struct sk_buff *)skb->next; - kfree_skb(skb, FREE_READ); - skb = skb2; - } - while(skb != sk->back_log); - sti(); + printk("cleaning back_log\n"); + kfree_skb(skb, FREE_READ); } - sk->back_log = NULL; /* Now if it has a half accepted/ closed socket. */ if (sk->pair) @@ -452,10 +411,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } switch(cmd) { case F_SETOWN: @@ -831,6 +786,7 @@ sk->nonagle = 0; #endif sk->type = sock->type; + sk->stamp.tv_sec=0; sk->protocol = protocol; sk->wmem_alloc = 0; sk->rmem_alloc = 0; @@ -882,14 +838,13 @@ sk->max_ack_backlog = 0; sk->inuse = 0; sk->delay_acks = 0; - sk->wback = NULL; - sk->wfront = NULL; - sk->rqueue = NULL; + skb_queue_head_init(&sk->write_queue); + skb_queue_head_init(&sk->receive_queue); sk->mtu = 576; sk->prot = prot; sk->sleep = sock->wait; sk->daddr = 0; - sk->saddr = my_addr(); + sk->saddr = ip_my_addr(); sk->err = 0; sk->next = NULL; sk->pair = NULL; @@ -899,7 +854,7 @@ sk->broadcast = 0; sk->timer.data = (unsigned long)sk; sk->timer.function = &net_timer; - sk->back_log = NULL; + skb_queue_head_init(&sk->back_log); sk->blog = 0; sock->data =(void *) sk; sk->dummy_th.doff = sizeof(sk->dummy_th)/4; @@ -1017,13 +972,9 @@ struct sock *sk, *sk2; unsigned short snum; int err; + int chk_addr_ret; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } - /* check this error. */ if (sk->state != TCP_CLOSE) return(-EIO); if (sk->num != 0) return(-EINVAL); @@ -1047,10 +998,11 @@ } if (snum < PROT_SOCK && !suser()) return(-EACCES); - if (addr.sin_addr.s_addr!=0 && chk_addr(addr.sin_addr.s_addr)!=IS_MYADDR) + chk_addr_ret = ip_chk_addr(addr.sin_addr.s_addr); + if (addr.sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR) return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ - if (chk_addr(addr.sin_addr.s_addr) || addr.sin_addr.s_addr == 0) + if (chk_addr_ret || addr.sin_addr.s_addr == 0) sk->saddr = addr.sin_addr.s_addr; DPRINTF((DBG_INET, "sock_array[%d] = %X:\n", snum &(SOCK_ARRAY_SIZE -1), @@ -1100,10 +1052,6 @@ sock->conn = NULL; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) { @@ -1184,23 +1132,19 @@ int err; sk1 = (struct sock *) sock->data; - if (sk1 == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } /* * We've been passed an extra socket. * We need to free it up because the tcp module creates * it's own when it accepts one. */ - if (newsock->data) { - struct sock * sk = (struct sock *) newsock->data; - newsock->data = NULL; - sk->dead = 1; + if (newsock->data) + { + struct sock *sk=(struct sock *)newsock->data; + newsock->data=NULL; destroy_sock(sk); } - + if (sk1->prot->accept == NULL) return(-EOPNOTSUPP); /* Restore the state if we have been interrupted, and then returned. */ @@ -1283,7 +1227,7 @@ sin.sin_addr.s_addr = sk->daddr; } else { sin.sin_port = sk->dummy_th.source; - if (sk->saddr == 0) sin.sin_addr.s_addr = my_addr(); + if (sk->saddr == 0) sin.sin_addr.s_addr = ip_my_addr(); else sin.sin_addr.s_addr = sk->saddr; } len = sizeof(sin); @@ -1301,10 +1245,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } /* We may need to bind the socket. */ if (sk->num == 0) { @@ -1324,10 +1264,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } /* We may need to bind the socket. */ if (sk->num == 0) { @@ -1346,10 +1282,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 1); return(-EPIPE); @@ -1374,10 +1306,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 1); return(-EPIPE); @@ -1402,10 +1330,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 1); return(-EPIPE); @@ -1433,10 +1357,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } if (sk->prot->recvfrom == NULL) return(-EOPNOTSUPP); @@ -1487,10 +1407,6 @@ struct sock *sk; sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } if (sk->prot->select == NULL) { DPRINTF((DBG_INET, "select on non-selectable socket.\n")); @@ -1531,6 +1447,20 @@ put_fs_long(sk->proc,(int *)arg); } return(0); + + case SIOCGSTAMP: + if (sk) + { + if(sk->stamp.tv_sec==0) + return -ENOENT; + err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); + if(err) + return err; + memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); + return 0; + } + return -EINVAL; + #if 0 /* FIXME: */ case SIOCATMARK: printk("AF_INET: ioctl(SIOCATMARK, 0x%08X)\n",(void *) arg); @@ -1542,14 +1472,13 @@ case SIOCADDRT: case SIOCADDRTOLD: case SIOCDELRT: case SIOCDELRTOLD: - return(rt_ioctl(cmd,(void *) arg)); + return(ip_rt_ioctl(cmd,(void *) arg)); case SIOCDARP: case SIOCGARP: case SIOCSARP: return(arp_ioctl(cmd,(void *) arg)); - case IP_SET_DEV: case SIOCGIFCONF: case SIOCGIFFLAGS: case SIOCSIFFLAGS: @@ -1569,6 +1498,8 @@ case SIOCSIFMTU: case SIOCSIFLINK: case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case OLD_SIOCGIFHWADDR: return(dev_ioctl(cmd,(void *) arg)); default: @@ -1589,7 +1520,7 @@ struct sk_buff * c = alloc_skb(size, priority); if (c) { cli(); - sk->wmem_alloc+= size; + sk->wmem_alloc+= c->mem_len; sti(); } return c; @@ -1610,7 +1541,7 @@ struct sk_buff *c = alloc_skb(size, priority); if (c) { cli(); - sk->rmem_alloc += size; + sk->rmem_alloc += c->mem_len; sti(); } return(c); @@ -1655,7 +1586,7 @@ { DPRINTF((DBG_INET, "sock_wfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size)); - IS_SKB((struct sk_buff *) mem); + IS_SKB(mem); kfree_skbmem(mem, size); if (sk) { sk->wmem_alloc -= size; @@ -1675,7 +1606,7 @@ sock_rfree(struct sock *sk, void *mem, unsigned long size) { DPRINTF((DBG_INET, "sock_rfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size)); - IS_SKB((struct sk_buff *) mem); + IS_SKB(mem); kfree_skbmem(mem, size); if (sk) { sk->rmem_alloc -= size; @@ -1733,45 +1664,25 @@ void release_sock(struct sock *sk) { - if (!sk) { - printk("sock.c: release_sock sk == NULL\n"); - return; - } - if (!sk->prot) { -/* printk("sock.c: release_sock sk->prot == NULL\n"); */ + struct sk_buff *skb; + + if (!sk->prot) return; - } if (sk->blog) return; /* See if we have any packets built up. */ - cli(); sk->inuse = 1; - while(sk->back_log != NULL) { - struct sk_buff *skb; - + while((skb = skb_dequeue(&sk->back_log)) != NULL) { sk->blog = 1; - skb =(struct sk_buff *)sk->back_log; DPRINTF((DBG_INET, "release_sock: skb = %X:\n", skb)); - if (skb->next != skb) { - sk->back_log = skb->next; - skb->prev->next = skb->next; - skb->next->prev = skb->prev; - } else { - sk->back_log = NULL; - } - sti(); - DPRINTF((DBG_INET, "sk->back_log = %X\n", sk->back_log)); if (sk->prot->rcv) sk->prot->rcv(skb, skb->dev, sk->opt, skb->saddr, skb->len, skb->daddr, 1, - - /* Only used for/by raw sockets. */ - (struct inet_protocol *)sk->pair); - cli(); + /* Only used for/by raw sockets. */ + (struct inet_protocol *)sk->pair); } sk->blog = 0; sk->inuse = 0; - sti(); if (sk->dead && sk->state == TCP_CLOSE) { /* Should be about 2 rtt's */ reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME)); @@ -1857,44 +1768,73 @@ extern unsigned long seq_offset; -/* Called by ddi.c on kernel startup. */ +/* + * Called by ddi.c on kernel startup. + */ + void inet_proto_init(struct ddi_proto *pro) { - struct inet_protocol *p; - int i; + struct inet_protocol *p; + int i; - printk("Swansea University Computer Society Net2Debugged [1.30]\n"); - /* Set up our UNIX VFS major device. */ - if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) { - printk("%s: cannot register major device %d!\n", - pro->name, AF_INET_MAJOR); - return; - } + printk("Swansea University Computer Society NET3.010\n"); + /* + * Set up our UNIX VFS major device. (compatibility) + */ - /* Tell SOCKET that we are alive... */ - (void) sock_register(inet_proto_ops.family, &inet_proto_ops); + if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) + { + printk("%s: cannot register major device %d!\n", + pro->name, AF_INET_MAJOR); + return; + } - seq_offset = CURRENT_TIME*250; + /* + * Tell SOCKET that we are alive... + */ + + (void) sock_register(inet_proto_ops.family, &inet_proto_ops); - /* Add all the protocols. */ - for(i = 0; i < SOCK_ARRAY_SIZE; i++) { - tcp_prot.sock_array[i] = NULL; - udp_prot.sock_array[i] = NULL; - raw_prot.sock_array[i] = NULL; - } - printk("IP Protocols: "); - for(p = inet_protocol_base; p != NULL;) { - struct inet_protocol *tmp; + seq_offset = CURRENT_TIME*250; - tmp = (struct inet_protocol *) p->next; - inet_add_protocol(p); - printk("%s%s",p->name,tmp?", ":"\n"); - p = tmp; - } + /* + * Add all the protocols. + */ + + for(i = 0; i < SOCK_ARRAY_SIZE; i++) + { + tcp_prot.sock_array[i] = NULL; + udp_prot.sock_array[i] = NULL; + raw_prot.sock_array[i] = NULL; + } - /* Initialize the DEV module. */ - dev_init(); + printk("IP Protocols: "); + for(p = inet_protocol_base; p != NULL;) + { + struct inet_protocol *tmp; + + tmp = (struct inet_protocol *) p->next; + inet_add_protocol(p); + printk("%s%s",p->name,tmp?", ":"\n"); + p = tmp; + } - /* Initialize the "Buffer Head" pointers. */ - bh_base[INET_BH].routine = inet_bh; + /* + * Initialize the DEV module. + */ + dev_init(); + /* + * Set the ARP module up + */ + arp_init(); + /* + * Set the IP module up + */ + ip_init(); + + /* + * Initialize the "Buffer Head" pointers. + */ + + bh_base[INET_BH].routine = inet_bh; } diff -u --recursive --new-file v1.1.3/linux/net/inet/sock.h linux/net/inet/sock.h --- v1.1.3/linux/net/inet/sock.h Wed Mar 2 11:29:06 1994 +++ linux/net/inet/sock.h Wed Apr 13 12:52:28 1994 @@ -34,7 +34,7 @@ #include /* struct options */ #include /* struct tcphdr */ -#include "skbuff.h" /* struct sk_buff */ +#include /* struct sk_buff */ #include "protocol.h" /* struct inet_protocol */ #ifdef CONFIG_AX25 #include "ax25.h" @@ -89,15 +89,14 @@ int proc; struct sock *next; struct sock *pair; - struct sk_buff *volatile send_tail; - struct sk_buff *volatile send_head; - struct sk_buff *volatile back_log; + struct sk_buff * volatile send_head; + struct sk_buff * volatile send_tail; + struct sk_buff_head back_log; struct sk_buff *partial; struct timer_list partial_timer; long retransmits; - struct sk_buff *volatile wback, - *volatile wfront, - *volatile rqueue; + struct sk_buff_head write_queue, + receive_queue; struct proto *prot; struct wait_queue **sleep; unsigned long daddr; @@ -158,6 +157,7 @@ /* This part is used for the timeout functions (timer.c). */ int timeout; /* What are we waiting for? */ struct timer_list timer; + struct timeval stamp; /* identd */ struct socket *socket; diff -u --recursive --new-file v1.1.3/linux/net/inet/tcp.c linux/net/inet/tcp.c --- v1.1.3/linux/net/inet/tcp.c Thu Apr 7 11:57:33 1994 +++ linux/net/inet/tcp.c Wed Apr 13 13:13:13 1994 @@ -63,7 +63,7 @@ * Charles Hedrick : TCP fixes * Toomas Tamm : TCP window fixes * Alan Cox : Small URG fix to rlogin ^C ack fight - * Charles Hedrick : Window fix + * Charles Hedrick : Rewrote most of it to actually work * Linus : Rewrote tcp_read() and URG handling * completely * Gerhard Koerting: Fixed some missing timer handling @@ -74,11 +74,7 @@ * 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). - * Add VJ Fastrecovery algorithm ? * Protocol closedown badly messed up. - * Incompatiblity with spider ports (tcp hangs on that - * socket occasionally). - * MSG_PEEK and read on same socket at once can cause crashes. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -94,15 +90,15 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include +#include "snmp.h" #include "ip.h" #include "protocol.h" #include "icmp.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" -#include "arp.h" #include #include #include @@ -111,6 +107,8 @@ #define SEQ_TICK 3 unsigned long seq_offset; +struct tcp_mib tcp_statistics; + #define SUBNETSARELOCAL static __inline__ int @@ -145,12 +143,6 @@ __print_th(th); } -/* This routine grabs the first thing off of a rcv queue. */ -static struct sk_buff * -get_firstr(struct sock *sk) -{ - return skb_dequeue(&sk->rqueue); -} /* This routine picks a TCP windows for a socket based on the following constraints @@ -276,6 +268,7 @@ */ if (icmp_err_convert[err & 0xff].fatal) { if (sk->state == TCP_SYN_SENT) { + tcp_statistics.TcpAttemptFails++; sk->state = TCP_CLOSE; sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ } @@ -295,7 +288,6 @@ unsigned long counted; unsigned long amount; struct sk_buff *skb; - int count=0; int sum; unsigned long flags; @@ -303,8 +295,11 @@ if(sk && sk->debug) printk("tcp_readable: %p - ",sk); - if (sk == NULL || skb_peek(&sk->rqueue) == NULL) /* Empty sockets are easy! */ + save_flags(flags); + cli(); + if (sk == NULL || (skb = skb_peek(&sk->receive_queue)) == NULL) { + restore_flags(flags); if(sk && sk->debug) printk("empty\n"); return(0); @@ -313,22 +308,8 @@ counted = sk->copied_seq+1; /* Where we are at the moment */ amount = 0; - save_flags(flags); /* So nobody adds things at the wrong moment */ - cli(); - skb =(struct sk_buff *)sk->rqueue; - /* Do until a push or until we are out of data. */ do { - count++; -#ifdef OLD - /* This is wrong: It breaks Chameleon amongst other stacks */ - if (count > 20) { - restore_flags(flags); - DPRINTF((DBG_TCP, "tcp_readable, more than 20 packets without a psh\n")); - printk("tcp_read: possible read_queue corruption.\n"); - return(amount); - } -#endif if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */ break; sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */ @@ -340,8 +321,8 @@ counted += sum; } if (amount && skb->h.th->psh) break; - skb =(struct sk_buff *)skb->next; /* Move along */ - } while(skb != sk->rqueue); + skb = skb->next; + } while(skb != (struct sk_buff *)&sk->receive_queue); if (amount && !sk->urginline && sk->urg_data && (sk->urg_seq - sk->copied_seq) <= (counted - sk->copied_seq)) amount--; /* don't count urg data */ @@ -372,7 +353,7 @@ select_wait(sk->sleep, wait); if(sk->debug) printk("-select out"); - if (skb_peek(&sk->rqueue) != NULL) { + if (skb_peek(&sk->receive_queue) != NULL) { if (sk->state == TCP_LISTEN || tcp_readable(sk)) { release_sock(sk); if(sk->debug) @@ -424,10 +405,8 @@ DPRINTF((DBG_TCP, "tcp_select: sleeping on write sk->wmem_alloc = %d, " "sk->packets_out = %d\n" - "sk->wback = %X, sk->wfront = %X\n" "sk->write_seq = %u, sk->window_seq=%u\n", sk->wmem_alloc, sk->packets_out, - sk->wback, sk->wfront, sk->write_seq, sk->window_seq)); release_sock(sk); @@ -513,7 +492,7 @@ { unsigned long sum; - if (saddr == 0) saddr = my_addr(); + if (saddr == 0) saddr = ip_my_addr(); print_th(th); __asm__("\t addl %%ecx,%%ebx\n" "\t adcl %%edx,%%ebx\n" @@ -602,7 +581,8 @@ return; } } - + + tcp_statistics.TcpOutSegs++; /* We need to complete and send the packet. */ tcp_send_check(th, sk->saddr, sk->daddr, size, sk); @@ -614,15 +594,12 @@ sk->cong_window, sk->packets_out)); DPRINTF((DBG_TCP, "sk->write_seq = %d, sk->window_seq = %d\n", sk->write_seq, sk->window_seq)); - skb->next = NULL; - skb->magic = TCP_WRITE_QUEUE_MAGIC; - if (sk->wback == NULL) { - sk->wfront = skb; - } else { - sk->wback->next = skb; + if (skb->next != NULL) { + printk("tcp_send_partial: next != NULL\n"); + skb_unlink(skb); } - sk->wback = skb; - if (before(sk->window_seq, sk->wfront->h.seq) && + skb_queue_tail(&sk->write_queue, skb); + if (before(sk->window_seq, sk->write_queue.next->h.seq) && sk->send_head == NULL && sk->ack_backlog == 0) reset_timer(sk, TIME_PROBE0, sk->rto); @@ -703,12 +680,10 @@ if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) { reset_timer(sk, TIME_WRITE, 10); } -if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n"); + if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n"); return; } - buff->mem_addr = buff; - buff->mem_len = MAX_ACK_SIZE; buff->len = sizeof(struct tcphdr); buff->sk = sk; t1 =(struct tcphdr *) buff->data; @@ -719,7 +694,7 @@ if (tmp < 0) { buff->free=1; sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); -if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n"); + if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n"); return; } buff->len += tmp; @@ -746,7 +721,8 @@ sk->ack_backlog = 0; sk->bytes_rcv = 0; sk->ack_timed = 0; - if (sk->send_head == NULL && sk->wfront == NULL && sk->timeout == TIME_WRITE) + if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL + && sk->timeout == TIME_WRITE) { if(sk->keepopen) reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN); @@ -759,6 +735,7 @@ tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk); if (sk->debug) printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack); + tcp_statistics.TcpOutSegs++; sk->prot->queue_xmit(sk, dev, buff, 1); } @@ -947,13 +924,13 @@ release_sock(sk); /* NB: following must be mtu, because mss can be increased. * mss is always <= mtu */ - skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header + sizeof(*skb), 0, GFP_KERNEL); + skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL); sk->inuse = 1; send_tmp = skb; } else { /* We will release the socket incase we sleep here. */ release_sock(sk); - skb = prot->wmalloc(sk, copy + prot->max_header + sizeof(*skb), 0, GFP_KERNEL); + skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL); sk->inuse = 1; } @@ -1106,8 +1083,6 @@ return; } - buff->mem_addr = buff; - buff->mem_len = MAX_ACK_SIZE; buff->len = sizeof(struct tcphdr); buff->sk = sk; @@ -1140,6 +1115,7 @@ t1->doff = sizeof(*t1)/4; tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); sk->prot->queue_xmit(sk, dev, buff, 1); + tcp_statistics.TcpOutSegs++; } @@ -1168,7 +1144,7 @@ * We have to loop through all the buffer headers, * and try to free up all the space we can. */ - while((skb=skb_peek(&sk->rqueue)) != NULL ) + while((skb=skb_peek(&sk->receive_queue)) != NULL) { if (!skb->used) break; @@ -1330,7 +1306,7 @@ current->state = TASK_INTERRUPTIBLE; - skb = sk->rqueue; + skb = skb_peek(&sk->receive_queue); do { if (!skb) break; @@ -1343,8 +1319,8 @@ goto found_ok_skb; if (!(flags & MSG_PEEK)) skb->used = 1; - skb = (struct sk_buff *)skb->next; - } while (skb != sk->rqueue); + skb = skb->next; + } while (skb != (struct sk_buff *)&sk->receive_queue); if (copied) break; @@ -1464,8 +1440,6 @@ sk->inuse = 1; DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff)); - buff->mem_addr = buff; - buff->mem_len = MAX_RESET_SIZE; buff->sk = sk; buff->len = sizeof(*t1); t1 =(struct tcphdr *) buff->data; @@ -1506,12 +1480,13 @@ * Can't just queue this up. * It should go at the end of the write queue. */ - if (sk->wback != NULL) { - buff->free=0; - buff->next = NULL; - sk->wback->next = buff; - sk->wback = buff; - buff->magic = TCP_WRITE_QUEUE_MAGIC; + if (skb_peek(&sk->write_queue) != NULL) { + buff->free=0; + if (buff->next != NULL) { + printk("tcp_shutdown: next != NULL\n"); + skb_unlink(buff); + } + skb_queue_tail(&sk->write_queue, buff); } else { sk->sent_seq = sk->write_seq; sk->prot->queue_xmit(sk, dev, buff, 0); @@ -1569,7 +1544,8 @@ struct sk_buff *buff; struct tcphdr *t1; int tmp; - + struct device *ndev=NULL; + /* * We need to grab some memory, and put together an RST, * and then put it into the queue to be sent. @@ -1579,8 +1555,6 @@ return; DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff)); - buff->mem_addr = buff; - buff->mem_len = MAX_RESET_SIZE; buff->len = sizeof(*t1); buff->sk = NULL; buff->dev = dev; @@ -1588,7 +1562,7 @@ t1 =(struct tcphdr *) buff->data; /* Put in the IP header and routing stuff. */ - tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt, + tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt, sizeof(struct tcphdr),tos,ttl); if (tmp < 0) { buff->free = 1; @@ -1628,6 +1602,7 @@ t1->doff = sizeof(*t1)/4; tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL); prot->queue_xmit(NULL, dev, buff, 1); + tcp_statistics.TcpOutSegs++; } @@ -1712,6 +1687,7 @@ unsigned char *ptr; struct sock *newsk; struct tcphdr *th; + struct device *ndev=NULL; int tmp; DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n" @@ -1726,6 +1702,7 @@ } else { DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n")); tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl); + tcp_statistics.TcpAttemptFails++; kfree_skb(skb, FREE_READ); return; } @@ -1735,6 +1712,7 @@ * flurry of syns from eating up all our memory. */ if (sk->ack_backlog >= sk->max_ack_backlog) { + tcp_statistics.TcpAttemptFails++; kfree_skb(skb, FREE_READ); return; } @@ -1749,18 +1727,18 @@ newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC); if (newsk == NULL) { /* just ignore the syn. It will get retransmitted. */ + tcp_statistics.TcpAttemptFails++; kfree_skb(skb, FREE_READ); return; } DPRINTF((DBG_TCP, "newsk = %X\n", newsk)); - memcpy((void *)newsk,(void *)sk, sizeof(*newsk)); - newsk->wback = NULL; - newsk->wfront = NULL; - newsk->rqueue = NULL; + memcpy(newsk, sk, sizeof(*newsk)); + skb_queue_head_init(&newsk->write_queue); + skb_queue_head_init(&newsk->receive_queue); newsk->send_head = NULL; newsk->send_tail = NULL; - newsk->back_log = NULL; + skb_queue_head_init(&newsk->back_log); newsk->rtt = TCP_CONNECT_TIME << 3; newsk->rto = TCP_CONNECT_TIME; newsk->mdev = 0; @@ -1846,18 +1824,17 @@ newsk->dead = 1; release_sock(newsk); kfree_skb(skb, FREE_READ); + tcp_statistics.TcpAttemptFails++; return; } - buff->mem_addr = buff; - buff->mem_len = MAX_SYN_SIZE; buff->len = sizeof(struct tcphdr)+4; buff->sk = newsk; t1 =(struct tcphdr *) buff->data; /* Put in the IP header and routing stuff. */ - tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev, + tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &ndev, IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl); /* Something went wrong. */ @@ -1869,6 +1846,7 @@ release_sock(newsk); skb->sk = sk; kfree_skb(skb, FREE_READ); + tcp_statistics.TcpAttemptFails++; return; } @@ -1911,9 +1889,10 @@ sk->rmem_alloc -= skb->mem_len; newsk->rmem_alloc += skb->mem_len; - skb_queue_tail(&sk->rqueue,skb); + skb_queue_tail(&sk->receive_queue,skb); sk->ack_backlog++; release_sock(newsk); + tcp_statistics.TcpOutSegs++; } @@ -1940,12 +1919,12 @@ sk->state_change(sk); /* We need to flush the recv. buffs. */ - if (skb_peek(&sk->rqueue) != NULL) + if (skb_peek(&sk->receive_queue) != NULL) { struct sk_buff *skb; if(sk->debug) printk("Clean rcv queue\n"); - while((skb=skb_dequeue(&sk->rqueue))!=NULL) + while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq)) need_reset = 1; @@ -1954,7 +1933,6 @@ if(sk->debug) printk("Cleaned.\n"); } - sk->rqueue = NULL; /* Get rid off any half-completed packets. */ if (sk->partial) { @@ -2004,8 +1982,6 @@ reset_timer(sk, TIME_CLOSE, 100); return; } - buff->mem_addr = buff; - buff->mem_len = MAX_FIN_SIZE; buff->sk = sk; buff->free = 1; buff->len = sizeof(*t1); @@ -2024,6 +2000,7 @@ reset_timer(sk, TIME_CLOSE,4*sk->rto); if(timeout) tcp_time_wait(sk); + DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); release_sock(sk); return; @@ -2047,19 +2024,18 @@ t1->doff = sizeof(*t1)/4; tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); - if (sk->wfront == NULL) { + tcp_statistics.TcpOutSegs++; + + if (skb_peek(&sk->write_queue) == NULL) { sk->sent_seq = sk->write_seq; prot->queue_xmit(sk, dev, buff, 0); } else { reset_timer(sk, TIME_WRITE, sk->rto); - buff->next = NULL; - if (sk->wback == NULL) { - sk->wfront = buff; - } else { - sk->wback->next = buff; + if (buff->next != NULL) { + printk("tcp_close: next != NULL\n"); + skb_unlink(buff); } - sk->wback = buff; - buff->magic = TCP_WRITE_QUEUE_MAGIC; + skb_queue_tail(&sk->write_queue, buff); } if (sk->state == TCP_CLOSE_WAIT) { @@ -2088,25 +2064,14 @@ if(sk->zapped) return; - while(sk->wfront != NULL && - before(sk->wfront->h.seq, sk->window_seq +1) && + while((skb = skb_peek(&sk->write_queue)) != NULL && + before(skb->h.seq, sk->window_seq + 1) && (sk->retransmits == 0 || sk->timeout != TIME_WRITE || - before(sk->wfront->h.seq, sk->rcv_ack_seq +1)) - && sk->packets_out < sk->cong_window) { - skb = sk->wfront; + before(skb->h.seq, sk->rcv_ack_seq + 1)) + && sk->packets_out < sk->cong_window) { IS_SKB(skb); - sk->wfront = skb->next; - if (sk->wfront == NULL) sk->wback = NULL; - skb->next = NULL; - if (skb->magic != TCP_WRITE_QUEUE_MAGIC) { - printk("tcp.c skb with bad magic(%X) on write queue. Squashing " - "queue\n", skb->magic); - sk->wfront = NULL; - sk->wback = NULL; - return; - } - skb->magic = 0; + skb_unlink(skb); DPRINTF((DBG_TCP, "Sending a packet.\n")); /* See if we really need to send the packet. */ @@ -2133,13 +2098,13 @@ struct sk_buff *skb,*skb2,*skb3; for (skb = sk->send_head; skb != NULL; skb = skb2) { - skb2 = (struct sk_buff *)skb->link3; + skb2 = skb->link3; if (list == NULL || before (skb2->h.seq, list->h.seq)) { skb->link3 = list; sk->send_tail = skb; list = skb; } else { - for (skb3 = list; ; skb3 = (struct sk_buff *)skb3->link3) { + for (skb3 = list; ; skb3 = skb3->link3) { if (skb3->link3 == NULL || before(skb->h.seq, skb3->link3->h.seq)) { skb->link3 = skb3->link3; @@ -2220,7 +2185,7 @@ cli(); while (skb2 != NULL) { skb = skb2; - skb2 = (struct sk_buff *)skb->link3; + skb2 = skb->link3; skb->link3 = NULL; if (after(skb->h.seq, sk->window_seq)) { if (sk->packets_out > 0) sk->packets_out--; @@ -2229,15 +2194,10 @@ skb_unlink(skb); } /* Now add it to the write_queue. */ - skb->magic = TCP_WRITE_QUEUE_MAGIC; - if (wskb == NULL) { - skb->next = sk->wfront; - sk->wfront = skb; - } else { - skb->next = wskb->next; - wskb->next = skb; - } - if (sk->wback == wskb) sk->wback = skb; + if (wskb == NULL) + skb_queue_head(&sk->write_queue,skb); + else + skb_append(wskb,skb); wskb = skb; } else { if (sk->send_head == NULL) { @@ -2297,8 +2257,8 @@ * it needs to be for normal retransmission */ if (sk->timeout == TIME_PROBE0) { - if (sk->wfront != NULL && /* should always be non-null */ - ! before (sk->window_seq, sk->wfront->h.seq)) { + if (skb_peek(&sk->write_queue) != NULL && /* should always be non-null */ + ! before (sk->window_seq, sk->write_queue.next->h.seq)) { sk->retransmits = 0; sk->backoff = 0; /* recompute rto from rtt. this eliminates any backoff */ @@ -2397,15 +2357,15 @@ oskb = sk->send_head; IS_SKB(oskb); - sk->send_head =(struct sk_buff *)oskb->link3; + sk->send_head = oskb->link3; if (sk->send_head == NULL) { sk->send_tail = NULL; } - /* We may need to remove this from the dev send list. */ - skb_unlink(oskb); /* Much easier! */ + /* We may need to remove this from the dev send list. */ + if (oskb->next) + skb_unlink(oskb); sti(); - oskb->magic = 0; kfree_skb(oskb, FREE_WRITE); /* write. */ if (!sk->dead) sk->write_space(sk); } else { @@ -2417,15 +2377,15 @@ * Maybe we can take some stuff off of the write queue, * and put it onto the xmit queue. */ - if (sk->wfront != NULL) { - if (after (sk->window_seq+1, sk->wfront->h.seq) && + if (skb_peek(&sk->write_queue) != NULL) { + if (after (sk->window_seq+1, sk->write_queue.next->h.seq) && (sk->retransmits == 0 || sk->timeout != TIME_WRITE || - before(sk->wfront->h.seq, sk->rcv_ack_seq +1)) + before(sk->write_queue.next->h.seq, sk->rcv_ack_seq + 1)) && sk->packets_out < sk->cong_window) { flag |= 1; tcp_write_xmit(sk); - } else if (before(sk->window_seq, sk->wfront->h.seq) && + } else if (before(sk->window_seq, sk->write_queue.next->h.seq) && sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT) { @@ -2452,7 +2412,7 @@ } if (sk->packets_out == 0 && sk->partial != NULL && - sk->wfront == NULL && sk->send_head == NULL) { + skb_peek(&sk->write_queue) == NULL && sk->send_head == NULL) { flag |= 1; tcp_send_partial(sk); } @@ -2555,7 +2515,8 @@ if (sk->shutdown & RCV_SHUTDOWN) { sk->acked_seq = th->seq + skb->len + th->syn + th->fin; tcp_reset(sk->saddr, sk->daddr, skb->h.th, - sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); + sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); + tcp_statistics.TcpEstabResets++; sk->state = TCP_CLOSE; sk->err = EPIPE; sk->shutdown = SHUTDOWN_MASK; @@ -2574,20 +2535,13 @@ */ /* This should start at the last one, and then go around forwards. */ - if (sk->rqueue == NULL) { + if (skb_peek(&sk->receive_queue) == NULL) { DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb)); -#ifdef OLDWAY - sk->rqueue = skb; - skb->next = skb; - skb->prev = skb; - skb->list = &sk->rqueue; -#else - skb_queue_head(&sk->rqueue,skb); -#endif + skb_queue_head(&sk->receive_queue,skb); skb1= NULL; } else { DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk)); - for(skb1=sk->rqueue->prev; ; skb1 =(struct sk_buff *)skb1->prev) { + for(skb1=sk->receive_queue.prev; ; skb1 = skb1->prev) { if(sk->debug) { printk("skb1=%p :", skb1); @@ -2596,25 +2550,6 @@ printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq, sk->acked_seq); } -#ifdef OLD - if (after(th->seq+1, skb1->h.th->seq)) { - skb->prev = skb1; - skb->next = skb1->next; - skb->next->prev = skb; - skb1->next = skb; - if (skb1 == sk->rqueue) sk->rqueue = skb; - break; - } - if (skb1->prev == sk->rqueue) { - skb->next= skb1; - skb->prev = skb1->prev; - skb->prev->next = skb; - skb1->prev = skb; - skb1 = NULL; /* so we know we might be able - to ack stuff. */ - break; - } -#else if (th->seq==skb1->h.th->seq && skb->len>= skb1->len) { skb_append(skb1,skb); @@ -2629,12 +2564,11 @@ skb_append(skb1,skb); break; } - if (skb1 == sk->rqueue) + if (skb1 == skb_peek(&sk->receive_queue)) { - skb_queue_head(&sk->rqueue, skb); + skb_queue_head(&sk->receive_queue, skb); break; } -#endif } DPRINTF((DBG_TCP, "skb = %X:\n", skb)); } @@ -2669,9 +2603,9 @@ sk->shutdown |= RCV_SHUTDOWN; } - for(skb2 = (struct sk_buff *)skb->next; - skb2 !=(struct sk_buff *) sk->rqueue; - skb2 = (struct sk_buff *)skb2->next) { + for(skb2 = skb->next; + skb2 != (struct sk_buff *)&sk->receive_queue; + skb2 = skb2->next) { if (before(skb2->h.th->seq, sk->acked_seq+1)) { if (after(skb2->h.th->ack_seq, sk->acked_seq)) { @@ -2729,7 +2663,7 @@ * for the send side. He could be sending us stuff as large as mtu. */ while (sk->prot->rspace(sk) < sk->mtu) { - skb1 = skb_peek(&sk->rqueue); + skb1 = skb_peek(&sk->receive_queue); if (skb1 == NULL) { printk("INET: tcp.c:tcp_data memory leak detected.\n"); break; @@ -2741,15 +2675,6 @@ } skb_unlink(skb1); -#ifdef OLDWAY - if (skb1->prev == skb1) { - sk->rqueue = NULL; - } else { - sk->rqueue = (struct sk_buff *)skb1->prev; - skb1->next->prev = skb1->prev; - skb1->prev->next = skb1->next; - } -#endif kfree_skb(skb1, FREE_READ); } tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); @@ -2832,7 +2757,7 @@ /* ok, got the correct packet, update info */ sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th); if (!sk->dead) - wake_up_interruptible(sk->sleep); + sk->data_ready(sk,0); return 0; } @@ -2856,6 +2781,7 @@ /* Contains the one that needs to be acked */ reset_timer(sk, TIME_CLOSE, TCP_TIMEOUT_LEN); sk->fin_seq = th->seq+1; + tcp_statistics.TcpCurrEstab--; sk->state = TCP_CLOSE_WAIT; if (th->rst) sk->shutdown = SHUTDOWN_MASK; break; @@ -2906,7 +2832,7 @@ /* avoid the race. */ cli(); sk->inuse = 1; - while((skb = get_firstr(sk)) == NULL) { + while((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if (flags & O_NONBLOCK) { sti(); release_sock(sk); @@ -2961,7 +2887,7 @@ DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr))); /* Don't want a TCP connection going to a broadcast address */ - if (chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) { + if (ip_chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) { DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n")); return(-ENETUNREACH); } @@ -2984,8 +2910,6 @@ return(-ENOMEM); } sk->inuse = 1; - buff->mem_addr = buff; - buff->mem_len = MAX_SYN_SIZE; buff->len = 24; buff->sk = sk; buff->free = 1; @@ -3050,6 +2974,8 @@ sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES; sk->prot->queue_xmit(sk, dev, buff, 0); + tcp_statistics.TcpActiveOpens++; + tcp_statistics.TcpOutSegs++; release_sock(sk); return(0); @@ -3091,6 +3017,9 @@ ignore_it: DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n")); + if (th->rst) + return 0; + /* * Send a reset if we get something not ours and we are * unsynchronized. Note: We don't do anything to our end. We @@ -3103,9 +3032,6 @@ return 1; } - if (th->rst) - return 0; - /* Try to resync things. */ tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); return 0; @@ -3124,20 +3050,15 @@ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n")); return(0); } -#if 0 /* FIXME: it's ok for protocol to be NULL */ - if (!protocol) { - DPRINTF((DBG_TCP, "tcp.c: tcp_rcv protocol = NULL\n")); - return(0); - } - if (!opt) { /* FIXME: it's ok for opt to be NULL */ - DPRINTF((DBG_TCP, "tcp.c: tcp_rcv opt = NULL\n")); - } -#endif - if (!dev) { + if (!dev) + { DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n")); return(0); } + + tcp_statistics.TcpInSegs++; + th = skb->h.th; /* Find the socket. */ @@ -3189,16 +3110,7 @@ /* We may need to add it to the backlog here. */ cli(); if (sk->inuse) { - if (sk->back_log == NULL) { - sk->back_log = skb; - skb->next = skb; - skb->prev = skb; - } else { - skb->next = sk->back_log; - skb->prev = sk->back_log->prev; - skb->prev->next = skb; - skb->next->prev = skb; - } + skb_queue_head(&sk->back_log, skb); sti(); return(0); } @@ -3254,24 +3166,23 @@ case TCP_FIN_WAIT2: case TCP_TIME_WAIT: if (!tcp_sequence(sk, th, len, opt, saddr,dev)) { -if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n"); -#ifdef undef -/* nice idea, but tcp_sequence already does this. Maybe it shouldn't?? */ - if(!th->rst) - tcp_send_ack(sk->sent_seq, sk->acked_seq, - sk, th, saddr); -#endif + if (inet_debug == DBG_SLIP) + printk("\rtcp_rcv: not in seq\n"); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } - if (th->rst) { + if (th->rst) + { + tcp_statistics.TcpEstabResets++; + tcp_statistics.TcpCurrEstab--; sk->zapped=1; /* This means the thing should really be closed. */ sk->err = ECONNRESET; - if (sk->state == TCP_CLOSE_WAIT) { + if (sk->state == TCP_CLOSE_WAIT) + { sk->err = EPIPE; } @@ -3281,19 +3192,18 @@ */ sk->state = TCP_CLOSE; sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) { + if (!sk->dead) + { sk->state_change(sk); } kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } - if ( -#if 0 - if ((opt && (opt->security != 0 || - opt->compartment != 0)) || -#endif - th->syn) { + if (th->syn) + { + tcp_statistics.TcpCurrEstab--; + tcp_statistics.TcpEstabResets++; sk->err = ECONNRESET; sk->state = TCP_CLOSE; sk->shutdown = SHUTDOWN_MASK; @@ -3364,15 +3274,8 @@ return(0); } - if (th->syn) { -#if 0 - if (opt->security != 0 || opt->compartment != 0) { - tcp_reset(daddr, saddr, th, prot, opt,dev); - release_sock(sk); - return(0); - } -#endif - + if (th->syn) + { /* * Now we just put the whole thing including * the header and saddr, and protocol pointer @@ -3398,41 +3301,33 @@ default: - if (!tcp_sequence(sk, th, len, opt, saddr,dev)) { + if (!tcp_sequence(sk, th, len, opt, saddr,dev)) + { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } case TCP_SYN_SENT: - if (th->rst) { + if (th->rst) + { + tcp_statistics.TcpAttemptFails++; sk->err = ECONNREFUSED; sk->state = TCP_CLOSE; sk->shutdown = SHUTDOWN_MASK; sk->zapped = 1; - if (!sk->dead) { + if (!sk->dead) + { sk->state_change(sk); } kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } -#if 0 - if (opt->security != 0 || opt->compartment != 0) { - sk->err = ECONNRESET; - sk->state = TCP_CLOSE; - sk->shutdown = SHUTDOWN_MASK; - tcp_reset(daddr, saddr, th, sk->prot, opt, dev); - if (!sk->dead) { - wake_up_interruptible(sk->sleep); - } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } -#endif - if (!th->ack) { - if (th->syn) { + if (!th->ack) + { + if (th->syn) + { sk->state = TCP_SYN_RECV; } @@ -3441,9 +3336,12 @@ return(0); } - switch(sk->state) { + switch(sk->state) + { case TCP_SYN_SENT: - if (!tcp_ack(sk, th, saddr, len)) { + if (!tcp_ack(sk, th, saddr, len)) + { + tcp_statistics.TcpAttemptFails++; tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); kfree_skb(skb, FREE_READ); @@ -3455,7 +3353,8 @@ * If the syn bit is also set, switch to * tcp_syn_recv, and then to established. */ - if (!th->syn) { + if (!th->syn) + { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3468,13 +3367,17 @@ sk, th, sk->daddr); case TCP_SYN_RECV: - if (!tcp_ack(sk, th, saddr, len)) { + if (!tcp_ack(sk, th, saddr, len)) + { + tcp_statistics.TcpAttemptFails++; tcp_reset(daddr, saddr, th, sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } + + tcp_statistics.TcpCurrEstab++; sk->state = TCP_ESTABLISHED; /* @@ -3569,8 +3472,6 @@ buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); if (buff == NULL) return; - buff->mem_addr = buff; - buff->mem_len = MAX_ACK_SIZE; buff->len = sizeof(struct tcphdr); buff->free = 1; buff->sk = sk; @@ -3612,6 +3513,7 @@ * This will prevent the timer from automatically being restarted. */ sk->prot->queue_xmit(sk, dev, buff, 1); + tcp_statistics.TcpOutSegs++; } void @@ -3629,10 +3531,10 @@ sk->prot->retransmits ++; } - /* * Socket option code for TCP. - */ + */ + int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val,err; diff -u --recursive --new-file v1.1.3/linux/net/inet/tcp.h linux/net/inet/tcp.h --- v1.1.3/linux/net/inet/tcp.h Thu Apr 7 11:57:33 1994 +++ linux/net/inet/tcp.h Wed Apr 13 19:34:08 1994 @@ -20,10 +20,10 @@ #include -#define MAX_SYN_SIZE 44 + sizeof (struct sk_buff) + MAX_HEADER -#define MAX_FIN_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER -#define MAX_ACK_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER -#define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER +#define MAX_SYN_SIZE 44 + MAX_HEADER +#define MAX_FIN_SIZE 40 + MAX_HEADER +#define MAX_ACK_SIZE 40 + MAX_HEADER +#define MAX_RESET_SIZE 40 + MAX_HEADER #define MAX_WINDOW 8192 #define MIN_WINDOW 2048 #define MAX_ACK_BACKLOG 2 @@ -64,7 +64,6 @@ #define TCP_NO_CHECK 0 /* turn to one if you want the default * to be no checksum */ -#define TCP_WRITE_QUEUE_MAGIC 0xa5f23477 /* * TCP option diff -u --recursive --new-file v1.1.3/linux/net/inet/timer.c linux/net/inet/timer.c --- v1.1.3/linux/net/inet/timer.c Tue Feb 1 09:27:53 1994 +++ linux/net/inet/timer.c Wed Apr 13 12:52:29 1994 @@ -40,12 +40,12 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include #include "ip.h" #include "protocol.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include "arp.h" @@ -68,8 +68,7 @@ { delete_timer (t); - if (timeout != -1) - t->timeout = timeout; + t->timeout = timeout; #if 1 /* FIXME: ??? */ @@ -93,16 +92,19 @@ int why = sk->timeout; /* timeout is overwritten by 'delete_timer' and 'reset_timer' */ - if (sk->inuse || in_inet_bh()) { + cli(); + if (sk->inuse || in_bh) { sk->timer.expires = 10; add_timer(&sk->timer); + sti(); return; } sk->inuse = 1; + sti(); DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why)); - if (sk->wfront && - before(sk->window_seq, sk->wfront->h.seq) && + if (skb_peek(&sk->write_queue) && + before(sk->window_seq, sk->write_queue.next->h.seq) && sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT) @@ -114,7 +116,7 @@ if (sk->ack_backlog) { sk->prot->read_wakeup (sk); if (! sk->dead) - wake_up_interruptible (sk->sleep); + sk->data_ready(sk,0); } /* Now we need to figure out why the socket was on the timer. */ @@ -147,9 +149,9 @@ sk->state = TCP_CLOSE; delete_timer (sk); /* Kill the ARP entry in case the hardware has changed. */ - arp_destroy_maybe (sk->daddr); + arp_destroy (sk->daddr, 0); if (!sk->dead) - wake_up_interruptible (sk->sleep); + sk->state_change(sk); sk->shutdown = SHUTDOWN_MASK; reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); release_sock (sk); @@ -162,13 +164,23 @@ /* It could be we got here because we needed to send an ack. * So we need to check for that. */ - if (sk->send_head) { - if (jiffies < (sk->send_head->when + sk->rto)) { - reset_timer (sk, TIME_WRITE, - (sk->send_head->when + sk->rto - jiffies)); + { + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); + skb = sk->send_head; + if (!skb) { + restore_flags(flags); + } else { + if (jiffies < skb->when + sk->rto) { + reset_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies); + restore_flags(flags); release_sock (sk); break; } + restore_flags(flags); /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, sk->retransmits, sk->packets_out, sk->cong_window); */ DPRINTF ((DBG_TMR, "retransmitting.\n")); @@ -176,7 +188,7 @@ if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); - arp_destroy_maybe (sk->daddr); + arp_destroy (sk->daddr, 0); ip_route_check (sk->daddr); } if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { @@ -194,6 +206,7 @@ } release_sock (sk); break; + } case TIME_KEEPOPEN: /* Send something to keep the connection open. */ if (sk->prot->write_wakeup) @@ -207,19 +220,19 @@ if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); - arp_destroy_maybe (sk->daddr); + arp_destroy (sk->daddr, 0); ip_route_check (sk->daddr); release_sock (sk); break; } if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); - arp_destroy_maybe (sk->daddr); + arp_destroy (sk->daddr, 0); sk->err = ETIMEDOUT; if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) { sk->state = TCP_TIME_WAIT; if (!sk->dead) - wake_up_interruptible (sk->sleep); + sk->state_change(sk); release_sock (sk); } else { sk->prot->close (sk, 1); @@ -229,7 +242,7 @@ release_sock (sk); break; default: - printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk); + printk ("net_timer: timer expired - reason unknown\n"); release_sock (sk); break; } diff -u --recursive --new-file v1.1.3/linux/net/inet/udp.c linux/net/inet/udp.c --- v1.1.3/linux/net/inet/udp.c Tue Apr 5 10:16:24 1994 +++ linux/net/inet/udp.c Wed Apr 13 12:52:30 1994 @@ -34,6 +34,7 @@ * Alan Cox : Broadcasting without option set returns EACCES. * Alan Cox : No wakeup calls. Instead we now use the callbacks. * Alan Cox : Use ip_tos and ip_ttl + * Alan Cox : SNMP Mibs * * * This program is free software; you can redistribute it and/or @@ -54,31 +55,40 @@ #include #include #include -#include "inet.h" -#include "dev.h" +#include +#include +#include "snmp.h" #include "ip.h" #include "protocol.h" #include "tcp.h" -#include "skbuff.h" +#include #include "sock.h" #include "udp.h" #include "icmp.h" +/* + * SNMP MIB for the UDP layer + */ -#define min(a,b) ((a)<(b)?(a):(b)) +struct udp_mib udp_statistics; -static void -print_udp(struct udphdr *uh) + + +#define min(a,b) ((a)<(b)?(a):(b)) + +static void print_udp(struct udphdr *uh) { - if (inet_debug != DBG_UDP) return; + if (inet_debug != DBG_UDP) + return; - if (uh == NULL) { - printk("(NULL)\n"); - return; - } - printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest)); - printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check)); + if (uh == NULL) + { + printk("(NULL)\n"); + return; + } + printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest)); + printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check)); } @@ -92,261 +102,332 @@ * header points to the first 8 bytes of the udp header. We need * to find the appropriate port. */ -void -udp_err(int err, unsigned char *header, unsigned long daddr, + +void udp_err(int err, unsigned char *header, unsigned long daddr, unsigned long saddr, struct inet_protocol *protocol) { - struct udphdr *th; - struct sock *sk; - struct iphdr *ip=(struct iphdr *)header; + struct udphdr *th; + struct sock *sk; + struct iphdr *ip=(struct iphdr *)header; - header += 4*ip->ihl; - - th = (struct udphdr *)header; + header += 4*ip->ihl; + + /* + * Find the 8 bytes of post IP header ICMP included for usA + */ + th = (struct udphdr *)header; - DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\ -sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest)); + DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\ + sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest)); - sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr); + sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr); - if (sk == NULL) - return; /* No socket for error */ + if (sk == NULL) + return; /* No socket for error */ - if (err < 0) /* As per the calling spec */ - { - sk->err = -err; - sk->error_report(sk); /* User process wakes to see error */ - return; - } - - if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */ - if (sk->cong_window > 1) - sk->cong_window = sk->cong_window/2; - return; - } + if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) + { /* Slow down! */ + if (sk->cong_window > 1) + sk->cong_window = sk->cong_window/2; + return; + } - sk->err = icmp_err_convert[err & 0xff].errno; + sk->err = icmp_err_convert[err & 0xff].errno; - /* It's only fatal if we have connected to them. */ - if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) { - sk->err=ECONNREFUSED; - } - sk->error_report(sk); + /* + * 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=ECONNREFUSED; + } + + sk->error_report(sk); } -static unsigned short -udp_check(struct udphdr *uh, int len, - unsigned long saddr, unsigned long daddr) +static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr) { - unsigned long sum; + unsigned long sum; - DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n", + DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n", uh, len, saddr, daddr)); - print_udp(uh); + print_udp(uh); + + __asm__( "\t addl %%ecx,%%ebx\n" + "\t adcl %%edx,%%ebx\n" + "\t adcl $0, %%ebx\n" + : "=b"(sum) + : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256) + : "cx","bx","dx" ); + + if (len > 3) + { + __asm__("\tclc\n" + "1:\n" + "\t lodsl\n" + "\t adcl %%eax, %%ebx\n" + "\t loop 1b\n" + "\t adcl $0, %%ebx\n" + : "=b"(sum) , "=S"(uh) + : "0"(sum), "c"(len/4) ,"1"(uh) + : "ax", "cx", "bx", "si" ); + } + + /* + * Convert from 32 bits to 16 bits. + */ - __asm__("\t addl %%ecx,%%ebx\n" - "\t adcl %%edx,%%ebx\n" - "\t adcl $0, %%ebx\n" - : "=b"(sum) - : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256) - : "cx","bx","dx" ); - - if (len > 3) { - __asm__("\tclc\n" - "1:\n" - "\t lodsl\n" - "\t adcl %%eax, %%ebx\n" - "\t loop 1b\n" - "\t adcl $0, %%ebx\n" - : "=b"(sum) , "=S"(uh) - : "0"(sum), "c"(len/4) ,"1"(uh) - : "ax", "cx", "bx", "si" ); - } - - /* Convert from 32 bits to 16 bits. */ - __asm__("\t movl %%ebx, %%ecx\n" - "\t shrl $16,%%ecx\n" - "\t addw %%cx, %%bx\n" - "\t adcw $0, %%bx\n" - : "=b"(sum) - : "0"(sum) - : "bx", "cx"); - - /* Check for an extra word. */ - if ((len & 2) != 0) { - __asm__("\t lodsw\n" - "\t addw %%ax,%%bx\n" - "\t adcw $0, %%bx\n" - : "=b"(sum), "=S"(uh) - : "0"(sum) ,"1"(uh) - : "si", "ax", "bx"); - } - - /* Now check for the extra byte. */ - if ((len & 1) != 0) { - __asm__("\t lodsb\n" - "\t movb $0,%%ah\n" - "\t addw %%ax,%%bx\n" - "\t adcw $0, %%bx\n" - : "=b"(sum) - : "0"(sum) ,"S"(uh) - : "si", "ax", "bx"); - } + __asm__("\t movl %%ebx, %%ecx\n" + "\t shrl $16,%%ecx\n" + "\t addw %%cx, %%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum) + : "0"(sum) + : "bx", "cx"); + + /* + * Check for an extra word. + */ + + if ((len & 2) != 0) + { + __asm__("\t lodsw\n" + "\t addw %%ax,%%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum), "=S"(uh) + : "0"(sum) ,"1"(uh) + : "si", "ax", "bx"); + } + + /* + * Now check for the extra byte. + */ + + if ((len & 1) != 0) + { + __asm__("\t lodsb\n" + "\t movb $0,%%ah\n" + "\t addw %%ax,%%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum) + : "0"(sum) ,"S"(uh) + : "si", "ax", "bx"); + } + + /* + * We only want the bottom 16 bits, but we never cleared the top 16. + */ - /* We only want the bottom 16 bits, but we never cleared the top 16. */ - return((~sum) & 0xffff); + return((~sum) & 0xffff); } +/* + * Generate UDP checksums. These may be disabled, eg for fast NFS over ethernet + * We default them enabled.. if you turn them off you either know what you are + * doing or get burned... + */ -static void -udp_send_check(struct udphdr *uh, unsigned long saddr, +static void udp_send_check(struct udphdr *uh, unsigned long saddr, unsigned long daddr, int len, struct sock *sk) { - uh->check = 0; - if (sk && sk->no_check) - return; - uh->check = udp_check(uh, len, saddr, daddr); - if (uh->check == 0) uh->check = 0xffff; + uh->check = 0; + if (sk && sk->no_check) + return; + uh->check = udp_check(uh, len, saddr, daddr); + + /* + * FFFF and 0 are the same, pick the right one as 0 in the + * actual field means no checksum. + */ + + if (uh->check == 0) + uh->check = 0xffff; } -static int -udp_send(struct sock *sk, struct sockaddr_in *sin, +static int udp_send(struct sock *sk, struct sockaddr_in *sin, unsigned char *from, int len) { - struct sk_buff *skb; - struct device *dev; - struct udphdr *uh; - unsigned char *buff; - unsigned long saddr; - int size, tmp; - int err; + struct sk_buff *skb; + struct device *dev; + struct udphdr *uh; + unsigned char *buff; + unsigned long saddr; + int size, tmp; + int err; - DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n", + DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n", in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port), from, len)); - err=verify_area(VERIFY_READ, from, len); - if(err) - return(err); - - /* Allocate a copy of the packet. */ - size = sizeof(struct sk_buff) + sk->prot->max_header + len; - skb = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL); - if (skb == NULL) return(-ENOMEM); - - skb->mem_addr = skb; - skb->mem_len = size; - skb->sk = NULL; /* to avoid changing sk->saddr */ - skb->free = 1; - skb->arp = 0; - - /* Now build the IP and MAC header. */ - buff = skb->data; - saddr = 0; - dev = NULL; - DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n", - saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len)); - tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr, - &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl); - skb->sk=sk; /* So memory is freed correctly */ - - if (tmp < 0 ) { - sk->prot->wfree(sk, skb->mem_addr, skb->mem_len); - return(tmp); - } - buff += tmp; - saddr = dev->pa_addr; - DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp)); + err=verify_area(VERIFY_READ, from, len); + if(err) + return(err); - skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */ - skb->dev = dev; + /* + * Allocate an sk_buff copy of the packet. + */ + + size = sk->prot->max_header + len; + skb = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL); + - /* Fill in the UDP header. */ - uh = (struct udphdr *) buff; - uh->len = htons(len + sizeof(struct udphdr)); - uh->source = sk->dummy_th.source; - uh->dest = sin->sin_port; - buff = (unsigned char *) (uh + 1); + if (skb == NULL) + return(-ENOMEM); - /* Copy the user data. */ - memcpy_fromfs(buff, from, len); + skb->sk = NULL; /* to avoid changing sk->saddr */ + skb->free = 1; + + /* + * Now build the IP and MAC header. + */ + + buff = skb->data; + saddr = 0; + dev = NULL; + DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n", + saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len)); + tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr, + &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl); + skb->sk=sk; /* So memory is freed correctly */ + + /* + * Unable to put a header on the packet. + */ + + if (tmp < 0 ) + { + sk->prot->wfree(sk, skb->mem_addr, skb->mem_len); + return(tmp); + } + + buff += tmp; + saddr = skb->saddr; /*dev->pa_addr;*/ + DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp)); + + skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */ + skb->dev = dev; + + /* + * Fill in the UDP header. + */ + + uh = (struct udphdr *) buff; + uh->len = htons(len + sizeof(struct udphdr)); + uh->source = sk->dummy_th.source; + uh->dest = sin->sin_port; + buff = (unsigned char *) (uh + 1); - /* Set up the UDP checksum. */ - udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk); + /* + * Copy the user data. + */ + + memcpy_fromfs(buff, from, len); - /* Send the datagram to the interface. */ - sk->prot->queue_xmit(sk, dev, skb, 1); + /* + * Set up the UDP checksum. + */ + + udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk); - return(len); + /* + * Send the datagram to the interface. + */ + + udp_statistics.UdpOutDatagrams++; + + sk->prot->queue_xmit(sk, dev, skb, 1); + return(len); } -static int -udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock, +static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) { - struct sockaddr_in sin; - int tmp; - int err; + struct sockaddr_in sin; + int tmp; + int err; - DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags)); + DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags)); - /* Check the flags. */ - if (flags) - return(-EINVAL); - if (len < 0) - return(-EINVAL); - if (len == 0) - return(0); + /* + * Check the flags. We support no flags for UDP sending + */ + if (flags) + return(-EINVAL); + if (len < 0) + return(-EINVAL); + if (len == 0) + return(0); - /* Get and verify the address. */ - if (usin) { - if (addr_len < sizeof(sin)) return(-EINVAL); - err=verify_area(VERIFY_READ, usin, sizeof(sin)); - if(err) - return err; - memcpy_fromfs(&sin, usin, sizeof(sin)); - if (sin.sin_family && sin.sin_family != AF_INET) - return(-EINVAL); - if (sin.sin_port == 0) - return(-EINVAL); - } else { - if (sk->state != TCP_ESTABLISHED) return(-EINVAL); - sin.sin_family = AF_INET; - sin.sin_port = sk->dummy_th.dest; - sin.sin_addr.s_addr = sk->daddr; - } + /* + * Get and verify the address. + */ + + if (usin) + { + if (addr_len < sizeof(sin)) + return(-EINVAL); + err=verify_area(VERIFY_READ, usin, sizeof(sin)); + if(err) + return err; + memcpy_fromfs(&sin, usin, sizeof(sin)); + if (sin.sin_family && sin.sin_family != AF_INET) + return(-EINVAL); + if (sin.sin_port == 0) + return(-EINVAL); + } + else + { + if (sk->state != TCP_ESTABLISHED) + return(-EINVAL); + sin.sin_family = AF_INET; + sin.sin_port = sk->dummy_th.dest; + sin.sin_addr.s_addr = sk->daddr; + } - if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) - return -EACCES; /* Must turn broadcast on first */ - sk->inuse = 1; + /* + * BSD socket semantics. You must set SO_BROADCAST to permit + * broadcasting of data. + */ + if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + return -EACCES; /* Must turn broadcast on first */ + + sk->inuse = 1; - /* Send the packet. */ - tmp = udp_send(sk, &sin, from, len); + /* Send the packet. */ + tmp = udp_send(sk, &sin, from, len); - /* The datagram has been sent off. Release the socket. */ - release_sock(sk); - return(tmp); + /* The datagram has been sent off. Release the socket. */ + release_sock(sk); + return(tmp); } +/* + * In BSD SOCK_DGRAM a write is just like a send. + */ -static int -udp_write(struct sock *sk, unsigned char *buff, int len, int noblock, +static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock, unsigned flags) { - return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0)); + return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0)); } -int -udp_ioctl(struct sock *sk, int cmd, unsigned long arg) +/* + * IOCTL requests applicable to the UDP protocol + */ + +int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - int err; - switch(cmd) { - case DDIOCSDBG: + int err; + switch(cmd) + { + case DDIOCSDBG: { int val; @@ -367,7 +448,7 @@ } } break; - case TIOCOUTQ: + case TIOCOUTQ: { unsigned long amount; @@ -381,14 +462,14 @@ return(0); } - case TIOCINQ: + case TIOCINQ: { struct sk_buff *skb; unsigned long amount; if (sk->state == TCP_LISTEN) return(-EINVAL); amount = 0; - skb = sk->rqueue; + skb = skb_peek(&sk->receive_queue); if (skb != NULL) { /* * We will only return the amount @@ -405,88 +486,115 @@ return(0); } - default: - return(-EINVAL); - } - return(0); + default: + return(-EINVAL); + } + return(0); } /* - * This should be easy, if there is something there we\ - * return it, otherwise we block. + * This should be easy, if there is something there we\ + * return it, otherwise we block. */ -int -udp_recvfrom(struct sock *sk, unsigned char *to, int len, + +int udp_recvfrom(struct sock *sk, unsigned char *to, int len, int noblock, unsigned flags, struct sockaddr_in *sin, int *addr_len) { - int copied = 0; - struct sk_buff *skb; - int er; - + int copied = 0; + struct sk_buff *skb; + int er; - /* - * This will pick up errors that occured while the program - * was doing something else. - */ - if (sk->err) { - int err; - err = -sk->err; - sk->err = 0; - return(err); - } - - if (len == 0) - return(0); - if (len < 0) - return(-EINVAL); + /* + * This will pick up errors that occured while the program + * was doing something else. + */ + + if (sk->err) + { + int err; + + err = -sk->err; + sk->err = 0; + return(err); + } + + if (len == 0) + return(0); + if (len < 0) + return(-EINVAL); - if (addr_len) { - er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); + /* + * Check any passed addresses + */ + + if (addr_len) + { + er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); + if(er) + return(er); + put_fs_long(sizeof(*sin), addr_len); + } + + if(sin) + { + er=verify_area(VERIFY_WRITE, sin, sizeof(*sin)); + if(er) + return(er); + } + + /* + * Check the buffer we were given + */ + + er=verify_area(VERIFY_WRITE,to,len); if(er) - return(er); - put_fs_long(sizeof(*sin), addr_len); - } - if(sin) - { - er=verify_area(VERIFY_WRITE, sin, sizeof(*sin)); - if(er) - return(er); - } - er=verify_area(VERIFY_WRITE,to,len); - if(er) - return er; - skb=skb_recv_datagram(sk,flags,noblock,&er); - if(skb==NULL) - return er; - copied = min(len, skb->len); + return er; + + /* + * From here the generic datagram does a lot of the work. Come + * the finished NET3, it will do _ALL_ the work! + */ + + skb=skb_recv_datagram(sk,flags,noblock,&er); + if(skb==NULL) + return er; + + copied = min(len, skb->len); + + /* + * FIXME : should use udp header size info value + */ + + skb_copy_datagram(skb,sizeof(struct udphdr),to,copied); + sk->stamp=skb->stamp; - /* FIXME : should use udp header size info value */ - skb_copy_datagram(skb,sizeof(struct udphdr),to,copied); + /* Copy the address. */ + if (sin) + { + struct sockaddr_in addr; - /* Copy the address. */ - if (sin) { - struct sockaddr_in addr; - - addr.sin_family = AF_INET; - addr.sin_port = skb->h.uh->source; - addr.sin_addr.s_addr = skb->daddr; - memcpy_tofs(sin, &addr, sizeof(*sin)); - } + addr.sin_family = AF_INET; + addr.sin_port = skb->h.uh->source; + addr.sin_addr.s_addr = skb->daddr; + memcpy_tofs(sin, &addr, sizeof(*sin)); + } - skb_free_datagram(skb); - release_sock(sk); - return(copied); + skb_free_datagram(skb); + release_sock(sk); + return(copied); } +/* + * Read has the same semantics as recv in SOCK_DGRAM + */ -int -udp_read(struct sock *sk, unsigned char *buff, int len, int noblock, +int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock, unsigned flags) { - return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); + return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); } @@ -507,7 +615,7 @@ if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT); - if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */ sk->daddr = sin.sin_addr.s_addr; @@ -527,74 +635,100 @@ } -/* All we need to do is get the socket, and then do a checksum. */ -int -udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, +/* + * All we need to do is get the socket, and then do a checksum. + */ + +int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, unsigned long daddr, unsigned short len, unsigned long saddr, int redo, struct inet_protocol *protocol) { - struct sock *sk; - struct udphdr *uh; + struct sock *sk; + struct udphdr *uh; + + /* + * Get the header. + */ + uh = (struct udphdr *) skb->h.uh; + + ip_statistics.IpInDelivers++; + + + sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr); + if (sk == NULL) + { + udp_statistics.UdpNoPorts++; + if (ip_chk_addr(daddr) == IS_MYADDR) + { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev); + } + /* + * Hmm. We got an UDP broadcast to a port to which we + * don't wanna listen. Ignore it. + */ + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + return(0); + } - uh = (struct udphdr *) skb->h.uh; - sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr); - if (sk == NULL) - { - if (chk_addr(daddr) == IS_MYADDR) + if (uh->check && udp_check(uh, len, saddr, daddr)) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev); + printk("UDP: bad checksum.\n"); + DPRINTF((DBG_UDP, "UDP: bad checksum\n")); + udp_statistics.UdpInErrors++; + kfree_skb(skb, FREE_WRITE); + return(0); } + + skb->sk = sk; + skb->dev = dev; + skb->len = len; + /* - * Hmm. We got an UDP broadcast to a port to which we - * don't wanna listen. The only thing we can do now is - * to ignore the packet... -FvK + * These are supposed to be switched. */ - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - return(0); - } + + skb->daddr = saddr; + skb->saddr = daddr; - if (uh->check && udp_check(uh, len, saddr, daddr)) { - DPRINTF((DBG_UDP, "UDP: bad checksum\n")); - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - return(0); - } - skb->sk = sk; - skb->dev = dev; - skb->len = len; - -/* These are supposed to be switched. */ - skb->daddr = saddr; - skb->saddr = daddr; - - - /* Charge it to the socket. */ - if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) - { - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - release_sock(sk); - return(0); - } - sk->rmem_alloc += skb->mem_len; + /* + * Charge it to the socket, dropping if the queue is full. + */ + + if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) + { + udp_statistics.UdpInErrors++; + ip_statistics.IpInDiscards++; + ip_statistics.IpInDelivers--; + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + release_sock(sk); + return(0); + } + sk->rmem_alloc += skb->mem_len; + udp_statistics.UdpInDatagrams++; + + /* + * At this point we should print the thing out. + */ - /* At this point we should print the thing out. */ - DPRINTF((DBG_UDP, "<< \n")); - print_udp(uh); + DPRINTF((DBG_UDP, "<< \n")); + print_udp(uh); - /* Now add it to the data chain and wake things up. */ + /* + * Now add it to the data chain and wake things up. + */ - skb_queue_tail(&sk->rqueue,skb); + skb->len = len - sizeof(*uh); + skb_queue_tail(&sk->receive_queue,skb); - skb->len = len - sizeof(*uh); - if (!sk->dead) - sk->data_ready(sk,skb->len); + if (!sk->dead) + sk->data_ready(sk,skb->len); - release_sock(sk); - return(0); + release_sock(sk); + return(0); } diff -u --recursive --new-file v1.1.3/linux/net/inet/utils.c linux/net/inet/utils.c --- v1.1.3/linux/net/inet/utils.c Wed Dec 1 14:44:15 1993 +++ linux/net/inet/utils.c Wed Apr 13 12:52:30 1994 @@ -19,6 +19,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + #include #include #include @@ -31,117 +32,136 @@ #include #include #include -#include "inet.h" -#include "dev.h" -#include "eth.h" +#include +#include +#include #include "ip.h" #include "protocol.h" #include "tcp.h" -#include "skbuff.h" -#include "arp.h" +#include -/* Display an IP address in readable format. */ +/* + * Display an IP address in readable format. + */ + char *in_ntoa(unsigned long in) { - static char buff[18]; - register char *p; + static char buff[18]; + char *p; - p = (char *) ∈ - sprintf(buff, "%d.%d.%d.%d", - (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); - return(buff); + p = (char *) ∈ + sprintf(buff, "%d.%d.%d.%d", + (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); + return(buff); } -/* Convert an ASCII string to binary IP. */ -unsigned long -in_aton(char *str) +/* + * Convert an ASCII string to binary IP. + */ + +unsigned long in_aton(char *str) { - unsigned long l; - unsigned int val; - int i; - - l = 0; - for (i = 0; i < 4; i++) { - l <<= 8; - if (*str != '\0') { - val = 0; - while (*str != '\0' && *str != '.') { - val *= 10; - val += *str - '0'; - str++; + unsigned long l; + unsigned int val; + int i; + + l = 0; + for (i = 0; i < 4; i++) + { + l <<= 8; + if (*str != '\0') + { + val = 0; + while (*str != '\0' && *str != '.') + { + val *= 10; + val += *str - '0'; + str++; + } + l |= val; + if (*str != '\0') + str++; } - l |= val; - if (*str != '\0') str++; } - } - return(htonl(l)); + return(htonl(l)); } -void -dprintf(int level, char *fmt, ...) +/* + * Debugging print out + */ + +void dprintf(int level, char *fmt, ...) { - va_list args; - char *buff; - extern int vsprintf(char * buf, const char * fmt, va_list args); - - if (level != inet_debug) return; - - buff = (char *) kmalloc(256, GFP_ATOMIC); - if (buff != NULL) { - va_start(args, fmt); - vsprintf(buff, fmt, args); - va_end(args); - printk(buff); - kfree(buff); - } + va_list args; + char *buff; + extern int vsprintf(char * buf, const char * fmt, va_list args); + + if (level != inet_debug) + return; + + buff = (char *) kmalloc(256, GFP_ATOMIC); + if (buff != NULL) + { + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + printk(buff); + kfree(buff); + } + else + printk("Debugging output lost: No free memory.\n"); } - -int -dbg_ioctl(void *arg, int level) +/* + * Debugging ioctl() requests + */ + +int dbg_ioctl(void *arg, int level) { - int val; - int err; + int val; + int err; - if (!suser()) return(-EPERM); - err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); - if(err) - return err; - val = get_fs_long((int *)arg); - switch(val) { - case 0: /* OFF */ - inet_debug = DBG_OFF; - break; - case 1: /* ON, INET */ - inet_debug = level; - break; - - case DBG_RT: /* modules */ - case DBG_DEV: - case DBG_ETH: - case DBG_PROTO: - case DBG_TMR: - case DBG_PKT: - case DBG_RAW: - - case DBG_LOOPB: /* drivers */ - case DBG_SLIP: - - case DBG_ARP: /* protocols */ - case DBG_IP: - case DBG_ICMP: - case DBG_TCP: - case DBG_UDP: - - inet_debug = val; - break; - - default: - return(-EINVAL); - } - - return(0); + if (!suser()) + return(-EPERM); + err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); + if(err) + return err; + val = get_fs_long((int *)arg); + switch(val) + { + case 0: /* OFF */ + inet_debug = DBG_OFF; + break; + case 1: /* ON, INET */ + inet_debug = level; + break; + + case DBG_RT: /* modules */ + case DBG_DEV: + case DBG_ETH: + case DBG_PROTO: + case DBG_TMR: + case DBG_PKT: + case DBG_RAW: + + case DBG_LOOPB: /* drivers */ + case DBG_SLIP: + + case DBG_ARP: /* protocols */ + case DBG_IP: + case DBG_ICMP: + case DBG_TCP: + case DBG_UDP: + + inet_debug = val; + break; + + default: + return(-EINVAL); + } + + return(0); } diff -u --recursive --new-file v1.1.3/linux/net/socket.c linux/net/socket.c --- v1.1.3/linux/net/socket.c Mon Jan 31 16:47:34 1994 +++ linux/net/socket.c Wed Apr 13 12:52:30 1994 @@ -17,6 +17,14 @@ * 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. + * + * + * This module is effectively the top level interface to the BSD socket + * paradigm. Because it is very simple it works well for Unix domain sockets, + * but requires a whole layer of substructure for the other protocols. + * + * In addition it lacks an effective kernel -> kernel interface to go with + * the user one. */ #include diff -u --recursive --new-file v1.1.3/linux/net/unix/proc.c linux/net/unix/proc.c --- v1.1.3/linux/net/unix/proc.c Fri Mar 4 09:25:21 1994 +++ linux/net/unix/proc.c Wed Apr 13 12:52:30 1994 @@ -35,44 +35,53 @@ /* Called from PROCfs. */ -int unix_get_info(char *buffer) +int unix_get_info(char *buffer, char **start, off_t offset, int length) { - char *pos; - int i; + off_t pos=0; + off_t begin=0; + int len=0; + int i; - pos = buffer; - pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n"); + len += sprintf(buffer, "Num RefCount Protocol Flags Type St Path\n"); - for(i = 0; i < NSOCKETS; i++) { - if (unix_datas[i].refcnt>0) { - pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i, - unix_datas[i].refcnt, - unix_datas[i].protocol, - unix_datas[i].socket->flags, - unix_datas[i].socket->type, - unix_datas[i].socket->state - ); + for(i = 0; i < NSOCKETS; i++) + { + if (unix_datas[i].refcnt>0) + { + len += sprintf(buffer+len, "%2d: %08X %08X %08lX %04X %02X", i, + unix_datas[i].refcnt, + unix_datas[i].protocol, + unix_datas[i].socket->flags, + unix_datas[i].socket->type, + unix_datas[i].socket->state + ); - /* If socket is bound to a filename, we'll print it. */ - if(unix_datas[i].sockaddr_len>0) { - pos += sprintf(pos, " %s\n", + /* If socket is bound to a filename, we'll print it. */ + if(unix_datas[i].sockaddr_len>0) + { + len += sprintf(buffer+len, " %s\n", unix_datas[i].sockaddr_un.sun_path); - } else { /* just add a newline */ - *pos='\n'; - pos++; - *pos='\0'; + } + else + { /* just add a newline */ + buffer[len++]='\n'; + buffer[len++]='\0'; + } + + pos=begin+len; + if(posoffset+length) + break; } - - /* - * Check whether buffer _may_ overflow in the next loop. - * Since sockets may have very very long paths, we make - * PATH_MAX+80 the minimum space left for a new line. - */ - if (pos > buffer+PAGE_SIZE-80-PATH_MAX) { - printk("UNIX: netinfo: oops, too many sockets.\n"); - return(pos - buffer); - } } - } - return(pos - buffer); + + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; } diff -u --recursive --new-file v1.1.3/linux/net/unix/sock.c linux/net/unix/sock.c --- v1.1.3/linux/net/unix/sock.c Thu Mar 17 10:01:26 1994 +++ linux/net/unix/sock.c Wed Apr 13 12:52:30 1994 @@ -413,13 +413,10 @@ old_fs = get_fs(); set_fs(get_ds()); i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0); - if (i == -EEXIST) - i = -EADDRINUSE; - if (i == 0) - i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL); + if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL); set_fs(old_fs); if (i < 0) { - dprintf(1, "UNIX: bind: can't open socket %s\n", fname); + printk("UNIX: bind: can't open socket %s\n", fname); return(i); } upd->sockaddr_len = sockaddr_len; /* now its legal */