panic if proc doing unlock is not proc that aquired the lock
[unix-history] / usr / src / sys / netccitt / pk_subr.c
index 44404e2..c6be578 100644 (file)
@@ -1,38 +1,57 @@
 /*
  * Copyright (c) University of British Columbia, 1984
 /*
  * Copyright (c) University of British Columbia, 1984
- * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (C) Computer Science Department IV, 
+ *              University of Erlangen-Nuremberg, Germany, 1992
+ * Copyright (c) 1991, 1992  The Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * This code is derived from software contributed to Berkeley by
- * the Laboratory for Computation Vision and the Computer Science Department
- * of the University of British Columbia.
+ * This code is derived from software contributed to Berkeley by the
+ * Laboratory for Computation Vision and the Computer Science Department
+ * of the the University of British Columbia and the Computer Science
+ * Department (IV) of the University of Erlangen-Nuremberg, Germany.
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)pk_subr.c   7.7 (Berkeley) %G%
+ *     @(#)pk_subr.c   7.24 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "mbuf.h"
-#include "socket.h"
-#include "protosw.h"
-#include "socketvar.h"
-#include "errno.h"
-#include "time.h"
-#include "kernel.h"
-
-#include "../net/if.h"
-
-#include "x25.h"
-#include "pk.h"
-#include "pk_var.h"
-#include "x25err.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netccitt/dll.h>
+#include <netccitt/x25.h>
+#include <netccitt/x25err.h>
+#include <netccitt/pk.h>
+#include <netccitt/pk_var.h>
 
 int     pk_sendspace = 1024 * 2 + 8;
 int     pk_recvspace = 1024 * 2 + 8;
 
 
 int     pk_sendspace = 1024 * 2 + 8;
 int     pk_recvspace = 1024 * 2 + 8;
 
-struct x25_packet *pk_template ();
+struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q};
+
+struct x25bitslice x25_bitslice[] = {
+/*       mask, shift value */
+       { 0xf0, 0x4 },
+       { 0xf,  0x0 },
+       { 0x80, 0x7 },
+       { 0x40, 0x6 },
+       { 0x30, 0x4 },
+       { 0xe0, 0x5 },
+       { 0x10, 0x4 },
+       { 0xe,  0x1 },
+       { 0x1,  0x0 }
+};
+
 
 /* 
  *  Attach X.25 protocol to socket, allocate logical channel descripter
 
 /* 
  *  Attach X.25 protocol to socket, allocate logical channel descripter
@@ -47,17 +66,19 @@ struct socket *so;
 {
        register struct pklcd *lcp;
        register int error = ENOBUFS;
 {
        register struct pklcd *lcp;
        register int error = ENOBUFS;
+       int pk_output();
 
 
-       MALLOC(lcp, struct pklcd *, sizeof(*lcp), M_PCB, M_NOWAIT);
+       MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT);
        if (lcp) {
        if (lcp) {
-               bzero((caddr_t)lcp, sizeof(*lcp));
+               bzero ((caddr_t)lcp, sizeof (*lcp));
+               insque (&lcp -> lcd_q, &pklcd_q);
+               lcp -> lcd_state = READY;
+               lcp -> lcd_send = pk_output;
                if (so) {
                        error = soreserve (so, pk_sendspace, pk_recvspace);
                        lcp -> lcd_so = so;
                        if (so -> so_options & SO_ACCEPTCONN)
                                lcp -> lcd_state = LISTEN;
                if (so) {
                        error = soreserve (so, pk_sendspace, pk_recvspace);
                        lcp -> lcd_so = so;
                        if (so -> so_options & SO_ACCEPTCONN)
                                lcp -> lcd_state = LISTEN;
-                       else
-                               lcp -> lcd_state = READY;
                } else
                        sbreserve (&lcp -> lcd_sb, pk_sendspace);
        }
                } else
                        sbreserve (&lcp -> lcd_sb, pk_sendspace);
        }
@@ -106,7 +127,7 @@ register struct pklcd *lcp;
                        soisdisconnecting (so);
                        sbflush (&so -> so_rcv);
                }
                        soisdisconnecting (so);
                        sbflush (&so -> so_rcv);
                }
-               pk_clear (lcp);
+               pk_clear (lcp, 241, 0); /* Normal Disconnect */
 
        }
 }
 
        }
 }
