]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.6 1.1.6
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:28 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:28 +0000 (15:09 -0500)
17 files changed:
Makefile
drivers/net/d_link.c
drivers/net/depca.c
drivers/net/slip.c
include/linux/skbuff.h
include/linux/socket.h
kernel/exit.c
net/inet/dev.c
net/inet/ip.c
net/inet/ipx.c
net/inet/raw.c
net/inet/route.c
net/inet/route.h
net/inet/sock.c
net/inet/sock.h
net/inet/tcp.c
net/inet/udp.c

index ba24d95451985798c0a57a8e72f81c6f6821202d..d2c13c7c45df081d4760251fbdcfe1508ab0edc6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 5
+SUBLEVEL = 6
 
 all:   Version zImage
 
index 5c8e61bdfe7a9dda1e12eeac3617f1c065d69b64..6154b3ee88695f739ef6240693348c7c9a5fd82e 100644 (file)
@@ -201,9 +201,10 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
 /*
  * Index to functions, as function prototypes.
  */
-
+#if 0
 /* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */
 static unsigned long   d_link_rspace(struct sock *sk);
+#endif
 
 /* Routines used internally. (See "convenience macros") */
 static int             d_link_read_status(struct device *dev);
@@ -689,6 +690,10 @@ adapter_init(struct device *dev)
        sti();
 }
 
+#if 0
+/*
+ *     The new router code (coming soon 8-) ) will fix this properly.
+ */
 #define D_LINK_MIN_WINDOW 1024
 #define D_LINK_MAX_WINDOW 2048
 #define D_LINK_TCP_WINDOW_DIFF 1024
@@ -724,3 +729,6 @@ d_link_rspace(struct sock *sk)
   }
   return(0);
 }
+
+
+#endif
index aa3da612927acbd16ee43cc65cca6ace498a1545..51d8818524e487874ec2f6d4d3191a6e7a7fd226 100644 (file)
@@ -644,32 +644,7 @@ depca_probe1(struct device *dev, short ioaddr)
        dev->mem_start = 0;
        
        /* 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 < dev->addr_len; 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);
       }
     } else {
       status = -ENXIO;
@@ -832,14 +807,6 @@ depca_start_xmit(struct sk_buff *skb, struct device *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;
-
     if (skb->len <= 0) {
       return 0;
     }
index e71952b1e5f12db079f31473812a66833ba8c371..7c555f93620c93ac185ad19903dcd34c389b78e7 100644 (file)
@@ -1030,6 +1030,12 @@ int sl_set_mac_address(struct device *dev, void *addr)
        memcpy_fromfs(dev->dev_addr,addr,7);    /* addr is an AX.25 shifted ASCII mac address */
        return 0;
 }
+
+static int sl_set_dev_mac_address(struct device *dev, void *addr)
+{
+       memcpy(dev->dev_addr,addr,7);
+       return 0;
+}
 #endif
 
 
@@ -1144,7 +1150,7 @@ slip_init(struct device *dev)
   dev->get_stats       = sl_get_stats;
 #ifdef HAVE_SET_MAC_ADDR
 #ifdef CONFIG_AX25
-  dev->set_mac_address  = sl_set_mac_address;
+  dev->set_mac_address  = sl_set_dev_mac_address;
 #endif
 #endif
   dev->hard_header_len = 0;
index 205a71c87cc90abca5986728353b436ab32178e0..07c86db8a53968e5c2fe94c9d2f601391dfdd391 100644 (file)
@@ -68,7 +68,7 @@ struct sk_buff {
                                used,
                                free,
                                arp;
-  unsigned char                        tries,lock;
+  unsigned char                        tries,lock,localroute;
   unsigned short               users;          /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
   unsigned long                        padding[0];
   unsigned char                        data[0];
index 3826b0254754785d7034f628af10dfb241ef3364..5945131502d6239d79ed5e5d89ed6812291d1fd4 100644 (file)
@@ -42,6 +42,7 @@ struct linger {
 /* Flags we can use with send/ and recv. */
 #define MSG_OOB                1
 #define MSG_PEEK       2
+#define MSG_DONTROUTE  4
 
 /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
 #define SOL_SOCKET     1
index 08a098e0d1e75e5ccda2bb379a75a415838f3412..bd115a8f7150c1b0c97cdaa840516161692ad8d5 100644 (file)
@@ -364,17 +364,6 @@ fake_volatile:
                sem_exit();
        if (current->shm)
                shm_exit();
-       free_page_tables(current);
-       for (i=0 ; i<NR_OPEN ; i++)
-               if (current->filp[i])
-                       sys_close(i);
-       forget_original_parent(current);
-       iput(current->pwd);
-       current->pwd = NULL;
-       iput(current->root);
-       current->root = NULL;
-       iput(current->executable);
-       current->executable = NULL;
        /* Release all of the old mmap stuff. */
        
        {
@@ -390,17 +379,28 @@ fake_volatile:
                }
        }
 
+       /* forget local segments */
+       __asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
+               : /* no outputs */
+               : "r" (0));
+       current->tss.ldt = 0;
        if (current->ldt) {
-               vfree(current->ldt);
+               void * ldt = current->ldt;
                current->ldt = NULL;
-               for (i=1 ; i<NR_TASKS ; i++) {
-                       if (task[i] == current) {
-                               set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, &default_ldt, 1);
-                               load_ldt(i);
-                       }
-               }
+               vfree(ldt);
        }
 
+       free_page_tables(current);
+       for (i=0 ; i<NR_OPEN ; i++)
+               if (current->filp[i])
+                       sys_close(i);
+       forget_original_parent(current);
+       iput(current->pwd);
+       current->pwd = NULL;
+       iput(current->root);
+       current->root = NULL;
+       iput(current->executable);
+       current->executable = NULL;
        /* 
         * Check to see if any process groups have become orphaned
         * as a result of our exiting, and if they have any stopped
index 2a30284bda0b61119bf3e62b75bd5dd8fc5cf607..92114101ab172d615bd393358928cd56c4bfd039 100644 (file)
@@ -549,7 +549,7 @@ void dev_transmit(void)
 
        for (dev = dev_base; dev != NULL; dev = dev->next) 
        {
-               if (!dev->tbusy) {
+               if (dev->flags != 0 && !dev->tbusy) {
                        /*
                         *      Kick the device
                         */
index 1be51881f16a79b4972bb927f7525aef148a3c1c..4d8a2cd4004a338c5372f98920c8fbf42d1eb2ec 100644 (file)
@@ -284,7 +284,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
         
        if (*dev == NULL) 
        {
-               rt = ip_rt_route(daddr, &optmem, &src);
+               if(skb->localroute)
+                       rt = ip_rt_local(daddr, &optmem, &src);
+               else
+                       rt = ip_rt_route(daddr, &optmem, &src);
                if (rt == NULL) 
                {
                        ip_statistics.IpOutNoRoutes++;
@@ -308,7 +311,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
                /* 
                 *      We still need the address of the first hop. 
                 */
-               rt = ip_rt_route(daddr, &optmem, &src);
+               if(skb->localroute)
+                       rt = ip_rt_local(daddr, &optmem, &src);
+               else
+                       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
index f2ed207b3eacdf13059f975fabf9b0da7115b8e6..716dcdfd8f5aba2aab54ba46daee781978dafd97 100644 (file)
@@ -503,6 +503,7 @@ static int ipx_create(struct socket *sock, int protocol)
        sk->type=sock->type;
        sk->ipx_type=0;         /* General user level IPX */
        sk->debug=0;
+       sk->localroute=0;
        
        memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr));
        memset(&sk->ipx_source_addr,'\0',sizeof(sk->ipx_source_addr));
@@ -836,7 +837,7 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
        int size;
        ipx_route *rt;
 
-       if(flags)
+       if(flags&~MSG_DONTROUTE)
                return -EINVAL;
        if(len<0)
                return -EINVAL;
@@ -882,7 +883,8 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
 
        /* Find out where this has to go */
        rt=ipxrtr_get_dev(sipx.sipx_network);
-       if(rt==NULL)
+       /* No suitable route - no gateways when not routing */
+       if(rt==NULL || ((flags&IPX_RT_ROUTED)&& ((flags&MSG_DONTROUTE)||sk->localroute)))
        {
                return -ENETUNREACH;
        }
@@ -917,7 +919,7 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
        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_BLUEBOOK)?ETH_P_IPX:ETH_P_802_3),
                (rt->flags&IPX_RT_ROUTED)?rt->router_node:sipx.sipx_node,
                NULL,
                len+sizeof(ipx_packet),
index ac59a0538e4aa37d01fdf74580293fd4d65968b6..958378cdf4e7dd4a21ce0ae14145fb40fc0e15bc 100644 (file)
@@ -142,143 +142,162 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
   return(0);
 }
 
+/*
+ *     Send a RAW IP packet.
+ */
 
-/* This will do terrible things if len + ipheader + devheader > dev->mtu */
-static int
-raw_sendto(struct sock *sk, unsigned char *from, int len,
-          int noblock,
-          unsigned flags, struct sockaddr_in *usin, int addr_len)
+static int raw_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=NULL;
-  struct sockaddr_in sin;
-  int tmp;
-  int err;
-
-  DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
-          "            usin=%X, addr_len = %d)\n", sk, from, len, noblock,
-          flags, usin, addr_len));
-
-  /* Check the flags. */
-  if (flags) return(-EINVAL);
-  if (len < 0) return(-EINVAL);
-
-  err=verify_area(VERIFY_READ,from,len);
-  if(err)
-       return err;
-  /* Get and verify the address. */
-  if (usin) {
-       if (addr_len < sizeof(sin)) return(-EINVAL);
-       err=verify_area (VERIFY_READ, usin, sizeof (sin));
+       struct sk_buff *skb;
+       struct device *dev=NULL;
+       struct sockaddr_in sin;
+       int tmp;
+       int err;
+
+       DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
+               "            usin=%X, addr_len = %d)\n", sk, from, len, noblock,
+               flags, usin, addr_len));
+
+       /*
+        *      Check the flags. Only MSG_DONTROUTE is permitted.
+        */
+        
+       if (flags&MSG_DONTROUTE)
+               return(-EINVAL);
+       if (len < 0) 
+               return(-EINVAL);
+
+       err=verify_area(VERIFY_READ,from,len);
        if(err)
                return err;
