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