@@ -121,16 +142,28 @@ struct pklcd *lcp;
 {
        register struct socket *so = lcp -> lcd_so;
 
 {
        register struct socket *so = lcp -> lcd_so;
 
-       pk_freelcd (lcp);
+       /*
+        * If the X.25 connection is torn down due to link
+        * level failure (e.g. LLC2 FRMR) and at the same the user
+        * level is still filling up the socket send buffer that
+        * send buffer is locked. An attempt to sbflush() that send
+        * buffer will lead us into - no, not temptation but - panic!
+        * So - we'll just check wether the send buffer is locked
+        * and if that's the case we'll mark the lcp as zombie and 
+        * have the pk_timer() do the cleaning ...
+        */
+       
+       if (so && so -> so_snd.sb_flags & SB_LOCK)
+               lcp -> lcd_state = LCN_ZOMBIE;
+       else
+               pk_freelcd (lcp);
 
        if (so == NULL)
                return;
 
        so -> so_pcb = 0;
 
        if (so == NULL)
                return;
 
        so -> so_pcb = 0;
-       sbflush (&so -> so_snd);
-       sbflush (&so -> so_rcv);
        soisdisconnected (so);
        soisdisconnected (so);
-       sofree (so);    /* gak!!! you can't do that here */
+       /* sofree (so); /* gak!!! you can't do that here */
 }
 
 /* 
 }
 
 /* 
@@ -140,7 +173,7 @@ struct pklcd *lcp;
  *  the remainer of the packet is filled in.
 */
 
  *  the remainer of the packet is filled in.
 */
 
-struct x25_packet *
+struct mbuf *
 pk_template (lcn, type)
 int lcn, type;
 {
 pk_template (lcn, type)
 int lcn, type;
 {
@@ -158,18 +191,18 @@ int lcn, type;
         * be enough room for the link level to insert its header.
         */
        m -> m_data += max_linkhdr;
         * be enough room for the link level to insert its header.
         */
        m -> m_data += max_linkhdr;
-       m -> m_len = PKHEADERLN;
+       m -> m_pkthdr.len = m -> m_len = PKHEADERLN;
 
        xp = mtod (m, struct x25_packet *);
        *(long *)xp = 0;                /* ugly, but fast */
 /*     xp -> q_bit = 0;*/
 
        xp = mtod (m, struct x25_packet *);
        *(long *)xp = 0;                /* ugly, but fast */
 /*     xp -> q_bit = 0;*/
-       xp -> fmt_identifier = 1;
+       X25SBITS(xp -> bits, fmt_identifier, 1);
 /*     xp -> lc_group_number = 0;*/
 
 /*     xp -> lc_group_number = 0;*/
 
-       xp -> logical_channel_number = lcn;
+       SET_LCN(xp, lcn);
        xp -> packet_type = type;
 
        xp -> packet_type = type;
 
-       return (xp);
+       return (m);
 }
 
 /* 
 }
 
 /* 
@@ -183,28 +216,45 @@ pk_restart (pkp, restart_cause)
 register struct pkcb *pkp;
 int restart_cause;
 {
 register struct pkcb *pkp;
 int restart_cause;
 {
-       register struct x25_packet *xp;
+       register struct mbuf *m;
        register struct pklcd *lcp;
        register int i;
 
        /* Restart all logical channels. */
        if (pkp -> pk_chan == 0)
                return;
        register struct pklcd *lcp;
        register int i;
 
        /* Restart all logical channels. */
        if (pkp -> pk_chan == 0)
                return;
-       for (i = 1; i <= pkp -> pk_maxlcn; ++i)
-               if ((lcp = pkp -> pk_chan[i]) != NULL) {
-                       if (lcp -> lcd_so)
-                               lcp -> lcd_so -> so_error = ENETRESET;
-                       pk_close (lcp);
-               }
+
+       /*
+        * Don't do this if we're doing a restart issued from
+        * inside pk_connect() --- which is only done if and
+        * only if the X.25 link is down, i.e. a RESTART needs
+        * to be done to get it up.
+        */
+       if (!(pkp -> pk_dxerole & DTE_CONNECTPENDING)) {
+               for (i = 1; i <= pkp -> pk_maxlcn; ++i)
+                       if ((lcp = pkp -> pk_chan[i]) != NULL) {
+                               if (lcp -> lcd_so) {
+                                       lcp -> lcd_so -> so_error = ENETRESET;
+                                       pk_close (lcp);
+                               } else {
+                                       pk_flush (lcp);
+                                       lcp -> lcd_state = READY;
+                                       if (lcp -> lcd_upper)
+                                               lcp -> lcd_upper (lcp, 0);
+                               }
+                       }
+       }
 
        if (restart_cause < 0)
                return;
 
        pkp -> pk_state = DTE_SENT_RESTART;
 
        if (restart_cause < 0)
                return;
 
        pkp -> pk_state = DTE_SENT_RESTART;
+       pkp -> pk_dxerole &= ~(DTE_PLAYDCE | DTE_PLAYDTE);
        lcp = pkp -> pk_chan[0];
        lcp = pkp -> pk_chan[0];
-       xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART);
-       (dtom (xp)) -> m_len++;
-       xp -> packet_data = 0;  /* DTE only */
+       m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART);
+       m -> m_pkthdr.len = m -> m_len += 2;
+       mtod (m, struct x25_packet *) -> packet_data = 0;       /* DTE only */
+       mtod (m, octet *)[4]  = restart_cause;
        pk_output (lcp);
 }
 
        pk_output (lcp);
 }
 
@@ -219,13 +269,12 @@ register struct pklcd *lcp;
        if (lcp == NULL)
                return;
 
        if (lcp == NULL)
                return;
 
-       if (lcp -> lcd_template)
-               m_freem (dtom (lcp -> lcd_template));
-
        if (lcp -> lcd_lcn > 0)
                lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL;
 
        if (lcp -> lcd_lcn > 0)
                lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL;
 
-       free((caddr_t)lcp, M_PCB);
+       pk_flush (lcp);
+       remque (&lcp -> lcd_q);
+       free ((caddr_t)lcp, M_PCB);
 }
 
 
 }
 
 
@@ -235,20 +284,26 @@ register struct pklcd *lcp;
  *  Call User Data field.
  */
 
  *  Call User Data field.
  */
 