-       memcpy_fromfs(&sin, usin, sizeof(sin));
-       if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
-  } else {
-       if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
-       sin.sin_family = AF_INET;
-       sin.sin_port = sk->protocol;
-       sin.sin_addr.s_addr = sk->daddr;
-  }
-  if (sin.sin_port == 0) sin.sin_port = sk->protocol;
+       /*
+        *      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);
+       }
+       else 
+       {
+               if (sk->state != TCP_ESTABLISHED) 
+                       return(-EINVAL);
+               sin.sin_family = AF_INET;
+               sin.sin_port = sk->protocol;
+               sin.sin_addr.s_addr = sk->daddr;
+       }
+       if (sin.sin_port == 0) 
+               sin.sin_port = sk->protocol;
   
-  if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
-       return -EACCES;
-
-  sk->inuse = 1;
-  skb = NULL;
-  while (skb == NULL) {
-       if(sk->err!=0)
-       {
-               err= -sk->err;
-               sk->err=0;
-               release_sock(sk);
-               return(err);
-       }
+       if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+               return -EACCES;
+
+       sk->inuse = 1;
+       skb = NULL;
+       while (skb == NULL) 
+       {
+               if(sk->err!=0)
+               {
+                       err= -sk->err;
+                       sk->err=0;
+                       release_sock(sk);
+                       return(err);
+               }
        
-       skb = sk->prot->wmalloc(sk,
-                       len + sk->prot->max_header,
-                       0, GFP_KERNEL);
-       if (skb == NULL) {
-               int tmp;
-
-               DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
-               if (noblock) 
-                       return(-EAGAIN);
-               tmp = sk->wmem_alloc;
-               release_sock(sk);
-               cli();
-               if (tmp <= sk->wmem_alloc) {
-                       interruptible_sleep_on(sk->sleep);
-                       if (current->signal & ~current->blocked) {
-                               sti();
-                               return(-ERESTARTSYS);
+               skb = sk->prot->wmalloc(sk,
+                               len + sk->prot->max_header,
+                               0, GFP_KERNEL);
+               if (skb == NULL) 
+               {
+                       int tmp;
+
+                       DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
+                       if (noblock) 
+                               return(-EAGAIN);
+                       tmp = sk->wmem_alloc;
+                       release_sock(sk);
+                       cli();
+                       if (tmp <= sk->wmem_alloc) {
+                               interruptible_sleep_on(sk->sleep);
+                               if (current->signal & ~current->blocked) {
+                                       sti();
+                                       return(-ERESTARTSYS);
+                               }
                        }
+                       sk->inuse = 1;
+                       sti();
                }
-               sk->inuse = 1;
-               sti();
        }
-  }
-  skb->sk = sk;
+       skb->sk = sk;
+       skb->free = 1;
+       skb->localroute = sk->localroute | (flags&MSG_DONTROUTE);
 
-  skb->free = 1;
-
-  tmp = sk->prot->build_header(skb, sk->saddr, 
+       tmp = sk->prot->build_header(skb, sk->saddr, 
                               sin.sin_addr.s_addr, &dev,
                               sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
-  if (tmp < 0) {
-       DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
-       kfree_skb(skb,FREE_WRITE);
-       release_sock(sk);
-       return(tmp);
-  }
+       if (tmp < 0) 
+       {
+               DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
+               kfree_skb(skb,FREE_WRITE);
+               release_sock(sk);
+               return(tmp);
+       }
 
-  /* verify_area(VERIFY_WRITE, from, len);*/
-  memcpy_fromfs(skb->data + tmp, from, len);
+       memcpy_fromfs(skb->data + tmp, from, len);
 
-  /* If we are using IPPROTO_RAW, we need to fill in the source address in
-     the IP header */
+       /*
+        *      If we are using IPPROTO_RAW, we need to fill in the source address in
+        *      the IP header 
+        */
 
-  if(sk->protocol==IPPROTO_RAW) {
-    unsigned char *buff;
-    struct iphdr *iph;
+       if(sk->protocol==IPPROTO_RAW) 
+       {
+               unsigned char *buff;
+               struct iphdr *iph;
 
-    buff = skb->data;
-    buff += tmp;
-    iph = (struct iphdr *)buff;
-    iph->saddr = sk->saddr;
-  }
+               buff = skb->data;
+               buff += tmp;
 
-  skb->len = tmp + len;
+               iph = (struct iphdr *)buff;
+               iph->saddr = sk->saddr;
+       }
+
+       skb->len = tmp + len;
   
-  sk->prot->queue_xmit(sk, dev, skb, 1);
-  release_sock(sk);
-  return(len);
+       sk->prot->queue_xmit(sk, dev, skb, 1);
+       release_sock(sk);
+       return(len);
 }
 
 
-static int
-raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
+static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
           unsigned flags)
 {
-  return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
+       return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
 }
 
 
-static void
-raw_close(struct sock *sk, int timeout)
+static void raw_close(struct sock *sk, int timeout)
 {
-  sk->inuse = 1;
-  sk->state = TCP_CLOSE;
+       sk->inuse = 1;
+       sk->state = TCP_CLOSE;
 
-  DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
+       DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
           ((struct inet_protocol *)sk->pair)->protocol));
 
-  if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
+       if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
                DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n"));
-  kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
-  sk->pair = NULL;
-  release_sock(sk);
+       kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
+       sk->pair = NULL;
+       release_sock(sk);
 }
 
 
index 3502fdc917d0513a262d6b6937b5897df230ca8b..ab2b312f2a7c8701d5abb18f3032f7d1582e19b8 100644 (file)
@@ -573,6 +573,42 @@ no_route:
        return NULL;
 }
 
+struct rtable * ip_rt_local(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) 
+       {
+               /*
+                *      No routed addressing.
+                */
+               if (rt->rt_flags&RTF_GATEWAY)
+                       continue;
+                       
+               if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
+                       break;
+               /*
+                *      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;
+       }
+       rt->rt_use++;
+       return rt;
+no_route:
+       return NULL;
+}
+
 /*
  *     Backwards compatibility
  */
index 4d1a3d2944119400be7b1d202d46b9ae53db33f3..d2f092daf9b56d2a9be95c6c86aa0e25e1c54d1e 100644 (file)
@@ -9,6 +9,8 @@
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Fixes:
+ *             Alan Cox        :       Reformatted. Added ip_rt_local()
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
 
 
 /* This is an entry in the IP routing table. */
-struct rtable {
-  struct rtable                *rt_next;
-  unsigned long                rt_dst;
-  unsigned long                rt_mask;
-  unsigned long                rt_gateway;
-  unsigned char                rt_flags;
-  unsigned char                rt_metric;
-  short                        rt_refcnt;
-  unsigned long                rt_use;
-  unsigned short       rt_mss, rt_mtu;
-  struct device                *rt_dev;
+struct rtable 
+{
+       struct rtable           *rt_next;
+       unsigned long           rt_dst;
+       unsigned long           rt_mask;
+       unsigned long           rt_gateway;
+       unsigned char           rt_flags;
+       unsigned char           rt_metric;
+       short                   rt_refcnt;
+       unsigned long           rt_use;
+       unsigned short          rt_mss, rt_mtu;
+       struct device           *rt_dev;
 };
 
 
@@ -41,6 +44,7 @@ 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   *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr);
+extern struct rtable   *ip_rt_local(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);
 
index b3f11248c05a0b2e40628e49a0a9e8703643ff39..dd7c008b53ac2f97a0a5d87db8d3d3ea79ca52d4 100644 (file)
@@ -489,7 +489,8 @@ int sock_setsockopt(struct sock *sk, int level, int optname,
 
                case SO_DEBUG:  
                        sk->debug=val?1:0;
-               case SO_DONTROUTE:      /* Still to be implemented */
+               case SO_DONTROUTE:
+                       sk->localroute=val?1:0;
                        return(0);
                case SO_BROADCAST:
                        sk->broadcast=val?1:0;
@@ -580,8 +581,8 @@ int sock_getsockopt(struct sock *sk, int level, int optname,
                        val = sk->debug;
                        break;
                
-               case SO_DONTROUTE:      /* One last option to implement */
-                       val = 0;
+               case SO_DONTROUTE:
+                       val = sk->localroute;
                        break;
                
                case SO_BROADCAST:
@@ -852,6 +853,7 @@ inet_create(struct socket *sock, int protocol)
   sk->send_head = NULL;
   sk->timeout = 0;
   sk->broadcast = 0;
+  sk->localroute = 0;
   sk->timer.data = (unsigned long)sk;
   sk->timer.function = &net_timer;
   skb_queue_head_init(&sk->back_log);
index 6e936329688cb2a467de37ff147b19abb142a64e..42e20a7e334f0f27ce5519e69cec36989093ff91 100644 (file)
@@ -132,6 +132,7 @@ struct sock {
   unsigned short               rcvbuf;
   unsigned short               sndbuf;
   unsigned short               type;
+  unsigned char                        localroute;     /* Route locally only */
 #ifdef CONFIG_IPX
   ipx_address                  ipx_source_addr,ipx_dest_addr;
   unsigned short               ipx_type;
index 51220f29aafacb567e416277085cc0530320c05f..18c097cbda650aa98c4e463933a5b0c6d53993ab 100644 (file)
@@ -662,81 +662,91 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
             struct sock *sk,
             struct tcphdr *th, unsigned long daddr)
 {
-  struct sk_buff *buff;
-  struct tcphdr *t1;
-  struct device *dev = NULL;
-  int tmp;
+       struct sk_buff *buff;
+       struct tcphdr *t1;
+       struct device *dev = NULL;
+       int tmp;
 
-  if(sk->zapped)
-       return;         /* We have been reset, we may not send again */
-  /*
-   * We need to grab some memory, and put together an ack,
-   * and then put it into the queue to be sent.
-   */
-  buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
-  if (buff == NULL) {
-       /* Force it to send an ack. */
-       sk->ack_backlog++;
-       if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) {
-               reset_timer(sk, TIME_WRITE, 10);
+       if(sk->zapped)
+               return;         /* We have been reset, we may not send again */
+       /*
+        * We need to grab some memory, and put together an ack,
+        * and then put it into the queue to be sent.
+        */
+
+       buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
+       if (buff == NULL) 
+       {
+               /* Force it to send an ack. */
+               sk->ack_backlog++;
+               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");
+               return;
        }
-  if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
-       return;
-  }
 
-  buff->len = sizeof(struct tcphdr);
-  buff->sk = sk;
-  t1 =(struct tcphdr *) buff->data;
+       buff->len = sizeof(struct tcphdr);
+       buff->sk = sk;
+       buff->localroute = sk->localroute;
+       t1 =(struct tcphdr *) buff->data;
 
-  /* Put in the IP header and routing stuff. */
-  tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
+       /* Put in the IP header and routing stuff. */
+       tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
                                IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
-  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");
-       return;
-  }
-  buff->len += tmp;
-  t1 =(struct tcphdr *)((char *)t1 +tmp);
+       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");
+               return;
+       }
+       buff->len += tmp;
+       t1 =(struct tcphdr *)((char *)t1 +tmp);
 
-  /* FIXME: */
-  memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
+       /* FIXME: */
+       memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
 
-  /* swap the send and the receive. */
-  t1->dest = th->source;
-  t1->source = th->dest;
-  t1->seq = ntohl(sequence);
-  t1->ack = 1;
-  sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/
-  t1->window = ntohs(sk->window);
-  t1->res1 = 0;
-  t1->res2 = 0;
-  t1->rst = 0;
-  t1->urg = 0;
-  t1->syn = 0;
-  t1->psh = 0;
-  t1->fin = 0;
-  if (ack == sk->acked_seq) {
-       sk->ack_backlog = 0;
-       sk->bytes_rcv = 0;
-       sk->ack_timed = 0;
-       if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL
-                                 && sk->timeout == TIME_WRITE) 
+       /*
+        *      Swap the send and the receive. 
+        */
+       t1->dest = th->source;
+       t1->source = th->dest;
+       t1->seq = ntohl(sequence);
+       t1->ack = 1;
+       sk->window = tcp_select_window(sk);
+       t1->window = ntohs(sk->window);
+       t1->res1 = 0;
+       t1->res2 = 0;
+       t1->rst = 0;
+       t1->urg = 0;
+       t1->syn = 0;
+       t1->psh = 0;
+       t1->fin = 0;
+       if (ack == sk->acked_seq) 
        {
-               if(sk->keepopen)
-                       reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
-               else
-                       delete_timer(sk);
-       }
-  }
-  t1->ack_seq = ntohl(ack);
-  t1->doff = sizeof(*t1)/4;
-  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);
+               sk->ack_backlog = 0;
+               sk->bytes_rcv = 0;
+               sk->ack_timed = 0;
+               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);
+                       else
+                               delete_timer(sk);
+               }
+       }
+       t1->ack_seq = ntohl(ack);
+       t1->doff = sizeof(*t1)/4;
+       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);
 }
 
 
