change iss increment to agree with tcp_input (and tcp_seq.h comments)
[unix-history] / usr / src / sys / netinet / tcp_usrreq.c
index c243372..31abe5c 100644 (file)
@@ -1,42 +1,42 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1988, 1993, 1995
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- *     @(#)tcp_usrreq.c        6.7 (Berkeley) %G%
+ * %sccs.include.redist.c%
+ *
+ *     @(#)tcp_usrreq.c        8.5 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "mbuf.h"
-#include "socket.h"
-#include "socketvar.h"
-#include "protosw.h"
-#include "errno.h"
-#include "stat.h"
-
-#include "../net/if.h"
-#include "../net/route.h"
-
-#include "in.h"
-#include "in_pcb.h"
-#include "in_systm.h"
-#include "ip.h"
-#include "ip_var.h"
-#include "tcp.h"
-#include "tcp_fsm.h"
-#include "tcp_seq.h"
-#include "tcp_timer.h"
-#include "tcp_var.h"
-#include "tcpip.h"
-#include "tcp_debug.h"
+#include <sys/param.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 <sys/stat.h>
+
+#include <net/if.h>
+#include <net/route.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/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>
+#include <netinet/tcp_debug.h>
 
 /*
  * TCP protocol interface to socket abstraction.
  */
 extern char *tcpstates[];
 
 /*
  * TCP protocol interface to socket abstraction.
  */
 extern char *tcpstates[];
-struct tcpcb *tcp_newtcpcb();
-int    tcpsenderrors;
 
 /*
  * Process a TCP user request for TCP tb.  If this is a send request
 
 /*
  * Process a TCP user request for TCP tb.  If this is a send request
@@ -44,24 +44,31 @@ int tcpsenderrors;
  * (called from the software clock routine), then timertype tells which timer.
  */
 /*ARGSUSED*/
  * (called from the software clock routine), then timertype tells which timer.
  */
 /*ARGSUSED*/
-tcp_usrreq(so, req, m, nam, rights)
+int
+tcp_usrreq(so, req, m, nam, control)
        struct socket *so;
        int req;
        struct socket *so;
        int req;
-       struct mbuf *m, *nam, *rights;
+       struct mbuf *m, *nam, *control;
 {
 {
-       register struct inpcb *inp = sotoinpcb(so);
+       register struct inpcb *inp;
        register struct tcpcb *tp;
        register struct tcpcb *tp;
-       int s = splnet();
+       int s;
        int error = 0;
        int ostate;
 
        int error = 0;
        int ostate;
 
+#if BSD>=43
        if (req == PRU_CONTROL)
        if (req == PRU_CONTROL)
-               return (in_control(so, (int)m, (caddr_t)nam,
-                       (struct ifnet *)rights));
-       if (rights && rights->m_len) {
-               splx(s);
+               return (in_control(so, (u_long)m, (caddr_t)nam,
+                       (struct ifnet *)control));
+       if (control && control->m_len) {
+               m_freem(control);
+               if (m)
+                       m_freem(m);
                return (EINVAL);
        }
                return (EINVAL);
        }
+
+       s = splnet();
+       inp = sotoinpcb(so);
        /*
         * When a TCP is attached to a socket, then there will be
         * a (struct inpcb) pointed at by the socket, and this
        /*
         * When a TCP is attached to a socket, then there will be
         * a (struct inpcb) pointed at by the socket, and this
@@ -69,6 +76,18 @@ tcp_usrreq(so, req, m, nam, rights)
         */
        if (inp == 0 && req != PRU_ATTACH) {
                splx(s);
         */
        if (inp == 0 && req != PRU_ATTACH) {
                splx(s);
+#if 0
+               /*
+                * The following corrects an mbuf leak under rare
+                * circumstances, but has not been fully tested.
+                */
+               if (m && req != PRU_SENSE)
+                       m_freem(m);
+#else
+               /* safer version of fix for mbuf leak */
+               if (m && (req == PRU_SEND || req == PRU_SENDOOB))
+                       m_freem(m);
+#endif
                return (EINVAL);                /* XXX */
        }
        if (inp) {
                return (EINVAL);                /* XXX */
        }
        if (inp) {
@@ -154,10 +173,15 @@ tcp_usrreq(so, req, m, nam, rights)
                        error = ENOBUFS;
                        break;
                }
                        error = ENOBUFS;
                        break;
                }
+               /* Compute window scaling to request.  */
+               while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+                   (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
+                       tp->request_r_scale++;
                soisconnecting(so);
                soisconnecting(so);
+               tcpstat.tcps_connattempt++;
                tp->t_state = TCPS_SYN_SENT;
                tp->t_state = TCPS_SYN_SENT;
-               tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
-               tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
+               tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+               tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/4;
                tcp_sendseqinit(tp);
                error = tcp_output(tp);
                break;
                tcp_sendseqinit(tp);
                error = tcp_output(tp);
                break;
@@ -189,15 +213,9 @@ tcp_usrreq(so, req, m, nam, rights)
         * done at higher levels; just return the address
         * of the peer, storing through addr.
         */
         * done at higher levels; just return the address
         * of the peer, storing through addr.
         */
-       case PRU_ACCEPT: {
-               struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
-
-               nam->m_len = sizeof (struct sockaddr_in);
-               sin->sin_family = AF_INET;
-               sin->sin_port = inp->inp_fport;
-               sin->sin_addr = inp->inp_faddr;
+       case PRU_ACCEPT:
+               in_setpeeraddr(inp, nam);
                break;
                break;
-               }
 
        /*
         * Mark the connection as being incapable of further output.
 
        /*
         * Mark the connection as being incapable of further output.
@@ -222,16 +240,7 @@ tcp_usrreq(so, req, m, nam, rights)
         */
        case PRU_SEND:
                sbappend(&so->so_snd, m);
         */
        case PRU_SEND:
                sbappend(&so->so_snd, m);
-#ifdef notdef
-               if (tp->t_flags & TF_PUSH)
-                       tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
-#endif
                error = tcp_output(tp);
                error = tcp_output(tp);
-               if (error) {            /* XXX fix to use other path */
-                       if (error == ENOBUFS)           /* XXX */
-                               error = 0;              /* XXX */
-                       tcpsenderrors++;
-               }
                break;
 
        /*
                break;
 
        /*
@@ -243,11 +252,15 @@ tcp_usrreq(so, req, m, nam, rights)
 
        case PRU_SENSE:
                ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
 
        case PRU_SENSE:
                ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
+               (void) splx(s);
                return (0);
 
        case PRU_RCVOOB:
                if ((so->so_oobmark == 0 &&
                    (so->so_state & SS_RCVATMARK) == 0) ||
                return (0);
 
        case PRU_RCVOOB:
                if ((so->so_oobmark == 0 &&
                    (so->so_state & SS_RCVATMARK) == 0) ||
+#ifdef SO_OOBINLINE
+                   so->so_options & SO_OOBINLINE ||
+#endif
                    tp->t_oobflags & TCPOOB_HADDATA) {
                        error = EINVAL;
                        break;
                    tp->t_oobflags & TCPOOB_HADDATA) {
                        error = EINVAL;
                        break;
@@ -268,8 +281,16 @@ tcp_usrreq(so, req, m, nam, rights)
                        error = ENOBUFS;
                        break;
                }
                        error = ENOBUFS;
                        break;
                }
-               tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1;
+               /*
+                * According to RFC961 (Assigned Protocols),
+                * the urgent pointer points to the last octet
+                * of urgent data.  We continue, however,
+                * to consider it to indicate the first octet
+                * of data past the urgent section.
+                * Otherwise, snd_up should be one lower.
+                */
                sbappend(&so->so_snd, m);
                sbappend(&so->so_snd, m);
+               tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
                tp->t_force = 1;
                error = tcp_output(tp);
                tp->t_force = 0;
                tp->t_force = 1;
                error = tcp_output(tp);
                tp->t_force = 0;
@@ -301,25 +322,96 @@ tcp_usrreq(so, req, m, nam, rights)
        return (error);
 }
 
        return (error);
 }
 
-tcp_ctloutput(op, so, level, optname, m)
+int
+#if BSD>=43
+tcp_ctloutput(op, so, level, optname, mp)
        int op;
        struct socket *so;
        int level, optname;
        int op;
        struct socket *so;
        int level, optname;
-       struct mbuf **m;
+       struct mbuf **mp;
 {
 {
-       if (level != IPPROTO_TCP)
-               return (ip_ctloutput(op, so, level, optname, m));
-       /* INCOMPLETE */
-       return (0);
+       int error = 0, s;
+       struct inpcb *inp;
+       register struct tcpcb *tp;
+       register struct mbuf *m;
+       register int i;
+
+       s = splnet();
+       inp = sotoinpcb(so);
+       if (inp == NULL) {
+               splx(s);
+               if (op == PRCO_SETOPT && *mp)
+                       (void) m_free(*mp);
+               return (ECONNRESET);
+       }
+       if (level != IPPROTO_TCP) {
+               error = ip_ctloutput(op, so, level, optname, mp);
+               splx(s);
+               return (error);
+       }
+       tp = intotcpcb(inp);
+
+       switch (op) {
+
+       case PRCO_SETOPT:
+               m = *mp;
+               switch (optname) {
+
+               case TCP_NODELAY:
+                       if (m == NULL || m->m_len < sizeof (int))
+                               error = EINVAL;
+                       else if (*mtod(m, int *))
+                               tp->t_flags |= TF_NODELAY;
+                       else
+                               tp->t_flags &= ~TF_NODELAY;
+                       break;
+
+               case TCP_MAXSEG:
+                       if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
+                               tp->t_maxseg = i;
+                       else
+                               error = EINVAL;
+                       break;
+
+               default:
+                       error = ENOPROTOOPT;
+                       break;
+               }
+               if (m)
+                       (void) m_free(m);
+               break;
+
+       case PRCO_GETOPT:
+               *mp = m = m_get(M_WAIT, MT_SOOPTS);
+               m->m_len = sizeof(int);
+
+               switch (optname) {
+               case TCP_NODELAY:
+                       *mtod(m, int *) = tp->t_flags & TF_NODELAY;
+                       break;
+               case TCP_MAXSEG:
+                       *mtod(m, int *) = tp->t_maxseg;
+                       break;
+               default:
+                       error = ENOPROTOOPT;
+                       break;
+               }
+               break;
+       }
+       splx(s);
+       return (error);
 }
 }
+#endif
+
+u_long tcp_sendspace = 1024*8;
+u_long tcp_recvspace = 1024*8;
 
 
-int    tcp_sendspace = 1024*4;
-int    tcp_recvspace = 1024*4;
 /*
  * Attach TCP protocol to socket, allocating
  * internet protocol control block, tcp control block,
  * bufer space, and entering LISTEN state if to accept connections.
  */
 /*
  * Attach TCP protocol to socket, allocating
  * internet protocol control block, tcp control block,
  * bufer space, and entering LISTEN state if to accept connections.
  */
+int
 tcp_attach(so)
        struct socket *so;
 {
 tcp_attach(so)
        struct socket *so;
 {
@@ -327,9 +419,11 @@ tcp_attach(so)
        struct inpcb *inp;
        int error;
 
        struct inpcb *inp;
        int error;
 
-       error = soreserve(so, tcp_sendspace, tcp_recvspace);
-       if (error)
-               return (error);
+       if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+               error = soreserve(so, tcp_sendspace, tcp_recvspace);
+               if (error)
+                       return (error);
+       }
        error = in_pcballoc(so, &tcb);
        if (error)
                return (error);
        error = in_pcballoc(so, &tcb);
        if (error)
                return (error);