+#define XTRACTPKP(rt)  ((rt)->rt_flags & RTF_GATEWAY ? \
+                        ((rt)->rt_llinfo ? \
+                         (struct pkcb *) ((struct rtentry *)((rt)->rt_llinfo))->rt_llinfo : \
+                         (struct pkcb *) NULL) : \
+                        (struct pkcb *)((rt)->rt_llinfo))
+
 pk_bind (lcp, nam)
 struct pklcd *lcp;
 struct mbuf *nam;
 {
        register struct pkcb *pkp;
 pk_bind (lcp, nam)
 struct pklcd *lcp;
 struct mbuf *nam;
 {
        register struct pkcb *pkp;
-       register struct mbuf *m;
        register struct pklcd *pp;
        register struct sockaddr_x25 *sa;
        register struct pklcd *pp;
        register struct sockaddr_x25 *sa;
+       register struct rtentry *rt;
 
        if (nam == NULL)
                return (EADDRNOTAVAIL);
        if (lcp -> lcd_ceaddr)                          /* XXX */
                return (EADDRINUSE);
 
        if (nam == NULL)
                return (EADDRNOTAVAIL);
        if (lcp -> lcd_ceaddr)                          /* XXX */
                return (EADDRINUSE);
-       if (checksockaddr (nam))
+       if (pk_checksockaddr (nam))
                return (EINVAL);
        sa = mtod (nam, struct sockaddr_x25 *);
 
                return (EINVAL);
        sa = mtod (nam, struct sockaddr_x25 *);
 
@@ -257,24 +312,81 @@ struct mbuf *nam;
         * net (net != 0), make sure the net is known
         */
 
         * net (net != 0), make sure the net is known
         */
 
-       if (sa -> x25_net)
-               for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
-                       if (pkp == 0)
-                               return (ENETUNREACH);
-                       if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net)
-                               break;
-               }
-
-       for (pp = pk_listenhead; pp; pp = pp -> lcd_listen)
-               if (bcmp (pp -> lcd_ceaddr -> x25_udata, sa -> x25_udata,
-                         min (pp -> lcd_ceaddr -> x25_udlen, sa -> x25_udlen)) == 0)
-                       return (EADDRINUSE);
+       if ( !(rt =  rtalloc1(sa, 1)))
+               return (ENETUNREACH);
+       pkp = XTRACTPKP(rt);
 
 
+       /*
+        * For ISO's sake permit default listeners, but only one such . . .
+        */
+       for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) {
+               register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr;
+               if ((sa2 -> x25_udlen == sa -> x25_udlen) &&
+                   (sa2 -> x25_udlen == 0 ||
+                    (bcmp (sa2 -> x25_udata, sa -> x25_udata,
+                           min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0)))
+                               return (EADDRINUSE);
+       }
        lcp -> lcd_laddr = *sa;
        lcp -> lcd_ceaddr = &lcp -> lcd_laddr;
        return (0);
 }
 
        lcp -> lcd_laddr = *sa;
        lcp -> lcd_ceaddr = &lcp -> lcd_laddr;
        return (0);
 }
 
+/*
+ * Include a bound control block in the list of listeners.
+ */
+pk_listen (lcp)
+register struct pklcd *lcp;
+{
+       register struct pklcd **pp;
+
+       if (lcp -> lcd_ceaddr == 0)
+               return (EDESTADDRREQ);
+
+       lcp -> lcd_state = LISTEN;
+       /*
+        * Add default listener at end, any others at start.
+        */
+       if (lcp -> lcd_ceaddr -> x25_udlen == 0) {
+               for (pp = &pk_listenhead; *pp; )
+                       pp = &((*pp) -> lcd_listen);
+               *pp = lcp;
+       } else {
+               lcp -> lcd_listen = pk_listenhead;
+               pk_listenhead = lcp;
+       }
+       return (0);
+}
+/*
+ * Include a listening control block for the benefit of other protocols.
+ */
+pk_protolisten (spi, spilen, callee)
+int (*callee) ();
+{
+       register struct pklcd *lcp = pk_attach ((struct socket *)0);
+       register struct mbuf *nam;
+       register struct sockaddr_x25 *sa;
+       int error = ENOBUFS;
+
+       if (lcp) {
+               if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) {
+                       sa = mtod (nam, struct sockaddr_x25 *);
+                       sa -> x25_family = AF_CCITT;
+                       sa -> x25_len = nam -> m_len = sizeof (*sa);
+                       sa -> x25_udlen = spilen;
+                       sa -> x25_udata[0] = spi;
+                       lcp -> lcd_upper = callee;
+                       lcp -> lcd_flags = X25_MBS_HOLD;
+                       if ((error = pk_bind (lcp, nam)) == 0)
+                               error = pk_listen (lcp);
+                       (void) m_free (nam);
+               }
+               if (error)
+                       pk_freelcd (lcp);
+       }
+       return error; /* Hopefully Zero !*/
+}
+
 /*
  * Associate a logical channel descriptor with a network.
  * Fill in the default network specific parameters and then
 /*
  * Associate a logical channel descriptor with a network.
  * Fill in the default network specific parameters and then
@@ -303,54 +415,155 @@ register struct sockaddr_x25 *sa;
        else
                sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
        sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
        else
                sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
        sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
-       lcp -> lcd_flags = sa -> x25_opts.op_flags;
+       lcp -> lcd_flags |= sa -> x25_opts.op_flags;
        lcp -> lcd_stime = time.tv_sec;
 }
 
        lcp -> lcd_stime = time.tv_sec;
 }
 
-pk_connect (lcp, nam, sa)
+pk_connect (lcp, sa)
 register struct pklcd *lcp;
 register struct sockaddr_x25 *sa;
 register struct pklcd *lcp;
 register struct sockaddr_x25 *sa;
-struct mbuf *nam;
 {
        register struct pkcb *pkp;
 {
        register struct pkcb *pkp;
-       register struct mbuf *m;
-       register struct ifnet *ifp;
+       register struct rtentry *rt;
+       register struct rtentry *nrt;
+
+       struct rtentry *npaidb_enter();
+       struct pkcb *pk_newlink();
 
 
-       if (sa == 0) {
-               if (checksockaddr (nam))
-                       return (EINVAL);
-               sa = mtod (nam, struct sockaddr_x25 *);
-       }
        if (sa -> x25_addr[0] == '\0')
                return (EDESTADDRREQ);
        if (sa -> x25_addr[0] == '\0')
                return (EDESTADDRREQ);
-       if (lcp -> lcd_pkp == 0)
-           for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
-               if (pkp == 0)
-                       return (ENETUNREACH);
-               /*
-                * use first net configured (last in list
-                * headed by pkcbhead) if net is zero
-                */
-               if (sa -> x25_net == 0 && pkp -> pk_next == 0)
-                       break;
-               if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net)
-                       break;
+
+       /*
+        * Is the destination address known?
+        */
+       if (!(rt = rtalloc1 (sa, 1)))
+               return (ENETUNREACH);
+
+       if (!(pkp = XTRACTPKP(rt)))
+               pkp = pk_newlink((struct x25_ifaddr *) (rt -> rt_ifa), 
+                                (caddr_t) 0);
+
+       /*
+        * Have we entered the LLC address?
+        */
+       if (nrt = npaidb_enter(rt -> rt_gateway, rt_key(rt), rt, 0))
+               pkp -> pk_llrt = nrt;
+
+       /*
+        * Have we allocated an LLC2 link yet?
+        */
+       if (pkp->pk_llnext == (caddr_t)0 && pkp->pk_llctlinput) {
+               struct dll_ctlinfo ctlinfo;
+
+               ctlinfo.dlcti_rt = rt;
+               ctlinfo.dlcti_pcb = (caddr_t) pkp;
+               ctlinfo.dlcti_conf = 
+                       (struct dllconfig *) (&((struct x25_ifaddr *)(rt->rt_ifa))->ia_xc);
+               pkp->pk_llnext = 
+                       (pkp->pk_llctlinput)(PRC_CONNECT_REQUEST, 0, &ctlinfo);
        }
 
        }
 