@@ -766,138 +776,165 @@ tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
  * This routine copies from a user buffer into a socket,
  * and starts the transmit system.
  */
-static int
-tcp_write(struct sock *sk, unsigned char *from,
+static int tcp_write(struct sock *sk, unsigned char *from,
          int len, int nonblock, unsigned flags)
 {
-  int copied = 0;
-  int copy;
-  int tmp;
-  struct sk_buff *skb;
-  struct sk_buff *send_tmp;
-  unsigned char *buff;
-  struct proto *prot;
-  struct device *dev = NULL;
+       int copied = 0;
+       int copy;
+       int tmp;
+       struct sk_buff *skb;
+       struct sk_buff *send_tmp;
+       unsigned char *buff;
+       struct proto *prot;
+       struct device *dev = NULL;
 
-  DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
+       DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
                                        sk, from, len, nonblock, flags));
 
-  sk->inuse=1;
-  prot = sk->prot;
-  while(len > 0) {
-       if (sk->err) {                  /* Stop on an error */
-               release_sock(sk);
-               if (copied) return(copied);
-               tmp = -sk->err;
-               sk->err = 0;
-               return(tmp);
-       }
-
-       /* First thing we do is make sure that we are established. */    
-       if (sk->shutdown & SEND_SHUTDOWN) {
-               release_sock(sk);
-               sk->err = EPIPE;
-               if (copied) return(copied);
-               sk->err = 0;
-               return(-EPIPE);
-       }
-
-
-       /* Wait for a connection to finish. */
-       
-       while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) {
-               if (sk->err) {
+       sk->inuse=1;
+       prot = sk->prot;
+       while(len > 0) 
+       {
+               if (sk->err) 
+               {                       /* Stop on an error */
                        release_sock(sk);
-                       if (copied) return(copied);
+                       if (copied) 
+                               return(copied);
                        tmp = -sk->err;
                        sk->err = 0;
                        return(tmp);
                }
 
-               if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) {
+       /*
+        *      First thing we do is make sure that we are established. 
+        */
+       
+               if (sk->shutdown & SEND_SHUTDOWN) 
+               {
                        release_sock(sk);
-                       DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
-                       if (copied) return(copied);
+                       sk->err = EPIPE;
+                       if (copied) 
+                               return(copied);
+                       sk->err = 0;
+                       return(-EPIPE);
+               }
 
-                       if (sk->err) {
+
+       /* 
+        *      Wait for a connection to finish.
+        */
+       
+               while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) 
+               {
+                       if (sk->err) 
+                       {
+                               release_sock(sk);
+                               if (copied) 
+                                       return(copied);
                                tmp = -sk->err;
                                sk->err = 0;
                                return(tmp);
                        }
 
-                       if (sk->keepopen) {
-                               send_sig(SIGPIPE, current, 0);
+                       if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) 
+                       {
+                               release_sock(sk);
+                               DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
+                               if (copied) 
+                                       return(copied);
+
+                               if (sk->err) 
+                               {
+                                       tmp = -sk->err;
+                                       sk->err = 0;
+                                       return(tmp);
+                               }
+
+                               if (sk->keepopen) 
+                               {
+                                       send_sig(SIGPIPE, current, 0);
+                               }
+                               return(-EPIPE);
                        }
-                       return(-EPIPE);
-               }
 
-               if (nonblock || copied) {
-                       release_sock(sk);
-                       DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
-                       if (copied) return(copied);
-                       return(-EAGAIN);
-               }
+                       if (nonblock || copied) 
+                       {
+                               release_sock(sk);
+                               DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
+                               if (copied) 
+                                       return(copied);
+                               return(-EAGAIN);
+                       }
 
-               release_sock(sk);
-               cli();
-               if (sk->state != TCP_ESTABLISHED &&
-                   sk->state != TCP_CLOSE_WAIT && sk->err == 0) {
-                       interruptible_sleep_on(sk->sleep);
-                       if (current->signal & ~current->blocked) {
-                               sti();
-                               DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
-                               if (copied) return(copied);
-                               return(-ERESTARTSYS);
+                       release_sock(sk);
+                       cli();
+               
+                       if (sk->state != TCP_ESTABLISHED &&
+                               sk->state != TCP_CLOSE_WAIT && sk->err == 0) 
+                       {
+                               interruptible_sleep_on(sk->sleep);
+                               if (current->signal & ~current->blocked) 
+                               {
+                                       sti();
+                                       DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
+                                       if (copied) 
+                                               return(copied);
+                                       return(-ERESTARTSYS);
+                               }
                        }
+                       sk->inuse = 1;
+                       sti();
                }
-               sk->inuse = 1;
-               sti();
-       }
 
-/*
- * The following code can result in copy <= if sk->mss is ever
- * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window).
- * sk->mtu is constant once SYN processing is finished.  I.e. we
- * had better not get here until we've seen his SYN and at least one
- * valid ack.  (The SYN sets sk->mtu and the ack sets sk->max_window.)
- * But ESTABLISHED should guarantee that.  sk->max_window is by definition
- * non-decreasing.  Note that any ioctl to set user_mss must be done
- * before the exchange of SYN's.  If the initial ack from the other
- * end has a window of 0, max_window and thus mss will both be 0.
- */
+       /*
       * The following code can result in copy <= if sk->mss is ever
       * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window).
       * sk->mtu is constant once SYN processing is finished.  I.e. we
       * had better not get here until we've seen his SYN and at least one
       * valid ack.  (The SYN sets sk->mtu and the ack sets sk->max_window.)
       * But ESTABLISHED should guarantee that.  sk->max_window is by definition
       * non-decreasing.  Note that any ioctl to set user_mss must be done
       * before the exchange of SYN's.  If the initial ack from the other
       * end has a window of 0, max_window and thus mss will both be 0.
       */
 
-       /* Now we need to check if we have a half built packet. */
-       if ((skb = tcp_dequeue_partial(sk)) != NULL) {
-               int hdrlen;
-
-                /* IP header + TCP header */
-               hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
-                        + sizeof(struct tcphdr);
-
-               /* Add more stuff to the end of skb->len */
-               if (!(flags & MSG_OOB)) {
-                       copy = min(sk->mss - (skb->len - hdrlen), len);
-                       /* FIXME: this is really a bug. */
-                       if (copy <= 0) {
-                         printk("TCP: **bug**: \"copy\" <= 0!!\n");
-                         copy = 0;
-                       }
+       /* 
+        *      Now we need to check if we have a half built packet. 
+        */
+
+               if ((skb = tcp_dequeue_partial(sk)) != NULL) 
+               {
+                       int hdrlen;
+
+                        /* IP header + TCP header */
+                       hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
+                                + sizeof(struct tcphdr);
+       
+                       /* Add more stuff to the end of skb->len */
+                       if (!(flags & MSG_OOB)) 
+                       {
+                               copy = min(sk->mss - (skb->len - hdrlen), len);
+                               /* FIXME: this is really a bug. */
+                               if (copy <= 0) 
+                               {
+                                       printk("TCP: **bug**: \"copy\" <= 0!!\n");
+                                       copy = 0;
+                               }
          
-                       memcpy_fromfs(skb->data + skb->len, from, copy);
-                       skb->len += copy;
-                       from += copy;
-                       copied += copy;
-                       len -= copy;
-                       sk->write_seq += copy;
-                     }
-               if ((skb->len - hdrlen) >= sk->mss ||
-                   (flags & MSG_OOB) ||
-                   !sk->packets_out)
-                       tcp_send_skb(sk, skb);
-               else
-                       tcp_enqueue_partial(skb, sk);
-               continue;
-       }
+                               memcpy_fromfs(skb->data + skb->len, from, copy);
+                               skb->len += copy;
+                               from += copy;
+                               copied += copy;
+                               len -= copy;
+                               sk->write_seq += copy;
+                       }
+                       if ((skb->len - hdrlen) >= sk->mss ||
+                               (flags & MSG_OOB) || !sk->packets_out)
+                               tcp_send_skb(sk, skb);
+                       else
+                               tcp_enqueue_partial(skb, sk);
+                       continue;
+               }
 
        /*
         * We also need to worry about the window.
@@ -911,112 +948,146 @@ tcp_write(struct sock *sk, unsigned char *from,
         *   be queued for later rather than sent.
         */
 
-       copy = sk->window_seq - sk->write_seq;
-       if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)
-               copy = sk->mss;
-       if (copy > len)
-               copy = len;
-
-  /* We should really check the window here also. */
-       send_tmp = NULL;
-       if (copy < sk->mss && !(flags & MSG_OOB)) {
-       /* We will release the socket incase we sleep here. */
-         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, 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 , 0, GFP_KERNEL);
-         sk->inuse = 1;
-       }
+               copy = sk->window_seq - sk->write_seq;
+               if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)
+                       copy = sk->mss;
+               if (copy > len)
+                       copy = len;
 
