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