BSD 4_4_Lite2 release
[unix-history] / usr / src / sys / netinet / tcp_subr.c
index ac60d93..9803ec9 100644 (file)
@@ -1,52 +1,79 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)tcp_subr.c  7.22 (Berkeley) %G%
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_subr.c  8.2 (Berkeley) 5/24/95
  */
 
  */
 
-#include "param.h"
-#include "proc.h"
-#include "systm.h"
-#include "malloc.h"
-#include "mbuf.h"
-#include "socket.h"
-#include "socketvar.h"
-#include "protosw.h"
-#include "errno.h"
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
 
 
-#include "../net/route.h"
-#include "../net/if.h"
+#include <net/route.h>
+#include <net/if.h>
 
 
-#include "in.h"
-#include "in_systm.h"
-#include "ip.h"
-#include "in_pcb.h"
-#include "ip_var.h"
-#include "ip_icmp.h"
-#include "tcp.h"
-#include "tcp_fsm.h"
-#include "tcp_seq.h"
-#include "tcp_timer.h"
-#include "tcp_var.h"
-#include "tcpip.h"
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcpip.h>
 
 /* patchable/settable parameters for tcp */
 
 /* patchable/settable parameters for tcp */
-int    tcp_ttl = TCP_TTL;
 int    tcp_mssdflt = TCP_MSS;
 int    tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
 int    tcp_mssdflt = TCP_MSS;
 int    tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
+int    tcp_do_rfc1323 = 1;
 
 extern struct inpcb *tcp_last_inpcb;
 
 /*
  * Tcp initialization
  */
 
 extern struct inpcb *tcp_last_inpcb;
 
 /*
  * Tcp initialization
  */
+void
 tcp_init()
 {
 
 tcp_init()
 {
 
-       tcp_iss = 1;            /* wrong */
+       tcp_iss = random();     /* wrong, but better than a constant */
        tcb.inp_next = tcb.inp_prev = &tcb;
        if (max_protohdr < sizeof(struct tcpiphdr))
                max_protohdr = sizeof(struct tcpiphdr);
        tcb.inp_next = tcb.inp_prev = &tcb;
        if (max_protohdr < sizeof(struct tcpiphdr))
                max_protohdr = sizeof(struct tcpiphdr);
@@ -107,6 +134,7 @@ tcp_template(tp)
  * In any case the ack and sequence number of the transmitted
  * segment are as specified by the parameters.
  */
  * In any case the ack and sequence number of the transmitted
  * segment are as specified by the parameters.
  */
+void
 tcp_respond(tp, ti, m, ack, seq, flags)
        struct tcpcb *tp;
        register struct tcpiphdr *ti;
 tcp_respond(tp, ti, m, ack, seq, flags)
        struct tcpcb *tp;
        register struct tcpiphdr *ti;
@@ -158,12 +186,16 @@ tcp_respond(tp, ti, m, ack, seq, flags)
        ti->ti_x2 = 0;
        ti->ti_off = sizeof (struct tcphdr) >> 2;
        ti->ti_flags = flags;
        ti->ti_x2 = 0;
        ti->ti_off = sizeof (struct tcphdr) >> 2;
        ti->ti_flags = flags;
-       ti->ti_win = htons((u_short)win);
+       if (tp)
+               ti->ti_win = htons((u_short) (win >> tp->rcv_scale));
+       else
+               ti->ti_win = htons((u_short)win);
        ti->ti_urp = 0;
        ti->ti_urp = 0;
+       ti->ti_sum = 0;
        ti->ti_sum = in_cksum(m, tlen);
        ((struct ip *)ti)->ip_len = tlen;
        ti->ti_sum = in_cksum(m, tlen);
        ((struct ip *)ti)->ip_len = tlen;
-       ((struct ip *)ti)->ip_ttl = tcp_ttl;
-       (void) ip_output(m, (struct mbuf *)0, ro, 0);
+       ((struct ip *)ti)->ip_ttl = ip_defttl;
+       (void) ip_output(m, NULL, ro, 0, NULL);
 }
 
 /*
 }
 
 /*
@@ -175,16 +207,16 @@ struct tcpcb *
 tcp_newtcpcb(inp)
        struct inpcb *inp;
 {
 tcp_newtcpcb(inp)
        struct inpcb *inp;
 {
-       struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
        register struct tcpcb *tp;
 
        register struct tcpcb *tp;
 
-       if (m == NULL)
+       tp = malloc(sizeof(*tp), M_PCB, M_NOWAIT);
+       if (tp == NULL)
                return ((struct tcpcb *)0);
                return ((struct tcpcb *)0);
-       tp = mtod(m, struct tcpcb *);
+       bzero((char *) tp, sizeof(struct tcpcb));
        tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
        tp->t_maxseg = tcp_mssdflt;
 
        tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
        tp->t_maxseg = tcp_mssdflt;
 
-       tp->t_flags = 0;                /* sends options! */
+       tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
        tp->t_inpcb = inp;
        /*
         * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
        tp->t_inpcb = inp;
        /*
         * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
@@ -197,9 +229,9 @@ tcp_newtcpcb(inp)
        TCPT_RANGESET(tp->t_rxtcur, 
            ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
            TCPTV_MIN, TCPTV_REXMTMAX);
        TCPT_RANGESET(tp->t_rxtcur, 
            ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
            TCPTV_MIN, TCPTV_REXMTMAX);
-       tp->snd_cwnd = TCP_MAXWIN;
-       tp->snd_ssthresh = TCP_MAXWIN;
-       inp->inp_ip.ip_ttl = tcp_ttl;
+       tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+       tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+       inp->inp_ip.ip_ttl = ip_defttl;
        inp->inp_ppcb = (caddr_t)tp;
        return (tp);
 }
        inp->inp_ppcb = (caddr_t)tp;
        return (tp);
 }
@@ -311,7 +343,7 @@ tcp_close(tp)
                                rt->rt_rmx.rmx_ssthresh = i;
                }
        }
                                rt->rt_rmx.rmx_ssthresh = i;
                }
        }
-#endif RTV_RTT
+#endif /* RTV_RTT */
        /* free the reassembly queue, if any */
        t = tp->seg_next;
        while (t != (struct tcpiphdr *)tp) {
        /* free the reassembly queue, if any */
        t = tp->seg_next;
        while (t != (struct tcpiphdr *)tp) {
@@ -322,7 +354,7 @@ tcp_close(tp)
        }
        if (tp->t_template)
                (void) m_free(dtom(tp->t_template));
        }
        if (tp->t_template)
                (void) m_free(dtom(tp->t_template));
-       (void) m_free(dtom(tp));
+       free(tp, M_PCB);
        inp->inp_ppcb = 0;
        soisdisconnected(so);
        /* clobber input pcb cache if we're closing the cached connection */
        inp->inp_ppcb = 0;
        soisdisconnected(so);
        /* clobber input pcb cache if we're closing the cached connection */
@@ -333,6 +365,7 @@ tcp_close(tp)
        return ((struct tcpcb *)0);
 }
 
        return ((struct tcpcb *)0);
 }
 