-       /* If we didn't get any memory, we need to sleep. */
-       if (skb == NULL) {
-               if (nonblock /* || copied */) {
+       /*
+        *      We should really check the window here also. 
+        */
+        
+               send_tmp = NULL;
+               if (copy < sk->mss && !(flags & MSG_OOB)) 
+               {
+                       /*
+                        *      We will release the socket incase we sleep here. 
+                        */
+                       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, 0, GFP_KERNEL);
+                       sk->inuse = 1;
+                       send_tmp = skb;
+               } 
+               else 
+               {
+                       /*
+                        *      We will release the socket incase we sleep here. 
+                        */
                        release_sock(sk);
-                       DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
-                       if (copied) return(copied);
-                       return(-EAGAIN);
+                       skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL);
+                       sk->inuse = 1;
                }
 
-               /* FIXME: here is another race condition. */
-               tmp = sk->wmem_alloc;
-               release_sock(sk);
-               cli();
-               /* Again we will try to avoid it. */
-               if (tmp <= sk->wmem_alloc &&
-                 (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
-                               && sk->err == 0) {
-                       interruptible_sleep_on(sk->sleep);
-                       if (current->signal & ~current->blocked) {
-                               sti();
-                               DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
-                               if (copied) return(copied);
-                               return(-ERESTARTSYS);
+               /*
+                *      If we didn't get any memory, we need to sleep. 
+                */
+
+               if (skb == NULL) 
+               {
+                       if (nonblock /* || copied */) 
+                       {
+                               release_sock(sk);
+                               DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
+                               if (copied) 
+                                       return(copied);
+                               return(-EAGAIN);
                        }
-               }
-               sk->inuse = 1;
-               sti();
-               continue;
-       }
 
-       skb->len = 0;
-       skb->sk = sk;
-       skb->free = 0;
+                       /*
+                        *      FIXME: here is another race condition. 
+                        */
 
-       buff = skb->data;
+                       tmp = sk->wmem_alloc;
+                       release_sock(sk);
+                       cli();
+                       /*
+                        *      Again we will try to avoid it. 
+                        */
+                       if (tmp <= sk->wmem_alloc &&
+                                 (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
+                               && sk->err == 0) 
+                       {
+                               interruptible_sleep_on(sk->sleep);
+                               if (current->signal & ~current->blocked) 
+                               {
+                                       sti();
+                                       DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
+                                       if (copied) 
+                                               return(copied);
+                                       return(-ERESTARTSYS);
+                               }
+                       }
+                       sk->inuse = 1;
+                       sti();
+                       continue;
+               }
 
-       /*
-        * FIXME: we need to optimize this.
-        * Perhaps some hints here would be good.
-        */
-       tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
+               skb->len = 0;
+               skb->sk = sk;
+               skb->free = 0;
+               skb->localroute = sk->localroute|(flags&MSG_DONTROUTE);
+       
+               buff = skb->data;
+       
+               /*
+                * FIXME: we need to optimize this.
+                * Perhaps some hints here would be good.
+                */
+               
+               tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
                                 IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
-       if (tmp < 0 ) {
-               prot->wfree(sk, skb->mem_addr, skb->mem_len);
-               release_sock(sk);
-               DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
-               if (copied) return(copied);
-               return(tmp);
-       }
-       skb->len += tmp;
-       skb->dev = dev;
-       buff += tmp;
-       skb->h.th =(struct tcphdr *) buff;
-       tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
-       if (tmp < 0) {
-               prot->wfree(sk, skb->mem_addr, skb->mem_len);
-               release_sock(sk);
-               DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
-               if (copied) return(copied);
-               return(tmp);
-       }
-
-       if (flags & MSG_OOB) {
-               ((struct tcphdr *)buff)->urg = 1;
-               ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
-       }
-       skb->len += tmp;
-       memcpy_fromfs(buff+tmp, from, copy);
-
-       from += copy;
-       copied += copy;
-       len -= copy;
-       skb->len += copy;
-       skb->free = 0;
-       sk->write_seq += copy;
+               if (tmp < 0 ) 
+               {
+                       prot->wfree(sk, skb->mem_addr, skb->mem_len);
+                       release_sock(sk);
+                       DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
+                       if (copied) 
+                               return(copied);
+                       return(tmp);
+               }
+               skb->len += tmp;
+               skb->dev = dev;
+               buff += tmp;
+               skb->h.th =(struct tcphdr *) buff;
+               tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
+               if (tmp < 0) 
+               {
+                       prot->wfree(sk, skb->mem_addr, skb->mem_len);
+                       release_sock(sk);
+                       DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
+                       if (copied) 
+                               return(copied);
+                       return(tmp);
+               }
 
-       if (send_tmp != NULL && sk->packets_out) {
-               tcp_enqueue_partial(send_tmp, sk);
-               continue;
+               if (flags & MSG_OOB) 
+               {
+                       ((struct tcphdr *)buff)->urg = 1;
+                       ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
+               }
+               skb->len += tmp;
+               memcpy_fromfs(buff+tmp, from, copy);
+
+               from += copy;
+               copied += copy;
+               len -= copy;
+               skb->len += copy;
+               skb->free = 0;
+               sk->write_seq += copy;
+       
+               if (send_tmp != NULL && sk->packets_out) 
+               {
+                       tcp_enqueue_partial(send_tmp, sk);
+                       continue;
+               }
+               tcp_send_skb(sk, skb);
        }
-       tcp_send_skb(sk, skb);
-  }
-  sk->err = 0;
+       sk->err = 0;
 
 /*
  *     Nagles rule. Turn Nagle off with TCP_NODELAY for highly
@@ -1025,181 +1096,204 @@ tcp_write(struct sock *sk, unsigned char *from,
  *     on my slow slip link - Alan
  */
 
-  /* Avoid possible race on send_tmp - c/o Johannes Stille */
-  if(sk->partial && 
-     ((!sk->packets_out) 
+/*
+ *     Avoid possible race on send_tmp - c/o Johannes Stille 
+ */
+       if(sk->partial && ((!sk->packets_out) 
      /* If not nagling we can send on the before case too.. */
-      || (sk->nonagle && before(sk->write_seq , sk->window_seq))
-      ))
-       tcp_send_partial(sk);
-  /* -- */
-  release_sock(sk);
-  DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
-  return(copied);
+             || (sk->nonagle && before(sk->write_seq , sk->window_seq))
+       ))
+               tcp_send_partial(sk);
+
+       release_sock(sk);
+       DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
+       return(copied);
 }
 
 
