date and time created 88/12/14 15:29:22 by sklower
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Thu, 15 Dec 1988 07:29:22 +0000 (23:29 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Thu, 15 Dec 1988 07:29:22 +0000 (23:29 -0800)
SCCS-vsn: sys/netiso/clnp_debug.c 7.1
SCCS-vsn: sys/netiso/clnp_er.c 7.1

usr/src/sys/netiso/clnp_debug.c [new file with mode: 0644]
usr/src/sys/netiso/clnp_er.c [new file with mode: 0644]

diff --git a/usr/src/sys/netiso/clnp_debug.c b/usr/src/sys/netiso/clnp_debug.c
new file mode 100644 (file)
index 0000000..2f47c47
--- /dev/null
@@ -0,0 +1,341 @@
+/***********************************************************
+               Copyright IBM Corporation 1987
+
+                      All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+/* $Header: clnp_debug.c,v 4.2 88/06/29 14:58:34 hagens Exp $ */
+/* $Source: /usr/argo/sys/netargo/RCS/clnp_debug.c,v $ */
+
+#ifndef lint
+static char *rcsid = "$Header: clnp_debug.c,v 4.2 88/06/29 14:58:34 hagens Exp $";
+#endif lint
+
+#include "../h/types.h"
+#include "../h/param.h"
+#include "../h/mbuf.h"
+#include "../h/domain.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/socketvar.h"
+#include "../h/errno.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "../netiso/iso.h"
+#include "../netiso/clnp.h"
+#include "../netiso/clnp_stat.h"
+#include "../netiso/argo_debug.h"
+
+#ifdef ARGO_DEBUG
+
+#ifdef TESTDEBUG
+#ifdef notdef
+struct addr_37 u_37 = {
+       {0x00, 0x02, 0x00, 0x10, 0x20, 0x30, 0x35}, 
+       {0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, 0x90}
+};
+struct addr_osinet u_osinet = {
+       {0x00, 0x04},
+       {0x00, 0x02, 0x00, 0x01, 0x23, 0x42, 0x78, 0x20, 0x01, 0x05, 0x00}
+};
+#endif notdef
+struct addr_rfc986 u_rfc986 = {
+       {0x00, 0x06},
+       {0x01, 0xc0, 0x0c, 0x0c, 0xab, 0x11}
+};
+struct addr_rfc986 u_bad = {
+       {0x00, 0x01},
+       {0x01, 0xc0, 0x0c, 0x0c, 0xab, 0x11}
+};
+#include <stdio.h>
+main()
+{
+       struct iso_addr a;
+
+       a.isoa_afi = AFI_37;
+       a.isoa_u.addr_37 = u_37;
+       a.isoa_len = 17;
+       printf("type 37: %s\n", clnp_iso_addrp(&a));
+
+       a.isoa_afi = AFI_OSINET;
+       a.isoa_u.addr_osinet = u_osinet;
+       a.isoa_len = 14;
+       printf("type osinet: %s\n", clnp_iso_addrp(&a));
+
+       a.isoa_afi = AFI_RFC986;
+       a.isoa_u.addr_rfc986 = u_rfc986;
+       a.isoa_len = 9;
+       printf("type rfc986: %s\n", clnp_iso_addrp(&a));
+
+       a.isoa_afi = 12;
+       a.isoa_u.addr_rfc986 = u_rfc986;
+       a.isoa_len = 9;
+       printf("type bad afi: %s\n", clnp_iso_addrp(&a));
+
+       a.isoa_afi = AFI_RFC986;
+       a.isoa_u.addr_rfc986 = u_bad;
+       a.isoa_len = 9;
+       printf("type bad idi: %s\n", clnp_iso_addrp(&a));
+}
+#endif TESTDEBUG
+
+unsigned int   clnp_debug;
+static char letters[] = "0123456789abcdef";
+
+/*
+ *     Print buffer in hex, return addr of where we left off.
+ *     Do not null terminate.
+ */
+char *
+clnp_hexp(src, len, where)
+char   *src;           /* src of data to print */
+int            len;            /* lengthof src */
+char   *where;         /* where to put data */
+{
+       int i;
+
+       for (i=0; i<len; i++) {
+               *where++ = letters[src[i] >> 4];
+               *where++ = letters[src[i] & 0x0f];
+       }
+       return where;
+}
+
+/*
+ *     Return a ptr to a human readable form of an iso addr 
+ */
+static char iso_addr_b[50];
+#define        DELIM   '.';
+
+char *
+clnp_iso_addrp(isoa)
+struct iso_addr *isoa;
+{
+       char    *cp;
+
+       /* print length */
+       clnp_sprintf(iso_addr_b, "[%d] ", isoa->isoa_len);
+
+       /* set cp to end of what we have */
+       cp = iso_addr_b;
+       while (*cp)
+               cp++;
+
+       /* print afi */
+       cp = clnp_hexp(&isoa->isoa_afi, 1, cp);
+       *cp++ = DELIM;
+
+       /* print type specific part */
+       switch(isoa->isoa_afi) {
+               case AFI_37:
+                       cp = clnp_hexp(isoa->t37_idi, ADDR37_IDI_LEN, cp);
+                       *cp++ = DELIM;
+                       cp = clnp_hexp(isoa->t37_dsp, ADDR37_DSP_LEN, cp);
+                       break;
+               
+/*             case AFI_OSINET:*/
+               case AFI_RFC986: {
+                       u_short idi;
+
+                       /* osinet and rfc986 have idi in the same place */
+                       /* print idi */
+                       cp = clnp_hexp(isoa->rfc986_idi, ADDROSINET_IDI_LEN, cp);
+                       *cp++ = DELIM;
+                       CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi);
+
+                       if (idi == IDI_OSINET) {
+                               struct ovl_osinet *oosi = (struct ovl_osinet *)isoa;
+                               cp = clnp_hexp(oosi->oosi_orgid, OVLOSINET_ORGID_LEN, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(oosi->oosi_snetid, OVLOSINET_SNETID_LEN, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(oosi->oosi_snpa, OVLOSINET_SNPA_LEN, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(oosi->oosi_nsap, OVLOSINET_NSAP_LEN, cp);
+                       } else if (idi == IDI_RFC986) {
+                               struct ovl_rfc986 *o986 = (struct ovl_rfc986 *)isoa;
+                               cp = clnp_hexp(&o986->o986_vers, 1, cp);
+                               *cp++ = DELIM;
+#ifdef  vax
+                               clnp_sprintf(cp, "%d.%d.%d.%d.%d", 
+                               o986->o986_inetaddr[0] & 0xff,
+                               o986->o986_inetaddr[1] & 0xff,
+                               o986->o986_inetaddr[2] & 0xff,
+                               o986->o986_inetaddr[3] & 0xff,
+                               o986->o986_upid & 0xff);
+                               return(iso_addr_b);
+#else
+                               cp = clnp_hexp(&o986->o986_inetaddr[0], 1, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(&o986->o986_inetaddr[1], 1, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(&o986->o986_inetaddr[2], 1, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(&o986->o986_inetaddr[3], 1, cp);
+                               *cp++ = DELIM;
+                               cp = clnp_hexp(&o986->o986_upid, 1, cp);
+#endif vax
+                       }
+                       
+               } break;
+
+               default:
+                       *cp++ = '?';
+                       break;
+       }
+       *cp = (char)0;
+       
+       return(iso_addr_b);
+}
+
+#define        MAX_COLUMNS     8
+/*
+ *     Dump the buffer to the screen in a readable format. Format is:
+ *
+ *             hex/dec  where hex is the hex format, dec is the decimal format.
+ *             columns of hex/dec numbers will be printed, followed by the
+ *             character representations (if printable).
+ */
+dump_buf(buf, len)
+char   *buf;
+int            len;
+{
+       int             i,j;
+
+       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]);
+                       } else {
+                               printf("        ");
+                       }
+               }
+
+               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);
+                               else
+                                       printf(".");
+                       }
+               }
+               printf("\n");
+       }
+}
+
+
+/*
+ *             The following hacks are a trimmed down version of sprintf.
+ */
+/*VARARGS1*/
+clnp_sprintf(buf, fmt, x1, x2)
+       register char *fmt;
+       unsigned x1, x2;
+{
+       clnp_prf(buf, fmt, &x1, 0);
+}
+
+clnp_prf(buf, fmt, adx, dummy)
+       register char   *buf;
+       register char *fmt;
+       register unsigned int *adx;
+       int     dummy;
+{
+       register int b, c, i;
+       char *s;
+       char *clnp_printn();
+
+loop:
+       while ((c = *fmt++) != '%') {
+               if(c == '\0') {
+                       *buf++ = (char)0;
+                       return;
+               }
+               *buf++ = c;
+       }
+again:
+       c = *fmt++;
+       switch (c) {
+       case 'l':
+               goto again;
+       case 'x': case 'X':
+               b = 16;
+               goto number;
+       case 'd': case 'D':
+       case 'u':               /* what a joke */
+               b = 10;
+               goto number;
+       case 'o': case 'O':
+               b = 8;
+number:
+               buf = clnp_printn((unsigned long)*adx, b, buf);
+               break;
+       case 'c':
+               b = *adx;
+               for (i = 24; i >= 0; i -= 8)
+                       if (c = (b >> i) & 0x7f)
+                               *buf++ = c;
+               break;
+
+       case 's':
+               s = (char *)*adx;
+               while (*s)
+                       *buf++ = *s++;
+               break;
+
+       case '%':
+               *buf++ = '%';
+               break;
+       }
+       adx++;
+       goto loop;
+}
+
+char *
+clnp_printn(n, b, where)
+unsigned long  n;
+int            b;
+char   *where;
+{
+       char prbuf[11];
+       register char *cp;
+
+       if (b == 10 && (int)n < 0) {
+               *where++ = '-';
+               n = (unsigned)(-(int)n);
+       }
+       cp = prbuf;
+       do {
+               *cp++ = "0123456789abcdef"[n%b];
+               n /= b;
+       } while (n);
+       do {
+               *where++ = *--cp;
+       } while (cp > prbuf);
+       return(where);
+}
+#endif ARGO_DEBUG
diff --git a/usr/src/sys/netiso/clnp_er.c b/usr/src/sys/netiso/clnp_er.c
new file mode 100644 (file)
index 0000000..71d0324
--- /dev/null
@@ -0,0 +1,352 @@
+/***********************************************************
+               Copyright IBM Corporation 1987
+
+                      All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+/* $Header: clnp_er.c,v 4.4 88/09/10 18:31:10 hagens Exp $ */
+/* $Source: /usr/argo/sys/netiso/RCS/clnp_er.c,v $ */
+
+#ifndef lint
+static char *rcsid = "$Header: clnp_er.c,v 4.4 88/09/10 18:31:10 hagens Exp $";
+#endif lint
+
+#ifdef ISO
+
+#include "../h/types.h"
+#include "../h/param.h"
+#include "../h/mbuf.h"
+#include "../h/domain.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/socketvar.h"
+#include "../h/errno.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "../netiso/iso.h"
+#include "../netiso/clnp.h"
+#include "../netiso/clnp_stat.h"
+#include "../netiso/argo_debug.h"
+
+static struct clnp_fixed er_template = {
+       ISO8473_CLNP,   /* network identifier */
+       0,                              /* length */
+       ISO8473_V1,             /* version */
+       CLNP_TTL,               /* ttl */
+#if BYTE_ORDER == LITTLE_ENDIAN
+       CLNP_ER,                /* type */
+       0,                              /* error report */
+       0,                              /* more segments */
+       0,                              /* segmentation permitted */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+       0,                              /* segmentation permitted */
+       0,                              /* more segments */
+       0,                              /* error report */
+       CLNP_ER,                /* type */
+#endif
+       0,                              /* segment length */
+       0                               /* checksum */
+};
+
+/*
+ * FUNCTION:           clnp_er_input
+ *
+ * PURPOSE:                    Process an ER pdu.
+ *
+ * RETURNS:                    
+ *
+ * SIDE EFFECTS:       
+ *
+ * NOTES:                      
+ */
+clnp_er_input(m, src, reason)
+struct mbuf            *m;             /* ptr to packet itself */
+struct iso_addr        *src;   /* ptr to src of er */
+char                   reason; /* reason code of er */
+{
+       int     cmd = -1;
+       extern u_char clnp_protox[];
+
+       IFDEBUG(D_CTLINPUT)
+               printf("clnp_er_input: m x%x, src %s, reason x%x\n", m, 
+                       clnp_iso_addrp(src), reason);
+       ENDDEBUG
+
+       INCSTAT(cns_errcvd);
+
+       switch (reason) {
+               case GEN_NOREAS:
+               case GEN_PROTOERR:
+                       INCSTAT(er_protoerr);
+                       break;
+               case GEN_BADCSUM:               
+                       cmd = PRC_PARAMPROB;
+                       INCSTAT(er_badcsum);
+                       break;
+               case GEN_CONGEST:               
+                       cmd = PRC_QUENCH;
+                       INCSTAT(er_congest);
+                       break;
+               case GEN_HDRSYNTAX:             
+                       cmd = PRC_PARAMPROB;
+                       INCSTAT(er_protoerr);
+                       break;
+               case GEN_SEGNEEDED:             
+                       cmd = PRC_UNREACH_NEEDFRAG; 
+                       INCSTAT(er_segneeded);
+                       break;
+               case GEN_INCOMPLETE:    
+                       cmd = PRC_PARAMPROB;            
+                       INCSTAT(er_reassfail);
+                       break;
+               case GEN_DUPOPT:                
+                       cmd = PRC_PARAMPROB;            
+                       INCSTAT(er_protoerr);
+                       break;
+               case ADDR_DESTUNREACH:  
+                       cmd = PRC_UNREACH_HOST;         
+                       INCSTAT(er_dstunreach);
+                       break;
+               case ADDR_DESTUNKNOWN:  
+                       cmd = PRC_UNREACH_PROTOCOL; 
+                       INCSTAT(er_dstunreach);
+                       break;
+               case SRCRT_UNSPECERR:
+               case SRCRT_SYNTAX:
+               case SRCRT_UNKNOWNADDR:
+               case SRCRT_BADPATH:
+                       cmd = PRC_UNREACH_SRCFAIL;
+                       INCSTAT(er_srcrterr);
+                       break;
+               case TTL_EXPTRANSIT:    
+                       cmd = PRC_TIMXCEED_INTRANS;     
+                       INCSTAT(er_ttlexpired);
+                       break;
+               case TTL_EXPREASS:              
+                       cmd = PRC_TIMXCEED_REASS;       
+                       INCSTAT(er_ttlexpired);
+                       break;
+               case DISC_UNSUPPOPT:
+               case DISC_UNSUPPVERS:
+               case DISC_UNSUPPSECURE:
+               case DISC_UNSUPPSRCRT:
+               case DISC_UNSUPPRECRT:
+                       cmd = PRC_PARAMPROB; 
+                       INCSTAT(er_unsupported); 
+                       break;
+               case REASS_INTERFERE:   
+                       cmd = PRC_TIMXCEED_REASS;
+                       INCSTAT(er_reassfail);
+                       break;
+       }
+
+       if (cmd >= 0)
+               (*isosw[clnp_protox[ISOPROTO_TP]].pr_ctlinput)(cmd, src);
+
+       m_freem(m);
+}
+
+/*
+ * FUNCTION:           clnp_discard
+ *
+ * PURPOSE:                    Discard a clnp datagram
+ *
+ * RETURNS:                    nothing
+ *
+ * SIDE EFFECTS:       Will emit an ER pdu if possible
+ *
+ * NOTES:                      This code assumes that we have previously tried to pull
+ *                                     up the header of the datagram into one mbuf.
+ */
+clnp_discard(m, reason)
+struct mbuf    *m;             /* header of packet to discard */
+char                                   reason; /* reason for discard */
+{
+       IFDEBUG(D_DISCARD)
+               printf("clnp_discard: m x%x, reason x%x\n", m, reason);
+       ENDDEBUG
+
+       if (m != NULL) {
+               if (m->m_len >= sizeof(struct clnp_fixed)) {
+                       register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
+
+                       if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_err_ok)) {
+                               clnp_emit_er(m, reason);
+                               return;
+                       }
+               }
+               m_freem(m);
+       }
+}
+
+/*
+ * FUNCTION:           clnp_emit_er
+ *
+ * PURPOSE:                    Send an ER pdu.
+ *                                     The src of the of the ER pdu is the host that is sending
+ *                                     the ER (ie. us), *not* the original destination of the
+ *                                     packet.
+ *
+ * RETURNS:                    nothing
+ *
+ * SIDE EFFECTS:       
+ *
+ * NOTES:                      Takes responsibility for freeing mbuf passed
+ *                                     This function may be called with a packet that
+ *                                     was created by us; in this case, do not send
+ *                                     an ER.
+ */
+clnp_emit_er(m, reason)
+struct mbuf    *m;             /* header of packet to discard */
+char                                   reason; /* reason for discard */
+{
+       register struct clnp_fixed      *clnp = mtod(m, struct clnp_fixed *);
+       register struct clnp_fixed      *er;
+       struct route                            route;
+       struct ifnet                            *ifp;
+       struct sockaddr                         *first_hop;
+       struct iso_addr                         src, dst, *our_addr;
+       caddr_t                                         hoff, hend;
+       int                                                     total_len;              /* total len of dg */
+       struct mbuf                             *m0;                    /* contains er pdu hdr */
+/*     struct clnp_optidx                      *oidx;   index for options on orig pkt */
+
+       IFDEBUG(D_DISCARD)
+               printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
+       ENDDEBUG
+
+       bzero((caddr_t)&route, sizeof(route));
+
+       /*
+        *      If header length is incorrect, or entire header is not contained
+        *      in this mbuf, we punt
+        */
+       if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
+               (clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
+               (clnp->cnf_hdr_len > m->m_len))
+               goto bad;
+       
+       /* extract src, dest address */
+       hend = (caddr_t)clnp + clnp->cnf_hdr_len;
+       hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
+       CLNP_EXTRACT_ADDR(dst, hoff, hend);
+       if (hoff == (caddr_t)0) {
+               goto bad;
+       }
+       CLNP_EXTRACT_ADDR(src, hoff, hend);
+       if (hoff == (caddr_t)0) {
+               goto bad;
+       }
+       
+       /*
+        *      Do not send ER if we generated the packet.
+        */
+       if (clnp_ours(&src))
+               goto bad;
+
+       /* 
+        *      Trim mbuf to hold only the header.
+        *      This mbuf will be the 'data' of the er pdu
+        */
+       if (m->m_next != NULL) {
+               m_freem(m->m_next);
+               m->m_next = NULL;
+       }
+
+       if (m->m_len > clnp->cnf_hdr_len)
+               m_adj(m, -(m->m_len - clnp->cnf_hdr_len));
+
+       /* route er pdu: note we send pkt to src of original packet  */
+       if (clnp_route(&src, &route, /* flags */0, &first_hop, &ifp) != 0)
+               goto bad;
+
+       /* compute our address based upon firsthop/ifp */
+       our_addr = 
+                       clnp_srcaddr(ifp, &((struct sockaddr_iso *)first_hop)->siso_addr);
+       if (our_addr == NULL)
+               goto bad;
+
+       IFDEBUG(D_DISCARD)
+               printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
+               printf(" from %s\n", clnp_iso_addrp(our_addr));
+       ENDDEBUG
+
+       IFDEBUG(D_DISCARD)
+               printf("clnp_emit_er: packet routed to %s\n", 
+                       clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
+       ENDDEBUG
+
+       /* allocate mbuf for er pdu header: punt on no space */
+       MGET(m0, M_DONTWAIT, MT_HEADER);
+       if (m0 == 0)
+               goto bad;
+       
+       m0->m_next = m;
+       er = mtod(m0, struct clnp_fixed *);
+       *er = er_template;
+
+       /* setup src/dst on er pdu */
+       /* NOTE REVERSAL OF SRC/DST */
+       hoff = (caddr_t)er + sizeof(struct clnp_fixed);
+       CLNP_INSERT_ADDR(hoff, &src);
+       CLNP_INSERT_ADDR(hoff, our_addr);
+
+       /*
+        *      TODO: if complete src rt was specified, then reverse path, and
+        *      copy into er as option.
+        */
+
+       /* add er option */
+       *hoff++ = CLNPOVAL_ERREAS;      /* code */
+       *hoff++ = 2;                            /* length */
+       *hoff++ = reason;                       /* discard reason */
+       *hoff++ = 0;                            /* error localization = not specified */
+
+       /* set length */
+       er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
+       total_len = m0->m_len + m->m_len;
+       HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
+
+       /* compute checksum (on header only) */
+       iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
+
+       /* trim packet if too large for interface */
+       if (total_len > ifp->if_mtu)
+               m_adj(m0, -(total_len - ifp->if_mtu));
+       
+       /* send packet */
+       (void) (*ifp->if_output)(ifp, m0, first_hop);
+       goto done;
+
+bad:
+       m_freem(m);
+
+done:
+       /* free route if it is a temp */
+       if (route.ro_rt != NULL)
+               RTFREE(route.ro_rt);
+}
+#endif ISO