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