-static int
-tcp_sendto(struct sock *sk, unsigned char *from,
+static int tcp_sendto(struct sock *sk, unsigned char *from,
           int len, int nonblock, unsigned flags,
           struct sockaddr_in *addr, int addr_len)
 {
-  struct sockaddr_in sin;
+       struct sockaddr_in sin;
 
-  if (addr_len < sizeof(sin)) return(-EINVAL);
-  memcpy_fromfs(&sin, addr, sizeof(sin));
-  if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
-  if (sin.sin_port != sk->dummy_th.dest) return(-EINVAL);
-  if (sin.sin_addr.s_addr != sk->daddr) return(-EINVAL);
-  return(tcp_write(sk, from, len, nonblock, flags));
+       if (flags & ~(MSG_OOB|MSG_DONTROUTE))
+               return -EINVAL;
+       if (addr_len < sizeof(sin)) 
+               return(-EINVAL);
+       memcpy_fromfs(&sin, addr, sizeof(sin));
+       if (sin.sin_family && sin.sin_family != AF_INET) 
+               return(-EINVAL);
+       if (sin.sin_port != sk->dummy_th.dest) 
+               return(-EINVAL);
+       if (sin.sin_addr.s_addr != sk->daddr) 
+               return(-EINVAL);
+       return(tcp_write(sk, from, len, nonblock, flags));
 }
 
 
 static void
 tcp_read_wakeup(struct sock *sk)
 {
-  int tmp;
-  struct device *dev = NULL;
-  struct tcphdr *t1;
-  struct sk_buff *buff;
+       int tmp;
+       struct device *dev = NULL;
+       struct tcphdr *t1;
+       struct sk_buff *buff;
 
-  DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
-  if (!sk->ack_backlog) return;
+       DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
+       if (!sk->ack_backlog) 
+               return;
 
-  /*
-   * FIXME: we need to put code here to prevent this routine from
-   * being called.  Being called once in a while is ok, so only check
-   * if this is the second time in a row.
-   */
+       /*
+        * FIXME: we need to put code here to prevent this routine from
+        * being called.  Being called once in a while is ok, so only check
+        * if this is the second time in a row.
+        */
 
-  /*
-   * We need to grab some memory, and put together an ack,
-   * and then put it into the queue to be sent.
-   */
-  buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
-  if (buff == NULL) {
-       /* Try again real soon. */
-       reset_timer(sk, TIME_WRITE, 10);
-       return;
-  }
+       /*
+        * We need to grab some memory, and put together an ack,
+        * and then put it into the queue to be sent.
+        */
 
-  buff->len = sizeof(struct tcphdr);
-  buff->sk = sk;
+       buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+       if (buff == NULL) 
+       {
+               /* Try again real soon. */
+               reset_timer(sk, TIME_WRITE, 10);
+               return;
+       }
 
-  /* Put in the IP header and routing stuff. */
-  tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
-                              IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
-  if (tmp < 0) {
-       buff->free=1;
-       sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
-       return;
-  }
+       buff->len = sizeof(struct tcphdr);
+       buff->sk = sk;
+       buff->localroute = sk->localroute;
+       
+       /*
+        *      Put in the IP header and routing stuff. 
+        */
 
-  buff->len += tmp;
-  t1 =(struct tcphdr *)(buff->data +tmp);
+       tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+                              IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
+       if (tmp < 0) 
+       {
+               buff->free=1;
+               sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+               return;
+       }
 
-  memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
-  t1->seq = htonl(sk->sent_seq);
-  t1->ack = 1;
-  t1->res1 = 0;
-  t1->res2 = 0;
-  t1->rst = 0;
-  t1->urg = 0;
-  t1->syn = 0;
-  t1->psh = 0;
-  sk->ack_backlog = 0;
-  sk->bytes_rcv = 0;
-  sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/
-  t1->window = ntohs(sk->window);
-  t1->ack_seq = ntohl(sk->acked_seq);
-  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++;
+       buff->len += tmp;
+       t1 =(struct tcphdr *)(buff->data +tmp);
+
+       memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
+       t1->seq = htonl(sk->sent_seq);
+       t1->ack = 1;
+       t1->res1 = 0;
+       t1->res2 = 0;
+       t1->rst = 0;
+       t1->urg = 0;
+       t1->syn = 0;
+       t1->psh = 0;
+       sk->ack_backlog = 0;
+       sk->bytes_rcv = 0;
+       sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/
+       t1->window = ntohs(sk->window);
+       t1->ack_seq = ntohl(sk->acked_seq);
+       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++;
 }
 
 
 /*
- * FIXME:
- * This routine frees used buffers.
- * It should consider sending an ACK to let the
- * other end know we now have a bigger window.
+ *     FIXME:
+ *     This routine frees used buffers.
+ *     It should consider sending an ACK to let the
+ *     other end know we now have a bigger window.
  */
-static void
-cleanup_rbuf(struct sock *sk)
+
+static void cleanup_rbuf(struct sock *sk)
 {
-  unsigned long flags;
-  int left;
-  struct sk_buff *skb;
+       unsigned long flags;
+       int left;
+       struct sk_buff *skb;
 
-  if(sk->debug)
-       printk("cleaning rbuf for sk=%p\n", sk);
+       if(sk->debug)
+               printk("cleaning rbuf for sk=%p\n", sk);
   
-  save_flags(flags);
-  cli();
+       save_flags(flags);
+       cli();
   
-  left = sk->prot->rspace(sk);
+       left = sk->prot->rspace(sk);
  
-  /*
-   * We have to loop through all the buffer headers,
-   * and try to free up all the space we can.
-   */
-  while((skb=skb_peek(&sk->receive_queue)) != NULL) 
-  {
-       if (!skb->used) 
-               break;
-       skb_unlink(skb);
-       skb->sk = sk;
-       kfree_skb(skb, FREE_READ);
-  }
+       /*
+        * We have to loop through all the buffer headers,
+        * and try to free up all the space we can.
+        */
 
-  restore_flags(flags);
+       while((skb=skb_peek(&sk->receive_queue)) != NULL) 
+       {
+               if (!skb->used) 
+                       break;
+               skb_unlink(skb);
+               skb->sk = sk;
+               kfree_skb(skb, FREE_READ);
+       }
 
-  /*
-   * FIXME:
-   * At this point we should send an ack if the difference
-   * in the window, and the amount of space is bigger than
-   * TCP_WINDOW_DIFF.
-   */
-  DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
+       restore_flags(flags);
+
+       /*
+        * FIXME:
+        * At this point we should send an ack if the difference
+        * in the window, and the amount of space is bigger than
+        * TCP_WINDOW_DIFF.
+        */
+
+       DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
                        sk->window - sk->bytes_rcv, sk->prot->rspace(sk)));
 
-  if(sk->debug)
-       printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),
+       if(sk->debug)
+               printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),
                                            left);
-  if (sk->prot->rspace(sk) != left) 
-  {
+       if (sk->prot->rspace(sk) != left) 
+       {
+               /*
+                * This area has caused the most trouble.  The current strategy
+                * is to simply do nothing if the other end has room to send at
+                * least 3 full packets, because the ack from those will auto-
+                * matically update the window.  If the other end doesn't think
+                * we have much space left, but we have room for atleast 1 more
+                * complete packet than it thinks we do, we will send an ack
+                * immediatedly.  Otherwise we will wait up to .5 seconds in case
+                * the user reads some more.
+                */
+               sk->ack_backlog++;
        /*
-        * This area has caused the most trouble.  The current strategy
-        * is to simply do nothing if the other end has room to send at
-        * least 3 full packets, because the ack from those will auto-
-        * matically update the window.  If the other end doesn't think
-        * we have much space left, but we have room for atleast 1 more
-        * complete packet than it thinks we do, we will send an ack
-        * immediatedly.  Otherwise we will wait up to .5 seconds in case
-        * the user reads some more.
+        * It's unclear whether to use sk->mtu or sk->mss here.  They differ only
+        * if the other end is offering a window smaller than the agreed on MSS
+        * (called sk->mtu here).  In theory there's no connection between send
+        * and receive, and so no reason to think that they're going to send
+        * small packets.  For the moment I'm using the hack of reducing the mss
+        * only on the send side, so I'm putting mtu here.
         */
-       sk->ack_backlog++;
-/*
- * It's unclear whether to use sk->mtu or sk->mss here.  They differ only
- * if the other end is offering a window smaller than the agreed on MSS
- * (called sk->mtu here).  In theory there's no connection between send
- * and receive, and so no reason to think that they're going to send
- * small packets.  For the moment I'm using the hack of reducing the mss
- * only on the send side, so I'm putting mtu here.
- */
-       if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) {
-               /* Send an ack right now. */
-               tcp_read_wakeup(sk);
-       } else {
-               /* Force it to send an ack soon. */
-               int was_active = del_timer(&sk->timer);
-               if (!was_active || TCP_ACK_TIME < sk->timer.expires) {
-                       reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
-               } else
-                       add_timer(&sk->timer);
+
+               if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) 
+               {
+                       /* Send an ack right now. */
+                       tcp_read_wakeup(sk);
+               } 
+               else 
+               {
+                       /* Force it to send an ack soon. */
+                       int was_active = del_timer(&sk->timer);
+                       if (!was_active || TCP_ACK_TIME < sk->timer.expires) 
+                       {
+                               reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
+                       } 
+                       else
+                               add_timer(&sk->timer);
+               }
        }
-  }
 } 
 
 
@@ -1407,95 +1501,119 @@ static int tcp_read(struct sock *sk, unsigned char *to,
  * Send a FIN without closing the connection.
  * Not called at interrupt time.
  */
-void
-tcp_shutdown(struct sock *sk, int how)
+
+void tcp_shutdown(struct sock *sk, int how)
 {
-  struct sk_buff *buff;
-  struct tcphdr *t1, *th;
-  struct proto *prot;
-  int tmp;
-  struct device *dev = NULL;
+       struct sk_buff *buff;
+       struct tcphdr *t1, *th;
+       struct proto *prot;
+       int tmp;
+       struct device *dev = NULL;
 
-  /*
-   * We need to grab some memory, and put together a FIN,
-   * and then put it into the queue to be sent.
-   * FIXME:
-   *   Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
-   *   Most of this is guesswork, so maybe it will work...
-   */
-  /* If we've already sent a FIN, return. */
-  if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) return;
-  if (!(how & SEND_SHUTDOWN)) return;
-  sk->inuse = 1;
+       /*
+        * We need to grab some memory, and put together a FIN,
+        * and then put it into the queue to be sent.
+        * FIXME:
+        *      Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
+        *      Most of this is guesswork, so maybe it will work...
+        */
+        
+       /*
+        *      If we've already sent a FIN, return. 
+        */
+        
+       if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) 
+               return;
+       if (!(how & SEND_SHUTDOWN)) 
+               return;
+       sk->inuse = 1;
 
-  /* Clear out any half completed packets. */
-  if (sk->partial)
-       tcp_send_partial(sk);
+       /*
+        *      Clear out any half completed packets. 
+        */
 
-  prot =(struct proto *)sk->prot;
-  th =(struct tcphdr *)&sk->dummy_th;
-  release_sock(sk); /* incase the malloc sleeps. */
-  buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
-  if (buff == NULL) return;
-  sk->inuse = 1;
+       if (sk->partial)
+               tcp_send_partial(sk);
 
-  DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
-  buff->sk = sk;
-  buff->len = sizeof(*t1);
-  t1 =(struct tcphdr *) buff->data;
+       prot =(struct proto *)sk->prot;
+       th =(struct tcphdr *)&sk->dummy_th;
+       release_sock(sk); /* incase the malloc sleeps. */
+       buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
+       if (buff == NULL)
+               return;
+       sk->inuse = 1;
 
-  /* Put in the IP header and routing stuff. */
-  tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
+       DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
+       buff->sk = sk;
+       buff->len = sizeof(*t1);
+       buff->localroute = sk->localroute;
+       t1 =(struct tcphdr *) buff->data;
+
+       /*
+        *      Put in the IP header and routing stuff. 
+        */
+
+       tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
                           IPPROTO_TCP, sk->opt,
                           sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
-  if (tmp < 0) {
-       /* Finish anyway, treat this as a send that got lost. */
-       buff->free=1;
-       prot->wfree(sk,buff->mem_addr, buff->mem_len);
-       if(sk->state==TCP_ESTABLISHED)
-               sk->state=TCP_FIN_WAIT1;
-       else
-               sk->state=TCP_FIN_WAIT2;
-       release_sock(sk);
-       DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
-       return;
-  }
+       if (tmp < 0) 
+       {
+               /*
+                *      Finish anyway, treat this as a send that got lost. 
+                */
+               buff->free=1;
+               prot->wfree(sk,buff->mem_addr, buff->mem_len);
+               if(sk->state==TCP_ESTABLISHED)
+                       sk->state=TCP_FIN_WAIT1;
+               else
+                       sk->state=TCP_FIN_WAIT2;
+               release_sock(sk);
+               DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
+               return;
+       }
 
-  t1 =(struct tcphdr *)((char *)t1 +tmp);
-  buff->len += tmp;
-  buff->dev = dev;
-  memcpy(t1, th, sizeof(*t1));
-  t1->seq = ntohl(sk->write_seq);
-  sk->write_seq++;
-  buff->h.seq = sk->write_seq;
-  t1->ack = 1;
-  t1->ack_seq = ntohl(sk->acked_seq);
-  t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
-  t1->fin = 1;
-  t1->rst = 0;
-  t1->doff = sizeof(*t1)/4;
-  tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+       t1 =(struct tcphdr *)((char *)t1 +tmp);
+       buff->len += tmp;
+       buff->dev = dev;
+       memcpy(t1, th, sizeof(*t1));
+       t1->seq = ntohl(sk->write_seq);
+       sk->write_seq++;
+       buff->h.seq = sk->write_seq;
+       t1->ack = 1;
+       t1->ack_seq = ntohl(sk->acked_seq);
+       t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
+       t1->fin = 1;
+       t1->rst = 0;
+       t1->doff = sizeof(*t1)/4;
+       tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
 
