checkpoint almost working version of kernel TP0/X.25; TP4/Cons seems
[unix-history] / usr / src / sys / netiso / tp_subr2.c
index 2fe935f..864f474 100644 (file)
@@ -1,3 +1,12 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)tp_subr2.c  7.12 (Berkeley) %G%
+ */
+
 /***********************************************************
                Copyright IBM Corporation 1987
 
 /***********************************************************
                Copyright IBM Corporation 1987
 
@@ -31,25 +40,20 @@ SOFTWARE.
  * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $
  *
  * Some auxiliary routines:
  * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $
  *
  * Some auxiliary routines:
- *             tp_protocol_error: required by xebec- called when a combo of state,
- *                     event, predicate isn't covered for by the transition file.
- *             tp_indicate: gives indications(signals) to the user process
- *             tp_getoptions: initializes variables that are affected by the options
- *          chosen.
+ *     tp_protocol_error: required by xebec- called when a combo of state,
+ *         event, predicate isn't covered for by the transition file.
+ *     tp_indicate: gives indications(signals) to the user process
+ *     tp_getoptions: initializes variables that are affected by the options
+ *         chosen.
  */
 
  */
 
-#ifndef lint
-static char *rcsid = "$Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $";
-#endif lint
-
-#include "argoxtwentyfive.h"
-
 /* this def'n is to cause the expansion of this macro in the
  * routine tp_local_credit :
  */
 #define LOCAL_CREDIT_EXPAND
 
 #include "param.h"
 /* this def'n is to cause the expansion of this macro in the
  * routine tp_local_credit :
  */
 #define LOCAL_CREDIT_EXPAND
 
 #include "param.h"
+#include "systm.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
@@ -75,6 +79,16 @@ static char *rcsid = "$Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $";
 #include "tp_user.h"
 #include "cons.h"
 
 #include "tp_user.h"
 #include "cons.h"
 
+#include "../net/if.h"
+#include "../net/if_types.h"
+#ifdef TRUE
+#undef FALSE
+#undef TRUE
+#endif
+#include "../netccitt/x25.h"
+#include "../netccitt/pk.h"
+#include "../netccitt/pk_var.h"
+
 /*
  * NAME:       tp_local_credit()
  *
 /*
  * NAME:       tp_local_credit()
  *
@@ -184,8 +198,8 @@ tp_indicate(ind, tpcb, error)
 {
        register struct socket *so = tpcb->tp_sock;
        IFTRACE(D_INDICATION)
 {
        register struct socket *so = tpcb->tp_sock;
        IFTRACE(D_INDICATION)
-               tptraceTPCB(TPPTindicate, ind, *(int *)(tpcb->tp_lsuffix), 
-                       *(int *)(tpcb->tp_fsuffix), error,so->so_pgid);
+               tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix), 
+                       *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
        ENDTRACE
        IFDEBUG(D_INDICATION)
                char *ls, *fs;
        ENDTRACE
        IFDEBUG(D_INDICATION)
                char *ls, *fs;
@@ -201,9 +215,27 @@ tp_indicate(ind, tpcb, error)
                tpcb->tp_lref);
        ENDDEBUG
 
                tpcb->tp_lref);
        ENDDEBUG
 
+       if (ind == ER_TPDU) {
+               register struct mbuf *m;
+               struct tp_disc_reason x;
+
+               if ((so->so_state & SS_CANTRCVMORE) == 0 &&
+                               (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) {
+
+                       x.dr_hdr.cmsg_len = m->m_len = sizeof(x);
+                       x.dr_hdr.cmsg_level = SOL_TRANSPORT;
+                       x.dr_hdr.cmsg_type= TPOPT_DISC_REASON;
+                       x.dr_reason = error;
+                       *mtod(m, struct tp_disc_reason *) = x;
+                       sbappendrecord(&tpcb->tp_Xrcv, m);
+                       error = 0;
+               } else
+                       error = ECONNRESET;
+       }
        so->so_error = error;
 
        if (ind == T_DISCONNECT)  {
        so->so_error = error;
 
        if (ind == T_DISCONNECT)  {
+               so->so_error = ENOTCONN;
                if ( tpcb->tp_no_disc_indications )
                        return;
        }
                if ( tpcb->tp_no_disc_indications )
                        return;
        }
@@ -304,7 +336,7 @@ tp_quench( tpcb, cmd )
 {
        IFDEBUG(D_QUENCH)
                printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
 {
        IFDEBUG(D_QUENCH)
                printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
-                       tpcb, tpcb->tp_lref, *(int *)(tpcb->tp_lsuffix));
+                       tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
                printf("cong_win 0x%x decbit 0x%x \n",
                        tpcb->tp_cong_win, tpcb->tp_decbit);
        ENDDEBUG
                printf("cong_win 0x%x decbit 0x%x \n",
                        tpcb->tp_cong_win, tpcb->tp_decbit);
        ENDDEBUG
@@ -339,24 +371,38 @@ tp_netcmd( tpcb, cmd )
        struct tp_pcb *tpcb;
        int cmd;
 {
        struct tp_pcb *tpcb;
        int cmd;
 {
-#if NARGOXTWENTYFIVE > 0
+#ifdef TPCONS
+       struct isopcb *isop;
+       struct pklcd *lcp;
+
+       if (tpcb->tp_netservice != ISO_CONS)
+               return;
+       isop = (struct isopcb *)tpcb->tp_npcb;
+       lcp = (struct pklcd *)isop->isop_chan;
        switch (cmd) {
 
        case CONN_CLOSE:
        case CONN_REFUSE:
        switch (cmd) {
 
        case CONN_CLOSE:
        case CONN_REFUSE:
-               cons_netcmd( cmd, tpcb->tp_npcb, 0, tpcb->tp_class == TP_CLASS_4);
-               /* TODO: can this last param be replaced by 
-               *       tpcb->tp_netserv != ISO_CONS?)
-               */
+               if (isop->isop_refcnt == 1) {
+                       /* This is really superfluous, since it would happen
+                          anyway in iso_pcbdetach, although it is a courtesy
+                          to free up the x.25 channel before the refwait timer
+                          expires. */
+                       lcp->lcd_upper = 0;
+                       lcp->lcd_upnext = 0;
+                       pk_disconnect(lcp);
+                       isop->isop_chan = 0;
+                       isop->isop_refcnt = 0;
+               }
                break;
 
        default:
                printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
                break;
        }
                break;
 
        default:
                printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
                break;
        }
