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