-  /*
-   * Can't just queue this up.
-   * It should go at the end of the write queue.
-   */
-  if (skb_peek(&sk->write_queue) != NULL) {
-       buff->free=0;
-       if (buff->next != NULL) {
-               printk("tcp_shutdown: next != NULL\n");
-               skb_unlink(buff);
+       /*
+        * Can't just queue this up.
+        * It should go at the end of the write queue.
+        */
+       
+       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);
        }
-       skb_queue_tail(&sk->write_queue, buff);
-  } else {
-        sk->sent_seq = sk->write_seq;
-       sk->prot->queue_xmit(sk, dev, buff, 0);
-  }
 
-  if (sk->state == TCP_ESTABLISHED) sk->state = TCP_FIN_WAIT1;
-    else sk->state = TCP_FIN_WAIT2;
+       if (sk->state == TCP_ESTABLISHED) 
+               sk->state = TCP_FIN_WAIT1;
+       else 
+               sk->state = TCP_FIN_WAIT2;
 
-  release_sock(sk);
+       release_sock(sk);
 }
 
 
@@ -1536,73 +1654,85 @@ tcp_recvfrom(struct sock *sk, unsigned char *to,
 }
 
 
-/* This routine will send an RST to the other tcp. */
-static void
-tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
+/*
+ *     This routine will send an RST to the other tcp. 
+ */
+static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
          struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl)
 {
-  struct sk_buff *buff;
-  struct tcphdr *t1;
-  int tmp;
-  struct device *ndev=NULL;
+       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.
-   */
-  buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
-  if (buff == NULL) 
-       return;
+/*
+ * We need to grab some memory, and put together an RST,
+ * and then put it into the queue to be sent.
+ */
 
-  DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
-  buff->len = sizeof(*t1);
-  buff->sk = NULL;
-  buff->dev = dev;
+       buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
+       if (buff == NULL) 
+               return;
 
-  t1 =(struct tcphdr *) buff->data;
+       DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
+       buff->len = sizeof(*t1);
+       buff->sk = NULL;
+       buff->dev = dev;
+       buff->localroute = 0;
 
-  /* Put in the IP header and routing stuff. */
-  tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt,
+       t1 =(struct tcphdr *) buff->data;
+
+       /*
+        *      Put in the IP header and routing stuff. 
+        */
+
+       tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt,
                           sizeof(struct tcphdr),tos,ttl);
-  if (tmp < 0) {
-       buff->free = 1;
-       prot->wfree(NULL, buff->mem_addr, buff->mem_len);
-       return;
-  }
-  t1 =(struct tcphdr *)((char *)t1 +tmp);
-  buff->len += tmp;
-  memcpy(t1, th, sizeof(*t1));
+       if (tmp < 0) 
+       {
+               buff->free = 1;
+               prot->wfree(NULL, buff->mem_addr, buff->mem_len);
+               return;
+       }
 
-  /* Swap the send and the receive. */
-  t1->dest = th->source;
-  t1->source = th->dest;
-  t1->rst = 1;  
-  t1->window = 0;
+       t1 =(struct tcphdr *)((char *)t1 +tmp);
+       buff->len += tmp;
+       memcpy(t1, th, sizeof(*t1));
+
+       /*
+        *      Swap the send and the receive. 
+        */
+
+       t1->dest = th->source;
+       t1->source = th->dest;
+       t1->rst = 1;  
+       t1->window = 0;
   
-  if(th->ack)
-  {
-       t1->ack = 0;
-       t1->seq = th->ack_seq;
-       t1->ack_seq = 0;
-  }
-  else
-  {
-       t1->ack = 1;
-       if(!th->syn)
-               t1->ack_seq=htonl(th->seq);
-       else
-               t1->ack_seq=htonl(th->seq+1);
-       t1->seq=0;
-  }
+       if(th->ack)
+       {
+               t1->ack = 0;
+               t1->seq = th->ack_seq;
+               t1->ack_seq = 0;
+       }
+       else
+       {
+               t1->ack = 1;
+               if(!th->syn)
+                       t1->ack_seq=htonl(th->seq);
+               else
+                       t1->ack_seq=htonl(th->seq+1);
+               t1->seq=0;
+       }
 
-  t1->syn = 0;
-  t1->urg = 0;
-  t1->fin = 0;
-  t1->psh = 0;
-  t1->doff = sizeof(*t1)/4;
-  tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
-  prot->queue_xmit(NULL, dev, buff, 1);
-  tcp_statistics.TcpOutSegs++;
+       t1->syn = 0;
+       t1->urg = 0;
+       t1->fin = 0;
+       t1->psh = 0;
+       t1->doff = sizeof(*t1)/4;
+       tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
+       prot->queue_xmit(NULL, dev, buff, 1);
+       tcp_statistics.TcpOutSegs++;
 }
 
 
@@ -1755,6 +1885,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
   newsk->pair = NULL;
   newsk->wmem_alloc = 0;
   newsk->rmem_alloc = 0;
+  newsk->localroute = sk->localroute;
 
   newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
 
@@ -1830,7 +1961,8 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
   
   buff->len = sizeof(struct tcphdr)+4;
   buff->sk = newsk;
-  
+  buff->localroute = newsk->localroute;
+    
   t1 =(struct tcphdr *) buff->data;
 
   /* Put in the IP header and routing stuff. */
@@ -1896,155 +2028,180 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
 }
 
 
-static void
-tcp_close(struct sock *sk, int timeout)
+static void tcp_close(struct sock *sk, int timeout)
 {
-  struct sk_buff *buff;
-  int need_reset = 0;
-  struct tcphdr *t1, *th;
-  struct proto *prot;
-  struct device *dev=NULL;
-  int tmp;
+       struct sk_buff *buff;
+       int need_reset = 0;
+       struct tcphdr *t1, *th;
+       struct proto *prot;
+       struct device *dev=NULL;
+       int tmp;
 
-  /*
-   * We need to grab some memory, and put together a FIN,
-   * and then put it into the queue to be sent.
-   */
-  DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
-  sk->inuse = 1;
-  sk->keepopen = 1;
-  sk->shutdown = SHUTDOWN_MASK;
+       /*
+        * We need to grab some memory, and put together a FIN, 
+        * and then put it into the queue to be sent.
+        */
+       DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
+       sk->inuse = 1;
+       sk->keepopen = 1;
+       sk->shutdown = SHUTDOWN_MASK;
 
-  if (!sk->dead) 
-       sk->state_change(sk);
+       if (!sk->dead) 
+               sk->state_change(sk);
 
-  /* We need to flush the recv. buffs. */
-  if (skb_peek(&sk->receive_queue) != NULL) 
-  {
-       struct sk_buff *skb;
-       if(sk->debug)
-               printk("Clean rcv queue\n");
-       while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+       /*
+        *      We need to flush the recv. buffs. 
+        */
+
+       if (skb_peek(&sk->receive_queue) != NULL) 
        {
-               if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
+               struct sk_buff *skb;
+               if(sk->debug)
+                       printk("Clean rcv queue\n");
+               while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+               {
+                       if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
                                need_reset = 1;
-               kfree_skb(skb, FREE_READ);
+                       kfree_skb(skb, FREE_READ);
+               }
+               if(sk->debug)
+                       printk("Cleaned.\n");
        }
-       if(sk->debug)
-               printk("Cleaned.\n");
-  }
 
-  /* Get rid off any half-completed packets. */
-  if (sk->partial) {
-       tcp_send_partial(sk);
-  }
+       /*
+        *      Get rid off any half-completed packets. 
+        */
+        
+       if (sk->partial) 
+       {
+               tcp_send_partial(sk);
+       }
 
-  switch(sk->state) {
-       case TCP_FIN_WAIT1:
-       case TCP_FIN_WAIT2:
-       case TCP_LAST_ACK:
-               /* start a timer. */
-                /* original code was 4 * sk->rtt.  In converting to the
-                * new rtt representation, we can't quite use that.
-                * it seems to make most sense to  use the backed off value
-                */
-               reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
-               if (timeout) tcp_time_wait(sk);
-               release_sock(sk);
-               return; /* break causes a double release - messy */
-       case TCP_TIME_WAIT:
-               if (timeout) {
-                 sk->state = TCP_CLOSE;
-               }
-               release_sock(sk);
-               return;
-       case TCP_LISTEN:
-               sk->state = TCP_CLOSE;
-               release_sock(sk);
-               return;
-       case TCP_CLOSE:
-               release_sock(sk);
-               return;
-       case TCP_CLOSE_WAIT:
-       case TCP_ESTABLISHED:
-       case TCP_SYN_SENT:
-       case TCP_SYN_RECV:
-               prot =(struct proto *)sk->prot;
-               th =(struct tcphdr *)&sk->dummy_th;
-               buff = prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
-               if (buff == NULL) {
-                       /* This will force it to try again later. */
-                       /* Or it would have if someone released the socket
-                          first. Anyway it might work now */
+       switch(sk->state) 
+       {
+               case TCP_FIN_WAIT1:
+               case TCP_FIN_WAIT2:
+               case TCP_LAST_ACK:
+                       /* 
+                        *      Start a timer.
+                        * original code was 4 * sk->rtt.  In converting to the
+                        * new rtt representation, we can't quite use that.
+                        * it seems to make most sense to  use the backed off value
+                        */
+                       reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
+                       if (timeout) 
+                               tcp_time_wait(sk);
+                       release_sock(sk);
+                       return; /* break causes a double release - messy */
+               case TCP_TIME_WAIT:
+                       if (timeout) 
+                       {
+                               sk->state = TCP_CLOSE;
+                       }
                        release_sock(sk);
-                       if (sk->state != TCP_CLOSE_WAIT)
-                                       sk->state = TCP_ESTABLISHED;
-                       reset_timer(sk, TIME_CLOSE, 100);
                        return;
-               }
-               buff->sk = sk;
-               buff->free = 1;
-               buff->len = sizeof(*t1);
-               t1 =(struct tcphdr *) buff->data;
-
-               /* Put in the IP header and routing stuff. */
-               tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
+               case TCP_LISTEN:
+                       sk->state = TCP_CLOSE;
+                       release_sock(sk);
+                       return;
+               case TCP_CLOSE:
+                       release_sock(sk);
+                       return;
+               case TCP_CLOSE_WAIT:
+               case TCP_ESTABLISHED:
+               case TCP_SYN_SENT:
+               case TCP_SYN_RECV:
+                       prot =(struct proto *)sk->prot;
+                       th =(struct tcphdr *)&sk->dummy_th;
+                       buff = prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
+                       if (buff == NULL) 
+                       {
+                               /* This will force it to try again later. */
+                               /* Or it would have if someone released the socket
+                                  first. Anyway it might work now */
+                               release_sock(sk);
+                               if (sk->state != TCP_CLOSE_WAIT)
+                                       sk->state = TCP_ESTABLISHED;
+                               reset_timer(sk, TIME_CLOSE, 100);
+                               return;
+                       }
+                       buff->sk = sk;
+                       buff->free = 1;
+                       buff->len = sizeof(*t1);
+                       buff->localroute = sk->localroute;
+                       t1 =(struct tcphdr *) buff->data;
+       
+                       /*
+                        *      Put in the IP header and routing stuff. 
+                        */
+                       tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
                                         IPPROTO_TCP, sk->opt,
                                         sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
-               if (tmp < 0) {
-                       kfree_skb(buff,FREE_WRITE);
-                       if(sk->state==TCP_ESTABLISHED)
-                               sk->state=TCP_FIN_WAIT1;
-                       else
-                               sk->state=TCP_FIN_WAIT2;
-                       reset_timer(sk, TIME_CLOSE,4*sk->rto);
-                       if(timeout)
-                               tcp_time_wait(sk);
+                       if (tmp < 0) 
+                       {
+                               kfree_skb(buff,FREE_WRITE);
+                               if(sk->state==TCP_ESTABLISHED)
+                                       sk->state=TCP_FIN_WAIT1;
+                               else
+                                       sk->state=TCP_FIN_WAIT2;
+                               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;
+                       }
 
-                       DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
-                       release_sock(sk);
-                       return;
-               }
+                       t1 =(struct tcphdr *)((char *)t1 +tmp);
+                       buff->len += tmp;
+                       buff->dev = dev;
+                       memcpy(t1, th, sizeof(*t1));
+                       t1->seq = ntohl(sk->write_seq);
+                       sk->write_seq++;
+                       buff->h.seq = sk->write_seq;
+                       t1->ack = 1;
+       
+                       /* 
+                        *      Ack everything immediately from now on. 
+                        */
 
-               t1 =(struct tcphdr *)((char *)t1 +tmp);
-               buff->len += tmp;
-               buff->dev = dev;
-               memcpy(t1, th, sizeof(*t1));
-               t1->seq = ntohl(sk->write_seq);
-               sk->write_seq++;
-               buff->h.seq = sk->write_seq;
-               t1->ack = 1;
-
-               /* Ack everything immediately from now on. */
-               sk->delay_acks = 0;
-               t1->ack_seq = ntohl(sk->acked_seq);
-               t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
-               t1->fin = 1;
-               t1->rst = need_reset;
-               t1->doff = sizeof(*t1)/4;
-               tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
-               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);
-                       if (buff->next != NULL) {
-                               printk("tcp_close: next != NULL\n");
-                               skb_unlink(buff);
+                       sk->delay_acks = 0;
+                       t1->ack_seq = ntohl(sk->acked_seq);
+                       t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
+                       t1->fin = 1;
+                       t1->rst = need_reset;
+                       t1->doff = sizeof(*t1)/4;
+                       tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+                       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);
+                               if (buff->next != NULL) 
+                               {
+                                       printk("tcp_close: next != NULL\n");
+                                       skb_unlink(buff);
+                               }
+                               skb_queue_tail(&sk->write_queue, buff);
                        }
-                       skb_queue_tail(&sk->write_queue, buff);
-               }
 