-#else NARGOXTWENTYFIVE
+#else TPCONS
        printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
        printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
-#endif NARGOXTWENTYFIVE > 0
+#endif
 }
 /*
  * CALLED FROM:
 }
 /*
  * CALLED FROM:
@@ -432,12 +478,12 @@ int
 tp_route_to( m, tpcb, channel)
        struct mbuf                                     *m;
        register struct tp_pcb          *tpcb;
 tp_route_to( m, tpcb, channel)
        struct mbuf                                     *m;
        register struct tp_pcb          *tpcb;
-       u_int                                           channel;
+       caddr_t                                         channel;
 {
        register struct sockaddr_iso *siso;     /* NOTE: this may be a sockaddr_in */
        extern struct tp_conn_param tp_conn_param[];
 {
        register struct sockaddr_iso *siso;     /* NOTE: this may be a sockaddr_in */
        extern struct tp_conn_param tp_conn_param[];
-       int error = 0;
-       int     vc_to_kill = 0; /* kludge */
+       int error = 0, save_netservice = tpcb->tp_netservice;
+       register struct rtentry *rt = 0;
 
        siso = mtod(m, struct sockaddr_iso *);
        IFTRACE(D_CONN)
 
        siso = mtod(m, struct sockaddr_iso *);
        IFTRACE(D_CONN)
@@ -452,21 +498,65 @@ tp_route_to( m, tpcb, channel)
                printf("m->mlen x%x, m->m_data:\n", m->m_len);
                dump_buf(mtod(m, caddr_t), m->m_len);
        ENDDEBUG
                printf("m->mlen x%x, m->m_data:\n", m->m_len);
                dump_buf(mtod(m, caddr_t), m->m_len);
        ENDDEBUG
-       if( siso->siso_family != tpcb->tp_domain ) {
-               error = EAFNOSUPPORT;
-               goto done;
+       if (channel) {
+#ifdef TPCONS
+               struct pklcd *lcp = (struct pklcd *)channel;
+               struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
+                       *isop_new = (struct isopcb *)tpcb->tp_npcb;
+               /* The next 2 lines believe that you haven't
+                  set any network level options or done a pcbconnect
+                  and XXXXXXX'edly apply to both inpcb's and isopcb's */
+               remque(isop_new);
+               free(isop_new, M_PCB);
+               tpcb->tp_npcb = (caddr_t)isop;
+               tpcb->tp_netservice = ISO_CONS;
+               tpcb->tp_nlproto = nl_protosw + ISO_CONS;
+               isop->isop_socket = tpcb->tp_sock;
+               if (isop->isop_refcnt == 0)
+                       iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
+               else
+                       /* there are already connections sharing this */;
+               isop->isop_refcnt++;
+#endif
+       } else {
+               switch (siso->siso_family) {
+               default:
+                       error = EAFNOSUPPORT;
+                       goto done;
+#ifdef ISO
+               case AF_ISO:
+                       tpcb->tp_netservice = ISO_CLNS;
+                       if (rt = rtalloc1((struct sockaddr *)siso, 0)) {
+                               rt->rt_refcnt--;
+                               if (rt->rt_flags & RTF_PROTO1)
+                                       tpcb->tp_netservice = ISO_CONS;
+                       }
+                       break;
+#endif
+#ifdef INET
+               case AF_INET:
+                       tpcb->tp_netservice = IN_CLNS;
+               }
+#endif
+               if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
+                       IFDEBUG(D_CONN)
+                               printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 
+                                               save_netservice, tpcb->tp_netservice);
+                       ENDDEBUG
+                       if (error = tp_set_npcb(tpcb))
+                               goto done;
+               }
+               IFDEBUG(D_CONN)
+                       printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
+                               tpcb->tp_netservice);
+               ENDDEBUG
+               tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
+               error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
        }
        }
