xref: /netbsd-src/external/bsd/tcpdump/dist/print-babel.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
19546e36dSchristos /*
29546e36dSchristos  * Copyright (c) 2007-2011 Grégoire Henry, Juliusz Chroboczek
39546e36dSchristos  *
49546e36dSchristos  * Redistribution and use in source and binary forms, with or without
59546e36dSchristos  * modification, are permitted provided that the following conditions
69546e36dSchristos  * are met:
79546e36dSchristos  * 1. Redistributions of source code must retain the above copyright
89546e36dSchristos  *    notice, this list of conditions and the following disclaimer.
99546e36dSchristos  * 2. Redistributions in binary form must reproduce the above copyright
109546e36dSchristos  *    notice, this list of conditions and the following disclaimer in the
119546e36dSchristos  *    documentation and/or other materials provided with the distribution.
129546e36dSchristos  * 3. Neither the name of the project nor the names of its contributors
139546e36dSchristos  *    may be used to endorse or promote products derived from this software
149546e36dSchristos  *    without specific prior written permission.
159546e36dSchristos  *
169546e36dSchristos  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
179546e36dSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189546e36dSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199546e36dSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
209546e36dSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219546e36dSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229546e36dSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239546e36dSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249546e36dSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259546e36dSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269546e36dSchristos  * SUCH DAMAGE.
279546e36dSchristos  */
289546e36dSchristos 
29fdccd7e4Schristos #include <sys/cdefs.h>
30fdccd7e4Schristos #ifndef lint
31*26ba0b50Schristos __RCSID("$NetBSD: print-babel.c,v 1.6 2024/09/02 16:15:30 christos Exp $");
32fdccd7e4Schristos #endif
33fdccd7e4Schristos 
34dc860a36Sspz /* \summary: Babel Routing Protocol printer */
35c74ad251Schristos /* Specifications:
36c74ad251Schristos  *
37c74ad251Schristos  * RFC 6126
38c74ad251Schristos  * RFC 7298
39c74ad251Schristos  * RFC 7557
40c74ad251Schristos  * draft-ietf-babel-rfc6126bis-17
41c74ad251Schristos  * draft-ietf-babel-hmac-10
42c74ad251Schristos  * draft-ietf-babel-source-specific-0
43c74ad251Schristos  */
44dc860a36Sspz 
45c74ad251Schristos #include <config.h>
469546e36dSchristos 
47c74ad251Schristos #include "netdissect-stdinc.h"
489546e36dSchristos 
499546e36dSchristos #include <stdio.h>
509546e36dSchristos #include <string.h>
519546e36dSchristos 
52784088dfSchristos #include "netdissect.h"
53c47fd378Schristos #include "addrtoname.h"
549546e36dSchristos #include "extract.h"
559546e36dSchristos 
56c47fd378Schristos static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
579546e36dSchristos 
589546e36dSchristos void
59c47fd378Schristos babel_print(netdissect_options *ndo,
603d25ea14Schristos             const u_char *cp, u_int length)
613d25ea14Schristos {
62c74ad251Schristos     ndo->ndo_protocol = "babel";
63c74ad251Schristos     ND_PRINT("babel");
649546e36dSchristos 
65c74ad251Schristos     ND_TCHECK_4(cp);
669546e36dSchristos 
67c74ad251Schristos     if(GET_U_1(cp) != 42) {
68c74ad251Schristos         ND_PRINT(" invalid header");
699546e36dSchristos         return;
709546e36dSchristos     } else {
71c74ad251Schristos         ND_PRINT(" %u", GET_U_1(cp + 1));
729546e36dSchristos     }
739546e36dSchristos 
74c74ad251Schristos     switch(GET_U_1(cp + 1)) {
759546e36dSchristos     case 2:
76c47fd378Schristos         babel_print_v2(ndo, cp, length);
779546e36dSchristos         break;
789546e36dSchristos     default:
79c74ad251Schristos         ND_PRINT(" unknown version");
809546e36dSchristos         break;
819546e36dSchristos     }
829546e36dSchristos 
839546e36dSchristos     return;
849546e36dSchristos 
859546e36dSchristos  trunc:
86c74ad251Schristos     nd_print_trunc(ndo);
879546e36dSchristos }
889546e36dSchristos 
89026d7285Schristos /* TLVs */
909546e36dSchristos #define MESSAGE_PAD1 0
919546e36dSchristos #define MESSAGE_PADN 1
929546e36dSchristos #define MESSAGE_ACK_REQ 2
939546e36dSchristos #define MESSAGE_ACK 3
949546e36dSchristos #define MESSAGE_HELLO 4
959546e36dSchristos #define MESSAGE_IHU 5
969546e36dSchristos #define MESSAGE_ROUTER_ID 6
979546e36dSchristos #define MESSAGE_NH 7
989546e36dSchristos #define MESSAGE_UPDATE 8
99c74ad251Schristos #define MESSAGE_ROUTE_REQUEST 9
100c74ad251Schristos #define MESSAGE_SEQNO_REQUEST 10
101026d7285Schristos #define MESSAGE_TSPC 11
102026d7285Schristos #define MESSAGE_HMAC 12
103c74ad251Schristos #define MESSAGE_UPDATE_SRC_SPECIFIC 13 /* last appearance in draft-boutier-babel-source-specific-01 */
104c74ad251Schristos #define MESSAGE_REQUEST_SRC_SPECIFIC 14 /* idem */
105c74ad251Schristos #define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15 /* idem */
106c74ad251Schristos #define MESSAGE_MAC 16
107c74ad251Schristos #define MESSAGE_PC 17
108c74ad251Schristos #define MESSAGE_CHALLENGE_REQUEST 18
109c74ad251Schristos #define MESSAGE_CHALLENGE_REPLY 19
110026d7285Schristos 
111026d7285Schristos /* sub-TLVs */
112026d7285Schristos #define MESSAGE_SUB_PAD1 0
113026d7285Schristos #define MESSAGE_SUB_PADN 1
114026d7285Schristos #define MESSAGE_SUB_DIVERSITY 2
115c47fd378Schristos #define MESSAGE_SUB_TIMESTAMP 3
116026d7285Schristos 
117c74ad251Schristos /* "Mandatory" bit in sub-TLV types */
118c74ad251Schristos #define MANDATORY_MASK 0x80
119c74ad251Schristos 
120c74ad251Schristos /* Flags for the Hello TLV */
121c74ad251Schristos #define UNICAST_MASK 0x8000
122c74ad251Schristos 
123026d7285Schristos /* Diversity sub-TLV channel codes */
124026d7285Schristos static const struct tok diversity_str[] = {
125026d7285Schristos     { 0,   "reserved" },
126026d7285Schristos     { 255, "all"      },
127026d7285Schristos     { 0, NULL }
128026d7285Schristos };
1299546e36dSchristos 
1309546e36dSchristos static const char *
131c74ad251Schristos format_id(netdissect_options *ndo, const u_char *id)
1329546e36dSchristos {
1339546e36dSchristos     static char buf[25];
1349546e36dSchristos     snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
135c74ad251Schristos              GET_U_1(id), GET_U_1(id + 1), GET_U_1(id + 2),
136c74ad251Schristos              GET_U_1(id + 3), GET_U_1(id + 4), GET_U_1(id + 5),
137c74ad251Schristos              GET_U_1(id + 6), GET_U_1(id + 7));
1389546e36dSchristos     buf[24] = '\0';
1399546e36dSchristos     return buf;
1409546e36dSchristos }
1419546e36dSchristos 
1429546e36dSchristos static const unsigned char v4prefix[16] =
1439546e36dSchristos     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
1449546e36dSchristos 
1459546e36dSchristos static const char *
146c47fd378Schristos format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
1479546e36dSchristos {
1489546e36dSchristos     static char buf[50];
149c74ad251Schristos 
150c74ad251Schristos     /*
151c74ad251Schristos      * prefix points to a buffer on the stack into which the prefix has
152c74ad251Schristos      * been placed, so we can't use GET_IPADDR_STRING() or
153c74ad251Schristos      * GET_IP6ADDR_STRING() on it.
154c74ad251Schristos      */
1559546e36dSchristos     if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
156c47fd378Schristos         snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
1579546e36dSchristos     else
158c47fd378Schristos         snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
1599546e36dSchristos     buf[49] = '\0';
1609546e36dSchristos     return buf;
1619546e36dSchristos }
1629546e36dSchristos 
1639546e36dSchristos static const char *
164c47fd378Schristos format_address(netdissect_options *ndo, const u_char *prefix)
1659546e36dSchristos {
166c74ad251Schristos     /*
167c74ad251Schristos      * prefix points to a buffer on the stack into which the prefix has
168c74ad251Schristos      * been placed, so we can't use GET_IPADDR_STRING() or
169c74ad251Schristos      * GET_IP6ADDR_STRING() on it.
170c74ad251Schristos      */
1719546e36dSchristos     if(memcmp(prefix, v4prefix, 12) == 0)
172c47fd378Schristos         return ipaddr_string(ndo, prefix + 12);
1739546e36dSchristos     else
174c47fd378Schristos         return ip6addr_string(ndo, prefix);
1759546e36dSchristos }
1769546e36dSchristos 
177026d7285Schristos static const char *
178c47fd378Schristos format_interval(const uint16_t i)
179026d7285Schristos {
180c47fd378Schristos     static char buf[sizeof("000.00s")];
181026d7285Schristos 
182026d7285Schristos     if (i == 0)
183026d7285Schristos         return "0.0s (bogus)";
184c47fd378Schristos     snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
185026d7285Schristos     return buf;
186026d7285Schristos }
187026d7285Schristos 
188026d7285Schristos static const char *
189c47fd378Schristos format_interval_update(const uint16_t i)
190026d7285Schristos {
191026d7285Schristos     return i == 0xFFFF ? "infinity" : format_interval(i);
192026d7285Schristos }
193026d7285Schristos 
194c47fd378Schristos static const char *
195c47fd378Schristos format_timestamp(const uint32_t i)
196c47fd378Schristos {
197c47fd378Schristos     static char buf[sizeof("0000.000000s")];
198c47fd378Schristos     snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
199c47fd378Schristos     return buf;
200c47fd378Schristos }
201c47fd378Schristos 
202026d7285Schristos /* Return number of octets consumed from the input buffer (not the prefix length
203026d7285Schristos  * in bytes), or -1 for encoding error. */
2049546e36dSchristos static int
2059546e36dSchristos network_prefix(int ae, int plen, unsigned int omitted,
2069546e36dSchristos                const unsigned char *p, const unsigned char *dp,
2079546e36dSchristos                unsigned int len, unsigned char *p_r)
2089546e36dSchristos {
2099546e36dSchristos     unsigned pb;
2109546e36dSchristos     unsigned char prefix[16];
211026d7285Schristos     int consumed = 0;
2129546e36dSchristos 
2139546e36dSchristos     if(plen >= 0)
2149546e36dSchristos         pb = (plen + 7) / 8;
2159546e36dSchristos     else if(ae == 1)
2169546e36dSchristos         pb = 4;
2179546e36dSchristos     else
2189546e36dSchristos         pb = 16;
2199546e36dSchristos 
2209546e36dSchristos     if(pb > 16)
2219546e36dSchristos         return -1;
2229546e36dSchristos 
2239546e36dSchristos     memset(prefix, 0, 16);
2249546e36dSchristos 
2259546e36dSchristos     switch(ae) {
2269546e36dSchristos     case 0: break;
2279546e36dSchristos     case 1:
2289546e36dSchristos         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
2299546e36dSchristos             return -1;
2309546e36dSchristos         memcpy(prefix, v4prefix, 12);
2319546e36dSchristos         if(omitted) {
2329546e36dSchristos             if (dp == NULL) return -1;
2339546e36dSchristos             memcpy(prefix, dp, 12 + omitted);
2349546e36dSchristos         }
235026d7285Schristos         if(pb > omitted) {
236026d7285Schristos             memcpy(prefix + 12 + omitted, p, pb - omitted);
237026d7285Schristos             consumed = pb - omitted;
238026d7285Schristos         }
2399546e36dSchristos         break;
2409546e36dSchristos     case 2:
2419546e36dSchristos         if(omitted > 16 || (pb > omitted && len < pb - omitted))
2429546e36dSchristos             return -1;
2439546e36dSchristos         if(omitted) {
2449546e36dSchristos             if (dp == NULL) return -1;
2459546e36dSchristos             memcpy(prefix, dp, omitted);
2469546e36dSchristos         }
247026d7285Schristos         if(pb > omitted) {
248026d7285Schristos             memcpy(prefix + omitted, p, pb - omitted);
249026d7285Schristos             consumed = pb - omitted;
250026d7285Schristos         }
2519546e36dSchristos         break;
2529546e36dSchristos     case 3:
2539546e36dSchristos         if(pb > 8 && len < pb - 8) return -1;
2549546e36dSchristos         prefix[0] = 0xfe;
2559546e36dSchristos         prefix[1] = 0x80;
256026d7285Schristos         if(pb > 8) {
257026d7285Schristos             memcpy(prefix + 8, p, pb - 8);
258026d7285Schristos             consumed = pb - 8;
259026d7285Schristos         }
2609546e36dSchristos         break;
2619546e36dSchristos     default:
2629546e36dSchristos         return -1;
2639546e36dSchristos     }
2649546e36dSchristos 
2659546e36dSchristos     memcpy(p_r, prefix, 16);
266026d7285Schristos     return consumed;
2679546e36dSchristos }
2689546e36dSchristos 
2699546e36dSchristos static int
2709546e36dSchristos network_address(int ae, const unsigned char *a, unsigned int len,
2719546e36dSchristos                 unsigned char *a_r)
2729546e36dSchristos {
2739546e36dSchristos     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
2749546e36dSchristos }
2759546e36dSchristos 
276026d7285Schristos /*
277026d7285Schristos  * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
278026d7285Schristos  * their encoding is similar to the encoding of TLVs, but the type namespace is
279026d7285Schristos  * different:
280026d7285Schristos  *
281026d7285Schristos  * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
282026d7285Schristos  * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
283026d7285Schristos  * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
284026d7285Schristos  *   data. Its body is a variable-length sequence of 8-bit unsigned integers,
285c74ad251Schristos  *   each representing per-hop number of interfering radio channel for the
286026d7285Schristos  *   prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
287026d7285Schristos  *   255 interferes with any other channel.
288c47fd378Schristos  * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
289c47fd378Schristos  *   neighbours. In the case of a Hello TLV, the body stores a 32-bits
290c47fd378Schristos  *   timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
291c47fd378Schristos  *   stored.
292026d7285Schristos  *
293026d7285Schristos  * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
294026d7285Schristos  * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
295026d7285Schristos  * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
296026d7285Schristos  * The former would mean a lack of any claims about the interference, and the
297c47fd378Schristos  * latter would state that interference is definitely absent.
298c47fd378Schristos  * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
299c47fd378Schristos  * semantic of the sub-TLV is different in each case.
300c47fd378Schristos  */
301026d7285Schristos static void
302c47fd378Schristos subtlvs_print(netdissect_options *ndo,
3033d25ea14Schristos               const u_char *cp, const u_char *ep, const uint8_t tlv_type)
3043d25ea14Schristos {
305026d7285Schristos     uint8_t subtype, sublen;
306026d7285Schristos     const char *sep;
307c47fd378Schristos     uint32_t t1, t2;
308026d7285Schristos 
309026d7285Schristos     while (cp < ep) {
310c74ad251Schristos         subtype = GET_U_1(cp);
311c74ad251Schristos         cp++;
312026d7285Schristos         if(subtype == MESSAGE_SUB_PAD1) {
313c74ad251Schristos             ND_PRINT(" sub-pad1");
314026d7285Schristos             continue;
315026d7285Schristos         }
316c74ad251Schristos         if ((MANDATORY_MASK & subtype) != 0)
317c74ad251Schristos             ND_PRINT(" (M)");
318026d7285Schristos         if(cp == ep)
319784088dfSchristos             goto invalid;
320c74ad251Schristos         sublen = GET_U_1(cp);
321c74ad251Schristos         cp++;
322026d7285Schristos         if(cp + sublen > ep)
323784088dfSchristos             goto invalid;
324026d7285Schristos 
325026d7285Schristos         switch(subtype) {
326026d7285Schristos         case MESSAGE_SUB_PADN:
327c74ad251Schristos             ND_PRINT(" sub-padn");
328026d7285Schristos             cp += sublen;
329026d7285Schristos             break;
330026d7285Schristos         case MESSAGE_SUB_DIVERSITY:
331c74ad251Schristos             ND_PRINT(" sub-diversity");
332026d7285Schristos             if (sublen == 0) {
333c74ad251Schristos                 ND_PRINT(" empty");
334026d7285Schristos                 break;
335026d7285Schristos             }
336026d7285Schristos             sep = " ";
337c74ad251Schristos             while (sublen) {
338c74ad251Schristos                 ND_PRINT("%s%s", sep,
339c74ad251Schristos                          tok2str(diversity_str, "%u", GET_U_1(cp)));
340c74ad251Schristos                 cp++;
341026d7285Schristos                 sep = "-";
342c74ad251Schristos                 sublen--;
343026d7285Schristos             }
344784088dfSchristos             if(tlv_type != MESSAGE_UPDATE &&
345784088dfSchristos                tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC)
346c74ad251Schristos                 ND_PRINT(" (bogus)");
347c47fd378Schristos             break;
348c47fd378Schristos         case MESSAGE_SUB_TIMESTAMP:
349c74ad251Schristos             ND_PRINT(" sub-timestamp");
350c47fd378Schristos             if(tlv_type == MESSAGE_HELLO) {
351c47fd378Schristos                 if(sublen < 4)
352784088dfSchristos                     goto invalid;
353c74ad251Schristos                 t1 = GET_BE_U_4(cp);
354c74ad251Schristos                 ND_PRINT(" %s", format_timestamp(t1));
355c47fd378Schristos             } else if(tlv_type == MESSAGE_IHU) {
356c47fd378Schristos                 if(sublen < 8)
357784088dfSchristos                     goto invalid;
358c74ad251Schristos                 t1 = GET_BE_U_4(cp);
359c74ad251Schristos                 ND_PRINT(" %s", format_timestamp(t1));
360c74ad251Schristos                 t2 = GET_BE_U_4(cp + 4);
361c74ad251Schristos                 ND_PRINT("|%s", format_timestamp(t2));
362c47fd378Schristos             } else
363c74ad251Schristos                 ND_PRINT(" (bogus)");
364c47fd378Schristos             cp += sublen;
365026d7285Schristos             break;
366026d7285Schristos         default:
367c74ad251Schristos             ND_PRINT(" sub-unknown-0x%02x", subtype);
368026d7285Schristos             cp += sublen;
369026d7285Schristos         } /* switch */
370026d7285Schristos     } /* while */
371026d7285Schristos     return;
372026d7285Schristos 
373784088dfSchristos  invalid:
374c74ad251Schristos     nd_print_invalid(ndo);
375026d7285Schristos }
376026d7285Schristos 
3779546e36dSchristos #define ICHECK(i, l) \
378c74ad251Schristos 	if ((i) + (l) > tlvs_length || (i) + (l) > packet_length_remaining) \
379c74ad251Schristos 	    goto invalid;
3809546e36dSchristos 
381c74ad251Schristos static int
382c74ad251Schristos babel_print_v2_tlvs(netdissect_options *ndo,
383c74ad251Schristos                     const u_char *cp, u_int tlvs_length,
384c74ad251Schristos                     u_int packet_length_remaining)
3853d25ea14Schristos {
3869546e36dSchristos     u_int i;
3879546e36dSchristos     u_char v4_prefix[16] =
3889546e36dSchristos         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
3899546e36dSchristos     u_char v6_prefix[16] = {0};
3909546e36dSchristos 
3919546e36dSchristos     i = 0;
392c74ad251Schristos     while(i < tlvs_length) {
3939546e36dSchristos         const u_char *message;
394c74ad251Schristos         uint8_t type;
395c74ad251Schristos         u_int len;
3969546e36dSchristos 
397c74ad251Schristos         message = cp + i;
398026d7285Schristos 
399c74ad251Schristos         ICHECK(i, 1);
400c74ad251Schristos         if((type = GET_U_1(message)) == MESSAGE_PAD1) {
401c74ad251Schristos             ND_PRINT(ndo->ndo_vflag ? "\n\tPad 1" : " pad1");
402026d7285Schristos             i += 1;
403026d7285Schristos             continue;
404026d7285Schristos         }
405026d7285Schristos 
4069546e36dSchristos         ICHECK(i, 2);
407c74ad251Schristos         ND_TCHECK_2(message);
408c74ad251Schristos         len = GET_U_1(message + 1);
4099546e36dSchristos 
4109546e36dSchristos         ICHECK(i, 2 + len);
411c74ad251Schristos         ND_TCHECK_LEN(message, 2 + len);
4129546e36dSchristos 
4139546e36dSchristos         switch(type) {
4149546e36dSchristos         case MESSAGE_PADN: {
415c47fd378Schristos             if (!ndo->ndo_vflag)
416c74ad251Schristos                 ND_PRINT(" padN");
4179546e36dSchristos             else
418c74ad251Schristos                 ND_PRINT("\n\tPad %u", len + 2);
4199546e36dSchristos         }
4209546e36dSchristos             break;
4219546e36dSchristos 
4229546e36dSchristos         case MESSAGE_ACK_REQ: {
4239546e36dSchristos             u_short nonce, interval;
424c47fd378Schristos             if (!ndo->ndo_vflag)
425c74ad251Schristos                 ND_PRINT(" ack-req");
4269546e36dSchristos             else {
427c74ad251Schristos                 ND_PRINT("\n\tAcknowledgment Request ");
428784088dfSchristos                 if(len < 6) goto invalid;
429c74ad251Schristos                 nonce = GET_BE_U_2(message + 4);
430c74ad251Schristos                 interval = GET_BE_U_2(message + 6);
431c74ad251Schristos                 ND_PRINT("%04x %s", nonce, format_interval(interval));
4329546e36dSchristos             }
4339546e36dSchristos         }
4349546e36dSchristos             break;
4359546e36dSchristos 
4369546e36dSchristos         case MESSAGE_ACK: {
4379546e36dSchristos             u_short nonce;
438c47fd378Schristos             if (!ndo->ndo_vflag)
439c74ad251Schristos                 ND_PRINT(" ack");
4409546e36dSchristos             else {
441c74ad251Schristos                 ND_PRINT("\n\tAcknowledgment ");
442784088dfSchristos                 if(len < 2) goto invalid;
443c74ad251Schristos                 nonce = GET_BE_U_2(message + 2);
444c74ad251Schristos                 ND_PRINT("%04x", nonce);
4459546e36dSchristos             }
4469546e36dSchristos         }
4479546e36dSchristos             break;
4489546e36dSchristos 
4499546e36dSchristos         case MESSAGE_HELLO:  {
450c74ad251Schristos             u_short seqno, interval, unicast;
451c47fd378Schristos             if (!ndo->ndo_vflag)
452c74ad251Schristos                 ND_PRINT(" hello");
4539546e36dSchristos             else {
454c74ad251Schristos                 ND_PRINT("\n\tHello ");
455784088dfSchristos                 if(len < 6) goto invalid;
456c74ad251Schristos                 unicast = (GET_BE_U_2(message + 2) & UNICAST_MASK);
457c74ad251Schristos                 seqno = GET_BE_U_2(message + 4);
458c74ad251Schristos                 interval = GET_BE_U_2(message + 6);
459c74ad251Schristos                 if(unicast)
460c74ad251Schristos                      ND_PRINT("(Unicast) ");
461c74ad251Schristos                 ND_PRINT("seqno %u ", seqno);
462c74ad251Schristos                 if(interval!=0)
463c74ad251Schristos                     ND_PRINT("interval %s", format_interval(interval));
464c74ad251Schristos                 else
465c74ad251Schristos                     ND_PRINT("unscheduled");
466c47fd378Schristos                 /* Extra data. */
467c47fd378Schristos                 if(len > 6)
468c47fd378Schristos                     subtlvs_print(ndo, message + 8, message + 2 + len, type);
4699546e36dSchristos             }
4709546e36dSchristos         }
4719546e36dSchristos             break;
4729546e36dSchristos 
4739546e36dSchristos         case MESSAGE_IHU: {
474c74ad251Schristos             unsigned short rxcost, interval;
475c47fd378Schristos             if (!ndo->ndo_vflag)
476c74ad251Schristos                 ND_PRINT(" ihu");
4779546e36dSchristos             else {
4789546e36dSchristos                 u_char address[16];
479c74ad251Schristos                 u_char ae;
4809546e36dSchristos                 int rc;
481c74ad251Schristos                 ND_PRINT("\n\tIHU ");
482784088dfSchristos                 if(len < 6) goto invalid;
483c74ad251Schristos                 rxcost = GET_BE_U_2(message + 4);
484c74ad251Schristos                 interval = GET_BE_U_2(message + 6);
485c74ad251Schristos                 ae = GET_U_1(message + 2);
486c74ad251Schristos                 rc = network_address(ae, message + 8,
487c74ad251Schristos                                      len - 6, address);
488c74ad251Schristos                 if(rc < 0) { nd_print_trunc(ndo); break; }
489c74ad251Schristos                 ND_PRINT("%s rxcost %u interval %s",
490c74ad251Schristos                        ae == 0 ? "any" : format_address(ndo, address),
491c74ad251Schristos                        rxcost, format_interval(interval));
492c47fd378Schristos                 /* Extra data. */
493c47fd378Schristos                 if((u_int)rc < len - 6)
494c47fd378Schristos                     subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
495c47fd378Schristos                                   type);
4969546e36dSchristos             }
4979546e36dSchristos         }
4989546e36dSchristos             break;
4999546e36dSchristos 
5009546e36dSchristos         case MESSAGE_ROUTER_ID: {
501c47fd378Schristos             if (!ndo->ndo_vflag)
502c74ad251Schristos                 ND_PRINT(" router-id");
5039546e36dSchristos             else {
504c74ad251Schristos                 ND_PRINT("\n\tRouter Id");
505784088dfSchristos                 if(len < 10) goto invalid;
506c74ad251Schristos                 ND_PRINT(" %s", format_id(ndo, message + 4));
5079546e36dSchristos             }
5089546e36dSchristos         }
5099546e36dSchristos             break;
5109546e36dSchristos 
5119546e36dSchristos         case MESSAGE_NH: {
512c47fd378Schristos             if (!ndo->ndo_vflag)
513c74ad251Schristos                 ND_PRINT(" nh");
5149546e36dSchristos             else {
5159546e36dSchristos                 int rc;
516c74ad251Schristos                 u_char ae;
5179546e36dSchristos                 u_char nh[16];
518c74ad251Schristos                 ND_PRINT("\n\tNext Hop");
519784088dfSchristos                 if(len < 2) goto invalid;
520c74ad251Schristos                 ae = GET_U_1(message + 2);
521c74ad251Schristos                 rc = network_address(ae, message + 4,
522c74ad251Schristos                                      len - 2, nh);
523784088dfSchristos                 if(rc < 0) goto invalid;
524c74ad251Schristos                 ND_PRINT(" %s", ae == 0 ? "invalid AE 0" : format_address(ndo, nh));
5259546e36dSchristos             }
5269546e36dSchristos         }
5279546e36dSchristos             break;
5289546e36dSchristos 
5299546e36dSchristos         case MESSAGE_UPDATE: {
530c47fd378Schristos             if (!ndo->ndo_vflag) {
531c74ad251Schristos                 ND_PRINT(" update");
532817e9a7eSchristos                 if(len < 10)
533c74ad251Schristos                     goto invalid;
5349546e36dSchristos                 else
535c74ad251Schristos                     ND_PRINT("%s%s%s",
536c74ad251Schristos                            (GET_U_1(message + 3) & 0x80) ? "/prefix": "",
537c74ad251Schristos                            (GET_U_1(message + 3) & 0x40) ? "/id" : "",
538c74ad251Schristos                            (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "");
5399546e36dSchristos             } else {
5409546e36dSchristos                 u_short interval, seqno, metric;
541c74ad251Schristos                 u_char ae, plen;
5429546e36dSchristos                 int rc;
5439546e36dSchristos                 u_char prefix[16];
544c74ad251Schristos                 ND_PRINT("\n\tUpdate");
545784088dfSchristos                 if(len < 10) goto invalid;
546c74ad251Schristos                 ae = GET_U_1(message + 2);
547c74ad251Schristos                 plen = GET_U_1(message + 4) + (GET_U_1(message + 2) == 1 ? 96 : 0);
548c74ad251Schristos                 rc = network_prefix(ae,
549c74ad251Schristos                                     GET_U_1(message + 4),
550c74ad251Schristos                                     GET_U_1(message + 5),
5519546e36dSchristos                                     message + 12,
552c74ad251Schristos                                     GET_U_1(message + 2) == 1 ? v4_prefix : v6_prefix,
5539546e36dSchristos                                     len - 10, prefix);
554784088dfSchristos                 if(rc < 0) goto invalid;
555c74ad251Schristos                 interval = GET_BE_U_2(message + 6);
556c74ad251Schristos                 seqno = GET_BE_U_2(message + 8);
557c74ad251Schristos                 metric = GET_BE_U_2(message + 10);
558c74ad251Schristos                 ND_PRINT("%s%s%s %s metric %u seqno %u interval %s",
559c74ad251Schristos                        (GET_U_1(message + 3) & 0x80) ? "/prefix": "",
560c74ad251Schristos                        (GET_U_1(message + 3) & 0x40) ? "/id" : "",
561c74ad251Schristos                        (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "",
562c74ad251Schristos                        ae == 0 ? "any" : format_prefix(ndo, prefix, plen),
563c74ad251Schristos                        metric, seqno, format_interval_update(interval));
564c74ad251Schristos                 if(GET_U_1(message + 3) & 0x80) {
565c74ad251Schristos                     if(GET_U_1(message + 2) == 1)
5669546e36dSchristos                         memcpy(v4_prefix, prefix, 16);
5679546e36dSchristos                     else
5689546e36dSchristos                         memcpy(v6_prefix, prefix, 16);
5699546e36dSchristos                 }
570026d7285Schristos                 /* extra data? */
571026d7285Schristos                 if((u_int)rc < len - 10)
572c47fd378Schristos                     subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
5739546e36dSchristos             }
5749546e36dSchristos         }
5759546e36dSchristos             break;
5769546e36dSchristos 
577c74ad251Schristos         case MESSAGE_ROUTE_REQUEST: {
578c47fd378Schristos             if (!ndo->ndo_vflag)
579c74ad251Schristos                 ND_PRINT(" route-request");
5809546e36dSchristos             else {
5819546e36dSchristos                 int rc;
582c74ad251Schristos                 u_char prefix[16], ae, plen;
583c74ad251Schristos                 ND_PRINT("\n\tRoute Request ");
584784088dfSchristos                 if(len < 2) goto invalid;
585c74ad251Schristos                 ae = GET_U_1(message + 2);
586c74ad251Schristos                 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0);
587c74ad251Schristos                 rc = network_prefix(ae,
588c74ad251Schristos                                     GET_U_1(message + 3), 0,
5899546e36dSchristos                                     message + 4, NULL, len - 2, prefix);
590784088dfSchristos                 if(rc < 0) goto invalid;
591c74ad251Schristos                 ND_PRINT("for %s",
592c74ad251Schristos                        ae == 0 ? "any" : format_prefix(ndo, prefix, plen));
5939546e36dSchristos             }
5949546e36dSchristos         }
5959546e36dSchristos             break;
5969546e36dSchristos 
597c74ad251Schristos         case MESSAGE_SEQNO_REQUEST : {
598c47fd378Schristos             if (!ndo->ndo_vflag)
599c74ad251Schristos                 ND_PRINT(" seqno-request");
6009546e36dSchristos             else {
6019546e36dSchristos                 int rc;
6029546e36dSchristos                 u_short seqno;
603c74ad251Schristos                 u_char prefix[16], ae, plen;
604c74ad251Schristos                 ND_PRINT("\n\tSeqno Request ");
605784088dfSchristos                 if(len < 14) goto invalid;
606c74ad251Schristos                 ae = GET_U_1(message + 2);
607c74ad251Schristos                 seqno = GET_BE_U_2(message + 4);
608c74ad251Schristos                 rc = network_prefix(ae,
609c74ad251Schristos                                     GET_U_1(message + 3), 0,
6109546e36dSchristos                                     message + 16, NULL, len - 14, prefix);
611784088dfSchristos                 if(rc < 0) goto invalid;
612c74ad251Schristos                 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0);
613c74ad251Schristos                 ND_PRINT("(%u hops) for %s seqno %u id %s",
614c74ad251Schristos                        GET_U_1(message + 6),
615c74ad251Schristos                        ae == 0 ? "invalid AE 0" : format_prefix(ndo, prefix, plen),
616c74ad251Schristos                        seqno, format_id(ndo, message + 8));
6179546e36dSchristos             }
6189546e36dSchristos         }
6199546e36dSchristos             break;
620026d7285Schristos         case MESSAGE_TSPC :
621c47fd378Schristos             if (!ndo->ndo_vflag)
622c74ad251Schristos                 ND_PRINT(" tspc");
623026d7285Schristos             else {
624c74ad251Schristos                 ND_PRINT("\n\tTS/PC ");
625784088dfSchristos                 if(len < 6) goto invalid;
626c74ad251Schristos                 ND_PRINT("timestamp %u packetcounter %u",
627c74ad251Schristos                           GET_BE_U_4(message + 4),
628c74ad251Schristos                           GET_BE_U_2(message + 2));
629026d7285Schristos             }
630026d7285Schristos             break;
631026d7285Schristos         case MESSAGE_HMAC : {
632c47fd378Schristos             if (!ndo->ndo_vflag)
633c74ad251Schristos                 ND_PRINT(" hmac");
634026d7285Schristos             else {
635026d7285Schristos                 unsigned j;
636c74ad251Schristos                 ND_PRINT("\n\tHMAC ");
637784088dfSchristos                 if(len < 18) goto invalid;
638c74ad251Schristos                 ND_PRINT("key-id %u digest-%u ", GET_BE_U_2(message + 2),
639c74ad251Schristos                          len - 2);
640026d7285Schristos                 for (j = 0; j < len - 2; j++)
641c74ad251Schristos                     ND_PRINT("%02X", GET_U_1(message + j + 4));
642026d7285Schristos             }
643026d7285Schristos         }
644026d7285Schristos             break;
645784088dfSchristos 
646784088dfSchristos         case MESSAGE_UPDATE_SRC_SPECIFIC : {
647784088dfSchristos             if(!ndo->ndo_vflag) {
648c74ad251Schristos                 ND_PRINT(" ss-update");
649784088dfSchristos             } else {
650784088dfSchristos                 u_char prefix[16], src_prefix[16];
651784088dfSchristos                 u_short interval, seqno, metric;
652784088dfSchristos                 u_char ae, plen, src_plen, omitted;
653784088dfSchristos                 int rc;
654784088dfSchristos                 int parsed_len = 10;
655c74ad251Schristos                 ND_PRINT("\n\tSS-Update");
656784088dfSchristos                 if(len < 10) goto invalid;
657c74ad251Schristos                 ae = GET_U_1(message + 2);
658c74ad251Schristos                 src_plen = GET_U_1(message + 3);
659c74ad251Schristos                 plen = GET_U_1(message + 4);
660c74ad251Schristos                 omitted = GET_U_1(message + 5);
661c74ad251Schristos                 interval = GET_BE_U_2(message + 6);
662c74ad251Schristos                 seqno = GET_BE_U_2(message + 8);
663c74ad251Schristos                 metric = GET_BE_U_2(message + 10);
664784088dfSchristos                 rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
665784088dfSchristos                                     ae == 1 ? v4_prefix : v6_prefix,
666784088dfSchristos                                     len - parsed_len, prefix);
667784088dfSchristos                 if(rc < 0) goto invalid;
668784088dfSchristos                 if(ae == 1)
669784088dfSchristos                     plen += 96;
670784088dfSchristos                 parsed_len += rc;
671784088dfSchristos                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
672784088dfSchristos                                     NULL, len - parsed_len, src_prefix);
673784088dfSchristos                 if(rc < 0) goto invalid;
674784088dfSchristos                 if(ae == 1)
675784088dfSchristos                     src_plen += 96;
676784088dfSchristos                 parsed_len += rc;
677784088dfSchristos 
678c74ad251Schristos                 ND_PRINT(" %s from", format_prefix(ndo, prefix, plen));
679c74ad251Schristos                 ND_PRINT(" %s metric %u seqno %u interval %s",
680784088dfSchristos                           format_prefix(ndo, src_prefix, src_plen),
681c74ad251Schristos                           metric, seqno, format_interval_update(interval));
682784088dfSchristos                 /* extra data? */
683784088dfSchristos                 if((u_int)parsed_len < len)
684784088dfSchristos                     subtlvs_print(ndo, message + 2 + parsed_len,
685784088dfSchristos                                   message + 2 + len, type);
686784088dfSchristos             }
687784088dfSchristos         }
688784088dfSchristos             break;
689784088dfSchristos 
690784088dfSchristos         case MESSAGE_REQUEST_SRC_SPECIFIC : {
691784088dfSchristos             if(!ndo->ndo_vflag)
692c74ad251Schristos                 ND_PRINT(" ss-request");
693784088dfSchristos             else {
694784088dfSchristos                 int rc, parsed_len = 3;
695784088dfSchristos                 u_char ae, plen, src_plen, prefix[16], src_prefix[16];
696c74ad251Schristos                 ND_PRINT("\n\tSS-Request ");
697784088dfSchristos                 if(len < 3) goto invalid;
698c74ad251Schristos                 ae = GET_U_1(message + 2);
699c74ad251Schristos                 plen = GET_U_1(message + 3);
700c74ad251Schristos                 src_plen = GET_U_1(message + 4);
701784088dfSchristos                 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
702784088dfSchristos                                     NULL, len - parsed_len, prefix);
703784088dfSchristos                 if(rc < 0) goto invalid;
704784088dfSchristos                 if(ae == 1)
705784088dfSchristos                     plen += 96;
706784088dfSchristos                 parsed_len += rc;
707784088dfSchristos                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
708784088dfSchristos                                     NULL, len - parsed_len, src_prefix);
709784088dfSchristos                 if(rc < 0) goto invalid;
710784088dfSchristos                 if(ae == 1)
711784088dfSchristos                     src_plen += 96;
712784088dfSchristos                 parsed_len += rc;
713784088dfSchristos                 if(ae == 0) {
714c74ad251Schristos                     ND_PRINT("for any");
715784088dfSchristos                 } else {
716c74ad251Schristos                     ND_PRINT("for (%s, ", format_prefix(ndo, prefix, plen));
717c74ad251Schristos                     ND_PRINT("%s)", format_prefix(ndo, src_prefix, src_plen));
718784088dfSchristos                 }
719784088dfSchristos             }
720784088dfSchristos         }
721784088dfSchristos             break;
722784088dfSchristos 
723784088dfSchristos         case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
724784088dfSchristos             if(!ndo->ndo_vflag)
725c74ad251Schristos                 ND_PRINT(" ss-mh-request");
726784088dfSchristos             else {
727784088dfSchristos                 int rc, parsed_len = 14;
728784088dfSchristos                 u_short seqno;
729784088dfSchristos                 u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
730784088dfSchristos                 const u_char *router_id = NULL;
731c74ad251Schristos                 ND_PRINT("\n\tSS-MH-Request ");
732784088dfSchristos                 if(len < 14) goto invalid;
733c74ad251Schristos                 ae = GET_U_1(message + 2);
734c74ad251Schristos                 plen = GET_U_1(message + 3);
735c74ad251Schristos                 seqno = GET_BE_U_2(message + 4);
736c74ad251Schristos                 hopc = GET_U_1(message + 6);
737c74ad251Schristos                 src_plen = GET_U_1(message + 7);
738784088dfSchristos                 router_id = message + 8;
739784088dfSchristos                 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
740784088dfSchristos                                     NULL, len - parsed_len, prefix);
741784088dfSchristos                 if(rc < 0) goto invalid;
742784088dfSchristos                 if(ae == 1)
743784088dfSchristos                     plen += 96;
744784088dfSchristos                 parsed_len += rc;
745784088dfSchristos                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
746784088dfSchristos                                     NULL, len - parsed_len, src_prefix);
747784088dfSchristos                 if(rc < 0) goto invalid;
748784088dfSchristos                 if(ae == 1)
749784088dfSchristos                     src_plen += 96;
750c74ad251Schristos                 ND_PRINT("(%u hops) for (%s, ",
751c74ad251Schristos                           hopc, format_prefix(ndo, prefix, plen));
752c74ad251Schristos                 ND_PRINT("%s) seqno %u id %s",
753784088dfSchristos                           format_prefix(ndo, src_prefix, src_plen),
754c74ad251Schristos                           seqno, format_id(ndo, router_id));
755c74ad251Schristos             }
756c74ad251Schristos         }
757c74ad251Schristos             break;
758c74ad251Schristos 
759c74ad251Schristos         case MESSAGE_MAC: {
760c74ad251Schristos             if (!ndo->ndo_vflag)
761c74ad251Schristos                 ND_PRINT(" mac");
762c74ad251Schristos             else {
763c74ad251Schristos                 ND_PRINT("\n\tMAC ");
764c74ad251Schristos                 ND_PRINT("len %u", len);
765c74ad251Schristos             }
766c74ad251Schristos         }
767c74ad251Schristos             break;
768c74ad251Schristos 
769c74ad251Schristos         case MESSAGE_PC: {
770c74ad251Schristos             if (!ndo->ndo_vflag)
771c74ad251Schristos                 ND_PRINT(" pc");
772c74ad251Schristos             else {
773c74ad251Schristos                 ND_PRINT("\n\tPC");
774c74ad251Schristos                 if(len < 4) goto invalid;
775c74ad251Schristos                 ND_PRINT(" value %u",
776c74ad251Schristos                     GET_BE_U_4(message + 2));
777c74ad251Schristos                 ND_PRINT(" index len %u", len-4);
778c74ad251Schristos             }
779c74ad251Schristos         }
780c74ad251Schristos             break;
781c74ad251Schristos 
782c74ad251Schristos         case MESSAGE_CHALLENGE_REQUEST: {
783c74ad251Schristos             if (!ndo->ndo_vflag)
784c74ad251Schristos                 ND_PRINT(" challenge_request");
785c74ad251Schristos             else {
786c74ad251Schristos                 ND_PRINT("\n\tChallenge Request");
787c74ad251Schristos                 if(len > 192) goto invalid;
788c74ad251Schristos                 ND_PRINT(" len %u", len);
789c74ad251Schristos             }
790c74ad251Schristos         }
791c74ad251Schristos             break;
792c74ad251Schristos 
793c74ad251Schristos         case MESSAGE_CHALLENGE_REPLY: {
794c74ad251Schristos             if (!ndo->ndo_vflag)
795c74ad251Schristos                 ND_PRINT(" challenge_reply");
796c74ad251Schristos             else {
797c74ad251Schristos                 ND_PRINT("\n\tChallenge Reply");
798c74ad251Schristos                 if (len > 192) goto invalid;
799c74ad251Schristos                 ND_PRINT(" len %u", len);
800784088dfSchristos             }
801784088dfSchristos         }
802784088dfSchristos             break;
803784088dfSchristos 
8049546e36dSchristos         default:
805c47fd378Schristos             if (!ndo->ndo_vflag)
806c74ad251Schristos                 ND_PRINT(" unknown");
8079546e36dSchristos             else
808c74ad251Schristos                 ND_PRINT("\n\tUnknown message type %u", type);
8099546e36dSchristos         }
8109546e36dSchristos         i += len + 2;
8119546e36dSchristos     }
812c74ad251Schristos 
813c74ad251Schristos     return 0; /* OK */
814c74ad251Schristos 
815c74ad251Schristos trunc:
816c74ad251Schristos     return -1; /* packet truncated by capture process */
817c74ad251Schristos 
818c74ad251Schristos invalid:
819c74ad251Schristos     return -2; /* packet is invalid */
820c74ad251Schristos }
821c74ad251Schristos 
822c74ad251Schristos static void
823c74ad251Schristos babel_print_v2(netdissect_options *ndo,
824c74ad251Schristos                const u_char *cp, u_int length)
825c74ad251Schristos {
826c74ad251Schristos     u_short bodylen;
827c74ad251Schristos     int ret;
828c74ad251Schristos 
829c74ad251Schristos     ND_TCHECK_4(cp);
830c74ad251Schristos     if (length < 4)
831c74ad251Schristos         goto invalid;
832c74ad251Schristos     bodylen = GET_BE_U_2(cp + 2);
833c74ad251Schristos     ND_PRINT(" (%u)", bodylen);
834c74ad251Schristos     length -= 4;
835c74ad251Schristos     cp += 4;
836c74ad251Schristos 
837c74ad251Schristos     /* Process the TLVs in the body */
838c74ad251Schristos     if (length < bodylen)
839c74ad251Schristos         goto invalid;
840c74ad251Schristos     ret = babel_print_v2_tlvs(ndo, cp, bodylen, length);
841c74ad251Schristos     if (ret == -1)
842c74ad251Schristos         goto trunc;
843c74ad251Schristos     if (ret == -2)
844c74ad251Schristos         goto invalid;
845c74ad251Schristos     length -= bodylen;
846c74ad251Schristos     cp += bodylen;
847c74ad251Schristos 
848c74ad251Schristos     /* If there's a trailer, process the TLVs in the trailer */
849c74ad251Schristos     if (length != 0) {
850c74ad251Schristos 	if(ndo->ndo_vflag) ND_PRINT("\n\t----");
851c74ad251Schristos 	else ND_PRINT(" |");
852c74ad251Schristos         ret = babel_print_v2_tlvs(ndo, cp, length, length);
853c74ad251Schristos         if (ret == -1)
854c74ad251Schristos             goto trunc;
855c74ad251Schristos         if (ret == -2)
856c74ad251Schristos             goto invalid;
857c74ad251Schristos     }
8589546e36dSchristos     return;
8599546e36dSchristos 
8609546e36dSchristos  trunc:
861c74ad251Schristos     nd_print_trunc(ndo);
8629546e36dSchristos     return;
8639546e36dSchristos 
864784088dfSchristos  invalid:
865c74ad251Schristos     nd_print_invalid(ndo);
8669546e36dSchristos }
867