-               if (sk->state == TCP_CLOSE_WAIT) {
-                       sk->state = TCP_FIN_WAIT2;
-               } else {
-                       sk->state = TCP_FIN_WAIT1;
+                       if (sk->state == TCP_CLOSE_WAIT) 
+                       {
+                               sk->state = TCP_FIN_WAIT2;
+                       } 
+                       else 
+                       {
+                               sk->state = TCP_FIN_WAIT1;
+                       }
        }
-  }
-  release_sock(sk);
+       release_sock(sk);
 }
 
 
@@ -2762,51 +2919,56 @@ static inline int tcp_urg(struct sock *sk, struct tcphdr *th,
 }
 
 
-/* This deals with incoming fins. 'Linus at 9 O'clock' 8-) */
-static int
-tcp_fin(struct sock *sk, struct tcphdr *th, 
+/*
+ *     This deals with incoming fins. 'Linus at 9 O'clock' 8-) 
+ */
+static int tcp_fin(struct sock *sk, struct tcphdr *th, 
         unsigned long saddr, struct device *dev)
 {
-  DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
-                                               sk, th, saddr, dev));
+       DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
+                                       sk, th, saddr, dev));
   
-  if (!sk->dead) {
-       sk->state_change(sk);
-  }
-
-  switch(sk->state) {
-       case TCP_SYN_RECV:
-       case TCP_SYN_SENT:
-       case TCP_ESTABLISHED:
-               /* 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;
+       if (!sk->dead) 
+       {
+               sk->state_change(sk);
+       }
 
-       case TCP_CLOSE_WAIT:
-       case TCP_FIN_WAIT2:
-               break; /* we got a retransmit of the fin. */
+       switch(sk->state) 
+       {
+               case TCP_SYN_RECV:
+               case TCP_SYN_SENT:
+               case TCP_ESTABLISHED:
+                       /* 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;
 
-       case TCP_FIN_WAIT1:
-               /* Contains the one that needs to be acked */
-               sk->fin_seq = th->seq+1;
-               sk->state = TCP_FIN_WAIT2;
-               break;
+               case TCP_CLOSE_WAIT:
+               case TCP_FIN_WAIT2:
+                       break; /* we got a retransmit of the fin. */
 
-       default:
-       case TCP_TIME_WAIT:
-               sk->state = TCP_LAST_ACK;
+               case TCP_FIN_WAIT1:
+                       /* Contains the one that needs to be acked */
+                       sk->fin_seq = th->seq+1;
+                       sk->state = TCP_FIN_WAIT2;
+                       break;
 
-               /* Start the timers. */
-               reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-               return(0);
-  }
-  sk->ack_backlog++;
+               default:
+               case TCP_TIME_WAIT:
+                       sk->state = TCP_LAST_ACK;
+       
+                       /* Start the timers. */
+                       reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+                       return(0);
+       }
+       sk->ack_backlog++;
 
-  return(0);
+       return(0);
 }
 
 
@@ -2861,124 +3023,164 @@ tcp_accept(struct sock *sk, int flags)
 }
 
 
-/* This will initiate an outgoing connection. */
-static int
-tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
+/*
+ *     This will initiate an outgoing connection. 
+ */
+static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
 {
-  struct sk_buff *buff;
-  struct sockaddr_in sin;
-  struct device *dev=NULL;
-  unsigned char *ptr;
-  int tmp;
-  struct tcphdr *t1;
-  int err;
+       struct sk_buff *buff;
+       struct sockaddr_in sin;
+       struct device *dev=NULL;
+       unsigned char *ptr;
+       int tmp;
+       struct tcphdr *t1;
+       int err;
 
-  if (sk->state != TCP_CLOSE) return(-EISCONN);
-  if (addr_len < 8) return(-EINVAL);
+       if (sk->state != TCP_CLOSE) 
+               return(-EISCONN);
+       if (addr_len < 8) 
+               return(-EINVAL);
 
-  err=verify_area(VERIFY_READ, usin, addr_len);
-  if(err)
-       return err;
+       err=verify_area(VERIFY_READ, usin, addr_len);
+       if(err)
+               return err;
        
-  memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
+       memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
 
-  if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
+       if (sin.sin_family && sin.sin_family != AF_INET) 
+               return(-EAFNOSUPPORT);
 
-  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 (ip_chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) { 
-       DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
-       return(-ENETUNREACH);
-  }
+       DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr)));
+       
+       /*
+        *      connect() to INADDR_ANY means loopback (BSD'ism).
+        */
+       
+       if(sin.sin_addr.s_addr==INADDR_ANY)
+               sin.sin_addr.s_addr=ip_my_addr();
+                 
+       /*
+        *      Don't want a TCP connection going to a broadcast address 
+        */
+
+       if (ip_chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) 
+       { 
+               DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
+               return(-ENETUNREACH);
+       }
   
-  /* Connect back to the same socket: Blows up so disallow it */
-  if(sk->saddr == sin.sin_addr.s_addr && sk->num==ntohs(sin.sin_port))
-       return -EBUSY;
+       /*
+        *      Connect back to the same socket: Blows up so disallow it 
+        */
 
-  sk->inuse = 1;
-  sk->daddr = sin.sin_addr.s_addr;
-  sk->write_seq = jiffies * SEQ_TICK - seq_offset;
-  sk->window_seq = sk->write_seq;
-  sk->rcv_ack_seq = sk->write_seq -1;
-  sk->err = 0;
-  sk->dummy_th.dest = sin.sin_port;
-  release_sock(sk);
+       if(sk->saddr == sin.sin_addr.s_addr && sk->num==ntohs(sin.sin_port))
+               return -EBUSY;
 
-  buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
-  if (buff == NULL) {
-       return(-ENOMEM);
-  }
-  sk->inuse = 1;
-  buff->len = 24;
-  buff->sk = sk;
-  buff->free = 1;
-  t1 = (struct tcphdr *) buff->data;
+       sk->inuse = 1;
+       sk->daddr = sin.sin_addr.s_addr;
+       sk->write_seq = jiffies * SEQ_TICK - seq_offset;
+       sk->window_seq = sk->write_seq;
+       sk->rcv_ack_seq = sk->write_seq -1;
+       sk->err = 0;
+       sk->dummy_th.dest = sin.sin_port;
+       release_sock(sk);
 
