]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-decnet.c
usr.sbin: Automated cleanup of cdefs and other formatting
[FreeBSD/FreeBSD.git] / contrib / tcpdump / print-decnet.c
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
40 typedef nd_uint8_t byte;                /* single byte field */
41 #else
42 /*
43  * the keyword 'byte' generates conflicts in Windows
44  */
45 typedef nd_uint8_t Byte;                /* single byte field */
46 #define byte Byte
47 #endif /* _WIN32 */
48 typedef nd_uint16_t word;               /* 2 byte field */
49 typedef nd_uint32_t longword;           /* 4 bytes field */
50
51 /*
52  * Definitions for DECNET Phase IV protocol headers
53  */
54 typedef 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  */
71 struct 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
79 struct 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
94 union 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  */
160 struct 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
173 struct 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
180 struct 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
187 struct 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
194 struct 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
201 struct 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
216 struct 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
233 union 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  */
358 struct 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
365 struct 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
373 struct 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
381 struct lsmsg                            /* link service message (after hdr) */
382   {
383     byte        ls_lsflags;             /* link service flags */
384     byte        ls_fcval;               /* flow control value */
385   };
386
387 struct 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
395 struct 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
403 struct ciackmsg                         /* connect acknowledgement message */
404   {
405     byte        ck_flags;               /* message flags */
406     word        ck_dst;                 /* destination link address */
407   };
408
409 struct 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
419 struct 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
430 struct 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
440 struct 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
449 struct 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 */
458 static int print_decnet_ctlmsg(netdissect_options *, const union routehdr *, u_int, u_int);
459 static void print_t_info(netdissect_options *, u_int);
460 static void print_l1_routes(netdissect_options *, const u_char *, u_int);
461 static void print_l2_routes(netdissect_options *, const u_char *, u_int);
462 static void print_i_info(netdissect_options *, u_int);
463 static void print_elist(const u_char *, u_int);
464 static int print_nsp(netdissect_options *, const u_char *, u_int);
465 static void print_reason(netdissect_options *, u_int);
466
467 void
468 decnet_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
573 invalid:
574         nd_print_invalid(ndo);
575 }
576
577 static int
578 print_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
694 invalid:
695         return (0);
696 }
697
698 static void
699 print_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
715 static void
716 print_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
742 static void
743 print_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
769 static void
770 print_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
788 static void
789 print_elist(const u_char *elp _U_, u_int len _U_)
790 {
791         /* Not enough examples available for me to debug this */
792 }
793
794 static int
795 print_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
1131 invalid:
1132         return (0);
1133 }
1134
1135 static 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
1161 static void
1162 print_reason(netdissect_options *ndo,
1163              u_int reason)
1164 {
1165         ND_PRINT("%s ", tok2str(reason2str, "reason-%u", reason));
1166 }
1167
1168 const char *
1169 dnnum_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 }