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