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