-       IFDEBUG(D_CONN)
-               printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
-                       tpcb->tp_netservice);
-       ENDDEBUG
-       error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_sock->so_pcb, m);
        if( error )
                goto done;
 
        {
        if( error )
                goto done;
 
        {
-               register int save_netservice = tpcb->tp_netservice;
-
                switch(tpcb->tp_netservice) {
                case ISO_COSNS:
                case ISO_CLNS:
                switch(tpcb->tp_netservice) {
                case ISO_COSNS:
                case ISO_CLNS:
@@ -474,7 +564,7 @@ tp_route_to( m, tpcb, channel)
                         * can get long enough timers. sigh.
                        if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
                         */
                         * can get long enough timers. sigh.
                        if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
                         */
-                       if( siso->siso_addr.isoa_genaddr[2] == (char)IDI_OSINET ) {
+                       if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_X25) {
                                if( tpcb->tp_dont_change_params == 0) {
                                        copyQOSparms( &tp_conn_param[ISO_COSNS],
                                                        &tpcb->_tp_param);
                                if( tpcb->tp_dont_change_params == 0) {
                                        copyQOSparms( &tp_conn_param[ISO_COSNS],
                                                        &tpcb->_tp_param);
@@ -485,7 +575,7 @@ tp_route_to( m, tpcb, channel)
                case IN_CLNS:
                        if (iso_localifa(siso))
                                tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
                case IN_CLNS:
                        if (iso_localifa(siso))
                                tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
-                       if( (tpcb->tp_class & TP_CLASS_4)==0 ) {
+                       if((tpcb->tp_class & TP_CLASS_4) == 0) {
                                error = EPROTOTYPE;
                                break;
                        } 
                                error = EPROTOTYPE;
                                break;
                        } 
@@ -493,7 +583,7 @@ tp_route_to( m, tpcb, channel)
                        break;
 
                case ISO_CONS:
                        break;
 
                case ISO_CONS:
-#if NARGOXTWENTYFIVE > 0
+#ifdef TPCONS
                        tpcb->tp_flags |= TPF_NLQOS_PDN;
                        if( tpcb->tp_dont_change_params == 0 ) {
                                copyQOSparms( &tp_conn_param[ISO_CONS],
                        tpcb->tp_flags |= TPF_NLQOS_PDN;
                        if( tpcb->tp_dont_change_params == 0 ) {
                                copyQOSparms( &tp_conn_param[ISO_CONS],
@@ -510,57 +600,19 @@ tp_route_to( m, tpcb, channel)
                        }
                        tpcb->tp_rx_strat =  TPRX_USE_CW;
 
                        }
                        tpcb->tp_rx_strat =  TPRX_USE_CW;
 
-                       if( (tpcb->tp_nlproto != &nl_protosw[ISO_CONS]) ) {
-                               /* if the listener was restricting us to clns,
-                                * ( we never get here if the listener isn't af_iso )
-                                * refuse the connection :
-                                * but we don't have a way to restrict thus - it's
-                                * utterly permissive.
-                                       if(channel)  {
-                                               (void) cons_netcmd(CONN_REFUSE, tpcb->tp_npcb, 
-                                                               channel, tpcb->tp_class == TP_CLASS_4);
-                                               error = EPFNOSUPPORT;
-                                               goto done;
-                                       }
-                                */
-                               IFDEBUG(D_CONN)
-                                       printf(
-                                       "tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 
-                                                       tpcb->tp_nlproto , &nl_protosw[ISO_CONS]);
-                               ENDDEBUG
-                               tpcb->tp_nlproto = &nl_protosw[ISO_CONS];
-                       }
-                       /* Now we've got the right nl_protosw. 
-                        * If we already have a channel (we were called from tp_input())
-                        * tell cons that we'll hang onto this channel.
-                        * If we don't already have one (we were called from usrreq())
-                        * -and if it's TP0 open a net connection and wait for it to finish.
-                        */
-                       if( channel ) {
-                               error = cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, 
-                                                               channel, tpcb->tp_class == TP_CLASS_4);
-                               vc_to_kill ++;
-                       } else if( tpcb->tp_class != TP_CLASS_4 /* class 4 only */) {
-                               /* better open vc if any possibility of ending up 
-                                * in non-multiplexing class
-                                */
-                               error = cons_openvc(tpcb->tp_npcb, siso, tpcb->tp_sock);
-                               vc_to_kill ++;
-                       }
                        /* class 4 doesn't need to open a vc now - may use one already 
                         * opened or may open one only when it sends a pkt.
                         */
                        /* class 4 doesn't need to open a vc now - may use one already 
                         * opened or may open one only when it sends a pkt.
                         */
-#else NARGOXTWENTYFIVE > 0
+#else TPCONS
                        error = ECONNREFUSED;
                        error = ECONNREFUSED;
-#endif NARGOXTWENTYFIVE > 0
+#endif TPCONS
                        break;
                default:
                        error = EPROTOTYPE;
                }
 
                        break;
                default:
                        error = EPROTOTYPE;
                }
 
-               ASSERT( save_netservice == tpcb->tp_netservice);
        }
        }
-       if( error && vc_to_kill ) {
+       if (error) {
                tp_netcmd( tpcb, CONN_CLOSE);
                goto done;
        } 
                tp_netcmd( tpcb, CONN_CLOSE);
                goto done;
        } 
@@ -582,6 +634,73 @@ done:
        return error;
 }
 
        return error;
 }
 
+
+/* class zero version */
+void
+tp0_stash( tpcb, e )
+       register struct tp_pcb          *tpcb;
+       register struct tp_event        *e;
+{
+#ifndef lint
+#define E e->ATTR(DT_TPDU)
+#else lint
+#define E e->ev_union.EV_DT_TPDU
+#endif lint
+
+       register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
+       register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
+
+       IFPERF(tpcb)
+               PStat(tpcb, Nb_from_ll) += E.e_datalen;
+               tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
+                               E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
+       ENDPERF
+
+       IFDEBUG(D_STASH)
+               printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 
+               E.e_seq, E.e_datalen, E.e_eot);
+       ENDDEBUG
+
+       IFTRACE(D_STASH)
+               tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 
+               E.e_seq, E.e_datalen, E.e_eot, 0);
+       ENDTRACE
+
+       if ( E.e_eot ) {
+               register struct mbuf *n = E.e_data;
+               n->m_flags |= M_EOR;
+               n->m_act = MNULL; /* set on tp_input */
+       }
+       sbappend(sb, E.e_data);
+       IFDEBUG(D_STASH)
+               dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
+       ENDDEBUG
+       if (tpcb->tp_netservice != ISO_CONS)
+               printf("tp0_stash: tp running over something wierd\n");
+       else {
+               register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
+               pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
+       }
+} 
+
+void
+tp0_openflow(tpcb)
+register struct tp_pcb *tpcb;
+{
+       register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
+       if (tpcb->tp_netservice != ISO_CONS)
+               printf("tp0_openflow: tp running over something wierd\n");
+       else {
+               register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
+               if (lcp->lcd_rxrnr_condition)
+                       pk_flowcontrol(lcp, 0, 0);
+       }
+}
+#ifndef TPCONS
+static
+pk_flowcontrol() {}
+#endif
+
 #ifdef TP_PERF_MEAS
 /*
  * CALLED FROM:
 #ifdef TP_PERF_MEAS
 /*
  * CALLED FROM:
@@ -658,13 +777,13 @@ caddr_t   buf;
 int            len;
 {
        int             i,j;
 int            len;
 {
        int             i,j;
-
+#define Buf ((u_char *)buf)
        printf("Dump buf 0x%x len 0x%x\n", buf, len);
        for (i = 0; i < len; i += MAX_COLUMNS) {
                printf("+%d:\t", i);
                for (j = 0; j < MAX_COLUMNS; j++) {
                        if (i + j < len) {
        printf("Dump buf 0x%x len 0x%x\n", buf, len);
        for (i = 0; i < len; i += MAX_COLUMNS) {
                printf("+%d:\t", i);
                for (j = 0; j < MAX_COLUMNS; j++) {
                        if (i + j < len) {
-                               printf("%x/%d\t", buf[i+j]&0xff, buf[i+j]);
+                               printf("%x/%d\t", Buf[i+j], Buf[i+j]);
                        } else {
                                printf("        ");
                        }
                        } else {
                                printf("        ");
                        }
@@ -672,8 +791,8 @@ int         len;
 
                for (j = 0; j < MAX_COLUMNS; j++) {
                        if (i + j < len) {
 
                for (j = 0; j < MAX_COLUMNS; j++) {
                        if (i + j < len) {
-                               if (((buf[i+j]) > 31) && ((buf[i+j]) < 128))
-                                       printf("%c", buf[i+j]&0xff);
+                               if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
+                                       printf("%c", Buf[i+j]);
                                else
                                        printf(".");
                        }
                                else
                                        printf(".");
                        }