xref: /freebsd/contrib/tcpdump/print-babel.c (revision 3c602fabf9b894ff79f08a80cbb7ad3b1eb84e62)
1cac3dcd5SXin LI /*
2cac3dcd5SXin LI  * Copyright (c) 2007-2011 Grégoire Henry, Juliusz Chroboczek
3cac3dcd5SXin LI  *
4cac3dcd5SXin LI  * Redistribution and use in source and binary forms, with or without
5cac3dcd5SXin LI  * modification, are permitted provided that the following conditions
6cac3dcd5SXin LI  * are met:
7cac3dcd5SXin LI  * 1. Redistributions of source code must retain the above copyright
8cac3dcd5SXin LI  *    notice, this list of conditions and the following disclaimer.
9cac3dcd5SXin LI  * 2. Redistributions in binary form must reproduce the above copyright
10cac3dcd5SXin LI  *    notice, this list of conditions and the following disclaimer in the
11cac3dcd5SXin LI  *    documentation and/or other materials provided with the distribution.
12cac3dcd5SXin LI  * 3. Neither the name of the project nor the names of its contributors
13cac3dcd5SXin LI  *    may be used to endorse or promote products derived from this software
14cac3dcd5SXin LI  *    without specific prior written permission.
15cac3dcd5SXin LI  *
16cac3dcd5SXin LI  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17cac3dcd5SXin LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18cac3dcd5SXin LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19cac3dcd5SXin LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20cac3dcd5SXin LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21cac3dcd5SXin LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22cac3dcd5SXin LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23cac3dcd5SXin LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24cac3dcd5SXin LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25cac3dcd5SXin LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26cac3dcd5SXin LI  * SUCH DAMAGE.
27cac3dcd5SXin LI  */
28cac3dcd5SXin LI 
29*3c602fabSXin LI #define NETDISSECT_REWORKED
30cac3dcd5SXin LI #ifdef HAVE_CONFIG_H
31cac3dcd5SXin LI #include "config.h"
32cac3dcd5SXin LI #endif
33cac3dcd5SXin LI 
34cac3dcd5SXin LI #include <tcpdump-stdinc.h>
35cac3dcd5SXin LI 
36cac3dcd5SXin LI #include <stdio.h>
37cac3dcd5SXin LI #include <string.h>
38cac3dcd5SXin LI 
39cac3dcd5SXin LI #include "interface.h"
40*3c602fabSXin LI #include "addrtoname.h"
41cac3dcd5SXin LI #include "extract.h"
42cac3dcd5SXin LI 
43*3c602fabSXin LI static const char tstr[] = "[|babel]";
44*3c602fabSXin LI 
45*3c602fabSXin LI static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
46cac3dcd5SXin LI 
47cac3dcd5SXin LI void
48*3c602fabSXin LI babel_print(netdissect_options *ndo,
49*3c602fabSXin LI             const u_char *cp, u_int length) {
50*3c602fabSXin LI     ND_PRINT((ndo, "babel"));
51cac3dcd5SXin LI 
52*3c602fabSXin LI     ND_TCHECK2(*cp, 4);
53cac3dcd5SXin LI 
54cac3dcd5SXin LI     if(cp[0] != 42) {
55*3c602fabSXin LI         ND_PRINT((ndo, " malformed header"));
56cac3dcd5SXin LI         return;
57cac3dcd5SXin LI     } else {
58*3c602fabSXin LI         ND_PRINT((ndo, " %d", cp[1]));
59cac3dcd5SXin LI     }
60cac3dcd5SXin LI 
61cac3dcd5SXin LI     switch(cp[1]) {
62cac3dcd5SXin LI     case 2:
63*3c602fabSXin LI         babel_print_v2(ndo, cp, length);
64cac3dcd5SXin LI         break;
65cac3dcd5SXin LI     default:
66*3c602fabSXin LI         ND_PRINT((ndo, " unknown version"));
67cac3dcd5SXin LI         break;
68cac3dcd5SXin LI     }
69cac3dcd5SXin LI 
70cac3dcd5SXin LI     return;
71cac3dcd5SXin LI 
72cac3dcd5SXin LI  trunc:
73*3c602fabSXin LI     ND_PRINT((ndo, " %s", tstr));
74cac3dcd5SXin LI     return;
75cac3dcd5SXin LI }
76cac3dcd5SXin LI 
77*3c602fabSXin LI /* TLVs */
78cac3dcd5SXin LI #define MESSAGE_PAD1 0
79cac3dcd5SXin LI #define MESSAGE_PADN 1
80cac3dcd5SXin LI #define MESSAGE_ACK_REQ 2
81cac3dcd5SXin LI #define MESSAGE_ACK 3
82cac3dcd5SXin LI #define MESSAGE_HELLO 4
83cac3dcd5SXin LI #define MESSAGE_IHU 5
84cac3dcd5SXin LI #define MESSAGE_ROUTER_ID 6
85cac3dcd5SXin LI #define MESSAGE_NH 7
86cac3dcd5SXin LI #define MESSAGE_UPDATE 8
87cac3dcd5SXin LI #define MESSAGE_REQUEST 9
88cac3dcd5SXin LI #define MESSAGE_MH_REQUEST 10
89d03c0883SXin LI #define MESSAGE_TSPC 11
90d03c0883SXin LI #define MESSAGE_HMAC 12
91cac3dcd5SXin LI 
92*3c602fabSXin LI /* sub-TLVs */
93*3c602fabSXin LI #define MESSAGE_SUB_PAD1 0
94*3c602fabSXin LI #define MESSAGE_SUB_PADN 1
95*3c602fabSXin LI #define MESSAGE_SUB_DIVERSITY 2
96*3c602fabSXin LI #define MESSAGE_SUB_TIMESTAMP 3
97*3c602fabSXin LI 
98*3c602fabSXin LI /* Diversity sub-TLV channel codes */
99*3c602fabSXin LI static const struct tok diversity_str[] = {
100*3c602fabSXin LI     { 0,   "reserved" },
101*3c602fabSXin LI     { 255, "all"      },
102*3c602fabSXin LI     { 0, NULL }
103*3c602fabSXin LI };
104*3c602fabSXin LI 
105cac3dcd5SXin LI static const char *
106cac3dcd5SXin LI format_id(const u_char *id)
107cac3dcd5SXin LI {
108cac3dcd5SXin LI     static char buf[25];
109cac3dcd5SXin LI     snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
110cac3dcd5SXin LI              id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
111cac3dcd5SXin LI     buf[24] = '\0';
112cac3dcd5SXin LI     return buf;
113cac3dcd5SXin LI }
114cac3dcd5SXin LI 
115cac3dcd5SXin LI static const unsigned char v4prefix[16] =
116cac3dcd5SXin LI     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
117cac3dcd5SXin LI 
118cac3dcd5SXin LI static const char *
119*3c602fabSXin LI format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
120cac3dcd5SXin LI {
121cac3dcd5SXin LI     static char buf[50];
122cac3dcd5SXin LI     if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
123*3c602fabSXin LI         snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
124cac3dcd5SXin LI     else
125d03c0883SXin LI #ifdef INET6
126*3c602fabSXin LI         snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
127d03c0883SXin LI #else
128d03c0883SXin LI         snprintf(buf, 50, "IPv6 addresses not supported");
129d03c0883SXin LI #endif
130cac3dcd5SXin LI     buf[49] = '\0';
131cac3dcd5SXin LI     return buf;
132cac3dcd5SXin LI }
133cac3dcd5SXin LI 
134cac3dcd5SXin LI static const char *
135*3c602fabSXin LI format_address(netdissect_options *ndo, const u_char *prefix)
136cac3dcd5SXin LI {
137cac3dcd5SXin LI     if(memcmp(prefix, v4prefix, 12) == 0)
138*3c602fabSXin LI         return ipaddr_string(ndo, prefix + 12);
139cac3dcd5SXin LI     else
140d03c0883SXin LI #ifdef INET6
141*3c602fabSXin LI         return ip6addr_string(ndo, prefix);
142d03c0883SXin LI #else
143d03c0883SXin LI         return "IPv6 addresses not supported";
144d03c0883SXin LI #endif
145cac3dcd5SXin LI }
146cac3dcd5SXin LI 
147*3c602fabSXin LI static const char *
148*3c602fabSXin LI format_interval(const uint16_t i)
149*3c602fabSXin LI {
150*3c602fabSXin LI     static char buf[sizeof("000.00s")];
151*3c602fabSXin LI 
152*3c602fabSXin LI     if (i == 0)
153*3c602fabSXin LI         return "0.0s (bogus)";
154*3c602fabSXin LI     snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
155*3c602fabSXin LI     return buf;
156*3c602fabSXin LI }
157*3c602fabSXin LI 
158*3c602fabSXin LI static const char *
159*3c602fabSXin LI format_interval_update(const uint16_t i)
160*3c602fabSXin LI {
161*3c602fabSXin LI     return i == 0xFFFF ? "infinity" : format_interval(i);
162*3c602fabSXin LI }
163*3c602fabSXin LI 
164*3c602fabSXin LI static const char *
165*3c602fabSXin LI format_timestamp(const uint32_t i)
166*3c602fabSXin LI {
167*3c602fabSXin LI     static char buf[sizeof("0000.000000s")];
168*3c602fabSXin LI     snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
169*3c602fabSXin LI     return buf;
170*3c602fabSXin LI }
171*3c602fabSXin LI 
172*3c602fabSXin LI /* Return number of octets consumed from the input buffer (not the prefix length
173*3c602fabSXin LI  * in bytes), or -1 for encoding error. */
174cac3dcd5SXin LI static int
175cac3dcd5SXin LI network_prefix(int ae, int plen, unsigned int omitted,
176cac3dcd5SXin LI                const unsigned char *p, const unsigned char *dp,
177cac3dcd5SXin LI                unsigned int len, unsigned char *p_r)
178cac3dcd5SXin LI {
179cac3dcd5SXin LI     unsigned pb;
180cac3dcd5SXin LI     unsigned char prefix[16];
181*3c602fabSXin LI     int consumed = 0;
182cac3dcd5SXin LI 
183cac3dcd5SXin LI     if(plen >= 0)
184cac3dcd5SXin LI         pb = (plen + 7) / 8;
185cac3dcd5SXin LI     else if(ae == 1)
186cac3dcd5SXin LI         pb = 4;
187cac3dcd5SXin LI     else
188cac3dcd5SXin LI         pb = 16;
189cac3dcd5SXin LI 
190cac3dcd5SXin LI     if(pb > 16)
191cac3dcd5SXin LI         return -1;
192cac3dcd5SXin LI 
193cac3dcd5SXin LI     memset(prefix, 0, 16);
194cac3dcd5SXin LI 
195cac3dcd5SXin LI     switch(ae) {
196cac3dcd5SXin LI     case 0: break;
197cac3dcd5SXin LI     case 1:
198cac3dcd5SXin LI         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
199cac3dcd5SXin LI             return -1;
200cac3dcd5SXin LI         memcpy(prefix, v4prefix, 12);
201cac3dcd5SXin LI         if(omitted) {
202cac3dcd5SXin LI             if (dp == NULL) return -1;
203cac3dcd5SXin LI             memcpy(prefix, dp, 12 + omitted);
204cac3dcd5SXin LI         }
205*3c602fabSXin LI         if(pb > omitted) {
206*3c602fabSXin LI             memcpy(prefix + 12 + omitted, p, pb - omitted);
207*3c602fabSXin LI             consumed = pb - omitted;
208*3c602fabSXin LI         }
209cac3dcd5SXin LI         break;
210cac3dcd5SXin LI     case 2:
211cac3dcd5SXin LI         if(omitted > 16 || (pb > omitted && len < pb - omitted))
212cac3dcd5SXin LI             return -1;
213cac3dcd5SXin LI         if(omitted) {
214cac3dcd5SXin LI             if (dp == NULL) return -1;
215cac3dcd5SXin LI             memcpy(prefix, dp, omitted);
216cac3dcd5SXin LI         }
217*3c602fabSXin LI         if(pb > omitted) {
218*3c602fabSXin LI             memcpy(prefix + omitted, p, pb - omitted);
219*3c602fabSXin LI             consumed = pb - omitted;
220*3c602fabSXin LI         }
221cac3dcd5SXin LI         break;
222cac3dcd5SXin LI     case 3:
223cac3dcd5SXin LI         if(pb > 8 && len < pb - 8) return -1;
224cac3dcd5SXin LI         prefix[0] = 0xfe;
225cac3dcd5SXin LI         prefix[1] = 0x80;
226*3c602fabSXin LI         if(pb > 8) {
227*3c602fabSXin LI             memcpy(prefix + 8, p, pb - 8);
228*3c602fabSXin LI             consumed = pb - 8;
229*3c602fabSXin LI         }
230cac3dcd5SXin LI         break;
231cac3dcd5SXin LI     default:
232cac3dcd5SXin LI         return -1;
233cac3dcd5SXin LI     }
234cac3dcd5SXin LI 
235cac3dcd5SXin LI     memcpy(p_r, prefix, 16);
236*3c602fabSXin LI     return consumed;
237cac3dcd5SXin LI }
238cac3dcd5SXin LI 
239cac3dcd5SXin LI static int
240cac3dcd5SXin LI network_address(int ae, const unsigned char *a, unsigned int len,
241cac3dcd5SXin LI                 unsigned char *a_r)
242cac3dcd5SXin LI {
243cac3dcd5SXin LI     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
244cac3dcd5SXin LI }
245cac3dcd5SXin LI 
246*3c602fabSXin LI /*
247*3c602fabSXin LI  * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
248*3c602fabSXin LI  * their encoding is similar to the encoding of TLVs, but the type namespace is
249*3c602fabSXin LI  * different:
250*3c602fabSXin LI  *
251*3c602fabSXin LI  * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
252*3c602fabSXin LI  * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
253*3c602fabSXin LI  * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
254*3c602fabSXin LI  *   data. Its body is a variable-length sequence of 8-bit unsigned integers,
255*3c602fabSXin LI  *   each representing per-hop number of interferring radio channel for the
256*3c602fabSXin LI  *   prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
257*3c602fabSXin LI  *   255 interferes with any other channel.
258*3c602fabSXin LI  * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
259*3c602fabSXin LI  *   neighbours. In the case of a Hello TLV, the body stores a 32-bits
260*3c602fabSXin LI  *   timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
261*3c602fabSXin LI  *   stored.
262*3c602fabSXin LI  *
263*3c602fabSXin LI  * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
264*3c602fabSXin LI  * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
265*3c602fabSXin LI  * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
266*3c602fabSXin LI  * The former would mean a lack of any claims about the interference, and the
267*3c602fabSXin LI  * latter would state that interference is definitely absent.
268*3c602fabSXin LI  * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
269*3c602fabSXin LI  * semantic of the sub-TLV is different in each case.
270*3c602fabSXin LI  */
271*3c602fabSXin LI static void
272*3c602fabSXin LI subtlvs_print(netdissect_options *ndo,
273*3c602fabSXin LI               const u_char *cp, const u_char *ep, const uint8_t tlv_type) {
274*3c602fabSXin LI     uint8_t subtype, sublen;
275*3c602fabSXin LI     const char *sep;
276*3c602fabSXin LI     uint32_t t1, t2;
277*3c602fabSXin LI 
278*3c602fabSXin LI     while (cp < ep) {
279*3c602fabSXin LI         subtype = *cp++;
280*3c602fabSXin LI         if(subtype == MESSAGE_SUB_PAD1) {
281*3c602fabSXin LI             ND_PRINT((ndo, " sub-pad1"));
282*3c602fabSXin LI             continue;
283*3c602fabSXin LI         }
284*3c602fabSXin LI         if(cp == ep)
285*3c602fabSXin LI             goto corrupt;
286*3c602fabSXin LI         sublen = *cp++;
287*3c602fabSXin LI         if(cp + sublen > ep)
288*3c602fabSXin LI             goto corrupt;
289*3c602fabSXin LI 
290*3c602fabSXin LI         switch(subtype) {
291*3c602fabSXin LI         case MESSAGE_SUB_PADN:
292*3c602fabSXin LI             ND_PRINT((ndo, " sub-padn"));
293*3c602fabSXin LI             cp += sublen;
294*3c602fabSXin LI             break;
295*3c602fabSXin LI         case MESSAGE_SUB_DIVERSITY:
296*3c602fabSXin LI             ND_PRINT((ndo, " sub-diversity"));
297*3c602fabSXin LI             if (sublen == 0) {
298*3c602fabSXin LI                 ND_PRINT((ndo, " empty"));
299*3c602fabSXin LI                 break;
300*3c602fabSXin LI             }
301*3c602fabSXin LI             sep = " ";
302*3c602fabSXin LI             while(sublen--) {
303*3c602fabSXin LI                 ND_PRINT((ndo, "%s%s", sep, tok2str(diversity_str, "%u", *cp++)));
304*3c602fabSXin LI                 sep = "-";
305*3c602fabSXin LI             }
306*3c602fabSXin LI             if(tlv_type != MESSAGE_UPDATE)
307*3c602fabSXin LI                 ND_PRINT((ndo, " (bogus)"));
308*3c602fabSXin LI             break;
309*3c602fabSXin LI         case MESSAGE_SUB_TIMESTAMP:
310*3c602fabSXin LI             ND_PRINT((ndo, " sub-timestamp"));
311*3c602fabSXin LI             if(tlv_type == MESSAGE_HELLO) {
312*3c602fabSXin LI                 if(sublen < 4)
313*3c602fabSXin LI                     goto corrupt;
314*3c602fabSXin LI                 t1 = EXTRACT_32BITS(cp);
315*3c602fabSXin LI                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
316*3c602fabSXin LI             } else if(tlv_type == MESSAGE_IHU) {
317*3c602fabSXin LI                 if(sublen < 8)
318*3c602fabSXin LI                     goto corrupt;
319*3c602fabSXin LI                 t1 = EXTRACT_32BITS(cp);
320*3c602fabSXin LI                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
321*3c602fabSXin LI                 t2 = EXTRACT_32BITS(cp + 4);
322*3c602fabSXin LI                 ND_PRINT((ndo, "|%s", format_timestamp(t2)));
323*3c602fabSXin LI             } else
324*3c602fabSXin LI                 ND_PRINT((ndo, " (bogus)"));
325*3c602fabSXin LI             cp += sublen;
326*3c602fabSXin LI             break;
327*3c602fabSXin LI         default:
328*3c602fabSXin LI             ND_PRINT((ndo, " sub-unknown-0x%02x", subtype));
329*3c602fabSXin LI             cp += sublen;
330*3c602fabSXin LI         } /* switch */
331*3c602fabSXin LI     } /* while */
332*3c602fabSXin LI     return;
333*3c602fabSXin LI 
334*3c602fabSXin LI  corrupt:
335*3c602fabSXin LI     ND_PRINT((ndo, " (corrupt)"));
336*3c602fabSXin LI }
337*3c602fabSXin LI 
338cac3dcd5SXin LI #define ICHECK(i, l) \
339cac3dcd5SXin LI 	if ((i) + (l) > bodylen || (i) + (l) > length) goto corrupt;
340cac3dcd5SXin LI 
341cac3dcd5SXin LI static void
342*3c602fabSXin LI babel_print_v2(netdissect_options *ndo,
343*3c602fabSXin LI                const u_char *cp, u_int length) {
344cac3dcd5SXin LI     u_int i;
345cac3dcd5SXin LI     u_short bodylen;
346cac3dcd5SXin LI     u_char v4_prefix[16] =
347cac3dcd5SXin LI         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
348cac3dcd5SXin LI     u_char v6_prefix[16] = {0};
349cac3dcd5SXin LI 
350*3c602fabSXin LI     ND_TCHECK2(*cp, 4);
351cac3dcd5SXin LI     if (length < 4)
352cac3dcd5SXin LI         goto corrupt;
353cac3dcd5SXin LI     bodylen = EXTRACT_16BITS(cp + 2);
354*3c602fabSXin LI     ND_PRINT((ndo, " (%u)", bodylen));
355cac3dcd5SXin LI 
356cac3dcd5SXin LI     /* Process the TLVs in the body */
357cac3dcd5SXin LI     i = 0;
358cac3dcd5SXin LI     while(i < bodylen) {
359cac3dcd5SXin LI         const u_char *message;
360d03c0883SXin LI         u_int type, len;
361cac3dcd5SXin LI 
362cac3dcd5SXin LI         message = cp + 4 + i;
363*3c602fabSXin LI 
364*3c602fabSXin LI         ND_TCHECK2(*message, 1);
365*3c602fabSXin LI         if((type = message[0]) == MESSAGE_PAD1) {
366*3c602fabSXin LI             ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
367*3c602fabSXin LI             i += 1;
368*3c602fabSXin LI             continue;
369*3c602fabSXin LI         }
370*3c602fabSXin LI 
371*3c602fabSXin LI         ND_TCHECK2(*message, 2);
372cac3dcd5SXin LI         ICHECK(i, 2);
373cac3dcd5SXin LI         len = message[1];
374cac3dcd5SXin LI 
375*3c602fabSXin LI         ND_TCHECK2(*message, 2 + len);
376cac3dcd5SXin LI         ICHECK(i, 2 + len);
377cac3dcd5SXin LI 
378cac3dcd5SXin LI         switch(type) {
379cac3dcd5SXin LI         case MESSAGE_PADN: {
380*3c602fabSXin LI             if (!ndo->ndo_vflag)
381*3c602fabSXin LI                 ND_PRINT((ndo, " padN"));
382cac3dcd5SXin LI             else
383*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tPad %d", len + 2));
384cac3dcd5SXin LI         }
385cac3dcd5SXin LI             break;
386cac3dcd5SXin LI 
387cac3dcd5SXin LI         case MESSAGE_ACK_REQ: {
388cac3dcd5SXin LI             u_short nonce, interval;
389*3c602fabSXin LI             if (!ndo->ndo_vflag)
390*3c602fabSXin LI                 ND_PRINT((ndo, " ack-req"));
391cac3dcd5SXin LI             else {
392*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tAcknowledgment Request "));
393cac3dcd5SXin LI                 if(len < 6) goto corrupt;
394cac3dcd5SXin LI                 nonce = EXTRACT_16BITS(message + 4);
395cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
396*3c602fabSXin LI                 ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
397cac3dcd5SXin LI             }
398cac3dcd5SXin LI         }
399cac3dcd5SXin LI             break;
400cac3dcd5SXin LI 
401cac3dcd5SXin LI         case MESSAGE_ACK: {
402cac3dcd5SXin LI             u_short nonce;
403*3c602fabSXin LI             if (!ndo->ndo_vflag)
404*3c602fabSXin LI                 ND_PRINT((ndo, " ack"));
405cac3dcd5SXin LI             else {
406*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tAcknowledgment "));
407cac3dcd5SXin LI                 if(len < 2) goto corrupt;
408cac3dcd5SXin LI                 nonce = EXTRACT_16BITS(message + 2);
409*3c602fabSXin LI                 ND_PRINT((ndo, "%04x", nonce));
410cac3dcd5SXin LI             }
411cac3dcd5SXin LI         }
412cac3dcd5SXin LI             break;
413cac3dcd5SXin LI 
414cac3dcd5SXin LI         case MESSAGE_HELLO:  {
415cac3dcd5SXin LI             u_short seqno, interval;
416*3c602fabSXin LI             if (!ndo->ndo_vflag)
417*3c602fabSXin LI                 ND_PRINT((ndo, " hello"));
418cac3dcd5SXin LI             else {
419*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tHello "));
420cac3dcd5SXin LI                 if(len < 6) goto corrupt;
421cac3dcd5SXin LI                 seqno = EXTRACT_16BITS(message + 4);
422cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
423*3c602fabSXin LI                 ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
424*3c602fabSXin LI                 /* Extra data. */
425*3c602fabSXin LI                 if(len > 6)
426*3c602fabSXin LI                     subtlvs_print(ndo, message + 8, message + 2 + len, type);
427cac3dcd5SXin LI             }
428cac3dcd5SXin LI         }
429cac3dcd5SXin LI             break;
430cac3dcd5SXin LI 
431cac3dcd5SXin LI         case MESSAGE_IHU: {
432cac3dcd5SXin LI             unsigned short txcost, interval;
433*3c602fabSXin LI             if (!ndo->ndo_vflag)
434*3c602fabSXin LI                 ND_PRINT((ndo, " ihu"));
435cac3dcd5SXin LI             else {
436cac3dcd5SXin LI                 u_char address[16];
437cac3dcd5SXin LI                 int rc;
438*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tIHU "));
439cac3dcd5SXin LI                 if(len < 6) goto corrupt;
440cac3dcd5SXin LI                 txcost = EXTRACT_16BITS(message + 4);
441cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
442cac3dcd5SXin LI                 rc = network_address(message[2], message + 8, len - 6, address);
443*3c602fabSXin LI                 if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
444*3c602fabSXin LI                 ND_PRINT((ndo, "%s txcost %u interval %s",
445*3c602fabSXin LI                        format_address(ndo, address), txcost, format_interval(interval)));
446*3c602fabSXin LI                 /* Extra data. */
447*3c602fabSXin LI                 if((u_int)rc < len - 6)
448*3c602fabSXin LI                     subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
449*3c602fabSXin LI                                   type);
450cac3dcd5SXin LI             }
451cac3dcd5SXin LI         }
452cac3dcd5SXin LI             break;
453cac3dcd5SXin LI 
454cac3dcd5SXin LI         case MESSAGE_ROUTER_ID: {
455*3c602fabSXin LI             if (!ndo->ndo_vflag)
456*3c602fabSXin LI                 ND_PRINT((ndo, " router-id"));
457cac3dcd5SXin LI             else {
458*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tRouter Id"));
459cac3dcd5SXin LI                 if(len < 10) goto corrupt;
460*3c602fabSXin LI                 ND_PRINT((ndo, " %s", format_id(message + 4)));
461cac3dcd5SXin LI             }
462cac3dcd5SXin LI         }
463cac3dcd5SXin LI             break;
464cac3dcd5SXin LI 
465cac3dcd5SXin LI         case MESSAGE_NH: {
466*3c602fabSXin LI             if (!ndo->ndo_vflag)
467*3c602fabSXin LI                 ND_PRINT((ndo, " nh"));
468cac3dcd5SXin LI             else {
469cac3dcd5SXin LI                 int rc;
470cac3dcd5SXin LI                 u_char nh[16];
471*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tNext Hop"));
472cac3dcd5SXin LI                 if(len < 2) goto corrupt;
473cac3dcd5SXin LI                 rc = network_address(message[2], message + 4, len - 2, nh);
474cac3dcd5SXin LI                 if(rc < 0) goto corrupt;
475*3c602fabSXin LI                 ND_PRINT((ndo, " %s", format_address(ndo, nh)));
476cac3dcd5SXin LI             }
477cac3dcd5SXin LI         }
478cac3dcd5SXin LI             break;
479cac3dcd5SXin LI 
480cac3dcd5SXin LI         case MESSAGE_UPDATE: {
481*3c602fabSXin LI             if (!ndo->ndo_vflag) {
482*3c602fabSXin LI                 ND_PRINT((ndo, " update"));
483cac3dcd5SXin LI                 if(len < 1)
484*3c602fabSXin LI                     ND_PRINT((ndo, "/truncated"));
485cac3dcd5SXin LI                 else
486*3c602fabSXin LI                     ND_PRINT((ndo, "%s%s%s",
487cac3dcd5SXin LI                            (message[3] & 0x80) ? "/prefix": "",
488cac3dcd5SXin LI                            (message[3] & 0x40) ? "/id" : "",
489*3c602fabSXin LI                            (message[3] & 0x3f) ? "/unknown" : ""));
490cac3dcd5SXin LI             } else {
491cac3dcd5SXin LI                 u_short interval, seqno, metric;
492cac3dcd5SXin LI                 u_char plen;
493cac3dcd5SXin LI                 int rc;
494cac3dcd5SXin LI                 u_char prefix[16];
495*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tUpdate"));
496cac3dcd5SXin LI                 if(len < 10) goto corrupt;
497cac3dcd5SXin LI                 plen = message[4] + (message[2] == 1 ? 96 : 0);
498cac3dcd5SXin LI                 rc = network_prefix(message[2], message[4], message[5],
499cac3dcd5SXin LI                                     message + 12,
500cac3dcd5SXin LI                                     message[2] == 1 ? v4_prefix : v6_prefix,
501cac3dcd5SXin LI                                     len - 10, prefix);
502cac3dcd5SXin LI                 if(rc < 0) goto corrupt;
503cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
504cac3dcd5SXin LI                 seqno = EXTRACT_16BITS(message + 8);
505cac3dcd5SXin LI                 metric = EXTRACT_16BITS(message + 10);
506*3c602fabSXin LI                 ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
507cac3dcd5SXin LI                        (message[3] & 0x80) ? "/prefix": "",
508cac3dcd5SXin LI                        (message[3] & 0x40) ? "/id" : "",
509cac3dcd5SXin LI                        (message[3] & 0x3f) ? "/unknown" : "",
510*3c602fabSXin LI                        format_prefix(ndo, prefix, plen),
511*3c602fabSXin LI                        metric, seqno, format_interval_update(interval)));
512cac3dcd5SXin LI                 if(message[3] & 0x80) {
513cac3dcd5SXin LI                     if(message[2] == 1)
514cac3dcd5SXin LI                         memcpy(v4_prefix, prefix, 16);
515cac3dcd5SXin LI                     else
516cac3dcd5SXin LI                         memcpy(v6_prefix, prefix, 16);
517cac3dcd5SXin LI                 }
518*3c602fabSXin LI                 /* extra data? */
519*3c602fabSXin LI                 if((u_int)rc < len - 10)
520*3c602fabSXin LI                     subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
521cac3dcd5SXin LI             }
522cac3dcd5SXin LI         }
523cac3dcd5SXin LI             break;
524cac3dcd5SXin LI 
525cac3dcd5SXin LI         case MESSAGE_REQUEST: {
526*3c602fabSXin LI             if (!ndo->ndo_vflag)
527*3c602fabSXin LI                 ND_PRINT((ndo, " request"));
528cac3dcd5SXin LI             else {
529cac3dcd5SXin LI                 int rc;
530cac3dcd5SXin LI                 u_char prefix[16], plen;
531*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tRequest "));
532cac3dcd5SXin LI                 if(len < 2) goto corrupt;
533cac3dcd5SXin LI                 plen = message[3] + (message[2] == 1 ? 96 : 0);
534cac3dcd5SXin LI                 rc = network_prefix(message[2], message[3], 0,
535cac3dcd5SXin LI                                     message + 4, NULL, len - 2, prefix);
536cac3dcd5SXin LI                 if(rc < 0) goto corrupt;
537*3c602fabSXin LI                 ND_PRINT((ndo, "for %s",
538*3c602fabSXin LI                        message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
539cac3dcd5SXin LI             }
540cac3dcd5SXin LI         }
541cac3dcd5SXin LI             break;
542cac3dcd5SXin LI 
543cac3dcd5SXin LI         case MESSAGE_MH_REQUEST : {
544*3c602fabSXin LI             if (!ndo->ndo_vflag)
545*3c602fabSXin LI                 ND_PRINT((ndo, " mh-request"));
546cac3dcd5SXin LI             else {
547cac3dcd5SXin LI                 int rc;
548cac3dcd5SXin LI                 u_short seqno;
549cac3dcd5SXin LI                 u_char prefix[16], plen;
550*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tMH-Request "));
551cac3dcd5SXin LI                 if(len < 14) goto corrupt;
552cac3dcd5SXin LI                 seqno = EXTRACT_16BITS(message + 4);
553cac3dcd5SXin LI                 rc = network_prefix(message[2], message[3], 0,
554cac3dcd5SXin LI                                     message + 16, NULL, len - 14, prefix);
555cac3dcd5SXin LI                 if(rc < 0) goto corrupt;
556cac3dcd5SXin LI                 plen = message[3] + (message[2] == 1 ? 96 : 0);
557*3c602fabSXin LI                 ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
558*3c602fabSXin LI                        message[6], format_prefix(ndo, prefix, plen),
559*3c602fabSXin LI                        seqno, format_id(message + 8)));
560cac3dcd5SXin LI             }
561cac3dcd5SXin LI         }
562cac3dcd5SXin LI             break;
563d03c0883SXin LI         case MESSAGE_TSPC :
564*3c602fabSXin LI             if (!ndo->ndo_vflag)
565*3c602fabSXin LI                 ND_PRINT((ndo, " tspc"));
566d03c0883SXin LI             else {
567*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tTS/PC "));
568d03c0883SXin LI                 if(len < 6) goto corrupt;
569*3c602fabSXin LI                 ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
570*3c602fabSXin LI                        EXTRACT_16BITS(message + 2)));
571d03c0883SXin LI             }
572d03c0883SXin LI             break;
573d03c0883SXin LI         case MESSAGE_HMAC : {
574*3c602fabSXin LI             if (!ndo->ndo_vflag)
575*3c602fabSXin LI                 ND_PRINT((ndo, " hmac"));
576d03c0883SXin LI             else {
577d03c0883SXin LI                 unsigned j;
578*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tHMAC "));
579d03c0883SXin LI                 if(len < 18) goto corrupt;
580*3c602fabSXin LI                 ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
581d03c0883SXin LI                 for (j = 0; j < len - 2; j++)
582*3c602fabSXin LI                     ND_PRINT((ndo, "%02X", message[4 + j]));
583d03c0883SXin LI             }
584d03c0883SXin LI         }
585d03c0883SXin LI             break;
586cac3dcd5SXin LI         default:
587*3c602fabSXin LI             if (!ndo->ndo_vflag)
588*3c602fabSXin LI                 ND_PRINT((ndo, " unknown"));
589cac3dcd5SXin LI             else
590*3c602fabSXin LI                 ND_PRINT((ndo, "\n\tUnknown message type %d", type));
591cac3dcd5SXin LI         }
592cac3dcd5SXin LI         i += len + 2;
593cac3dcd5SXin LI     }
594cac3dcd5SXin LI     return;
595cac3dcd5SXin LI 
596cac3dcd5SXin LI  trunc:
597*3c602fabSXin LI     ND_PRINT((ndo, " %s", tstr));
598cac3dcd5SXin LI     return;
599cac3dcd5SXin LI 
600cac3dcd5SXin LI  corrupt:
601*3c602fabSXin LI     ND_PRINT((ndo, " (corrupt)"));
602cac3dcd5SXin LI     return;
603cac3dcd5SXin LI }
604