-       if (pkp -> pk_state != DTE_READY)
-               return (ENETDOWN);
+       if (pkp -> pk_state != DTE_READY && pkp -> pk_state != DTE_WAITING)
+                       return (ENETDOWN);
        if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
                return (EMFILE);
        if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
                return (EMFILE);
+
        lcp -> lcd_faddr = *sa;
        lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
        pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
        lcp -> lcd_faddr = *sa;
        lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
        pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
+
+       /*
+        * If the link is not up yet, initiate an X.25 RESTART
+        */
+       if (pkp -> pk_state == DTE_WAITING) {
+               pkp -> pk_dxerole |= DTE_CONNECTPENDING;
+               pk_ctlinput(PRC_LINKUP, (struct sockaddr *)0, pkp);
+               if (lcp -> lcd_so)
+                       soisconnecting (lcp -> lcd_so);
+               return 0;
+       }
+
        if (lcp -> lcd_so)
                soisconnecting (lcp -> lcd_so);
        lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
        pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
        if (lcp -> lcd_so)
                soisconnecting (lcp -> lcd_so);
        lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
        pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
-       return (*pkp -> pk_start)(lcp);
+       return (*pkp -> pk_ia -> ia_start) (lcp);
 }
 
 }
 
+/*
+ * Complete all pending X.25 call requests --- this gets called after
+ * the X.25 link has been restarted.
+ */
+#define RESHUFFLELCN(maxlcn, lcn) ((maxlcn) - (lcn) + 1)
+
+pk_callcomplete(pkp)
+       register struct pkcb *pkp;
+{
+       register struct pklcd *lcp;
+       register int i;
+       register int ni;
+       
+
+       if (pkp -> pk_dxerole & DTE_CONNECTPENDING) 
+               pkp -> pk_dxerole &= ~DTE_CONNECTPENDING;
+       else return;
+
+       if (pkp -> pk_chan == 0)
+               return;
+       
+       /*
+        * We pretended to be a DTE for allocating lcns, if
+        * it turns out that we are in reality performing as a
+        * DCE we need to reshuffle the lcps.
+        *                                                    
+         *             /+---------------+--------     -              
+        *            / | a  (maxlcn-1) |              \      
+        *           /  +---------------+               \     
+        *     +--- *   | b  (maxlcn-2) |                \    
+        *     |     \  +---------------+                 \   
+        *   r |      \ | c  (maxlcn-3) |                  \  
+        *   e |       \+---------------+                   | 
+        *   s |        |        .                          |  
+        *   h |        |        .                          | m
+        *   u |        |        .                          | a
+        *   f |        |        .                          | x
+        *   f |        |        .                          | l
+        *   l |       /+---------------+                   | c
+        *   e |      / | c' (   3    ) |                   | n
+        *     |     /  +---------------+                   | 
+        *     +--> *   | b' (   2    ) |                  /
+        *           \  +---------------+                 / 
+        *            \ | a' (   1    ) |                /  
+        *             \+---------------+               /   
+         *              | 0             |              /    
+        *              +---------------+--------     -     
+        *          
+        */         
+       if (pkp -> pk_dxerole & DTE_PLAYDCE) {
+               /* Sigh, reshuffle it */
+               for (i = pkp -> pk_maxlcn; i > 0; --i)
+                       if (pkp -> pk_chan[i]) {
+                               ni = RESHUFFLELCN(pkp -> pk_maxlcn, i);
+                               pkp -> pk_chan[ni] = pkp -> pk_chan[i];
+                               pkp -> pk_chan[i] = NULL;
+                               pkp -> pk_chan[ni] -> lcd_lcn = ni;
+                       }
+       }
+
+       for (i = 1; i <= pkp -> pk_maxlcn; ++i)
+               if ((lcp = pkp -> pk_chan[i]) != NULL) {
+                       /* if (lcp -> lcd_so)
+                               soisconnecting (lcp -> lcd_so); */
+                       lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
+                       pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
+                       (*pkp -> pk_ia -> ia_start)(lcp);
+               }
+}
+
+struct bcdinfo {
+       octet *cp;
+       unsigned posn;
+};
 /* 
  *  Build the rest of the CALL REQUEST packet. Fill in calling
  *  address, facilities fields and the user data field.
 /* 
  *  Build the rest of the CALL REQUEST packet. Fill in calling
  *  address, facilities fields and the user data field.
@@ -362,42 +575,41 @@ register struct sockaddr_x25 *sa;
 register struct x25config *xcp;
 {
        register struct x25_calladdr *a;
 register struct x25config *xcp;
 {
        register struct x25_calladdr *a;
-       register struct mbuf *m = dtom (lcp -> lcd_template);
-       unsigned posn = 0;
-       octet *cp;
-
-       a = (struct x25_calladdr *) &lcp -> lcd_template -> packet_data;
-       a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr);
-       a -> called_addrlen = strlen (sa -> x25_addr);
-       cp = (octet *) a -> address_field;
-       to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn);
-       to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn);
-       if (posn & 0x01)
-               *cp++ &= 0xf0;
-
-       build_facilities (&cp, sa, (int)xcp -> xc_type);
-
-       bcopy (sa -> x25_udata, (caddr_t)cp, (unsigned)sa -> x25_udlen);
-       cp += sa -> x25_udlen;
-
-       m -> m_len += cp - (octet *) a;
-
-#ifdef ANDREW
-       printf ("call: ");
-       for (cp = mtod (m, octet *), posn = 0; posn < m -> m_len; ++posn)
-               printf ("%x ", *cp++);
-       printf ("\n");
-#endif
+       register struct mbuf *m = lcp -> lcd_template;
+       register struct x25_packet *xp = mtod (m, struct x25_packet *);
+       struct bcdinfo b;
+
+       if (lcp -> lcd_flags & X25_DBIT)
+               X25SBITS(xp -> bits, d_bit, 1);
+       a = (struct x25_calladdr *) &xp -> packet_data;
+       b.cp = (octet *) a -> address_field;
+       b.posn = 0;
+       X25SBITS(a -> addrlens, called_addrlen, to_bcd (&b, sa, xcp));
+       X25SBITS(a -> addrlens, calling_addrlen, to_bcd (&b, &xcp -> xc_addr, xcp));
+       if (b.posn & 0x01)
+               *b.cp++ &= 0xf0;
+       m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a;
+
+       if (lcp -> lcd_facilities) {
+               m -> m_pkthdr.len += 
+                       (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len;
+               lcp -> lcd_facilities = 0;
+       } else
+               pk_build_facilities (m, sa, (int)xcp -> xc_type);
+
+       m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);
 }
 
 }
 
-build_facilities (cp, sa, type)
-register octet **cp;
+pk_build_facilities (m, sa, type)
+register struct mbuf *m;
 struct sockaddr_x25 *sa;
 {
 struct sockaddr_x25 *sa;
 {
+       register octet *cp;
        register octet *fcp;
        register int revcharge;
 
        register octet *fcp;
        register int revcharge;
 
-       fcp = *cp + 1;
+       cp = mtod (m, octet *) + m -> m_len;
+       fcp = cp + 1;
        revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
        /*
         * This is specific to Datapac X.25(1976) DTEs.  International
        revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
        /*
         * This is specific to Datapac X.25(1976) DTEs.  International
@@ -420,26 +632,52 @@ struct sockaddr_x25 *sa;
                *fcp++ = sa -> x25_opts.op_wsize;
                *fcp++ = sa -> x25_opts.op_wsize;
        }
                *fcp++ = sa -> x25_opts.op_wsize;
                *fcp++ = sa -> x25_opts.op_wsize;
        }
-       **cp = fcp - *cp - 1;
-       *cp = fcp;
+       *cp = fcp - cp - 1;
+       m -> m_pkthdr.len = (m -> m_len += *cp + 1);
 }
 
 }
 
-to_bcd (a, len, x, posn)
-register octet **a;
-register char *x;
-register int len;
-register unsigned *posn;
+to_bcd (b, sa, xcp)
+register struct bcdinfo *b;
+struct sockaddr_x25 *sa;
+register struct x25config *xcp;
 {
 {
-       while (--len >= 0)
-               if ((*posn)++ & 0x01)
-                       *(*a)++ |= *x++ & 0x0F;
+       register char *x = sa -> x25_addr;
+       unsigned start = b -> posn;
+       /*
+        * The nodnic and prepnd0 stuff looks tedious,
+        * but it does allow full X.121 addresses to be used,
+        * which is handy for routing info (& OSI type 37 addresses).
+        */
+       if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) {
+               char dnicname[sizeof(long) * NBBY/3 + 2];
+               register char *p = dnicname;
+
+               sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff);
+               for (; *p; p++) /* *p == 0 means dnic matched */
+                       if ((*p ^ *x++) & 0x0f)
+                               break;
+               if (*p || xcp -> xc_nodnic == 0)
+                       x = sa -> x25_addr;
+               if (*p && xcp -> xc_prepnd0) {
+                       if ((b -> posn)++ & 0x01)
+                               *(b -> cp)++;
+                       else
+                               *(b -> cp) = 0;
+               }
+       }
+       while (*x)
+               if ((b -> posn)++ & 0x01)
+                       *(b -> cp)++ |= *x++ & 0x0F;
                else
                else
