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