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