-                       **a = *x++ << 4;
+                       *(b -> cp) = *x++ << 4;
+       return ((b -> posn) - start);
 }
 
 /* 
  *  This routine gets the  first available logical channel number.  The
 }
 
 /* 
  *  This routine gets the  first available logical channel number.  The
- *  search is from the highest number to lowest number (DTE).
+ *  search is 
+ *             - from the highest number to lowest number if playing DTE, and
+ *             - from lowest to highest number if playing DCE.
  */
 
 pk_getlcn (pkp)
  */
 
 pk_getlcn (pkp)
@@ -449,31 +687,17 @@ register struct pkcb *pkp;
 
        if (pkp -> pk_chan == 0)
                return (0);
 
        if (pkp -> pk_chan == 0)
                return (0);
-       for (i = pkp -> pk_maxlcn; i > 0; --i)
-               if (pkp -> pk_chan[i] == NULL)
-                       break;
-       return (i);
-
-}
-
-static
-checksockaddr (m)
-struct mbuf *m;
-{
-       register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *);
-       register char *cp;
-
-       if (m -> m_len != sizeof (struct sockaddr_x25))
-               return (1);
-       if (sa -> x25_family != AF_CCITT || sa -> x25_udlen == 0 ||
-               sa -> x25_udlen > sizeof (sa -> x25_udata))
-               return (1);
-       for (cp = sa -> x25_addr; *cp; cp++) {
-               if (*cp < '0' || *cp > '9' ||
-                       cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1])
-                       return (1);
+       if ( pkp -> pk_dxerole & DTE_PLAYDCE ) {
+               for (i = 1; i <= pkp -> pk_maxlcn; ++i)
+                       if (pkp -> pk_chan[i] == NULL)
+                               break;
+       } else { 
+               for (i = pkp -> pk_maxlcn; i > 0; --i)
+                       if (pkp -> pk_chan[i] == NULL)
+                               break;
        }
        }
