xref: /minix/external/bsd/tcpdump/dist/print-decnet.c (revision bb9622b5)
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 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-decnet.c,v 1.6 2015/03/31 21:59:35 christos Exp $");
25 #endif
26 
27 #define NETDISSECT_REWORKED
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <tcpdump-stdinc.h>
33 
34 struct mbuf;
35 struct rtentry;
36 
37 #ifdef HAVE_NETDNET_DNETDB_H
38 #include <netdnet/dnetdb.h>
39 #endif
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include "extract.h"
46 #include "interface.h"
47 #include "addrtoname.h"
48 
49 static const char tstr[] = "[|decnet]";
50 
51 #ifndef WIN32
52 typedef uint8_t byte[1];		/* single byte field */
53 #else
54 /*
55  * the keyword 'byte' generates conflicts in Windows
56  */
57 typedef unsigned char Byte[1];		/* single byte field */
58 #define byte Byte
59 #endif /* WIN32 */
60 typedef uint8_t word[2];		/* 2 byte field */
61 typedef uint8_t longword[4];		/* 4 bytes field */
62 
63 /*
64  * Definitions for DECNET Phase IV protocol headers
65  */
66 union etheraddress {
67 	uint8_t   dne_addr[6];		/* full ethernet address */
68 	struct {
69 		uint8_t dne_hiord[4];	/* DECnet HIORD prefix */
70 		uint8_t dne_nodeaddr[2]; /* DECnet node address */
71 	} dne_remote;
72 };
73 
74 typedef union etheraddress etheraddr;	/* Ethernet address */
75 
76 #define HIORD 0x000400aa		/* high 32-bits of address (swapped) */
77 
78 #define AREAMASK	0176000		/* mask for area field */
79 #define	AREASHIFT	10		/* bit-offset for area field */
80 #define NODEMASK	01777		/* mask for node address field */
81 
82 #define DN_MAXADDL	20		/* max size of DECnet address */
83 struct dn_naddr {
84 	uint16_t	a_len;		/* length of address */
85 	uint8_t a_addr[DN_MAXADDL]; /* address as bytes */
86 };
87 
88 /*
89  * Define long and short header formats.
90  */
91 struct shorthdr
92   {
93     byte	sh_flags;		/* route flags */
94     word	sh_dst;			/* destination node address */
95     word	sh_src;			/* source node address */
96     byte	sh_visits;		/* visit count */
97   };
98 
99 struct longhdr
100   {
101     byte	lg_flags;		/* route flags */
102     byte	lg_darea;		/* destination area (reserved) */
103     byte	lg_dsarea;		/* destination subarea (reserved) */
104     etheraddr	lg_dst;			/* destination id */
105     byte	lg_sarea;		/* source area (reserved) */
106     byte	lg_ssarea;		/* source subarea (reserved) */
107     etheraddr	lg_src;			/* source id */
108     byte	lg_nextl2;		/* next level 2 router (reserved) */
109     byte	lg_visits;		/* visit count */
110     byte	lg_service;		/* service class (reserved) */
111     byte	lg_pt;			/* protocol type (reserved) */
112   };
113 
114 union routehdr
115   {
116     struct shorthdr rh_short;		/* short route header */
117     struct longhdr rh_long;		/* long route header */
118   };
119 
120 /*
121  * Define the values of various fields in the protocol messages.
122  *
123  * 1. Data packet formats.
124  */
125 #define RMF_MASK	7		/* mask for message type */
126 #define RMF_SHORT	2		/* short message format */
127 #define RMF_LONG	6		/* long message format */
128 #ifndef RMF_RQR
129 #define RMF_RQR		010		/* request return to sender */
130 #define RMF_RTS		020		/* returning to sender */
131 #define RMF_IE		040		/* intra-ethernet packet */
132 #endif /* RMR_RQR */
133 #define RMF_FVER	0100		/* future version flag */
134 #define RMF_PAD		0200		/* pad field */
135 #define RMF_PADMASK	0177		/* pad field mask */
136 
137 #define VIS_MASK	077		/* visit field mask */
138 
139 /*
140  * 2. Control packet formats.
141  */
142 #define RMF_CTLMASK	017		/* mask for message type */
143 #define RMF_CTLMSG	01		/* control message indicator */
144 #define RMF_INIT	01		/* initialization message */
145 #define RMF_VER		03		/* verification message */
146 #define RMF_TEST	05		/* hello and test message */
147 #define RMF_L1ROUT	07		/* level 1 routing message */
148 #define RMF_L2ROUT	011		/* level 2 routing message */
149 #define RMF_RHELLO	013		/* router hello message */
150 #define RMF_EHELLO	015		/* endnode hello message */
151 
152 #define TI_L2ROUT	01		/* level 2 router */
153 #define TI_L1ROUT	02		/* level 1 router */
154 #define TI_ENDNODE	03		/* endnode */
155 #define TI_VERIF	04		/* verification required */
156 #define TI_BLOCK	010		/* blocking requested */
157 
158 #define VE_VERS		2		/* version number (2) */
159 #define VE_ECO		0		/* ECO number */
160 #define VE_UECO		0		/* user ECO number (0) */
161 
162 #define P3_VERS		1		/* phase III version number (1) */
163 #define P3_ECO		3		/* ECO number (3) */
164 #define P3_UECO		0		/* user ECO number (0) */
165 
166 #define II_L2ROUT	01		/* level 2 router */
167 #define II_L1ROUT	02		/* level 1 router */
168 #define II_ENDNODE	03		/* endnode */
169 #define II_VERIF	04		/* verification required */
170 #define II_NOMCAST	040		/* no multicast traffic accepted */
171 #define II_BLOCK	0100		/* blocking requested */
172 #define II_TYPEMASK	03		/* mask for node type */
173 
174 #define TESTDATA	0252		/* test data bytes */
175 #define TESTLEN		1		/* length of transmitted test data */
176 
177 /*
178  * Define control message formats.
179  */
180 struct initmsgIII			/* phase III initialization message */
181   {
182     byte	inIII_flags;		/* route flags */
183     word	inIII_src;		/* source node address */
184     byte	inIII_info;		/* routing layer information */
185     word	inIII_blksize;		/* maximum data link block size */
186     byte	inIII_vers;		/* version number */
187     byte	inIII_eco;		/* ECO number */
188     byte	inIII_ueco;		/* user ECO number */
189     byte	inIII_rsvd;		/* reserved image field */
190   };
191 
192 struct initmsg				/* initialization message */
193   {
194     byte	in_flags;		/* route flags */
195     word	in_src;			/* source node address */
196     byte	in_info;		/* routing layer information */
197     word	in_blksize;		/* maximum data link block size */
198     byte	in_vers;		/* version number */
199     byte	in_eco;			/* ECO number */
200     byte	in_ueco;		/* user ECO number */
201     word	in_hello;		/* hello timer */
202     byte	in_rsvd;		/* reserved image field */
203   };
204 
205 struct verifmsg				/* verification message */
206   {
207     byte	ve_flags;		/* route flags */
208     word	ve_src;			/* source node address */
209     byte	ve_fcnval;		/* function value image field */
210   };
211 
212 struct testmsg				/* hello and test message */
213   {
214     byte	te_flags;		/* route flags */
215     word	te_src;			/* source node address */
216     byte	te_data;		/* test data image field */
217   };
218 
219 struct l1rout				/* level 1 routing message */
220   {
221     byte	r1_flags;		/* route flags */
222     word	r1_src;			/* source node address */
223     byte	r1_rsvd;		/* reserved field */
224   };
225 
226 struct l2rout				/* level 2 routing message */
227   {
228     byte	r2_flags;		/* route flags */
229     word	r2_src;			/* source node address */
230     byte	r2_rsvd;		/* reserved field */
231   };
232 
233 struct rhellomsg			/* router hello message */
234   {
235     byte	rh_flags;		/* route flags */
236     byte	rh_vers;		/* version number */
237     byte	rh_eco;			/* ECO number */
238     byte	rh_ueco;		/* user ECO number */
239     etheraddr	rh_src;			/* source id */
240     byte	rh_info;		/* routing layer information */
241     word	rh_blksize;		/* maximum data link block size */
242     byte	rh_priority;		/* router's priority */
243     byte	rh_area;		/* reserved */
244     word	rh_hello;		/* hello timer */
245     byte	rh_mpd;			/* reserved */
246   };
247 
248 struct ehellomsg			/* endnode hello message */
249   {
250     byte	eh_flags;		/* route flags */
251     byte	eh_vers;		/* version number */
252     byte	eh_eco;			/* ECO number */
253     byte	eh_ueco;		/* user ECO number */
254     etheraddr	eh_src;			/* source id */
255     byte	eh_info;		/* routing layer information */
256     word	eh_blksize;		/* maximum data link block size */
257     byte	eh_area;		/* area (reserved) */
258     byte	eh_seed[8];		/* verification seed */
259     etheraddr	eh_router;		/* designated router */
260     word	eh_hello;		/* hello timer */
261     byte	eh_mpd;			/* (reserved) */
262     byte	eh_data;		/* test data image field */
263   };
264 
265 union controlmsg
266   {
267     struct initmsg	cm_init;	/* initialization message */
268     struct verifmsg	cm_ver;		/* verification message */
269     struct testmsg	cm_test;	/* hello and test message */
270     struct l1rout	cm_l1rou;	/* level 1 routing message */
271     struct l2rout	cm_l2rout;	/* level 2 routing message */
272     struct rhellomsg	cm_rhello;	/* router hello message */
273     struct ehellomsg	cm_ehello;	/* endnode hello message */
274   };
275 
276 /* Macros for decoding routing-info fields */
277 #define	RI_COST(x)	((x)&0777)
278 #define	RI_HOPS(x)	(((x)>>10)&037)
279 
280 /*
281  * NSP protocol fields and values.
282  */
283 
284 #define NSP_TYPEMASK 014		/* mask to isolate type code */
285 #define NSP_SUBMASK 0160		/* mask to isolate subtype code */
286 #define NSP_SUBSHFT 4			/* shift to move subtype code */
287 
288 #define MFT_DATA 0			/* data message */
289 #define MFT_ACK  04			/* acknowledgement message */
290 #define MFT_CTL  010			/* control message */
291 
292 #define MFS_ILS  020			/* data or I/LS indicator */
293 #define MFS_BOM  040			/* beginning of message (data) */
294 #define MFS_MOM  0			/* middle of message (data) */
295 #define MFS_EOM  0100			/* end of message (data) */
296 #define MFS_INT  040			/* interrupt message */
297 
298 #define MFS_DACK 0			/* data acknowledgement */
299 #define MFS_IACK 020			/* I/LS acknowledgement */
300 #define MFS_CACK 040			/* connect acknowledgement */
301 
302 #define MFS_NOP  0			/* no operation */
303 #define MFS_CI   020			/* connect initiate */
304 #define MFS_CC   040			/* connect confirm */
305 #define MFS_DI   060			/* disconnect initiate */
306 #define MFS_DC   0100			/* disconnect confirm */
307 #define MFS_RCI  0140			/* retransmitted connect initiate */
308 
309 #define SGQ_ACK  0100000		/* ack */
310 #define SGQ_NAK  0110000		/* negative ack */
311 #define SGQ_OACK 0120000		/* other channel ack */
312 #define SGQ_ONAK 0130000		/* other channel negative ack */
313 #define SGQ_MASK 07777			/* mask to isolate seq # */
314 #define SGQ_OTHER 020000		/* other channel qualifier */
315 #define SGQ_DELAY 010000		/* ack delay flag */
316 
317 #define SGQ_EOM  0100000		/* pseudo flag for end-of-message */
318 
319 #define LSM_MASK 03			/* mask for modifier field */
320 #define LSM_NOCHANGE 0			/* no change */
321 #define LSM_DONOTSEND 1			/* do not send data */
322 #define LSM_SEND 2			/* send data */
323 
324 #define LSI_MASK 014			/* mask for interpretation field */
325 #define LSI_DATA 0			/* data segment or message count */
326 #define LSI_INTR 4			/* interrupt request count */
327 #define LSI_INTM 0377			/* funny marker for int. message */
328 
329 #define COS_MASK 014			/* mask for flow control field */
330 #define COS_NONE 0			/* no flow control */
331 #define COS_SEGMENT 04			/* segment flow control */
332 #define COS_MESSAGE 010			/* message flow control */
333 #define COS_CRYPTSER 020		/* cryptographic services requested */
334 #define COS_DEFAULT 1			/* default value for field */
335 
336 #define COI_MASK 3			/* mask for version field */
337 #define COI_32 0			/* version 3.2 */
338 #define COI_31 1			/* version 3.1 */
339 #define COI_40 2			/* version 4.0 */
340 #define COI_41 3			/* version 4.1 */
341 
342 #define MNU_MASK 140			/* mask for session control version */
343 #define MNU_10 000				/* session V1.0 */
344 #define MNU_20 040				/* session V2.0 */
345 #define MNU_ACCESS 1			/* access control present */
346 #define MNU_USRDATA 2			/* user data field present */
347 #define MNU_INVKPROXY 4			/* invoke proxy field present */
348 #define MNU_UICPROXY 8			/* use uic-based proxy */
349 
350 #define DC_NORESOURCES 1		/* no resource reason code */
351 #define DC_NOLINK 41			/* no link terminate reason code */
352 #define DC_COMPLETE 42			/* disconnect complete reason code */
353 
354 #define DI_NOERROR 0			/* user disconnect */
355 #define DI_SHUT 3			/* node is shutting down */
356 #define DI_NOUSER 4			/* destination end user does not exist */
357 #define DI_INVDEST 5			/* invalid end user destination */
358 #define DI_REMRESRC 6			/* insufficient remote resources */
359 #define DI_TPA 8			/* third party abort */
360 #define DI_PROTOCOL 7			/* protocol error discovered */
361 #define DI_ABORT 9			/* user abort */
362 #define DI_LOCALRESRC 32		/* insufficient local resources */
363 #define DI_REMUSERRESRC 33		/* insufficient remote user resources */
364 #define DI_BADACCESS 34			/* bad access control information */
365 #define DI_BADACCNT 36			/* bad ACCOUNT information */
366 #define DI_CONNECTABORT 38		/* connect request cancelled */
367 #define DI_TIMEDOUT 38			/* remote node or user crashed */
368 #define DI_UNREACHABLE 39		/* local timers expired due to ... */
369 #define DI_BADIMAGE 43			/* bad image data in connect */
370 #define DI_SERVMISMATCH 54		/* cryptographic service mismatch */
371 
372 #define UC_OBJREJECT 0			/* object rejected connect */
373 #define UC_USERDISCONNECT 0		/* user disconnect */
374 #define UC_RESOURCES 1			/* insufficient resources (local or remote) */
375 #define UC_NOSUCHNODE 2			/* unrecognized node name */
376 #define UC_REMOTESHUT 3			/* remote node shutting down */
377 #define UC_NOSUCHOBJ 4			/* unrecognized object */
378 #define UC_INVOBJFORMAT 5		/* invalid object name format */
379 #define UC_OBJTOOBUSY 6			/* object too busy */
380 #define UC_NETWORKABORT 8		/* network abort */
381 #define UC_USERABORT 9			/* user abort */
382 #define UC_INVNODEFORMAT 10		/* invalid node name format */
383 #define UC_LOCALSHUT 11			/* local node shutting down */
384 #define UC_ACCESSREJECT 34		/* invalid access control information */
385 #define UC_NORESPONSE 38		/* no response from object */
386 #define UC_UNREACHABLE 39		/* node unreachable */
387 
388 /*
389  * NSP message formats.
390  */
391 struct nsphdr				/* general nsp header */
392   {
393     byte	nh_flags;		/* message flags */
394     word	nh_dst;			/* destination link address */
395     word	nh_src;			/* source link address */
396   };
397 
398 struct seghdr				/* data segment header */
399   {
400     byte	sh_flags;		/* message flags */
401     word	sh_dst;			/* destination link address */
402     word	sh_src;			/* source link address */
403     word	sh_seq[3];		/* sequence numbers */
404   };
405 
406 struct minseghdr			/* minimum data segment header */
407   {
408     byte	ms_flags;		/* message flags */
409     word	ms_dst;			/* destination link address */
410     word	ms_src;			/* source link address */
411     word	ms_seq;			/* sequence number */
412   };
413 
414 struct lsmsg				/* link service message (after hdr) */
415   {
416     byte	ls_lsflags;		/* link service flags */
417     byte	ls_fcval;		/* flow control value */
418   };
419 
420 struct ackmsg				/* acknowledgement message */
421   {
422     byte	ak_flags;		/* message flags */
423     word	ak_dst;			/* destination link address */
424     word	ak_src;			/* source link address */
425     word	ak_acknum[2];		/* acknowledgement numbers */
426   };
427 
428 struct minackmsg			/* minimum acknowledgement message */
429   {
430     byte	mk_flags;		/* message flags */
431     word	mk_dst;			/* destination link address */
432     word	mk_src;			/* source link address */
433     word	mk_acknum;		/* acknowledgement number */
434   };
435 
436 struct ciackmsg				/* connect acknowledgement message */
437   {
438     byte	ck_flags;		/* message flags */
439     word	ck_dst;			/* destination link address */
440   };
441 
442 struct cimsg				/* connect initiate message */
443   {
444     byte	ci_flags;		/* message flags */
445     word	ci_dst;			/* destination link address (0) */
446     word	ci_src;			/* source link address */
447     byte	ci_services;		/* requested services */
448     byte	ci_info;		/* information */
449     word	ci_segsize;		/* maximum segment size */
450   };
451 
452 struct ccmsg				/* connect confirm message */
453   {
454     byte	cc_flags;		/* message flags */
455     word	cc_dst;			/* destination link address */
456     word	cc_src;			/* source link address */
457     byte	cc_services;		/* requested services */
458     byte	cc_info;		/* information */
459     word	cc_segsize;		/* maximum segment size */
460     byte	cc_optlen;		/* optional data length */
461   };
462 
463 struct cnmsg				/* generic connect message */
464   {
465     byte	cn_flags;		/* message flags */
466     word	cn_dst;			/* destination link address */
467     word	cn_src;			/* source link address */
468     byte	cn_services;		/* requested services */
469     byte	cn_info;		/* information */
470     word	cn_segsize;		/* maximum segment size */
471   };
472 
473 struct dimsg				/* disconnect initiate message */
474   {
475     byte	di_flags;		/* message flags */
476     word	di_dst;			/* destination link address */
477     word	di_src;			/* source link address */
478     word	di_reason;		/* reason code */
479     byte	di_optlen;		/* optional data length */
480   };
481 
482 struct dcmsg				/* disconnect confirm message */
483   {
484     byte	dc_flags;		/* message flags */
485     word	dc_dst;			/* destination link address */
486     word	dc_src;			/* source link address */
487     word	dc_reason;		/* reason code */
488   };
489 
490 /* Forwards */
491 static int print_decnet_ctlmsg(netdissect_options *, const union routehdr *, u_int, u_int);
492 static void print_t_info(netdissect_options *, int);
493 static int print_l1_routes(netdissect_options *, const char *, u_int);
494 static int print_l2_routes(netdissect_options *, const char *, u_int);
495 static void print_i_info(netdissect_options *, int);
496 static int print_elist(const char *, u_int);
497 static int print_nsp(netdissect_options *, const u_char *, u_int);
498 static void print_reason(netdissect_options *, int);
499 #ifdef	PRINT_NSPDATA
500 static void pdata(netdissect_options *, u_char *, u_int);
501 #endif
502 
503 #ifndef HAVE_NETDNET_DNETDB_H_DNET_HTOA
504 extern char *dnet_htoa(struct dn_naddr *);
505 #endif
506 
507 void
508 decnet_print(netdissect_options *ndo,
509              register const u_char *ap, register u_int length,
510              register u_int caplen)
511 {
512 	register const union routehdr *rhp;
513 	register int mflags;
514 	int dst, src, hops;
515 	u_int nsplen, pktlen;
516 	const u_char *nspp;
517 
518 	if (length < sizeof(struct shorthdr)) {
519 		ND_PRINT((ndo, "%s", tstr));
520 		return;
521 	}
522 
523 	ND_TCHECK2(*ap, sizeof(short));
524 	pktlen = EXTRACT_LE_16BITS(ap);
525 	if (pktlen < sizeof(struct shorthdr)) {
526 		ND_PRINT((ndo, "%s", tstr));
527 		return;
528 	}
529 	if (pktlen > length) {
530 		ND_PRINT((ndo, "%s", tstr));
531 		return;
532 	}
533 	length = pktlen;
534 
535 	rhp = (const union routehdr *)&(ap[sizeof(short)]);
536 	ND_TCHECK(rhp->rh_short.sh_flags);
537 	mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
538 
539 	if (mflags & RMF_PAD) {
540 	    /* pad bytes of some sort in front of message */
541 	    u_int padlen = mflags & RMF_PADMASK;
542 	    if (ndo->ndo_vflag)
543 		ND_PRINT((ndo, "[pad:%d] ", padlen));
544 	    if (length < padlen + 2) {
545 		ND_PRINT((ndo, "%s", tstr));
546 		return;
547 	    }
548 	    ND_TCHECK2(ap[sizeof(short)], padlen);
549 	    ap += padlen;
550 	    length -= padlen;
551 	    caplen -= padlen;
552 	    rhp = (const union routehdr *)&(ap[sizeof(short)]);
553 	    mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
554 	}
555 
556 	if (mflags & RMF_FVER) {
557 		ND_PRINT((ndo, "future-version-decnet"));
558 		ND_DEFAULTPRINT(ap, min(length, caplen));
559 		return;
560 	}
561 
562 	/* is it a control message? */
563 	if (mflags & RMF_CTLMSG) {
564 		if (!print_decnet_ctlmsg(ndo, rhp, length, caplen))
565 			goto trunc;
566 		return;
567 	}
568 
569 	switch (mflags & RMF_MASK) {
570 	case RMF_LONG:
571 	    if (length < sizeof(struct longhdr)) {
572 		ND_PRINT((ndo, "%s", tstr));
573 		return;
574 	    }
575 	    ND_TCHECK(rhp->rh_long);
576 	    dst =
577 		EXTRACT_LE_16BITS(rhp->rh_long.lg_dst.dne_remote.dne_nodeaddr);
578 	    src =
579 		EXTRACT_LE_16BITS(rhp->rh_long.lg_src.dne_remote.dne_nodeaddr);
580 	    hops = EXTRACT_LE_8BITS(rhp->rh_long.lg_visits);
581 	    nspp = &(ap[sizeof(short) + sizeof(struct longhdr)]);
582 	    nsplen = length - sizeof(struct longhdr);
583 	    break;
584 	case RMF_SHORT:
585 	    ND_TCHECK(rhp->rh_short);
586 	    dst = EXTRACT_LE_16BITS(rhp->rh_short.sh_dst);
587 	    src = EXTRACT_LE_16BITS(rhp->rh_short.sh_src);
588 	    hops = (EXTRACT_LE_8BITS(rhp->rh_short.sh_visits) & VIS_MASK)+1;
589 	    nspp = &(ap[sizeof(short) + sizeof(struct shorthdr)]);
590 	    nsplen = length - sizeof(struct shorthdr);
591 	    break;
592 	default:
593 	    ND_PRINT((ndo, "unknown message flags under mask"));
594 	    ND_DEFAULTPRINT((u_char *)ap, min(length, caplen));
595 	    return;
596 	}
597 
598 	ND_PRINT((ndo, "%s > %s %d ",
599 			dnaddr_string(ndo, src), dnaddr_string(ndo, dst), pktlen));
600 	if (ndo->ndo_vflag) {
601 	    if (mflags & RMF_RQR)
602 		ND_PRINT((ndo, "RQR "));
603 	    if (mflags & RMF_RTS)
604 		ND_PRINT((ndo, "RTS "));
605 	    if (mflags & RMF_IE)
606 		ND_PRINT((ndo, "IE "));
607 	    ND_PRINT((ndo, "%d hops ", hops));
608 	}
609 
610 	if (!print_nsp(ndo, nspp, nsplen))
611 		goto trunc;
612 	return;
613 
614 trunc:
615 	ND_PRINT((ndo, "%s", tstr));
616 	return;
617 }
618 
619 static int
620 print_decnet_ctlmsg(netdissect_options *ndo,
621                     register const union routehdr *rhp, u_int length,
622                     u_int caplen)
623 {
624 	int mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
625 	register union controlmsg *cmp = (union controlmsg *)rhp;
626 	int src, dst, info, blksize, eco, ueco, hello, other, vers;
627 	etheraddr srcea, rtea;
628 	int priority;
629 	char *rhpx = (char *)rhp;
630 	int ret;
631 
632 	switch (mflags & RMF_CTLMASK) {
633 	case RMF_INIT:
634 	    ND_PRINT((ndo, "init "));
635 	    if (length < sizeof(struct initmsg))
636 		goto trunc;
637 	    ND_TCHECK(cmp->cm_init);
638 	    src = EXTRACT_LE_16BITS(cmp->cm_init.in_src);
639 	    info = EXTRACT_LE_8BITS(cmp->cm_init.in_info);
640 	    blksize = EXTRACT_LE_16BITS(cmp->cm_init.in_blksize);
641 	    vers = EXTRACT_LE_8BITS(cmp->cm_init.in_vers);
642 	    eco = EXTRACT_LE_8BITS(cmp->cm_init.in_eco);
643 	    ueco = EXTRACT_LE_8BITS(cmp->cm_init.in_ueco);
644 	    hello = EXTRACT_LE_16BITS(cmp->cm_init.in_hello);
645 	    print_t_info(ndo, info);
646 	    ND_PRINT((ndo,
647 		"src %sblksize %d vers %d eco %d ueco %d hello %d",
648 			dnaddr_string(ndo, src), blksize, vers, eco, ueco,
649 			hello));
650 	    ret = 1;
651 	    break;
652 	case RMF_VER:
653 	    ND_PRINT((ndo, "verification "));
654 	    if (length < sizeof(struct verifmsg))
655 		goto trunc;
656 	    ND_TCHECK(cmp->cm_ver);
657 	    src = EXTRACT_LE_16BITS(cmp->cm_ver.ve_src);
658 	    other = EXTRACT_LE_8BITS(cmp->cm_ver.ve_fcnval);
659 	    ND_PRINT((ndo, "src %s fcnval %o", dnaddr_string(ndo, src), other));
660 	    ret = 1;
661 	    break;
662 	case RMF_TEST:
663 	    ND_PRINT((ndo, "test "));
664 	    if (length < sizeof(struct testmsg))
665 		goto trunc;
666 	    ND_TCHECK(cmp->cm_test);
667 	    src = EXTRACT_LE_16BITS(cmp->cm_test.te_src);
668 	    other = EXTRACT_LE_8BITS(cmp->cm_test.te_data);
669 	    ND_PRINT((ndo, "src %s data %o", dnaddr_string(ndo, src), other));
670 	    ret = 1;
671 	    break;
672 	case RMF_L1ROUT:
673 	    ND_PRINT((ndo, "lev-1-routing "));
674 	    if (length < sizeof(struct l1rout))
675 		goto trunc;
676 	    ND_TCHECK(cmp->cm_l1rou);
677 	    src = EXTRACT_LE_16BITS(cmp->cm_l1rou.r1_src);
678 	    ND_PRINT((ndo, "src %s ", dnaddr_string(ndo, src)));
679 	    ret = print_l1_routes(ndo, &(rhpx[sizeof(struct l1rout)]),
680 				length - sizeof(struct l1rout));
681 	    break;
682 	case RMF_L2ROUT:
683 	    ND_PRINT((ndo, "lev-2-routing "));
684 	    if (length < sizeof(struct l2rout))
685 		goto trunc;
686 	    ND_TCHECK(cmp->cm_l2rout);
687 	    src = EXTRACT_LE_16BITS(cmp->cm_l2rout.r2_src);
688 	    ND_PRINT((ndo, "src %s ", dnaddr_string(ndo, src)));
689 	    ret = print_l2_routes(ndo, &(rhpx[sizeof(struct l2rout)]),
690 				length - sizeof(struct l2rout));
691 	    break;
692 	case RMF_RHELLO:
693 	    ND_PRINT((ndo, "router-hello "));
694 	    if (length < sizeof(struct rhellomsg))
695 		goto trunc;
696 	    ND_TCHECK(cmp->cm_rhello);
697 	    vers = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_vers);
698 	    eco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_eco);
699 	    ueco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_ueco);
700 	    memcpy((char *)&srcea, (char *)&(cmp->cm_rhello.rh_src),
701 		sizeof(srcea));
702 	    src = EXTRACT_LE_16BITS(srcea.dne_remote.dne_nodeaddr);
703 	    info = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_info);
704 	    blksize = EXTRACT_LE_16BITS(cmp->cm_rhello.rh_blksize);
705 	    priority = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_priority);
706 	    hello = EXTRACT_LE_16BITS(cmp->cm_rhello.rh_hello);
707 	    print_i_info(ndo, info);
708 	    ND_PRINT((ndo,
709 	    "vers %d eco %d ueco %d src %s blksize %d pri %d hello %d",
710 			vers, eco, ueco, dnaddr_string(ndo, src),
711 			blksize, priority, hello));
712 	    ret = print_elist(&(rhpx[sizeof(struct rhellomsg)]),
713 				length - sizeof(struct rhellomsg));
714 	    break;
715 	case RMF_EHELLO:
716 	    ND_PRINT((ndo, "endnode-hello "));
717 	    if (length < sizeof(struct ehellomsg))
718 		goto trunc;
719 	    ND_TCHECK(cmp->cm_ehello);
720 	    vers = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_vers);
721 	    eco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_eco);
722 	    ueco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_ueco);
723 	    memcpy((char *)&srcea, (char *)&(cmp->cm_ehello.eh_src),
724 		sizeof(srcea));
725 	    src = EXTRACT_LE_16BITS(srcea.dne_remote.dne_nodeaddr);
726 	    info = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_info);
727 	    blksize = EXTRACT_LE_16BITS(cmp->cm_ehello.eh_blksize);
728 	    /*seed*/
729 	    memcpy((char *)&rtea, (char *)&(cmp->cm_ehello.eh_router),
730 		sizeof(rtea));
731 	    dst = EXTRACT_LE_16BITS(rtea.dne_remote.dne_nodeaddr);
732 	    hello = EXTRACT_LE_16BITS(cmp->cm_ehello.eh_hello);
733 	    other = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_data);
734 	    print_i_info(ndo, info);
735 	    ND_PRINT((ndo,
736 	"vers %d eco %d ueco %d src %s blksize %d rtr %s hello %d data %o",
737 			vers, eco, ueco, dnaddr_string(ndo, src),
738 			blksize, dnaddr_string(ndo, dst), hello, other));
739 	    ret = 1;
740 	    break;
741 
742 	default:
743 	    ND_PRINT((ndo, "unknown control message"));
744 	    ND_DEFAULTPRINT((u_char *)rhp, min(length, caplen));
745 	    ret = 1;
746 	    break;
747 	}
748 	return (ret);
749 
750 trunc:
751 	return (0);
752 }
753 
754 static void
755 print_t_info(netdissect_options *ndo,
756              int info)
757 {
758 	int ntype = info & 3;
759 	switch (ntype) {
760 	case 0: ND_PRINT((ndo, "reserved-ntype? ")); break;
761 	case TI_L2ROUT: ND_PRINT((ndo, "l2rout ")); break;
762 	case TI_L1ROUT: ND_PRINT((ndo, "l1rout ")); break;
763 	case TI_ENDNODE: ND_PRINT((ndo, "endnode ")); break;
764 	}
765 	if (info & TI_VERIF)
766 	    ND_PRINT((ndo, "verif "));
767 	if (info & TI_BLOCK)
768 	    ND_PRINT((ndo, "blo "));
769 }
770 
771 static int
772 print_l1_routes(netdissect_options *ndo,
773                 const char *rp, u_int len)
774 {
775 	int count;
776 	int id;
777 	int info;
778 
779 	/* The last short is a checksum */
780 	while (len > (3 * sizeof(short))) {
781 	    ND_TCHECK2(*rp, 3 * sizeof(short));
782 	    count = EXTRACT_LE_16BITS(rp);
783 	    if (count > 1024)
784 		return (1);	/* seems to be bogus from here on */
785 	    rp += sizeof(short);
786 	    len -= sizeof(short);
787 	    id = EXTRACT_LE_16BITS(rp);
788 	    rp += sizeof(short);
789 	    len -= sizeof(short);
790 	    info = EXTRACT_LE_16BITS(rp);
791 	    rp += sizeof(short);
792 	    len -= sizeof(short);
793 	    ND_PRINT((ndo, "{ids %d-%d cost %d hops %d} ", id, id + count,
794 			    RI_COST(info), RI_HOPS(info)));
795 	}
796 	return (1);
797 
798 trunc:
799 	return (0);
800 }
801 
802 static int
803 print_l2_routes(netdissect_options *ndo,
804                 const char *rp, u_int len)
805 {
806 	int count;
807 	int area;
808 	int info;
809 
810 	/* The last short is a checksum */
811 	while (len > (3 * sizeof(short))) {
812 	    ND_TCHECK2(*rp, 3 * sizeof(short));
813 	    count = EXTRACT_LE_16BITS(rp);
814 	    if (count > 1024)
815 		return (1);	/* seems to be bogus from here on */
816 	    rp += sizeof(short);
817 	    len -= sizeof(short);
818 	    area = EXTRACT_LE_16BITS(rp);
819 	    rp += sizeof(short);
820 	    len -= sizeof(short);
821 	    info = EXTRACT_LE_16BITS(rp);
822 	    rp += sizeof(short);
823 	    len -= sizeof(short);
824 	    ND_PRINT((ndo, "{areas %d-%d cost %d hops %d} ", area, area + count,
825 			    RI_COST(info), RI_HOPS(info)));
826 	}
827 	return (1);
828 
829 trunc:
830 	return (0);
831 }
832 
833 static void
834 print_i_info(netdissect_options *ndo,
835              int info)
836 {
837 	int ntype = info & II_TYPEMASK;
838 	switch (ntype) {
839 	case 0: ND_PRINT((ndo, "reserved-ntype? ")); break;
840 	case II_L2ROUT: ND_PRINT((ndo, "l2rout ")); break;
841 	case II_L1ROUT: ND_PRINT((ndo, "l1rout ")); break;
842 	case II_ENDNODE: ND_PRINT((ndo, "endnode ")); break;
843 	}
844 	if (info & II_VERIF)
845 	    ND_PRINT((ndo, "verif "));
846 	if (info & II_NOMCAST)
847 	    ND_PRINT((ndo, "nomcast "));
848 	if (info & II_BLOCK)
849 	    ND_PRINT((ndo, "blo "));
850 }
851 
852 static int
853 print_elist(const char *elp _U_, u_int len _U_)
854 {
855 	/* Not enough examples available for me to debug this */
856 	return (1);
857 }
858 
859 static int
860 print_nsp(netdissect_options *ndo,
861           const u_char *nspp, u_int nsplen)
862 {
863 	const struct nsphdr *nsphp = (struct nsphdr *)nspp;
864 	int dst, src, flags;
865 
866 	if (nsplen < sizeof(struct nsphdr))
867 		goto trunc;
868 	ND_TCHECK(*nsphp);
869 	flags = EXTRACT_LE_8BITS(nsphp->nh_flags);
870 	dst = EXTRACT_LE_16BITS(nsphp->nh_dst);
871 	src = EXTRACT_LE_16BITS(nsphp->nh_src);
872 
873 	switch (flags & NSP_TYPEMASK) {
874 	case MFT_DATA:
875 	    switch (flags & NSP_SUBMASK) {
876 	    case MFS_BOM:
877 	    case MFS_MOM:
878 	    case MFS_EOM:
879 	    case MFS_BOM+MFS_EOM:
880 		ND_PRINT((ndo, "data %d>%d ", src, dst));
881 		{
882 		    struct seghdr *shp = (struct seghdr *)nspp;
883 		    int ack;
884 #ifdef	PRINT_NSPDATA
885 		    u_char *dp;
886 #endif
887 		    u_int data_off = sizeof(struct minseghdr);
888 
889 		    if (nsplen < data_off)
890 			goto trunc;
891 		    ND_TCHECK(shp->sh_seq[0]);
892 		    ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
893 		    if (ack & SGQ_ACK) {	/* acknum field */
894 			if ((ack & SGQ_NAK) == SGQ_NAK)
895 			    ND_PRINT((ndo, "nak %d ", ack & SGQ_MASK));
896 			else
897 			    ND_PRINT((ndo, "ack %d ", ack & SGQ_MASK));
898 			data_off += sizeof(short);
899 			if (nsplen < data_off)
900 			    goto trunc;
901 			ND_TCHECK(shp->sh_seq[1]);
902 		        ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
903 			if (ack & SGQ_OACK) {	/* ackoth field */
904 			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
905 				ND_PRINT((ndo, "onak %d ", ack & SGQ_MASK));
906 			    else
907 				ND_PRINT((ndo, "oack %d ", ack & SGQ_MASK));
908 			    data_off += sizeof(short);
909 			    if (nsplen < data_off)
910 				goto trunc;
911 			    ND_TCHECK(shp->sh_seq[2]);
912 			    ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
913 			}
914 		    }
915 		    ND_PRINT((ndo, "seg %d ", ack & SGQ_MASK));
916 #ifdef	PRINT_NSPDATA
917 		    if (nsplen > data_off) {
918 			dp = &(nspp[data_off]);
919 			ND_TCHECK2(*dp, nsplen - data_off);
920 			pdata(ndo, dp, nsplen - data_off);
921 		    }
922 #endif
923 		}
924 		break;
925 	    case MFS_ILS+MFS_INT:
926 		ND_PRINT((ndo, "intr "));
927 		{
928 		    struct seghdr *shp = (struct seghdr *)nspp;
929 		    int ack;
930 #ifdef	PRINT_NSPDATA
931 		    u_char *dp;
932 #endif
933 		    u_int data_off = sizeof(struct minseghdr);
934 
935 		    if (nsplen < data_off)
936 			goto trunc;
937 		    ND_TCHECK(shp->sh_seq[0]);
938 		    ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
939 		    if (ack & SGQ_ACK) {	/* acknum field */
940 			if ((ack & SGQ_NAK) == SGQ_NAK)
941 			    ND_PRINT((ndo, "nak %d ", ack & SGQ_MASK));
942 			else
943 			    ND_PRINT((ndo, "ack %d ", ack & SGQ_MASK));
944 			data_off += sizeof(short);
945 			if (nsplen < data_off)
946 			    goto trunc;
947 			ND_TCHECK(shp->sh_seq[1]);
948 		        ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
949 			if (ack & SGQ_OACK) {	/* ackdat field */
950 			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
951 				ND_PRINT((ndo, "nakdat %d ", ack & SGQ_MASK));
952 			    else
953 				ND_PRINT((ndo, "ackdat %d ", ack & SGQ_MASK));
954 			    data_off += sizeof(short);
955 			    if (nsplen < data_off)
956 				goto trunc;
957 			    ND_TCHECK(shp->sh_seq[2]);
958 			    ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
959 			}
960 		    }
961 		    ND_PRINT((ndo, "seg %d ", ack & SGQ_MASK));
962 #ifdef	PRINT_NSPDATA
963 		    if (nsplen > data_off) {
964 			dp = &(nspp[data_off]);
965 			ND_TCHECK2(*dp, nsplen - data_off);
966 			pdata(ndo, dp, nsplen - data_off);
967 		    }
968 #endif
969 		}
970 		break;
971 	    case MFS_ILS:
972 		ND_PRINT((ndo, "link-service %d>%d ", src, dst));
973 		{
974 		    struct seghdr *shp = (struct seghdr *)nspp;
975 		    struct lsmsg *lsmp =
976 			(struct lsmsg *)&(nspp[sizeof(struct seghdr)]);
977 		    int ack;
978 		    int lsflags, fcval;
979 
980 		    if (nsplen < sizeof(struct seghdr) + sizeof(struct lsmsg))
981 			goto trunc;
982 		    ND_TCHECK(shp->sh_seq[0]);
983 		    ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
984 		    if (ack & SGQ_ACK) {	/* acknum field */
985 			if ((ack & SGQ_NAK) == SGQ_NAK)
986 			    ND_PRINT((ndo, "nak %d ", ack & SGQ_MASK));
987 			else
988 			    ND_PRINT((ndo, "ack %d ", ack & SGQ_MASK));
989 			ND_TCHECK(shp->sh_seq[1]);
990 		        ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
991 			if (ack & SGQ_OACK) {	/* ackdat field */
992 			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
993 				ND_PRINT((ndo, "nakdat %d ", ack & SGQ_MASK));
994 			    else
995 				ND_PRINT((ndo, "ackdat %d ", ack & SGQ_MASK));
996 			    ND_TCHECK(shp->sh_seq[2]);
997 			    ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
998 			}
999 		    }
1000 		    ND_PRINT((ndo, "seg %d ", ack & SGQ_MASK));
1001 		    ND_TCHECK(*lsmp);
1002 		    lsflags = EXTRACT_LE_8BITS(lsmp->ls_lsflags);
1003 		    fcval = EXTRACT_LE_8BITS(lsmp->ls_fcval);
1004 		    switch (lsflags & LSI_MASK) {
1005 		    case LSI_DATA:
1006 			ND_PRINT((ndo, "dat seg count %d ", fcval));
1007 			switch (lsflags & LSM_MASK) {
1008 			case LSM_NOCHANGE:
1009 			    break;
1010 			case LSM_DONOTSEND:
1011 			    ND_PRINT((ndo, "donotsend-data "));
1012 			    break;
1013 			case LSM_SEND:
1014 			    ND_PRINT((ndo, "send-data "));
1015 			    break;
1016 			default:
1017 			    ND_PRINT((ndo, "reserved-fcmod? %x", lsflags));
1018 			    break;
1019 			}
1020 			break;
1021 		    case LSI_INTR:
1022 			ND_PRINT((ndo, "intr req count %d ", fcval));
1023 			break;
1024 		    default:
1025 			ND_PRINT((ndo, "reserved-fcval-int? %x", lsflags));
1026 			break;
1027 		    }
1028 		}
1029 		break;
1030 	    default:
1031 		ND_PRINT((ndo, "reserved-subtype? %x %d > %d", flags, src, dst));
1032 		break;
1033 	    }
1034 	    break;
1035 	case MFT_ACK:
1036 	    switch (flags & NSP_SUBMASK) {
1037 	    case MFS_DACK:
1038 		ND_PRINT((ndo, "data-ack %d>%d ", src, dst));
1039 		{
1040 		    struct ackmsg *amp = (struct ackmsg *)nspp;
1041 		    int ack;
1042 
1043 		    if (nsplen < sizeof(struct ackmsg))
1044 			goto trunc;
1045 		    ND_TCHECK(*amp);
1046 		    ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]);
1047 		    if (ack & SGQ_ACK) {	/* acknum field */
1048 			if ((ack & SGQ_NAK) == SGQ_NAK)
1049 			    ND_PRINT((ndo, "nak %d ", ack & SGQ_MASK));
1050 			else
1051 			    ND_PRINT((ndo, "ack %d ", ack & SGQ_MASK));
1052 		        ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]);
1053 			if (ack & SGQ_OACK) {	/* ackoth field */
1054 			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
1055 				ND_PRINT((ndo, "onak %d ", ack & SGQ_MASK));
1056 			    else
1057 				ND_PRINT((ndo, "oack %d ", ack & SGQ_MASK));
1058 			}
1059 		    }
1060 		}
1061 		break;
1062 	    case MFS_IACK:
1063 		ND_PRINT((ndo, "ils-ack %d>%d ", src, dst));
1064 		{
1065 		    struct ackmsg *amp = (struct ackmsg *)nspp;
1066 		    int ack;
1067 
1068 		    if (nsplen < sizeof(struct ackmsg))
1069 			goto trunc;
1070 		    ND_TCHECK(*amp);
1071 		    ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]);
1072 		    if (ack & SGQ_ACK) {	/* acknum field */
1073 			if ((ack & SGQ_NAK) == SGQ_NAK)
1074 			    ND_PRINT((ndo, "nak %d ", ack & SGQ_MASK));
1075 			else
1076 			    ND_PRINT((ndo, "ack %d ", ack & SGQ_MASK));
1077 			ND_TCHECK(amp->ak_acknum[1]);
1078 		        ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]);
1079 			if (ack & SGQ_OACK) {	/* ackdat field */
1080 			    if ((ack & SGQ_ONAK) == SGQ_ONAK)
1081 				ND_PRINT((ndo, "nakdat %d ", ack & SGQ_MASK));
1082 			    else
1083 				ND_PRINT((ndo, "ackdat %d ", ack & SGQ_MASK));
1084 			}
1085 		    }
1086 		}
1087 		break;
1088 	    case MFS_CACK:
1089 		ND_PRINT((ndo, "conn-ack %d", dst));
1090 		break;
1091 	    default:
1092 		ND_PRINT((ndo, "reserved-acktype? %x %d > %d", flags, src, dst));
1093 		break;
1094 	    }
1095 	    break;
1096 	case MFT_CTL:
1097 	    switch (flags & NSP_SUBMASK) {
1098 	    case MFS_CI:
1099 	    case MFS_RCI:
1100 		if ((flags & NSP_SUBMASK) == MFS_CI)
1101 		    ND_PRINT((ndo, "conn-initiate "));
1102 		else
1103 		    ND_PRINT((ndo, "retrans-conn-initiate "));
1104 		ND_PRINT((ndo, "%d>%d ", src, dst));
1105 		{
1106 		    struct cimsg *cimp = (struct cimsg *)nspp;
1107 		    int services, info, segsize;
1108 #ifdef	PRINT_NSPDATA
1109 		    u_char *dp;
1110 #endif
1111 
1112 		    if (nsplen < sizeof(struct cimsg))
1113 			goto trunc;
1114 		    ND_TCHECK(*cimp);
1115 		    services = EXTRACT_LE_8BITS(cimp->ci_services);
1116 		    info = EXTRACT_LE_8BITS(cimp->ci_info);
1117 		    segsize = EXTRACT_LE_16BITS(cimp->ci_segsize);
1118 
1119 		    switch (services & COS_MASK) {
1120 		    case COS_NONE:
1121 			break;
1122 		    case COS_SEGMENT:
1123 			ND_PRINT((ndo, "seg "));
1124 			break;
1125 		    case COS_MESSAGE:
1126 			ND_PRINT((ndo, "msg "));
1127 			break;
1128 		    case COS_CRYPTSER:
1129 			ND_PRINT((ndo, "crypt "));
1130 			break;
1131 		    }
1132 		    switch (info & COI_MASK) {
1133 		    case COI_32:
1134 			ND_PRINT((ndo, "ver 3.2 "));
1135 			break;
1136 		    case COI_31:
1137 			ND_PRINT((ndo, "ver 3.1 "));
1138 			break;
1139 		    case COI_40:
1140 			ND_PRINT((ndo, "ver 4.0 "));
1141 			break;
1142 		    case COI_41:
1143 			ND_PRINT((ndo, "ver 4.1 "));
1144 			break;
1145 		    }
1146 		    ND_PRINT((ndo, "segsize %d ", segsize));
1147 #ifdef	PRINT_NSPDATA
1148 		    if (nsplen > sizeof(struct cimsg)) {
1149 			dp = &(nspp[sizeof(struct cimsg)]);
1150 			ND_TCHECK2(*dp, nsplen - sizeof(struct cimsg));
1151 			pdata(ndo, dp, nsplen - sizeof(struct cimsg));
1152 		    }
1153 #endif
1154 		}
1155 		break;
1156 	    case MFS_CC:
1157 		ND_PRINT((ndo, "conn-confirm %d>%d ", src, dst));
1158 		{
1159 		    struct ccmsg *ccmp = (struct ccmsg *)nspp;
1160 		    int services, info;
1161 		    u_int segsize, optlen;
1162 #ifdef	PRINT_NSPDATA
1163 		    u_char *dp;
1164 #endif
1165 
1166 		    if (nsplen < sizeof(struct ccmsg))
1167 			goto trunc;
1168 		    ND_TCHECK(*ccmp);
1169 		    services = EXTRACT_LE_8BITS(ccmp->cc_services);
1170 		    info = EXTRACT_LE_8BITS(ccmp->cc_info);
1171 		    segsize = EXTRACT_LE_16BITS(ccmp->cc_segsize);
1172 		    optlen = EXTRACT_LE_8BITS(ccmp->cc_optlen);
1173 
1174 		    switch (services & COS_MASK) {
1175 		    case COS_NONE:
1176 			break;
1177 		    case COS_SEGMENT:
1178 			ND_PRINT((ndo, "seg "));
1179 			break;
1180 		    case COS_MESSAGE:
1181 			ND_PRINT((ndo, "msg "));
1182 			break;
1183 		    case COS_CRYPTSER:
1184 			ND_PRINT((ndo, "crypt "));
1185 			break;
1186 		    }
1187 		    switch (info & COI_MASK) {
1188 		    case COI_32:
1189 			ND_PRINT((ndo, "ver 3.2 "));
1190 			break;
1191 		    case COI_31:
1192 			ND_PRINT((ndo, "ver 3.1 "));
1193 			break;
1194 		    case COI_40:
1195 			ND_PRINT((ndo, "ver 4.0 "));
1196 			break;
1197 		    case COI_41:
1198 			ND_PRINT((ndo, "ver 4.1 "));
1199 			break;
1200 		    }
1201 		    ND_PRINT((ndo, "segsize %d ", segsize));
1202 		    if (optlen) {
1203 			ND_PRINT((ndo, "optlen %d ", optlen));
1204 #ifdef	PRINT_NSPDATA
1205 			if (optlen > nsplen - sizeof(struct ccmsg))
1206 			    goto trunc;
1207 			dp = &(nspp[sizeof(struct ccmsg)]);
1208 			ND_TCHECK2(*dp, optlen);
1209 			pdata(ndo, dp, optlen);
1210 #endif
1211 		    }
1212 		}
1213 		break;
1214 	    case MFS_DI:
1215 		ND_PRINT((ndo, "disconn-initiate %d>%d ", src, dst));
1216 		{
1217 		    struct dimsg *dimp = (struct dimsg *)nspp;
1218 		    int reason;
1219 		    u_int optlen;
1220 #ifdef	PRINT_NSPDATA
1221 		    u_char *dp;
1222 #endif
1223 
1224 		    if (nsplen < sizeof(struct dimsg))
1225 			goto trunc;
1226 		    ND_TCHECK(*dimp);
1227 		    reason = EXTRACT_LE_16BITS(dimp->di_reason);
1228 		    optlen = EXTRACT_LE_8BITS(dimp->di_optlen);
1229 
1230 		    print_reason(ndo, reason);
1231 		    if (optlen) {
1232 			ND_PRINT((ndo, "optlen %d ", optlen));
1233 #ifdef	PRINT_NSPDATA
1234 			if (optlen > nsplen - sizeof(struct dimsg))
1235 			    goto trunc;
1236 			dp = &(nspp[sizeof(struct dimsg)]);
1237 			ND_TCHECK2(*dp, optlen);
1238 			pdata(ndo, dp, optlen);
1239 #endif
1240 		    }
1241 		}
1242 		break;
1243 	    case MFS_DC:
1244 		ND_PRINT((ndo, "disconn-confirm %d>%d ", src, dst));
1245 		{
1246 		    struct dcmsg *dcmp = (struct dcmsg *)nspp;
1247 		    int reason;
1248 
1249 		    ND_TCHECK(*dcmp);
1250 		    reason = EXTRACT_LE_16BITS(dcmp->dc_reason);
1251 
1252 		    print_reason(ndo, reason);
1253 		}
1254 		break;
1255 	    default:
1256 		ND_PRINT((ndo, "reserved-ctltype? %x %d > %d", flags, src, dst));
1257 		break;
1258 	    }
1259 	    break;
1260 	default:
1261 	    ND_PRINT((ndo, "reserved-type? %x %d > %d", flags, src, dst));
1262 	    break;
1263 	}
1264 	return (1);
1265 
1266 trunc:
1267 	return (0);
1268 }
1269 
1270 static const struct tok reason2str[] = {
1271 	{ UC_OBJREJECT,		"object rejected connect" },
1272 	{ UC_RESOURCES,		"insufficient resources" },
1273 	{ UC_NOSUCHNODE,	"unrecognized node name" },
1274 	{ DI_SHUT,		"node is shutting down" },
1275 	{ UC_NOSUCHOBJ,		"unrecognized object" },
1276 	{ UC_INVOBJFORMAT,	"invalid object name format" },
1277 	{ UC_OBJTOOBUSY,	"object too busy" },
1278 	{ DI_PROTOCOL,		"protocol error discovered" },
1279 	{ DI_TPA,		"third party abort" },
1280 	{ UC_USERABORT,		"user abort" },
1281 	{ UC_INVNODEFORMAT,	"invalid node name format" },
1282 	{ UC_LOCALSHUT,		"local node shutting down" },
1283 	{ DI_LOCALRESRC,	"insufficient local resources" },
1284 	{ DI_REMUSERRESRC,	"insufficient remote user resources" },
1285 	{ UC_ACCESSREJECT,	"invalid access control information" },
1286 	{ DI_BADACCNT,		"bad ACCOUNT information" },
1287 	{ UC_NORESPONSE,	"no response from object" },
1288 	{ UC_UNREACHABLE,	"node unreachable" },
1289 	{ DC_NOLINK,		"no link terminate" },
1290 	{ DC_COMPLETE,		"disconnect complete" },
1291 	{ DI_BADIMAGE,		"bad image data in connect" },
1292 	{ DI_SERVMISMATCH,	"cryptographic service mismatch" },
1293 	{ 0,			NULL }
1294 };
1295 
1296 static void
1297 print_reason(netdissect_options *ndo,
1298              register int reason)
1299 {
1300 	ND_PRINT((ndo, "%s ", tok2str(reason2str, "reason-%d", reason)));
1301 }
1302 
1303 const char *
1304 dnnum_string(u_short dnaddr)
1305 {
1306 	char *str;
1307 	size_t siz;
1308 	int area = (u_short)(dnaddr & AREAMASK) >> AREASHIFT;
1309 	int node = dnaddr & NODEMASK;
1310 
1311 	str = (char *)malloc(siz = sizeof("00.0000"));
1312 	if (str == NULL)
1313 		error("dnnum_string: malloc");
1314 	snprintf(str, siz, "%d.%d", area, node);
1315 	return(str);
1316 }
1317 
1318 const char *
1319 dnname_string(u_short dnaddr)
1320 {
1321 #ifdef HAVE_DNET_HTOA
1322 	struct dn_naddr dna;
1323 	char *dnname;
1324 
1325 	dna.a_len = sizeof(short);
1326 	memcpy((char *)dna.a_addr, (char *)&dnaddr, sizeof(short));
1327 	dnname = dnet_htoa(&dna);
1328 	if(dnname != NULL)
1329 		return (strdup(dnname));
1330 	else
1331 		return(dnnum_string(dnaddr));
1332 #else
1333 	return(dnnum_string(dnaddr));	/* punt */
1334 #endif
1335 }
1336 
1337 #ifdef	PRINT_NSPDATA
1338 static void
1339 pdata(netdissect_options *ndo,
1340       u_char *dp, u_int maxlen)
1341 {
1342 	char c;
1343 	u_int x = maxlen;
1344 
1345 	while (x-- > 0) {
1346 	    c = *dp++;
1347 	    safeputchar(ndo, c);
1348 	}
1349 }
1350 #endif
1351