+void
 tcp_drain()
 {
 
 tcp_drain()
 {
 
@@ -343,6 +376,7 @@ tcp_drain()
  * store error as soft error, but wake up user
  * (for now, won't do anything until can select for soft error).
  */
  * store error as soft error, but wake up user
  * (for now, won't do anything until can select for soft error).
  */
+void
 tcp_notify(inp, error)
        struct inpcb *inp;
        int error;
 tcp_notify(inp, error)
        struct inpcb *inp;
        int error;
@@ -351,21 +385,27 @@ tcp_notify(inp, error)
        register struct socket *so = inp->inp_socket;
 
        /*
        register struct socket *so = inp->inp_socket;
 
        /*
+        * Ignore some errors if we are hooked up.
         * If connection hasn't completed, has retransmitted several times,
         * and receives a second error, give up now.  This is better
         * than waiting a long time to establish a connection that
         * can never complete.
         */
         * If connection hasn't completed, has retransmitted several times,
         * and receives a second error, give up now.  This is better
         * than waiting a long time to establish a connection that
         * can never complete.
         */
-       if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
+       if (tp->t_state == TCPS_ESTABLISHED &&
+            (error == EHOSTUNREACH || error == ENETUNREACH ||
+             error == EHOSTDOWN)) {
+               return;
+       } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
            tp->t_softerror)
                so->so_error = error;
            tp->t_softerror)
                so->so_error = error;
-       else
+       else 
                tp->t_softerror = error;
        wakeup((caddr_t) &so->so_timeo);
        sorwakeup(so);
        sowwakeup(so);
 }
 
                tp->t_softerror = error;
        wakeup((caddr_t) &so->so_timeo);
        sorwakeup(so);
        sowwakeup(so);
 }
 
+void
 tcp_ctlinput(cmd, sa, ip)
        int cmd;
        struct sockaddr *sa;
 tcp_ctlinput(cmd, sa, ip)
        int cmd;
        struct sockaddr *sa;
@@ -374,11 +414,12 @@ tcp_ctlinput(cmd, sa, ip)
        register struct tcphdr *th;
        extern struct in_addr zeroin_addr;
        extern u_char inetctlerrmap[];
        register struct tcphdr *th;
        extern struct in_addr zeroin_addr;
        extern u_char inetctlerrmap[];
-       int (*notify)() = tcp_notify, tcp_quench();
+       void (*notify) __P((struct inpcb *, int)) = tcp_notify;
 
        if (cmd == PRC_QUENCH)
                notify = tcp_quench;
 
        if (cmd == PRC_QUENCH)
                notify = tcp_quench;
-       else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
+       else if (!PRC_IS_REDIRECT(cmd) &&
+                ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
                return;
        if (ip) {
                th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
                return;
        if (ip) {
                th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
@@ -388,21 +429,14 @@ tcp_ctlinput(cmd, sa, ip)
                in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
 }
 
                in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
 }
 
-#if BSD<43
-/* XXX fake routine */
-tcp_abort(inp)
-       struct inpcb *inp;
-{
-       return;
-}
-#endif
-
 /*
  * When a source quench is received, close congestion window
  * to one segment.  We will gradually open it again as we proceed.
  */
 /*
  * When a source quench is received, close congestion window
  * to one segment.  We will gradually open it again as we proceed.
  */
-tcp_quench(inp)
+void
+tcp_quench(inp, errno)
        struct inpcb *inp;
        struct inpcb *inp;
+       int errno;
 {
        struct tcpcb *tp = intotcpcb(inp);
 
 {
        struct tcpcb *tp = intotcpcb(inp);