-       return (0);
+       i = ( i > pkp -> pk_maxlcn ? 0 : i );
+       return (i);
 }
 
 /* 
 }
 
 /* 
@@ -481,61 +705,116 @@ struct mbuf *m;
  *  set to "SENT_CLEAR". 
  */
 
  *  set to "SENT_CLEAR". 
  */
 
-pk_clear (lcp)
-struct pklcd *lcp;
+pk_clear (lcp, diagnostic, abortive)
+register struct pklcd *lcp;
 {
 {
-       register struct x25_packet *xp;
+       register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR);
+
+       m -> m_len += 2;
+       m -> m_pkthdr.len += 2;
+       mtod (m, struct x25_packet *) -> packet_data = 0;
+       mtod (m, octet *)[4] = diagnostic;
+       if (lcp -> lcd_facilities) {
+               m -> m_next = lcp -> lcd_facilities;
+               m -> m_pkthdr.len += m -> m_next -> m_len;
+               lcp -> lcd_facilities = 0;
+       }
+       if (abortive)
+               lcp -> lcd_template = m;
+       else {
+               struct socket *so = lcp -> lcd_so;
+               struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb;
+               sbappendrecord (sb, m);
+       }
+       pk_output (lcp);
 
 
-       xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR);
-       (dtom (xp)) -> m_len++;
-       xp -> packet_data = 0;
+}
 
 
+/*
+ * This procedure generates RNR's or RR's to inhibit or enable
+ * inward data flow, if the current state changes (blocked ==> open or
+ * vice versa), or if forced to generate one.  One forces RNR's to ack data.  
+ */
+pk_flowcontrol (lcp, inhibit, forced)
+register struct pklcd *lcp;
+{
+       inhibit = (inhibit != 0);
+       if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER ||
+           (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit))
+               return;
+       lcp -> lcd_rxrnr_condition = inhibit;
+       lcp -> lcd_template =
+               pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR);
        pk_output (lcp);
        pk_output (lcp);
-
 }
 
 /* 
 }
 
 /* 
- *  This procedure sends a RESET request packet. It re-intializes 
+ *  This procedure sends a RESET request packet. It re-intializes
  *  virtual circuit.
  */
 
 static
  *  virtual circuit.
  */
 
 static
-pk_reset (lcp)
+pk_reset (lcp, diagnostic)
 register struct pklcd *lcp;
 {
 register struct pklcd *lcp;
 {
-       register struct x25_packet *xp;
-       register struct socket *so;
+       register struct mbuf *m;
+       register struct socket *so = lcp -> lcd_so;
 
        if (lcp -> lcd_state != DATA_TRANSFER)
                return;
 
 
        if (lcp -> lcd_state != DATA_TRANSFER)
                return;
 
+       if (so)
+               so -> so_error = ECONNRESET;
        lcp -> lcd_reset_condition = TRUE;
 
        /* Reset all the control variables for the channel. */
        lcp -> lcd_reset_condition = TRUE;
 
        /* Reset all the control variables for the channel. */
+       pk_flush (lcp);
        lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
                lcp -> lcd_intrconf_pending = FALSE;
        lcp -> lcd_rsn = MODULUS - 1;
        lcp -> lcd_ssn = 0;
        lcp -> lcd_output_window = lcp -> lcd_input_window =
                lcp -> lcd_last_transmitted_pr = 0;
        lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
                lcp -> lcd_intrconf_pending = FALSE;
        lcp -> lcd_rsn = MODULUS - 1;
        lcp -> lcd_ssn = 0;
        lcp -> lcd_output_window = lcp -> lcd_input_window =
                lcp -> lcd_last_transmitted_pr = 0;
-       if (so = lcp -> lcd_so)  {
-               so -> so_error = ECONNRESET;
-               sbflush (&so -> so_rcv);
-               sbflush (&so -> so_snd);
-       }
-       xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
-       (dtom (xp)) -> m_len += 2;
-       xp -> packet_data = 0;
+       m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
+       m -> m_pkthdr.len = m -> m_len += 2;
+       mtod (m, struct x25_packet *) -> packet_data = 0;
+       mtod (m, octet *)[4] = diagnostic;
        pk_output (lcp);
 
 }
 
        pk_output (lcp);
 
 }
 
+/*
+ * This procedure frees all data queued for output or delivery on a
+ *  virtual circuit.
+ */
+
+pk_flush (lcp)
+register struct pklcd *lcp;
+{
+       register struct socket *so;
+
+       if (lcp -> lcd_template)
+               m_freem (lcp -> lcd_template);
+
+       if (lcp -> lcd_cps) {
+               m_freem (lcp -> lcd_cps);
+               lcp -> lcd_cps = 0;
+       }
+       if (lcp -> lcd_facilities) {
+               m_freem (lcp -> lcd_facilities);
+               lcp -> lcd_facilities = 0;
+       }
+       if (so = lcp -> lcd_so) 
+               sbflush (&so -> so_snd);
+       else 
+               sbflush (&lcp -> lcd_sb);
+}
 
 /* 
  *  This procedure handles all local protocol procedure errors.
  */
 
 
 /* 
  *  This procedure handles all local protocol procedure errors.
  */
 
