print-decnet.c revision 75115
1/*
2 * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static const char rcsid[] =
24    "@(#) $Header: /tcpdump/master/tcpdump/print-decnet.c,v 1.30 2000/09/28 06:42:57 guy Exp $ (LBL)";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <sys/param.h>
32#include <sys/time.h>
33#include <sys/socket.h>
34
35struct mbuf;
36struct rtentry;
37
38#ifdef	HAVE_LIBDNET
39#include <netdnet/dnetdb.h>
40#endif
41
42#include <ctype.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47
48#include "decnet.h"
49#include "extract.h"
50#include "interface.h"
51#include "addrtoname.h"
52
53/* Forwards */
54static void print_decnet_ctlmsg(const union routehdr *, u_int);
55static void print_t_info(int);
56static void print_l1_routes(const char *, u_int);
57static void print_l2_routes(const char *, u_int);
58static void print_i_info(int);
59static void print_elist(const char *, u_int);
60static void print_nsp(const u_char *, u_int);
61static void print_reason(int);
62#ifdef	PRINT_NSPDATA
63static void pdata(u_char *, int);
64#endif
65
66#ifdef	HAVE_LIBDNET
67extern char *dnet_htoa(struct dn_naddr *);
68#endif
69
70void
71decnet_print(register const u_char *ap, register u_int length,
72	     register u_int caplen)
73{
74	static union routehdr rhcopy;
75	register union routehdr *rhp = &rhcopy;
76	register int mflags;
77	int dst, src, hops;
78	u_int rhlen, nsplen, pktlen;
79	const u_char *nspp;
80
81	if (length < sizeof(struct shorthdr)) {
82		(void)printf("[|decnet]");
83		return;
84	}
85
86	pktlen = EXTRACT_LE_16BITS(ap);
87
88	rhlen = min(length, caplen);
89	rhlen = min(rhlen, sizeof(*rhp));
90	memcpy((char *)rhp, (char *)&(ap[sizeof(short)]), rhlen);
91
92	mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
93
94	if (mflags & RMF_PAD) {
95	    /* pad bytes of some sort in front of message */
96	    u_int padlen = mflags & RMF_PADMASK;
97	    if (vflag)
98		(void) printf("[pad:%d] ", padlen);
99	    ap += padlen;
100	    length -= padlen;
101	    caplen -= padlen;
102	    rhlen = min(length, caplen);
103	    rhlen = min(rhlen, sizeof(*rhp));
104	    memcpy((char *)rhp, (char *)&(ap[sizeof(short)]), rhlen);
105	    mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
106	}
107
108	if (mflags & RMF_FVER) {
109		(void) printf("future-version-decnet");
110		default_print(ap, length);
111		return;
112	}
113
114	/* is it a control message? */
115	if (mflags & RMF_CTLMSG) {
116		print_decnet_ctlmsg(rhp, min(length, caplen));
117		return;
118	}
119
120	switch (mflags & RMF_MASK) {
121	case RMF_LONG:
122	    dst =
123		EXTRACT_LE_16BITS(rhp->rh_long.lg_dst.dne_remote.dne_nodeaddr);
124	    src =
125		EXTRACT_LE_16BITS(rhp->rh_long.lg_src.dne_remote.dne_nodeaddr);
126	    hops = EXTRACT_LE_8BITS(rhp->rh_long.lg_visits);
127	    nspp = &(ap[sizeof(short) + sizeof(struct longhdr)]);
128	    nsplen = min((length - sizeof(struct longhdr)),
129			 (caplen - sizeof(struct longhdr)));
130	    break;
131	case RMF_SHORT:
132	    dst = EXTRACT_LE_16BITS(rhp->rh_short.sh_dst);
133	    src = EXTRACT_LE_16BITS(rhp->rh_short.sh_src);
134	    hops = (EXTRACT_LE_8BITS(rhp->rh_short.sh_visits) & VIS_MASK)+1;
135	    nspp = &(ap[sizeof(short) + sizeof(struct shorthdr)]);
136	    nsplen = min((length - sizeof(struct shorthdr)),
137			 (caplen - sizeof(struct shorthdr)));
138	    break;
139	default:
140	    (void) printf("unknown message flags under mask");
141	    default_print((u_char *)ap, length);
142	    return;
143	}
144
145	(void)printf("%s > %s %d ",
146			dnaddr_string(src), dnaddr_string(dst), pktlen);
147	if (vflag) {
148	    if (mflags & RMF_RQR)
149		(void)printf("RQR ");
150	    if (mflags & RMF_RTS)
151		(void)printf("RTS ");
152	    if (mflags & RMF_IE)
153		(void)printf("IE ");
154	    (void)printf("%d hops ", hops);
155	}
156
157	print_nsp(nspp, nsplen);
158}
159
160static void
161print_decnet_ctlmsg(register const union routehdr *rhp, u_int length)
162{
163	int mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
164	register union controlmsg *cmp = (union controlmsg *)rhp;
165	int src, dst, info, blksize, eco, ueco, hello, other, vers;
166	etheraddr srcea, rtea;
167	int priority;
168	char *rhpx = (char *)rhp;
169
170	switch (mflags & RMF_CTLMASK) {
171	case RMF_INIT:
172	    (void)printf("init ");
173	    src = EXTRACT_LE_16BITS(cmp->cm_init.in_src);
174	    info = EXTRACT_LE_8BITS(cmp->cm_init.in_info);
175	    blksize = EXTRACT_LE_16BITS(cmp->cm_init.in_blksize);
176	    vers = EXTRACT_LE_8BITS(cmp->cm_init.in_vers);
177	    eco = EXTRACT_LE_8BITS(cmp->cm_init.in_eco);
178	    ueco = EXTRACT_LE_8BITS(cmp->cm_init.in_ueco);
179	    hello = EXTRACT_LE_16BITS(cmp->cm_init.in_hello);
180	    print_t_info(info);
181	    (void)printf(
182		"src %sblksize %d vers %d eco %d ueco %d hello %d",
183			dnaddr_string(src), blksize, vers, eco, ueco,
184			hello);
185	    break;
186	case RMF_VER:
187	    (void)printf("verification ");
188	    src = EXTRACT_LE_16BITS(cmp->cm_ver.ve_src);
189	    other = EXTRACT_LE_8BITS(cmp->cm_ver.ve_fcnval);
190	    (void)printf("src %s fcnval %o", dnaddr_string(src), other);
191	    break;
192	case RMF_TEST:
193	    (void)printf("test ");
194	    src = EXTRACT_LE_16BITS(cmp->cm_test.te_src);
195	    other = EXTRACT_LE_8BITS(cmp->cm_test.te_data);
196	    (void)printf("src %s data %o", dnaddr_string(src), other);
197	    break;
198	case RMF_L1ROUT:
199	    (void)printf("lev-1-routing ");
200	    src = EXTRACT_LE_16BITS(cmp->cm_l1rou.r1_src);
201	    (void)printf("src %s ", dnaddr_string(src));
202	    print_l1_routes(&(rhpx[sizeof(struct l1rout)]),
203				length - sizeof(struct l1rout));
204	    break;
205	case RMF_L2ROUT:
206	    (void)printf("lev-2-routing ");
207	    src = EXTRACT_LE_16BITS(cmp->cm_l2rout.r2_src);
208	    (void)printf("src %s ", dnaddr_string(src));
209	    print_l2_routes(&(rhpx[sizeof(struct l2rout)]),
210				length - sizeof(struct l2rout));
211	    break;
212	case RMF_RHELLO:
213	    (void)printf("router-hello ");
214	    vers = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_vers);
215	    eco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_eco);
216	    ueco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_ueco);
217	    memcpy((char *)&srcea, (char *)&(cmp->cm_rhello.rh_src),
218		sizeof(srcea));
219	    src = EXTRACT_LE_16BITS(srcea.dne_remote.dne_nodeaddr);
220	    info = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_info);
221	    blksize = EXTRACT_LE_16BITS(cmp->cm_rhello.rh_blksize);
222	    priority = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_priority);
223	    hello = EXTRACT_LE_16BITS(cmp->cm_rhello.rh_hello);
224	    print_i_info(info);
225	    (void)printf(
226	    "vers %d eco %d ueco %d src %s blksize %d pri %d hello %d",
227			vers, eco, ueco, dnaddr_string(src),
228			blksize, priority, hello);
229	    print_elist(&(rhpx[sizeof(struct rhellomsg)]),
230				length - sizeof(struct rhellomsg));
231	    break;
232	case RMF_EHELLO:
233	    (void)printf("endnode-hello ");
234	    vers = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_vers);
235	    eco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_eco);
236	    ueco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_ueco);
237	    memcpy((char *)&srcea, (char *)&(cmp->cm_ehello.eh_src),
238		sizeof(srcea));
239	    src = EXTRACT_LE_16BITS(srcea.dne_remote.dne_nodeaddr);
240	    info = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_info);
241	    blksize = EXTRACT_LE_16BITS(cmp->cm_ehello.eh_blksize);
242	    /*seed*/
243	    memcpy((char *)&rtea, (char *)&(cmp->cm_ehello.eh_router),
244		sizeof(rtea));
245	    dst = EXTRACT_LE_16BITS(rtea.dne_remote.dne_nodeaddr);
246	    hello = EXTRACT_LE_16BITS(cmp->cm_ehello.eh_hello);
247	    other = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_data);
248	    print_i_info(info);
249	    (void)printf(
250	"vers %d eco %d ueco %d src %s blksize %d rtr %s hello %d data %o",
251			vers, eco, ueco, dnaddr_string(src),
252			blksize, dnaddr_string(dst), hello, other);
253	    break;
254
255	default:
256	    (void)printf("unknown control message");
257	    default_print((u_char *)rhp, length);
258	    break;
259	}
260}
261
262static void
263print_t_info(int info)
264{
265	int ntype = info & 3;
266	switch (ntype) {
267	case 0: (void)printf("reserved-ntype? "); break;
268	case TI_L2ROUT: (void)printf("l2rout "); break;
269	case TI_L1ROUT: (void)printf("l1rout "); break;
270	case TI_ENDNODE: (void)printf("endnode "); break;
271	}
272	if (info & TI_VERIF)
273	    (void)printf("verif ");
274	if (info & TI_BLOCK)
275	    (void)printf("blo ");
276}
277
278static void
279print_l1_routes(const char *rp, u_int len)
280{
281	int count;
282	int id;
283	int info;
284
285	/* The last short is a checksum */
286	while (len > (3 * sizeof(short))) {
287	    count = EXTRACT_LE_16BITS(rp);
288	    if (count > 1024)
289		return;	/* seems to be bogus from here on */
290	    rp += sizeof(short);
291	    len -= sizeof(short);
292	    id = EXTRACT_LE_16BITS(rp);
293	    rp += sizeof(short);
294	    len -= sizeof(short);
295	    info = EXTRACT_LE_16BITS(rp);
296	    rp += sizeof(short);
297	    len -= sizeof(short);
298	    (void)printf("{ids %d-%d cost %d hops %d} ", id, id + count,
299			    RI_COST(info), RI_HOPS(info));
300	}
301}
302
303static void
304print_l2_routes(const char *rp, u_int len)
305{
306	int count;
307	int area;
308	int info;
309
310	/* The last short is a checksum */
311	while (len > (3 * sizeof(short))) {
312	    count = EXTRACT_LE_16BITS(rp);
313	    if (count > 1024)
314		return;	/* seems to be bogus from here on */
315	    rp += sizeof(short);
316	    len -= sizeof(short);
317	    area = EXTRACT_LE_16BITS(rp);
318	    rp += sizeof(short);
319	    len -= sizeof(short);
320	    info = EXTRACT_LE_16BITS(rp);
321	    rp += sizeof(short);
322	    len -= sizeof(short);
323	    (void)printf("{areas %d-%d cost %d hops %d} ", area, area + count,
324			    RI_COST(info), RI_HOPS(info));
325	}
326}
327
328static void
329print_i_info(int info)
330{
331	int ntype = info & II_TYPEMASK;
332	switch (ntype) {
333	case 0: (void)printf("reserved-ntype? "); break;
334	case II_L2ROUT: (void)printf("l2rout "); break;
335	case II_L1ROUT: (void)printf("l1rout "); break;
336	case II_ENDNODE: (void)printf("endnode "); break;
337	}
338	if (info & II_VERIF)
339	    (void)printf("verif ");
340	if (info & II_NOMCAST)
341	    (void)printf("nomcast ");
342	if (info & II_BLOCK)
343	    (void)printf("blo ");
344}
345
346static void
347print_elist(const char *elp, u_int len)
348{
349	/* Not enough examples available for me to debug this */
350}
351
352static void
353print_nsp(const u_char *nspp, u_int nsplen)
354{
355	const struct nsphdr *nsphp = (struct nsphdr *)nspp;
356	int dst, src, flags;
357
358	flags = EXTRACT_LE_8BITS(nsphp->nh_flags);
359	dst = EXTRACT_LE_16BITS(nsphp->nh_dst);
360	src = EXTRACT_LE_16BITS(nsphp->nh_src);
361
362	switch (flags & NSP_TYPEMASK) {
363	case MFT_DATA:
364	    switch (flags & NSP_SUBMASK) {
365	    case MFS_BOM:
366	    case MFS_MOM:
367	    case MFS_EOM:
368	    case MFS_BOM+MFS_EOM:
369		printf("data %d>%d ", src, dst);
370		{
371		    struct seghdr *shp = (struct seghdr *)nspp;
372		    int ack;
373#ifdef	PRINT_NSPDATA
374		    u_char *dp;
375#endif
376		    u_int data_off = sizeof(struct minseghdr);
377
378		    ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
379		    if (ack & SGQ_ACK) {	/* acknum field */
380			if ((ack & SGQ_NAK) == SGQ_NAK)
381			    (void)printf("nak %d ", ack & SGQ_MASK);
382			else
383			    (void)printf("ack %d ", ack & SGQ_MASK);
384		        ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
385			data_off += sizeof(short);
386			if (ack & SGQ_OACK) {	/* ackoth field */
387			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
388				(void)printf("onak %d ", ack & SGQ_MASK);
389			    else
390				(void)printf("oack %d ", ack & SGQ_MASK);
391			    ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
392			    data_off += sizeof(short);
393			}
394		    }
395		    (void)printf("seg %d ", ack & SGQ_MASK);
396#ifdef	PRINT_NSPDATA
397		    dp = &(nspp[data_off]);
398		    pdata(dp, 10);
399#endif
400		}
401		break;
402	    case MFS_ILS+MFS_INT:
403		printf("intr ");
404		{
405		    struct seghdr *shp = (struct seghdr *)nspp;
406		    int ack;
407#ifdef	PRINT_NSPDATA
408		    u_char *dp;
409#endif
410		    u_int data_off = sizeof(struct minseghdr);
411
412		    ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
413		    if (ack & SGQ_ACK) {	/* acknum field */
414			if ((ack & SGQ_NAK) == SGQ_NAK)
415			    (void)printf("nak %d ", ack & SGQ_MASK);
416			else
417			    (void)printf("ack %d ", ack & SGQ_MASK);
418		        ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
419			data_off += sizeof(short);
420			if (ack & SGQ_OACK) {	/* ackdat field */
421			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
422				(void)printf("nakdat %d ", ack & SGQ_MASK);
423			    else
424				(void)printf("ackdat %d ", ack & SGQ_MASK);
425			    ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
426			    data_off += sizeof(short);
427			}
428		    }
429		    (void)printf("seg %d ", ack & SGQ_MASK);
430#ifdef	PRINT_NSPDATA
431		    dp = &(nspp[data_off]);
432		    pdata(dp, 10);
433#endif
434		}
435		break;
436	    case MFS_ILS:
437		(void)printf("link-service %d>%d ", src, dst);
438		{
439		    struct seghdr *shp = (struct seghdr *)nspp;
440		    struct lsmsg *lsmp =
441			(struct lsmsg *)&(nspp[sizeof(struct seghdr)]);
442		    int ack;
443		    int lsflags, fcval;
444
445		    ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
446		    if (ack & SGQ_ACK) {	/* acknum field */
447			if ((ack & SGQ_NAK) == SGQ_NAK)
448			    (void)printf("nak %d ", ack & SGQ_MASK);
449			else
450			    (void)printf("ack %d ", ack & SGQ_MASK);
451		        ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
452			if (ack & SGQ_OACK) {	/* ackdat field */
453			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
454				(void)printf("nakdat %d ", ack & SGQ_MASK);
455			    else
456				(void)printf("ackdat %d ", ack & SGQ_MASK);
457			    ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
458			}
459		    }
460		    (void)printf("seg %d ", ack & SGQ_MASK);
461		    lsflags = EXTRACT_LE_8BITS(lsmp->ls_lsflags);
462		    fcval = EXTRACT_LE_8BITS(lsmp->ls_fcval);
463		    switch (lsflags & LSI_MASK) {
464		    case LSI_DATA:
465			(void)printf("dat seg count %d ", fcval);
466			switch (lsflags & LSM_MASK) {
467			case LSM_NOCHANGE:
468			    break;
469			case LSM_DONOTSEND:
470			    (void)printf("donotsend-data ");
471			    break;
472			case LSM_SEND:
473			    (void)printf("send-data ");
474			    break;
475			default:
476			    (void)printf("reserved-fcmod? %x", lsflags);
477			    break;
478			}
479			break;
480		    case LSI_INTR:
481			(void)printf("intr req count %d ", fcval);
482			break;
483		    default:
484			(void)printf("reserved-fcval-int? %x", lsflags);
485			break;
486		    }
487		}
488		break;
489	    default:
490		(void)printf("reserved-subtype? %x %d > %d", flags, src, dst);
491		break;
492	    }
493	    break;
494	case MFT_ACK:
495	    switch (flags & NSP_SUBMASK) {
496	    case MFS_DACK:
497		(void)printf("data-ack %d>%d ", src, dst);
498		{
499		    struct ackmsg *amp = (struct ackmsg *)nspp;
500		    int ack;
501
502		    ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]);
503		    if (ack & SGQ_ACK) {	/* acknum field */
504			if ((ack & SGQ_NAK) == SGQ_NAK)
505			    (void)printf("nak %d ", ack & SGQ_MASK);
506			else
507			    (void)printf("ack %d ", ack & SGQ_MASK);
508		        ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]);
509			if (ack & SGQ_OACK) {	/* ackoth field */
510			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
511				(void)printf("onak %d ", ack & SGQ_MASK);
512			    else
513				(void)printf("oack %d ", ack & SGQ_MASK);
514			}
515		    }
516		}
517		break;
518	    case MFS_IACK:
519		(void)printf("ils-ack %d>%d ", src, dst);
520		{
521		    struct ackmsg *amp = (struct ackmsg *)nspp;
522		    int ack;
523
524		    ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]);
525		    if (ack & SGQ_ACK) {	/* acknum field */
526			if ((ack & SGQ_NAK) == SGQ_NAK)
527			    (void)printf("nak %d ", ack & SGQ_MASK);
528			else
529			    (void)printf("ack %d ", ack & SGQ_MASK);
530		        ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]);
531			if (ack & SGQ_OACK) {	/* ackdat field */
532			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
533				(void)printf("nakdat %d ", ack & SGQ_MASK);
534			    else
535				(void)printf("ackdat %d ", ack & SGQ_MASK);
536			}
537		    }
538		}
539		break;
540	    case MFS_CACK:
541		(void)printf("conn-ack %d", dst);
542		break;
543	    default:
544		(void)printf("reserved-acktype? %x %d > %d", flags, src, dst);
545		break;
546	    }
547	    break;
548	case MFT_CTL:
549	    switch (flags & NSP_SUBMASK) {
550	    case MFS_CI:
551	    case MFS_RCI:
552		if ((flags & NSP_SUBMASK) == MFS_CI)
553		    (void)printf("conn-initiate ");
554		else
555		    (void)printf("retrans-conn-initiate ");
556		(void)printf("%d>%d ", src, dst);
557		{
558		    struct cimsg *cimp = (struct cimsg *)nspp;
559		    int services, info, segsize;
560#ifdef	PRINT_NSPDATA
561		    u_char *dp;
562#endif
563
564		    services = EXTRACT_LE_8BITS(cimp->ci_services);
565		    info = EXTRACT_LE_8BITS(cimp->ci_info);
566		    segsize = EXTRACT_LE_16BITS(cimp->ci_segsize);
567
568		    switch (services & COS_MASK) {
569		    case COS_NONE:
570			break;
571		    case COS_SEGMENT:
572			(void)printf("seg ");
573			break;
574		    case COS_MESSAGE:
575			(void)printf("msg ");
576			break;
577		    case COS_CRYPTSER:
578			(void)printf("crypt ");
579			break;
580		    }
581		    switch (info & COI_MASK) {
582		    case COI_32:
583			(void)printf("ver 3.2 ");
584			break;
585		    case COI_31:
586			(void)printf("ver 3.1 ");
587			break;
588		    case COI_40:
589			(void)printf("ver 4.0 ");
590			break;
591		    case COI_41:
592			(void)printf("ver 4.1 ");
593			break;
594		    }
595		    (void)printf("segsize %d ", segsize);
596#ifdef	PRINT_NSPDATA
597		    dp = &(nspp[sizeof(struct cimsg)]);
598		    pdata(dp, nsplen - sizeof(struct cimsg));
599#endif
600		}
601		break;
602	    case MFS_CC:
603		(void)printf("conn-confirm %d>%d ", src, dst);
604		{
605		    struct ccmsg *ccmp = (struct ccmsg *)nspp;
606		    int services, info;
607		    u_int segsize, optlen;
608#ifdef	PRINT_NSPDATA
609		    u_char *dp;
610#endif
611
612		    services = EXTRACT_LE_8BITS(ccmp->cc_services);
613		    info = EXTRACT_LE_8BITS(ccmp->cc_info);
614		    segsize = EXTRACT_LE_16BITS(ccmp->cc_segsize);
615		    optlen = EXTRACT_LE_8BITS(ccmp->cc_optlen);
616
617		    switch (services & COS_MASK) {
618		    case COS_NONE:
619			break;
620		    case COS_SEGMENT:
621			(void)printf("seg ");
622			break;
623		    case COS_MESSAGE:
624			(void)printf("msg ");
625			break;
626		    case COS_CRYPTSER:
627			(void)printf("crypt ");
628			break;
629		    }
630		    switch (info & COI_MASK) {
631		    case COI_32:
632			(void)printf("ver 3.2 ");
633			break;
634		    case COI_31:
635			(void)printf("ver 3.1 ");
636			break;
637		    case COI_40:
638			(void)printf("ver 4.0 ");
639			break;
640		    case COI_41:
641			(void)printf("ver 4.1 ");
642			break;
643		    }
644		    (void)printf("segsize %d ", segsize);
645		    if (optlen) {
646			(void)printf("optlen %d ", optlen);
647#ifdef	PRINT_NSPDATA
648			optlen = min(optlen, nsplen - sizeof(struct ccmsg));
649			dp = &(nspp[sizeof(struct ccmsg)]);
650			pdata(dp, optlen);
651#endif
652		    }
653		}
654		break;
655	    case MFS_DI:
656		(void)printf("disconn-initiate %d>%d ", src, dst);
657		{
658		    struct dimsg *dimp = (struct dimsg *)nspp;
659		    int reason;
660		    u_int optlen;
661#ifdef	PRINT_NSPDATA
662		    u_char *dp;
663#endif
664
665		    reason = EXTRACT_LE_16BITS(dimp->di_reason);
666		    optlen = EXTRACT_LE_8BITS(dimp->di_optlen);
667
668		    print_reason(reason);
669		    if (optlen) {
670			(void)printf("optlen %d ", optlen);
671#ifdef	PRINT_NSPDATA
672			optlen = min(optlen, nsplen - sizeof(struct dimsg));
673			dp = &(nspp[sizeof(struct dimsg)]);
674			pdata(dp, optlen);
675#endif
676		    }
677		}
678		break;
679	    case MFS_DC:
680		(void)printf("disconn-confirm %d>%d ", src, dst);
681		{
682		    struct dcmsg *dcmp = (struct dcmsg *)nspp;
683		    int reason;
684
685		    reason = EXTRACT_LE_16BITS(dcmp->dc_reason);
686
687		    print_reason(reason);
688		}
689		break;
690	    default:
691		(void)printf("reserved-ctltype? %x %d > %d", flags, src, dst);
692		break;
693	    }
694	    break;
695	default:
696	    (void)printf("reserved-type? %x %d > %d", flags, src, dst);
697	    break;
698	}
699}
700
701static struct tok reason2str[] = {
702	{ UC_OBJREJECT,		"object rejected connect" },
703	{ UC_RESOURCES,		"insufficient resources" },
704	{ UC_NOSUCHNODE,	"unrecognized node name" },
705	{ DI_SHUT,		"node is shutting down" },
706	{ UC_NOSUCHOBJ,		"unrecognized object" },
707	{ UC_INVOBJFORMAT,	"invalid object name format" },
708	{ UC_OBJTOOBUSY,	"object too busy" },
709	{ DI_PROTOCOL,		"protocol error discovered" },
710	{ DI_TPA,		"third party abort" },
711	{ UC_USERABORT,		"user abort" },
712	{ UC_INVNODEFORMAT,	"invalid node name format" },
713	{ UC_LOCALSHUT,		"local node shutting down" },
714	{ DI_LOCALRESRC,	"insufficient local resources" },
715	{ DI_REMUSERRESRC,	"insufficient remote user resources" },
716	{ UC_ACCESSREJECT,	"invalid access control information" },
717	{ DI_BADACCNT,		"bad ACCOUNT information" },
718	{ UC_NORESPONSE,	"no response from object" },
719	{ UC_UNREACHABLE,	"node unreachable" },
720	{ DC_NOLINK,		"no link terminate" },
721	{ DC_COMPLETE,		"disconnect complete" },
722	{ DI_BADIMAGE,		"bad image data in connect" },
723	{ DI_SERVMISMATCH,	"cryptographic service mismatch" },
724	{ 0,			NULL }
725};
726
727static void
728print_reason(register int reason)
729{
730	printf("%s ", tok2str(reason2str, "reason-%d", reason));
731}
732
733char *
734dnnum_string(u_short dnaddr)
735{
736	char *str;
737	size_t siz;
738	int area = (u_short)(dnaddr & AREAMASK) >> AREASHIFT;
739	int node = dnaddr & NODEMASK;
740
741	str = (char *)malloc(siz = sizeof("00.0000"));
742	if (str == NULL)
743		error("dnnum_string: malloc");
744	snprintf(str, siz, "%d.%d", area, node);
745	return(str);
746}
747
748char *
749dnname_string(u_short dnaddr)
750{
751#ifdef	HAVE_LIBDNET
752	struct dn_naddr dna;
753
754	dna.a_len = sizeof(short);
755	memcpy((char *)dna.a_addr, (char *)&dnaddr, sizeof(short));
756	return (savestr(dnet_htoa(&dna)));
757#else
758	return(dnnum_string(dnaddr));	/* punt */
759#endif
760}
761
762#ifdef	PRINT_NSPDATA
763static void
764pdata(u_char *dp, u_int maxlen)
765{
766	char c;
767	u_int x = maxlen;
768
769	while (x-- > 0) {
770	    c = *dp++;
771	    if (isprint(c))
772		putchar(c);
773	    else
774		printf("\\%o", c & 0xFF);
775	}
776}
777#endif
778