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