-pk_procerror (error, lcp, errstr)
+pk_procerror (error, lcp, errstr, diagnostic)
 register struct pklcd *lcp;
 char *errstr;
 {
 register struct pklcd *lcp;
 char *errstr;
 {
@@ -548,11 +827,11 @@ char *errstr;
                        lcp -> lcd_so -> so_error = ECONNABORTED;
                        soisdisconnecting (lcp -> lcd_so);
                }
                        lcp -> lcd_so -> so_error = ECONNABORTED;
                        soisdisconnecting (lcp -> lcd_so);
                }
-               pk_clear (lcp);
+               pk_clear (lcp, diagnostic, 1);
                break;
 
        case RESET: 
                break;
 
        case RESET: 
-               pk_reset (lcp);
+               pk_reset (lcp, diagnostic);
        }
 }
 
        }
 }
 
@@ -572,13 +851,15 @@ unsigned pr;
                return (PACKET_OK);
        if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
                if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
                return (PACKET_OK);
        if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
                if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
-                       pk_procerror (RESET, lcp, "p(r) flow control error");
+                       pk_procerror (RESET, lcp,
+                               "p(r) flow control error", 2);
                        return (ERROR_PACKET);
                }
        }
        else {
                if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
                        return (ERROR_PACKET);
                }
        }
        else {
                if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
-                       pk_procerror (RESET, lcp, "p(r) flow control error");
+                       pk_procerror (RESET, lcp,
+                               "p(r) flow control error #2", 2);
                        return (ERROR_PACKET);
                }
        }
                        return (ERROR_PACKET);
                }
        }
@@ -587,10 +868,9 @@ unsigned pr;
        if (lcp -> lcd_window_condition == TRUE)
                lcp -> lcd_window_condition = FALSE;
 
        if (lcp -> lcd_window_condition == TRUE)
                lcp -> lcd_window_condition = FALSE;
 
-       if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel))
+       if (so && ((so -> so_snd.sb_flags & SB_WAIT) || 
+                  (so -> so_snd.sb_flags & SB_NOTIFY)))
                sowwakeup (so);
                sowwakeup (so);
-       if (lcp -> lcd_upper)
-               (*lcp -> lcd_upper)(lcp, 0);
 
        return (PACKET_OK);
 }
 
        return (PACKET_OK);
 }
@@ -605,16 +885,16 @@ register struct x25_packet *xp;
 {
        register int type;
 
 {
        register int type;
 
-       if (xp -> fmt_identifier != 1)
+       if (X25GBITS(xp -> bits, fmt_identifier) != 1)
                return (INVALID_PACKET);
                return (INVALID_PACKET);
-
+#ifdef ancient_history
        /* 
         *  Make sure that the logical channel group number is 0.
         *  This restriction may be removed at some later date.
         */
        if (xp -> lc_group_number != 0)
                return (INVALID_PACKET);
        /* 
         *  Make sure that the logical channel group number is 0.
         *  This restriction may be removed at some later date.
         */
        if (xp -> lc_group_number != 0)
                return (INVALID_PACKET);
-
+#endif
        /* 
         *  Test for data packet first.
         */
        /* 
         *  Test for data packet first.
         */
@@ -625,10 +905,14 @@ register struct x25_packet *xp;
         *  Test if flow control packet (RR or RNR).
         */
        if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
         *  Test if flow control packet (RR or RNR).
         */
        if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
-               if (!(xp -> packet_type & RR_PACKET_DESIGNATOR))
+               switch (xp -> packet_type & 0x1f) {
+               case X25_RR:
                        return (RR);
                        return (RR);
-               else
+               case X25_RNR:
                        return (RNR);
                        return (RNR);
+               case X25_REJECT:
+                       return (REJECT);
+               }
 
        /* 
         *  Determine the rest of the packet types.
 
        /* 
         *  Determine the rest of the packet types.
@@ -674,6 +958,10 @@ register struct x25_packet *xp;
                type = RESTART_CONF;
                break;
 
                type = RESTART_CONF;
                break;
 
+       case X25_DIAGNOSTIC:
+               type = DIAG_TYPE;
+               break;
+
        default: 
                type = INVALID_PACKET;
        }
        default: 
                type = INVALID_PACKET;
        }
@@ -690,7 +978,7 @@ struct pkcb *pkp;
 register struct x25_packet *xp;
 {
        register struct x25config *xcp = pkp -> pk_xcp;
 register struct x25_packet *xp;
 {
        register struct x25config *xcp = pkp -> pk_xcp;
-       register int lcn = xp -> logical_channel_number;
+       register int lcn = LCN(xp);
 
        switch (xp -> packet_data) {
        case X25_RESTART_LOCAL_PROCEDURE_ERROR: 
 
        switch (xp -> packet_data) {
        case X25_RESTART_LOCAL_PROCEDURE_ERROR: 
@@ -725,13 +1013,17 @@ struct pkcb *pkp;
 register struct x25_packet *xp;
 {
        register struct pklcd *lcp =
 register struct x25_packet *xp;
 {
        register struct pklcd *lcp =
-                               pkp -> pk_chan[xp -> logical_channel_number];
+                               pkp -> pk_chan[LCN(xp)];
        register int code = xp -> packet_data;
 
        if (code > MAXRESETCAUSE)
                code = 7;       /* EXRNCG */
 
        register int code = xp -> packet_data;
 
        if (code > MAXRESETCAUSE)
                code = 7;       /* EXRNCG */
 
-       lcp -> lcd_so -> so_error = Reset_cause[code];
+       pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x",
+                       xp -> packet_data, 4[(u_char *)xp]);
+                       
+       if (lcp -> lcd_so)
+               lcp -> lcd_so -> so_error = Reset_cause[code];
 }
 
 #define MAXCLEARCAUSE  25
 }
 
 #define MAXCLEARCAUSE  25