-  /* Put in the IP header and routing stuff. */
-  /* We need to build the routing stuff fromt the things saved in skb. */
-  tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+       buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
+       if (buff == NULL) 
+       {
+               return(-ENOMEM);
+       }
+       sk->inuse = 1;
+       buff->len = 24;
+       buff->sk = sk;
+       buff->free = 1;
+       buff->localroute = sk->localroute;
+       
+       t1 = (struct tcphdr *) buff->data;
+
+       /*
+        *      Put in the IP header and routing stuff. 
+        */
+
+       /*
+        *      We need to build the routing stuff fromt the things saved in skb. 
+        */
+
+       tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
                                        IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
-  if (tmp < 0) {
-       sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
-       release_sock(sk);
-       return(-ENETUNREACH);
-  }
-  buff->len += tmp;
-  t1 = (struct tcphdr *)((char *)t1 +tmp);
-
-  memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
-  t1->seq = ntohl(sk->write_seq++);
-  sk->sent_seq = sk->write_seq;
-  buff->h.seq = sk->write_seq;
-  t1->ack = 0;
-  t1->window = 2;
-  t1->res1=0;
-  t1->res2=0;
-  t1->rst = 0;
-  t1->urg = 0;
-  t1->psh = 0;
-  t1->syn = 1;
-  t1->urg_ptr = 0;
-  t1->doff = 6;
+       if (tmp < 0) 
+       {
+               sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+               release_sock(sk);
+               return(-ENETUNREACH);
+       }
 
-/* use 512 or whatever user asked for */
-  if (sk->user_mss)
-    sk->mtu = sk->user_mss;
-  else {
+       buff->len += tmp;
+       t1 = (struct tcphdr *)((char *)t1 +tmp);
+
+       memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
+       t1->seq = ntohl(sk->write_seq++);
+       sk->sent_seq = sk->write_seq;
+       buff->h.seq = sk->write_seq;
+       t1->ack = 0;
+       t1->window = 2;
+       t1->res1=0;
+       t1->res2=0;
+       t1->rst = 0;
+       t1->urg = 0;
+       t1->psh = 0;
+       t1->syn = 1;
+       t1->urg_ptr = 0;
+       t1->doff = 6;
+       /* use 512 or whatever user asked for */
+
+       if (sk->user_mss)
+               sk->mtu = sk->user_mss;
+       else 
+       {
 #ifdef SUBNETSARELOCAL
-    if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr))
+               if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr))
 #else
-    if ((sk->saddr ^ sk->daddr) & dev->pa_mask)
+               if ((sk->saddr ^ sk->daddr) & dev->pa_mask)
 #endif
-      sk->mtu = 576 - HEADER_SIZE;
-    else
-      sk->mtu = MAX_WINDOW;
-  }
-/* but not bigger than device MTU */
-  sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
+                       sk->mtu = 576 - HEADER_SIZE;
+               else
+                       sk->mtu = MAX_WINDOW;
+       }
+       /*
+        *      but not bigger than device MTU 
+        */
 
-  /* Put in the TCP options to say MTU. */
-  ptr = (unsigned char *)(t1+1);
-  ptr[0] = 2;
-  ptr[1] = 4;
-  ptr[2] = (sk->mtu) >> 8;
-  ptr[3] = (sk->mtu) & 0xff;
-  tcp_send_check(t1, sk->saddr, sk->daddr,
+       sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
+
+       /*
+        *      Put in the TCP options to say MTU. 
+        */
+
+       ptr = (unsigned char *)(t1+1);
+       ptr[0] = 2;
+       ptr[1] = 4;
+       ptr[2] = (sk->mtu) >> 8;
+       ptr[3] = (sk->mtu) & 0xff;
+       tcp_send_check(t1, sk->saddr, sk->daddr,
                  sizeof(struct tcphdr) + 4, sk);
 
-  /* This must go first otherwise a really quick response will get reset. */
-  sk->state = TCP_SYN_SENT;
-  sk->rtt = TCP_CONNECT_TIME;
-  reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME);       /* Timer for repeating the SYN until an answer */
-  sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
+       /*
+        *      This must go first otherwise a really quick response will get reset. 
+        */
 
-  sk->prot->queue_xmit(sk, dev, buff, 0);  
-  tcp_statistics.TcpActiveOpens++;
-  tcp_statistics.TcpOutSegs++;
+       sk->state = TCP_SYN_SENT;
+       sk->rtt = TCP_CONNECT_TIME;
+       reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME);  /* Timer for repeating the SYN until an answer */
+       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);
+       release_sock(sk);
+       return(0);
 }
 
 
@@ -3451,69 +3653,73 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
 
 
 /*
 * This routine sends a packet with an out of date sequence
 * number. It assumes the other end will try to ack it.
 */
-static void
-tcp_write_wakeup(struct sock *sk)
+ * This routine sends a packet with an out of date sequence
+ * number. It assumes the other end will try to ack it.
+ */
+
+static void tcp_write_wakeup(struct sock *sk)
 {
-  struct sk_buff *buff;
-  struct tcphdr *t1;
-  struct device *dev=NULL;
-  int tmp;
+       struct sk_buff *buff;
+       struct tcphdr *t1;
+       struct device *dev=NULL;
+       int tmp;
 
-  if (sk->zapped)
-       return; /* Afer a valid reset we can send no more */
+       if (sk->zapped)
+               return; /* Afer a valid reset we can send no more */
 
-  if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
-      sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2)
-       return;
+       if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
+               sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2)
+               return;
 
-  buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
-  if (buff == NULL) return;
+       buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+       if (buff == NULL) 
+               return;
 
-  buff->len = sizeof(struct tcphdr);
-  buff->free = 1;
-  buff->sk = sk;
-  DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
-  t1 = (struct tcphdr *) buff->data;
+       buff->len = sizeof(struct tcphdr);
+       buff->free = 1;
+       buff->sk = sk;
+       buff->localroute = sk->localroute;
 
-  /* Put in the IP header and routing stuff. */
-  tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+       DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
+       t1 = (struct tcphdr *) buff->data;
+
+       /* Put in the IP header and routing stuff. */
+       tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
                                IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
-  if (tmp < 0) {
-       sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
-       return;
-  }
+       if (tmp < 0) 
+       {
+               sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+               return;
+       }
 
-  buff->len += tmp;
-  t1 = (struct tcphdr *)((char *)t1 +tmp);
+       buff->len += tmp;
+       t1 = (struct tcphdr *)((char *)t1 +tmp);
 
-  memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
+       memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
 
-  /*
-   * Use a previous sequence.
-   * This should cause the other end to send an ack.
-   */
-  t1->seq = htonl(sk->sent_seq-1);
-  t1->ack = 1; 
-  t1->res1= 0;
-  t1->res2= 0;
-  t1->rst = 0;
-  t1->urg = 0;
-  t1->psh = 0;
-  t1->fin = 0;
-  t1->syn = 0;
-  t1->ack_seq = ntohl(sk->acked_seq);
-  t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
-  t1->doff = sizeof(*t1)/4;
-  tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
-  /* Send it and free it.
-   * This will prevent the timer from automatically being restarted.
-  */
-  sk->prot->queue_xmit(sk, dev, buff, 1);
-  tcp_statistics.TcpOutSegs++;
+       /*
+        * Use a previous sequence.
+        * This should cause the other end to send an ack.
+        */
+       t1->seq = htonl(sk->sent_seq-1);
+       t1->ack = 1; 
+       t1->res1= 0;
+       t1->res2= 0;
+       t1->rst = 0;
+       t1->urg = 0;
+       t1->psh = 0;
+       t1->fin = 0;
+       t1->syn = 0;
+       t1->ack_seq = ntohl(sk->acked_seq);
+       t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
+       t1->doff = sizeof(*t1)/4;
+       tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+        /*     Send it and free it.
+         *     This will prevent the timer from automatically being restarted.
+         */
+       sk->prot->queue_xmit(sk, dev, buff, 1);
+       tcp_statistics.TcpOutSegs++;
 }
 
 void
index f2cca9472677263be91605b4cc505bd2c573c8c9..da63bc9f0f3b4ca3521409ad8af86bbdf31d566d 100644 (file)
@@ -250,7 +250,7 @@ static void udp_send_check(struct udphdr *uh, unsigned long saddr,
 
 
 static int udp_send(struct sock *sk, struct sockaddr_in *sin,
-        unsigned char *from, int len)
+        unsigned char *from, int len, int rt)
 {
        struct sk_buff *skb;
        struct device *dev;
@@ -281,6 +281,7 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
 
        skb->sk       = NULL;   /* to avoid changing sk->saddr */
        skb->free     = 1;
+       skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
 
        /*
         *      Now build the IP and MAC header. 
@@ -357,7 +358,7 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
        /* 
         *      Check the flags. We support no flags for UDP sending
         */
-       if (flags) 
+       if (flags&~MSG_DONTROUTE
                return(-EINVAL);
        if (len < 0) 
                return(-EINVAL);
@@ -400,7 +401,7 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
        sk->inuse = 1;
 
        /* Send the packet. */
-       tmp = udp_send(sk, &sin, from, len);
+       tmp = udp_send(sk, &sin, from, len, flags);
 
        /* The datagram has been sent off.  Release the socket. */
        release_sock(sk);
@@ -601,27 +602,29 @@ int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
 int
 udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
 {
-  struct sockaddr_in sin;
-  int er;
+       struct sockaddr_in sin;
+       int er;
   
-  if (addr_len < sizeof(sin)) 
-       return(-EINVAL);
+       if (addr_len < sizeof(sin)) 
+               return(-EINVAL);
 
-  er=verify_area(VERIFY_READ, usin, sizeof(sin));
-  if(er)
-       return er;
+       er=verify_area(VERIFY_READ, usin, sizeof(sin));
+       if(er)
+               return er;
 
-  memcpy_fromfs(&sin, usin, sizeof(sin));
-  if (sin.sin_family && sin.sin_family != AF_INET) 
-       return(-EAFNOSUPPORT);
+       memcpy_fromfs(&sin, usin, sizeof(sin));
+       if (sin.sin_family && sin.sin_family != AF_INET) 
+               return(-EAFNOSUPPORT);
+       if (sin.sin_addr.s_addr==INADDR_ANY)
+               sin.sin_addr.s_addr=ip_my_addr();
 
-  if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
-       return -EACCES;                 /* Must turn broadcast on first */
+       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;
-  sk->dummy_th.dest = sin.sin_port;
-  sk->state = TCP_ESTABLISHED;
-  return(0);
+       sk->daddr = sin.sin_addr.s_addr;
+       sk->dummy_th.dest = sin.sin_port;
+       sk->state = TCP_ESTABLISHED;
+       return(0);
 }