@@ -751,12 +1043,13 @@ struct pkcb *pkp;
 register struct x25_packet *xp;
 {
        register struct pklcd *lcp =
 register struct x25_packet *xp;
 {
        register struct pklcd *lcp =
-               pkp -> pk_chan[xp -> logical_channel_number];
+               pkp -> pk_chan[LCN(xp)];
        register int code = xp -> packet_data;
 
        if (code > MAXCLEARCAUSE)
                code = 5;       /* EXRNCG */
        register int code = xp -> packet_data;
 
        if (code > MAXCLEARCAUSE)
                code = 5;       /* EXRNCG */
-       lcp -> lcd_so -> so_error = Clear_cause[code];
+       if (lcp -> lcd_so)
+               lcp -> lcd_so -> so_error = Clear_cause[code];
 }
 
 char *
 }
 
 char *
@@ -774,12 +1067,12 @@ char *fmt;
 {
 
        if (lcn)
 {
 
        if (lcn)
-               if (pkcbhead -> pk_next)
+               if (!PQEMPTY)
                        printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
                else
                        printf ("X.25: lcn %d: ", lcn);
        else
                        printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
                else
                        printf ("X.25: lcn %d: ", lcn);
        else
-               if (pkcbhead -> pk_next)
+               if (!PQEMPTY)
                        printf ("X.25(%s): ", format_ntn (xcp));
                else
                        printf ("X.25: ");
                        printf ("X.25(%s): ", format_ntn (xcp));
                else
                        printf ("X.25: ");
@@ -788,66 +1081,63 @@ char *fmt;
        printf ("\n");
 }
 
        printf ("\n");
 }
 
-pk_ifattach(ia, lloutput, llnext)
-register struct x25_ifaddr *ia;
-int (*lloutput)();
-caddr_t llnext;
-{
-       /* this is here because you can't include both pk_var and hd_var */
-       /* this will probably be replace by a streams gluing mechanism */
-       ia -> ia_pkcb.pk_lloutput = lloutput;
-       ia -> ia_pkcb.pk_llnext = llnext;
-}
-
-pk_fragment(lcp, m0, qbit, mbit, wait)
+pk_fragment (lcp, m0, qbit, mbit, wait)
 struct mbuf *m0;
 register struct pklcd *lcp;
 {
        register struct mbuf *m = m0;
        register struct x25_packet *xp;
        register struct sockbuf *sb;
 struct mbuf *m0;
 register struct pklcd *lcp;
 {
        register struct mbuf *m = m0;
        register struct x25_packet *xp;
        register struct sockbuf *sb;
-       struct mbuf *next = 0;
+       struct mbuf *head = 0, *next, **mp = &head, *m_split ();
        int totlen, psize = 1 << (lcp -> lcd_packetsize);
 
        if (m == 0)
        int totlen, psize = 1 << (lcp -> lcd_packetsize);
 
        if (m == 0)
-               return;
-       if (m->m_flags & M_PKTHDR == 0)
-               panic("pk_fragment");
+               return 0;
+       if (m -> m_flags & M_PKTHDR == 0)
+               panic ("pk_fragment");
        totlen = m -> m_pkthdr.len;
        totlen = m -> m_pkthdr.len;
+       m -> m_act = 0;
        sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
        do {
                if (totlen > psize) {
        sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
        do {
                if (totlen > psize) {
-                       next = m;
-                       m = m_copym(m, 0, psize, wait);
-                       if (m == 0)
+                       if ((next = m_split (m, psize, wait)) == 0)
                                goto abort;
                                goto abort;
-                       m_adj(next, psize);
                        totlen -= psize;
                        totlen -= psize;
-               }
+               } else
+                       next = 0;
                M_PREPEND(m, PKHEADERLN, wait);
                if (m == 0)
                        goto abort;
                M_PREPEND(m, PKHEADERLN, wait);
                if (m == 0)
                        goto abort;
-               xp = mtod(m, struct x25_packet *);
+               *mp = m;
+               mp = & m -> m_act;
+               *mp = 0;
+               xp = mtod (m, struct x25_packet *);
                0[(char *)xp] = 0;
                if (qbit)
                0[(char *)xp] = 0;
                if (qbit)
-                       xp -> q_bit = qbit;
-               xp -> fmt_identifier = 1;
-               xp -> logical_channel_number = lcp -> lcd_lcn;
+                       X25SBITS(xp -> bits, q_bit, 1);
+               if (lcp -> lcd_flags & X25_DBIT)
+                       X25SBITS(xp -> bits, d_bit, 1);
+               X25SBITS(xp -> bits, fmt_identifier, 1);
                xp -> packet_type = X25_DATA;
                xp -> packet_type = X25_DATA;
-               if (next || mbit)
-                       MBIT(xp) = 1;
-               m->m_act = next;
+               SET_LCN(xp, lcp -> lcd_lcn);
+               if (next || (mbit && (totlen == psize ||
+                                     (lcp -> lcd_flags & X25_DBIT))))
+                       SMBIT(xp, 1);
        } while (m = next);
        } while (m = next);
-       for (m = m0; m; m = next) {
+       for (m = head; m; m = next) {
                next = m -> m_act;
                m -> m_act = 0;
                next = m -> m_act;
                m -> m_act = 0;
-               sbappendrecord(sb, m);
+               sbappendrecord (sb, m);
        }
        return 0;
 abort:
        }
        return 0;
 abort:
-       for (m = m0; m; m = next) {
+       if (wait)
+               panic ("pk_fragment null mbuf after wait");
+       if (next)
+               m_freem (next);
+       for (m = head; m; m = next) {
                next = m -> m_act;
                next = m -> m_act;
-               m_freem(m);
+               m_freem (m);
        }
        return ENOBUFS;
 }
        }
        return ENOBUFS;
 }