xref: /freebsd/contrib/tcpdump/print-babel.c (revision 39e421e8cedb2a1e819ab3f703a22b4c3da76b61)
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 
293340d773SGleb Smirnoff /* \summary: Babel Routing Protocol printer */
303340d773SGleb Smirnoff 
31cac3dcd5SXin LI #ifdef HAVE_CONFIG_H
32cac3dcd5SXin LI #include "config.h"
33cac3dcd5SXin LI #endif
34cac3dcd5SXin LI 
353340d773SGleb Smirnoff #include <netdissect-stdinc.h>
36cac3dcd5SXin LI 
37cac3dcd5SXin LI #include <stdio.h>
38cac3dcd5SXin LI #include <string.h>
39cac3dcd5SXin LI 
403340d773SGleb Smirnoff #include "netdissect.h"
413c602fabSXin LI #include "addrtoname.h"
42cac3dcd5SXin LI #include "extract.h"
43cac3dcd5SXin LI 
443c602fabSXin LI static const char tstr[] = "[|babel]";
453c602fabSXin LI 
463c602fabSXin LI static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
47cac3dcd5SXin LI 
48cac3dcd5SXin LI void
493c602fabSXin LI babel_print(netdissect_options *ndo,
508bdc5a62SPatrick Kelsey             const u_char *cp, u_int length)
518bdc5a62SPatrick Kelsey {
523c602fabSXin LI     ND_PRINT((ndo, "babel"));
53cac3dcd5SXin LI 
543c602fabSXin LI     ND_TCHECK2(*cp, 4);
55cac3dcd5SXin LI 
56cac3dcd5SXin LI     if(cp[0] != 42) {
573340d773SGleb Smirnoff         ND_PRINT((ndo, " invalid header"));
58cac3dcd5SXin LI         return;
59cac3dcd5SXin LI     } else {
603c602fabSXin LI         ND_PRINT((ndo, " %d", cp[1]));
61cac3dcd5SXin LI     }
62cac3dcd5SXin LI 
63cac3dcd5SXin LI     switch(cp[1]) {
64cac3dcd5SXin LI     case 2:
653c602fabSXin LI         babel_print_v2(ndo, cp, length);
66cac3dcd5SXin LI         break;
67cac3dcd5SXin LI     default:
683c602fabSXin LI         ND_PRINT((ndo, " unknown version"));
69cac3dcd5SXin LI         break;
70cac3dcd5SXin LI     }
71cac3dcd5SXin LI 
72cac3dcd5SXin LI     return;
73cac3dcd5SXin LI 
74cac3dcd5SXin LI  trunc:
753c602fabSXin LI     ND_PRINT((ndo, " %s", tstr));
76cac3dcd5SXin LI     return;
77cac3dcd5SXin LI }
78cac3dcd5SXin LI 
793c602fabSXin LI /* TLVs */
80cac3dcd5SXin LI #define MESSAGE_PAD1 0
81cac3dcd5SXin LI #define MESSAGE_PADN 1
82cac3dcd5SXin LI #define MESSAGE_ACK_REQ 2
83cac3dcd5SXin LI #define MESSAGE_ACK 3
84cac3dcd5SXin LI #define MESSAGE_HELLO 4
85cac3dcd5SXin LI #define MESSAGE_IHU 5
86cac3dcd5SXin LI #define MESSAGE_ROUTER_ID 6
87cac3dcd5SXin LI #define MESSAGE_NH 7
88cac3dcd5SXin LI #define MESSAGE_UPDATE 8
89cac3dcd5SXin LI #define MESSAGE_REQUEST 9
90cac3dcd5SXin LI #define MESSAGE_MH_REQUEST 10
91d03c0883SXin LI #define MESSAGE_TSPC 11
92d03c0883SXin LI #define MESSAGE_HMAC 12
933340d773SGleb Smirnoff #define MESSAGE_UPDATE_SRC_SPECIFIC 13
943340d773SGleb Smirnoff #define MESSAGE_REQUEST_SRC_SPECIFIC 14
953340d773SGleb Smirnoff #define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15
96cac3dcd5SXin LI 
973c602fabSXin LI /* sub-TLVs */
983c602fabSXin LI #define MESSAGE_SUB_PAD1 0
993c602fabSXin LI #define MESSAGE_SUB_PADN 1
1003c602fabSXin LI #define MESSAGE_SUB_DIVERSITY 2
1013c602fabSXin LI #define MESSAGE_SUB_TIMESTAMP 3
1023c602fabSXin LI 
1033c602fabSXin LI /* Diversity sub-TLV channel codes */
1043c602fabSXin LI static const struct tok diversity_str[] = {
1053c602fabSXin LI     { 0,   "reserved" },
1063c602fabSXin LI     { 255, "all"      },
1073c602fabSXin LI     { 0, NULL }
1083c602fabSXin LI };
1093c602fabSXin LI 
110cac3dcd5SXin LI static const char *
111cac3dcd5SXin LI format_id(const u_char *id)
112cac3dcd5SXin LI {
113cac3dcd5SXin LI     static char buf[25];
114cac3dcd5SXin LI     snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
115cac3dcd5SXin LI              id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
116cac3dcd5SXin LI     buf[24] = '\0';
117cac3dcd5SXin LI     return buf;
118cac3dcd5SXin LI }
119cac3dcd5SXin LI 
120cac3dcd5SXin LI static const unsigned char v4prefix[16] =
121cac3dcd5SXin LI     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
122cac3dcd5SXin LI 
123cac3dcd5SXin LI static const char *
1243c602fabSXin LI format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
125cac3dcd5SXin LI {
126cac3dcd5SXin LI     static char buf[50];
127cac3dcd5SXin LI     if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
1283c602fabSXin LI         snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
129cac3dcd5SXin LI     else
1303c602fabSXin LI         snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
131cac3dcd5SXin LI     buf[49] = '\0';
132cac3dcd5SXin LI     return buf;
133cac3dcd5SXin LI }
134cac3dcd5SXin LI 
135cac3dcd5SXin LI static const char *
1363c602fabSXin LI format_address(netdissect_options *ndo, const u_char *prefix)
137cac3dcd5SXin LI {
138cac3dcd5SXin LI     if(memcmp(prefix, v4prefix, 12) == 0)
1393c602fabSXin LI         return ipaddr_string(ndo, prefix + 12);
140cac3dcd5SXin LI     else
1413c602fabSXin LI         return ip6addr_string(ndo, prefix);
142cac3dcd5SXin LI }
143cac3dcd5SXin LI 
1443c602fabSXin LI static const char *
1453c602fabSXin LI format_interval(const uint16_t i)
1463c602fabSXin LI {
1473c602fabSXin LI     static char buf[sizeof("000.00s")];
1483c602fabSXin LI 
1493c602fabSXin LI     if (i == 0)
1503c602fabSXin LI         return "0.0s (bogus)";
1513c602fabSXin LI     snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
1523c602fabSXin LI     return buf;
1533c602fabSXin LI }
1543c602fabSXin LI 
1553c602fabSXin LI static const char *
1563c602fabSXin LI format_interval_update(const uint16_t i)
1573c602fabSXin LI {
1583c602fabSXin LI     return i == 0xFFFF ? "infinity" : format_interval(i);
1593c602fabSXin LI }
1603c602fabSXin LI 
1613c602fabSXin LI static const char *
1623c602fabSXin LI format_timestamp(const uint32_t i)
1633c602fabSXin LI {
1643c602fabSXin LI     static char buf[sizeof("0000.000000s")];
1653c602fabSXin LI     snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
1663c602fabSXin LI     return buf;
1673c602fabSXin LI }
1683c602fabSXin LI 
1693c602fabSXin LI /* Return number of octets consumed from the input buffer (not the prefix length
1703c602fabSXin LI  * in bytes), or -1 for encoding error. */
171cac3dcd5SXin LI static int
172cac3dcd5SXin LI network_prefix(int ae, int plen, unsigned int omitted,
173cac3dcd5SXin LI                const unsigned char *p, const unsigned char *dp,
174cac3dcd5SXin LI                unsigned int len, unsigned char *p_r)
175cac3dcd5SXin LI {
176cac3dcd5SXin LI     unsigned pb;
177cac3dcd5SXin LI     unsigned char prefix[16];
1783c602fabSXin LI     int consumed = 0;
179cac3dcd5SXin LI 
180cac3dcd5SXin LI     if(plen >= 0)
181cac3dcd5SXin LI         pb = (plen + 7) / 8;
182cac3dcd5SXin LI     else if(ae == 1)
183cac3dcd5SXin LI         pb = 4;
184cac3dcd5SXin LI     else
185cac3dcd5SXin LI         pb = 16;
186cac3dcd5SXin LI 
187cac3dcd5SXin LI     if(pb > 16)
188cac3dcd5SXin LI         return -1;
189cac3dcd5SXin LI 
190cac3dcd5SXin LI     memset(prefix, 0, 16);
191cac3dcd5SXin LI 
192cac3dcd5SXin LI     switch(ae) {
193cac3dcd5SXin LI     case 0: break;
194cac3dcd5SXin LI     case 1:
195cac3dcd5SXin LI         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
196cac3dcd5SXin LI             return -1;
197cac3dcd5SXin LI         memcpy(prefix, v4prefix, 12);
198cac3dcd5SXin LI         if(omitted) {
199cac3dcd5SXin LI             if (dp == NULL) return -1;
200cac3dcd5SXin LI             memcpy(prefix, dp, 12 + omitted);
201cac3dcd5SXin LI         }
2023c602fabSXin LI         if(pb > omitted) {
2033c602fabSXin LI             memcpy(prefix + 12 + omitted, p, pb - omitted);
2043c602fabSXin LI             consumed = pb - omitted;
2053c602fabSXin LI         }
206cac3dcd5SXin LI         break;
207cac3dcd5SXin LI     case 2:
208cac3dcd5SXin LI         if(omitted > 16 || (pb > omitted && len < pb - omitted))
209cac3dcd5SXin LI             return -1;
210cac3dcd5SXin LI         if(omitted) {
211cac3dcd5SXin LI             if (dp == NULL) return -1;
212cac3dcd5SXin LI             memcpy(prefix, dp, omitted);
213cac3dcd5SXin LI         }
2143c602fabSXin LI         if(pb > omitted) {
2153c602fabSXin LI             memcpy(prefix + omitted, p, pb - omitted);
2163c602fabSXin LI             consumed = pb - omitted;
2173c602fabSXin LI         }
218cac3dcd5SXin LI         break;
219cac3dcd5SXin LI     case 3:
220cac3dcd5SXin LI         if(pb > 8 && len < pb - 8) return -1;
221cac3dcd5SXin LI         prefix[0] = 0xfe;
222cac3dcd5SXin LI         prefix[1] = 0x80;
2233c602fabSXin LI         if(pb > 8) {
2243c602fabSXin LI             memcpy(prefix + 8, p, pb - 8);
2253c602fabSXin LI             consumed = pb - 8;
2263c602fabSXin LI         }
227cac3dcd5SXin LI         break;
228cac3dcd5SXin LI     default:
229cac3dcd5SXin LI         return -1;
230cac3dcd5SXin LI     }
231cac3dcd5SXin LI 
232cac3dcd5SXin LI     memcpy(p_r, prefix, 16);
2333c602fabSXin LI     return consumed;
234cac3dcd5SXin LI }
235cac3dcd5SXin LI 
236cac3dcd5SXin LI static int
237cac3dcd5SXin LI network_address(int ae, const unsigned char *a, unsigned int len,
238cac3dcd5SXin LI                 unsigned char *a_r)
239cac3dcd5SXin LI {
240cac3dcd5SXin LI     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
241cac3dcd5SXin LI }
242cac3dcd5SXin LI 
2433c602fabSXin LI /*
2443c602fabSXin LI  * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
2453c602fabSXin LI  * their encoding is similar to the encoding of TLVs, but the type namespace is
2463c602fabSXin LI  * different:
2473c602fabSXin LI  *
2483c602fabSXin LI  * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
2493c602fabSXin LI  * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
2503c602fabSXin LI  * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
2513c602fabSXin LI  *   data. Its body is a variable-length sequence of 8-bit unsigned integers,
2523c602fabSXin LI  *   each representing per-hop number of interferring radio channel for the
2533c602fabSXin LI  *   prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
2543c602fabSXin LI  *   255 interferes with any other channel.
2553c602fabSXin LI  * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
2563c602fabSXin LI  *   neighbours. In the case of a Hello TLV, the body stores a 32-bits
2573c602fabSXin LI  *   timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
2583c602fabSXin LI  *   stored.
2593c602fabSXin LI  *
2603c602fabSXin LI  * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
2613c602fabSXin LI  * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
2623c602fabSXin LI  * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
2633c602fabSXin LI  * The former would mean a lack of any claims about the interference, and the
2643c602fabSXin LI  * latter would state that interference is definitely absent.
2653c602fabSXin LI  * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
2663c602fabSXin LI  * semantic of the sub-TLV is different in each case.
2673c602fabSXin LI  */
2683c602fabSXin LI static void
2693c602fabSXin LI subtlvs_print(netdissect_options *ndo,
2708bdc5a62SPatrick Kelsey               const u_char *cp, const u_char *ep, const uint8_t tlv_type)
2718bdc5a62SPatrick Kelsey {
2723c602fabSXin LI     uint8_t subtype, sublen;
2733c602fabSXin LI     const char *sep;
2743c602fabSXin LI     uint32_t t1, t2;
2753c602fabSXin LI 
2763c602fabSXin LI     while (cp < ep) {
2773c602fabSXin LI         subtype = *cp++;
2783c602fabSXin LI         if(subtype == MESSAGE_SUB_PAD1) {
2793c602fabSXin LI             ND_PRINT((ndo, " sub-pad1"));
2803c602fabSXin LI             continue;
2813c602fabSXin LI         }
2823c602fabSXin LI         if(cp == ep)
2833340d773SGleb Smirnoff             goto invalid;
2843c602fabSXin LI         sublen = *cp++;
2853c602fabSXin LI         if(cp + sublen > ep)
2863340d773SGleb Smirnoff             goto invalid;
2873c602fabSXin LI 
2883c602fabSXin LI         switch(subtype) {
2893c602fabSXin LI         case MESSAGE_SUB_PADN:
2903c602fabSXin LI             ND_PRINT((ndo, " sub-padn"));
2913c602fabSXin LI             cp += sublen;
2923c602fabSXin LI             break;
2933c602fabSXin LI         case MESSAGE_SUB_DIVERSITY:
2943c602fabSXin LI             ND_PRINT((ndo, " sub-diversity"));
2953c602fabSXin LI             if (sublen == 0) {
2963c602fabSXin LI                 ND_PRINT((ndo, " empty"));
2973c602fabSXin LI                 break;
2983c602fabSXin LI             }
2993c602fabSXin LI             sep = " ";
3003c602fabSXin LI             while(sublen--) {
3013c602fabSXin LI                 ND_PRINT((ndo, "%s%s", sep, tok2str(diversity_str, "%u", *cp++)));
3023c602fabSXin LI                 sep = "-";
3033c602fabSXin LI             }
3043340d773SGleb Smirnoff             if(tlv_type != MESSAGE_UPDATE &&
3053340d773SGleb Smirnoff                tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC)
3063c602fabSXin LI                 ND_PRINT((ndo, " (bogus)"));
3073c602fabSXin LI             break;
3083c602fabSXin LI         case MESSAGE_SUB_TIMESTAMP:
3093c602fabSXin LI             ND_PRINT((ndo, " sub-timestamp"));
3103c602fabSXin LI             if(tlv_type == MESSAGE_HELLO) {
3113c602fabSXin LI                 if(sublen < 4)
3123340d773SGleb Smirnoff                     goto invalid;
3133c602fabSXin LI                 t1 = EXTRACT_32BITS(cp);
3143c602fabSXin LI                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
3153c602fabSXin LI             } else if(tlv_type == MESSAGE_IHU) {
3163c602fabSXin LI                 if(sublen < 8)
3173340d773SGleb Smirnoff                     goto invalid;
3183c602fabSXin LI                 t1 = EXTRACT_32BITS(cp);
3193c602fabSXin LI                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
3203c602fabSXin LI                 t2 = EXTRACT_32BITS(cp + 4);
3213c602fabSXin LI                 ND_PRINT((ndo, "|%s", format_timestamp(t2)));
3223c602fabSXin LI             } else
3233c602fabSXin LI                 ND_PRINT((ndo, " (bogus)"));
3243c602fabSXin LI             cp += sublen;
3253c602fabSXin LI             break;
3263c602fabSXin LI         default:
3273c602fabSXin LI             ND_PRINT((ndo, " sub-unknown-0x%02x", subtype));
3283c602fabSXin LI             cp += sublen;
3293c602fabSXin LI         } /* switch */
3303c602fabSXin LI     } /* while */
3313c602fabSXin LI     return;
3323c602fabSXin LI 
3333340d773SGleb Smirnoff  invalid:
3343340d773SGleb Smirnoff     ND_PRINT((ndo, "%s", istr));
3353c602fabSXin LI }
3363c602fabSXin LI 
337cac3dcd5SXin LI #define ICHECK(i, l) \
3383340d773SGleb Smirnoff 	if ((i) + (l) > bodylen || (i) + (l) > length) goto invalid;
339cac3dcd5SXin LI 
340cac3dcd5SXin LI static void
3413c602fabSXin LI babel_print_v2(netdissect_options *ndo,
3428bdc5a62SPatrick Kelsey                const u_char *cp, u_int length)
3438bdc5a62SPatrick Kelsey {
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 
3503c602fabSXin LI     ND_TCHECK2(*cp, 4);
351cac3dcd5SXin LI     if (length < 4)
3523340d773SGleb Smirnoff         goto invalid;
353cac3dcd5SXin LI     bodylen = EXTRACT_16BITS(cp + 2);
3543c602fabSXin LI     ND_PRINT((ndo, " (%u)", bodylen));
355*39e421e8SCy Schubert     if (4U + bodylen > length)
356*39e421e8SCy Schubert         goto invalid;
357cac3dcd5SXin LI 
358cac3dcd5SXin LI     /* Process the TLVs in the body */
359cac3dcd5SXin LI     i = 0;
360cac3dcd5SXin LI     while(i < bodylen) {
361cac3dcd5SXin LI         const u_char *message;
362d03c0883SXin LI         u_int type, len;
363cac3dcd5SXin LI 
364cac3dcd5SXin LI         message = cp + 4 + i;
3653c602fabSXin LI 
3663c602fabSXin LI         ND_TCHECK2(*message, 1);
3673c602fabSXin LI         if((type = message[0]) == MESSAGE_PAD1) {
3683c602fabSXin LI             ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
3693c602fabSXin LI             i += 1;
3703c602fabSXin LI             continue;
3713c602fabSXin LI         }
3723c602fabSXin LI 
3733c602fabSXin LI         ND_TCHECK2(*message, 2);
374cac3dcd5SXin LI         ICHECK(i, 2);
375cac3dcd5SXin LI         len = message[1];
376cac3dcd5SXin LI 
3773c602fabSXin LI         ND_TCHECK2(*message, 2 + len);
378cac3dcd5SXin LI         ICHECK(i, 2 + len);
379cac3dcd5SXin LI 
380cac3dcd5SXin LI         switch(type) {
381cac3dcd5SXin LI         case MESSAGE_PADN: {
3823c602fabSXin LI             if (!ndo->ndo_vflag)
3833c602fabSXin LI                 ND_PRINT((ndo, " padN"));
384cac3dcd5SXin LI             else
3853c602fabSXin LI                 ND_PRINT((ndo, "\n\tPad %d", len + 2));
386cac3dcd5SXin LI         }
387cac3dcd5SXin LI             break;
388cac3dcd5SXin LI 
389cac3dcd5SXin LI         case MESSAGE_ACK_REQ: {
390cac3dcd5SXin LI             u_short nonce, interval;
3913c602fabSXin LI             if (!ndo->ndo_vflag)
3923c602fabSXin LI                 ND_PRINT((ndo, " ack-req"));
393cac3dcd5SXin LI             else {
3943c602fabSXin LI                 ND_PRINT((ndo, "\n\tAcknowledgment Request "));
3953340d773SGleb Smirnoff                 if(len < 6) goto invalid;
396cac3dcd5SXin LI                 nonce = EXTRACT_16BITS(message + 4);
397cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
3983c602fabSXin LI                 ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
399cac3dcd5SXin LI             }
400cac3dcd5SXin LI         }
401cac3dcd5SXin LI             break;
402cac3dcd5SXin LI 
403cac3dcd5SXin LI         case MESSAGE_ACK: {
404cac3dcd5SXin LI             u_short nonce;
4053c602fabSXin LI             if (!ndo->ndo_vflag)
4063c602fabSXin LI                 ND_PRINT((ndo, " ack"));
407cac3dcd5SXin LI             else {
4083c602fabSXin LI                 ND_PRINT((ndo, "\n\tAcknowledgment "));
4093340d773SGleb Smirnoff                 if(len < 2) goto invalid;
410cac3dcd5SXin LI                 nonce = EXTRACT_16BITS(message + 2);
4113c602fabSXin LI                 ND_PRINT((ndo, "%04x", nonce));
412cac3dcd5SXin LI             }
413cac3dcd5SXin LI         }
414cac3dcd5SXin LI             break;
415cac3dcd5SXin LI 
416cac3dcd5SXin LI         case MESSAGE_HELLO:  {
417cac3dcd5SXin LI             u_short seqno, interval;
4183c602fabSXin LI             if (!ndo->ndo_vflag)
4193c602fabSXin LI                 ND_PRINT((ndo, " hello"));
420cac3dcd5SXin LI             else {
4213c602fabSXin LI                 ND_PRINT((ndo, "\n\tHello "));
4223340d773SGleb Smirnoff                 if(len < 6) goto invalid;
423cac3dcd5SXin LI                 seqno = EXTRACT_16BITS(message + 4);
424cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
4253c602fabSXin LI                 ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
4263c602fabSXin LI                 /* Extra data. */
4273c602fabSXin LI                 if(len > 6)
4283c602fabSXin LI                     subtlvs_print(ndo, message + 8, message + 2 + len, type);
429cac3dcd5SXin LI             }
430cac3dcd5SXin LI         }
431cac3dcd5SXin LI             break;
432cac3dcd5SXin LI 
433cac3dcd5SXin LI         case MESSAGE_IHU: {
434cac3dcd5SXin LI             unsigned short txcost, interval;
4353c602fabSXin LI             if (!ndo->ndo_vflag)
4363c602fabSXin LI                 ND_PRINT((ndo, " ihu"));
437cac3dcd5SXin LI             else {
438cac3dcd5SXin LI                 u_char address[16];
439cac3dcd5SXin LI                 int rc;
4403c602fabSXin LI                 ND_PRINT((ndo, "\n\tIHU "));
4413340d773SGleb Smirnoff                 if(len < 6) goto invalid;
442cac3dcd5SXin LI                 txcost = EXTRACT_16BITS(message + 4);
443cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
444cac3dcd5SXin LI                 rc = network_address(message[2], message + 8, len - 6, address);
4453c602fabSXin LI                 if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
4463c602fabSXin LI                 ND_PRINT((ndo, "%s txcost %u interval %s",
4473c602fabSXin LI                        format_address(ndo, address), txcost, format_interval(interval)));
4483c602fabSXin LI                 /* Extra data. */
4493c602fabSXin LI                 if((u_int)rc < len - 6)
4503c602fabSXin LI                     subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
4513c602fabSXin LI                                   type);
452cac3dcd5SXin LI             }
453cac3dcd5SXin LI         }
454cac3dcd5SXin LI             break;
455cac3dcd5SXin LI 
456cac3dcd5SXin LI         case MESSAGE_ROUTER_ID: {
4573c602fabSXin LI             if (!ndo->ndo_vflag)
4583c602fabSXin LI                 ND_PRINT((ndo, " router-id"));
459cac3dcd5SXin LI             else {
4603c602fabSXin LI                 ND_PRINT((ndo, "\n\tRouter Id"));
4613340d773SGleb Smirnoff                 if(len < 10) goto invalid;
4623c602fabSXin LI                 ND_PRINT((ndo, " %s", format_id(message + 4)));
463cac3dcd5SXin LI             }
464cac3dcd5SXin LI         }
465cac3dcd5SXin LI             break;
466cac3dcd5SXin LI 
467cac3dcd5SXin LI         case MESSAGE_NH: {
4683c602fabSXin LI             if (!ndo->ndo_vflag)
4693c602fabSXin LI                 ND_PRINT((ndo, " nh"));
470cac3dcd5SXin LI             else {
471cac3dcd5SXin LI                 int rc;
472cac3dcd5SXin LI                 u_char nh[16];
4733c602fabSXin LI                 ND_PRINT((ndo, "\n\tNext Hop"));
4743340d773SGleb Smirnoff                 if(len < 2) goto invalid;
475cac3dcd5SXin LI                 rc = network_address(message[2], message + 4, len - 2, nh);
4763340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
4773c602fabSXin LI                 ND_PRINT((ndo, " %s", format_address(ndo, nh)));
478cac3dcd5SXin LI             }
479cac3dcd5SXin LI         }
480cac3dcd5SXin LI             break;
481cac3dcd5SXin LI 
482cac3dcd5SXin LI         case MESSAGE_UPDATE: {
4833c602fabSXin LI             if (!ndo->ndo_vflag) {
4843c602fabSXin LI                 ND_PRINT((ndo, " update"));
485*39e421e8SCy Schubert                 if(len < 10)
4863c602fabSXin LI                     ND_PRINT((ndo, "/truncated"));
487cac3dcd5SXin LI                 else
4883c602fabSXin LI                     ND_PRINT((ndo, "%s%s%s",
489cac3dcd5SXin LI                            (message[3] & 0x80) ? "/prefix": "",
490cac3dcd5SXin LI                            (message[3] & 0x40) ? "/id" : "",
4913c602fabSXin LI                            (message[3] & 0x3f) ? "/unknown" : ""));
492cac3dcd5SXin LI             } else {
493cac3dcd5SXin LI                 u_short interval, seqno, metric;
494cac3dcd5SXin LI                 u_char plen;
495cac3dcd5SXin LI                 int rc;
496cac3dcd5SXin LI                 u_char prefix[16];
4973c602fabSXin LI                 ND_PRINT((ndo, "\n\tUpdate"));
4983340d773SGleb Smirnoff                 if(len < 10) goto invalid;
499cac3dcd5SXin LI                 plen = message[4] + (message[2] == 1 ? 96 : 0);
500cac3dcd5SXin LI                 rc = network_prefix(message[2], message[4], message[5],
501cac3dcd5SXin LI                                     message + 12,
502cac3dcd5SXin LI                                     message[2] == 1 ? v4_prefix : v6_prefix,
503cac3dcd5SXin LI                                     len - 10, prefix);
5043340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
505cac3dcd5SXin LI                 interval = EXTRACT_16BITS(message + 6);
506cac3dcd5SXin LI                 seqno = EXTRACT_16BITS(message + 8);
507cac3dcd5SXin LI                 metric = EXTRACT_16BITS(message + 10);
5083c602fabSXin LI                 ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
509cac3dcd5SXin LI                        (message[3] & 0x80) ? "/prefix": "",
510cac3dcd5SXin LI                        (message[3] & 0x40) ? "/id" : "",
511cac3dcd5SXin LI                        (message[3] & 0x3f) ? "/unknown" : "",
5123c602fabSXin LI                        format_prefix(ndo, prefix, plen),
5133c602fabSXin LI                        metric, seqno, format_interval_update(interval)));
514cac3dcd5SXin LI                 if(message[3] & 0x80) {
515cac3dcd5SXin LI                     if(message[2] == 1)
516cac3dcd5SXin LI                         memcpy(v4_prefix, prefix, 16);
517cac3dcd5SXin LI                     else
518cac3dcd5SXin LI                         memcpy(v6_prefix, prefix, 16);
519cac3dcd5SXin LI                 }
5203c602fabSXin LI                 /* extra data? */
5213c602fabSXin LI                 if((u_int)rc < len - 10)
5223c602fabSXin LI                     subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
523cac3dcd5SXin LI             }
524cac3dcd5SXin LI         }
525cac3dcd5SXin LI             break;
526cac3dcd5SXin LI 
527cac3dcd5SXin LI         case MESSAGE_REQUEST: {
5283c602fabSXin LI             if (!ndo->ndo_vflag)
5293c602fabSXin LI                 ND_PRINT((ndo, " request"));
530cac3dcd5SXin LI             else {
531cac3dcd5SXin LI                 int rc;
532cac3dcd5SXin LI                 u_char prefix[16], plen;
5333c602fabSXin LI                 ND_PRINT((ndo, "\n\tRequest "));
5343340d773SGleb Smirnoff                 if(len < 2) goto invalid;
535cac3dcd5SXin LI                 plen = message[3] + (message[2] == 1 ? 96 : 0);
536cac3dcd5SXin LI                 rc = network_prefix(message[2], message[3], 0,
537cac3dcd5SXin LI                                     message + 4, NULL, len - 2, prefix);
5383340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
5393c602fabSXin LI                 ND_PRINT((ndo, "for %s",
5403c602fabSXin LI                        message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
541cac3dcd5SXin LI             }
542cac3dcd5SXin LI         }
543cac3dcd5SXin LI             break;
544cac3dcd5SXin LI 
545cac3dcd5SXin LI         case MESSAGE_MH_REQUEST : {
5463c602fabSXin LI             if (!ndo->ndo_vflag)
5473c602fabSXin LI                 ND_PRINT((ndo, " mh-request"));
548cac3dcd5SXin LI             else {
549cac3dcd5SXin LI                 int rc;
550cac3dcd5SXin LI                 u_short seqno;
551cac3dcd5SXin LI                 u_char prefix[16], plen;
5523c602fabSXin LI                 ND_PRINT((ndo, "\n\tMH-Request "));
5533340d773SGleb Smirnoff                 if(len < 14) goto invalid;
554cac3dcd5SXin LI                 seqno = EXTRACT_16BITS(message + 4);
555cac3dcd5SXin LI                 rc = network_prefix(message[2], message[3], 0,
556cac3dcd5SXin LI                                     message + 16, NULL, len - 14, prefix);
5573340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
558cac3dcd5SXin LI                 plen = message[3] + (message[2] == 1 ? 96 : 0);
5593c602fabSXin LI                 ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
5603c602fabSXin LI                        message[6], format_prefix(ndo, prefix, plen),
5613c602fabSXin LI                        seqno, format_id(message + 8)));
562cac3dcd5SXin LI             }
563cac3dcd5SXin LI         }
564cac3dcd5SXin LI             break;
565d03c0883SXin LI         case MESSAGE_TSPC :
5663c602fabSXin LI             if (!ndo->ndo_vflag)
5673c602fabSXin LI                 ND_PRINT((ndo, " tspc"));
568d03c0883SXin LI             else {
5693c602fabSXin LI                 ND_PRINT((ndo, "\n\tTS/PC "));
5703340d773SGleb Smirnoff                 if(len < 6) goto invalid;
5713c602fabSXin LI                 ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
5723c602fabSXin LI                        EXTRACT_16BITS(message + 2)));
573d03c0883SXin LI             }
574d03c0883SXin LI             break;
575d03c0883SXin LI         case MESSAGE_HMAC : {
5763c602fabSXin LI             if (!ndo->ndo_vflag)
5773c602fabSXin LI                 ND_PRINT((ndo, " hmac"));
578d03c0883SXin LI             else {
579d03c0883SXin LI                 unsigned j;
5803c602fabSXin LI                 ND_PRINT((ndo, "\n\tHMAC "));
5813340d773SGleb Smirnoff                 if(len < 18) goto invalid;
5823c602fabSXin LI                 ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
583d03c0883SXin LI                 for (j = 0; j < len - 2; j++)
5843c602fabSXin LI                     ND_PRINT((ndo, "%02X", message[4 + j]));
585d03c0883SXin LI             }
586d03c0883SXin LI         }
587d03c0883SXin LI             break;
5883340d773SGleb Smirnoff 
5893340d773SGleb Smirnoff         case MESSAGE_UPDATE_SRC_SPECIFIC : {
5903340d773SGleb Smirnoff             if(!ndo->ndo_vflag) {
5913340d773SGleb Smirnoff                 ND_PRINT((ndo, " ss-update"));
5923340d773SGleb Smirnoff             } else {
5933340d773SGleb Smirnoff                 u_char prefix[16], src_prefix[16];
5943340d773SGleb Smirnoff                 u_short interval, seqno, metric;
5953340d773SGleb Smirnoff                 u_char ae, plen, src_plen, omitted;
5963340d773SGleb Smirnoff                 int rc;
5973340d773SGleb Smirnoff                 int parsed_len = 10;
5983340d773SGleb Smirnoff                 ND_PRINT((ndo, "\n\tSS-Update"));
5993340d773SGleb Smirnoff                 if(len < 10) goto invalid;
6003340d773SGleb Smirnoff                 ae = message[2];
6013340d773SGleb Smirnoff                 src_plen = message[3];
6023340d773SGleb Smirnoff                 plen = message[4];
6033340d773SGleb Smirnoff                 omitted = message[5];
6043340d773SGleb Smirnoff                 interval = EXTRACT_16BITS(message + 6);
6053340d773SGleb Smirnoff                 seqno = EXTRACT_16BITS(message + 8);
6063340d773SGleb Smirnoff                 metric = EXTRACT_16BITS(message + 10);
6073340d773SGleb Smirnoff                 rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
6083340d773SGleb Smirnoff                                     ae == 1 ? v4_prefix : v6_prefix,
6093340d773SGleb Smirnoff                                     len - parsed_len, prefix);
6103340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
6113340d773SGleb Smirnoff                 if(ae == 1)
6123340d773SGleb Smirnoff                     plen += 96;
6133340d773SGleb Smirnoff                 parsed_len += rc;
6143340d773SGleb Smirnoff                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
6153340d773SGleb Smirnoff                                     NULL, len - parsed_len, src_prefix);
6163340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
6173340d773SGleb Smirnoff                 if(ae == 1)
6183340d773SGleb Smirnoff                     src_plen += 96;
6193340d773SGleb Smirnoff                 parsed_len += rc;
6203340d773SGleb Smirnoff 
6213340d773SGleb Smirnoff                 ND_PRINT((ndo, " %s from", format_prefix(ndo, prefix, plen)));
6223340d773SGleb Smirnoff                 ND_PRINT((ndo, " %s metric %u seqno %u interval %s",
6233340d773SGleb Smirnoff                           format_prefix(ndo, src_prefix, src_plen),
6243340d773SGleb Smirnoff                           metric, seqno, format_interval_update(interval)));
6253340d773SGleb Smirnoff                 /* extra data? */
6263340d773SGleb Smirnoff                 if((u_int)parsed_len < len)
6273340d773SGleb Smirnoff                     subtlvs_print(ndo, message + 2 + parsed_len,
6283340d773SGleb Smirnoff                                   message + 2 + len, type);
6293340d773SGleb Smirnoff             }
6303340d773SGleb Smirnoff         }
6313340d773SGleb Smirnoff             break;
6323340d773SGleb Smirnoff 
6333340d773SGleb Smirnoff         case MESSAGE_REQUEST_SRC_SPECIFIC : {
6343340d773SGleb Smirnoff             if(!ndo->ndo_vflag)
6353340d773SGleb Smirnoff                 ND_PRINT((ndo, " ss-request"));
6363340d773SGleb Smirnoff             else {
6373340d773SGleb Smirnoff                 int rc, parsed_len = 3;
6383340d773SGleb Smirnoff                 u_char ae, plen, src_plen, prefix[16], src_prefix[16];
6393340d773SGleb Smirnoff                 ND_PRINT((ndo, "\n\tSS-Request "));
6403340d773SGleb Smirnoff                 if(len < 3) goto invalid;
6413340d773SGleb Smirnoff                 ae = message[2];
6423340d773SGleb Smirnoff                 plen = message[3];
6433340d773SGleb Smirnoff                 src_plen = message[4];
6443340d773SGleb Smirnoff                 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
6453340d773SGleb Smirnoff                                     NULL, len - parsed_len, prefix);
6463340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
6473340d773SGleb Smirnoff                 if(ae == 1)
6483340d773SGleb Smirnoff                     plen += 96;
6493340d773SGleb Smirnoff                 parsed_len += rc;
6503340d773SGleb Smirnoff                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
6513340d773SGleb Smirnoff                                     NULL, len - parsed_len, src_prefix);
6523340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
6533340d773SGleb Smirnoff                 if(ae == 1)
6543340d773SGleb Smirnoff                     src_plen += 96;
6553340d773SGleb Smirnoff                 parsed_len += rc;
6563340d773SGleb Smirnoff                 if(ae == 0) {
6573340d773SGleb Smirnoff                     ND_PRINT((ndo, "for any"));
6583340d773SGleb Smirnoff                 } else {
6593340d773SGleb Smirnoff                     ND_PRINT((ndo, "for (%s, ", format_prefix(ndo, prefix, plen)));
6603340d773SGleb Smirnoff                     ND_PRINT((ndo, "%s)", format_prefix(ndo, src_prefix, src_plen)));
6613340d773SGleb Smirnoff                 }
6623340d773SGleb Smirnoff             }
6633340d773SGleb Smirnoff         }
6643340d773SGleb Smirnoff             break;
6653340d773SGleb Smirnoff 
6663340d773SGleb Smirnoff         case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
6673340d773SGleb Smirnoff             if(!ndo->ndo_vflag)
6683340d773SGleb Smirnoff                 ND_PRINT((ndo, " ss-mh-request"));
6693340d773SGleb Smirnoff             else {
6703340d773SGleb Smirnoff                 int rc, parsed_len = 14;
6713340d773SGleb Smirnoff                 u_short seqno;
6723340d773SGleb Smirnoff                 u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
6733340d773SGleb Smirnoff                 const u_char *router_id = NULL;
6743340d773SGleb Smirnoff                 ND_PRINT((ndo, "\n\tSS-MH-Request "));
6753340d773SGleb Smirnoff                 if(len < 14) goto invalid;
6763340d773SGleb Smirnoff                 ae = message[2];
6773340d773SGleb Smirnoff                 plen = message[3];
6783340d773SGleb Smirnoff                 seqno = EXTRACT_16BITS(message + 4);
6793340d773SGleb Smirnoff                 hopc = message[6];
6803340d773SGleb Smirnoff                 src_plen = message[7];
6813340d773SGleb Smirnoff                 router_id = message + 8;
6823340d773SGleb Smirnoff                 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
6833340d773SGleb Smirnoff                                     NULL, len - parsed_len, prefix);
6843340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
6853340d773SGleb Smirnoff                 if(ae == 1)
6863340d773SGleb Smirnoff                     plen += 96;
6873340d773SGleb Smirnoff                 parsed_len += rc;
6883340d773SGleb Smirnoff                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
6893340d773SGleb Smirnoff                                     NULL, len - parsed_len, src_prefix);
6903340d773SGleb Smirnoff                 if(rc < 0) goto invalid;
6913340d773SGleb Smirnoff                 if(ae == 1)
6923340d773SGleb Smirnoff                     src_plen += 96;
6933340d773SGleb Smirnoff                 ND_PRINT((ndo, "(%u hops) for (%s, ",
6943340d773SGleb Smirnoff                           hopc, format_prefix(ndo, prefix, plen)));
6953340d773SGleb Smirnoff                 ND_PRINT((ndo, "%s) seqno %u id %s",
6963340d773SGleb Smirnoff                           format_prefix(ndo, src_prefix, src_plen),
6973340d773SGleb Smirnoff                           seqno, format_id(router_id)));
6983340d773SGleb Smirnoff             }
6993340d773SGleb Smirnoff         }
7003340d773SGleb Smirnoff             break;
7013340d773SGleb Smirnoff 
702cac3dcd5SXin LI         default:
7033c602fabSXin LI             if (!ndo->ndo_vflag)
7043c602fabSXin LI                 ND_PRINT((ndo, " unknown"));
705cac3dcd5SXin LI             else
7063c602fabSXin LI                 ND_PRINT((ndo, "\n\tUnknown message type %d", type));
707cac3dcd5SXin LI         }
708cac3dcd5SXin LI         i += len + 2;
709cac3dcd5SXin LI     }
710cac3dcd5SXin LI     return;
711cac3dcd5SXin LI 
712cac3dcd5SXin LI  trunc:
7133c602fabSXin LI     ND_PRINT((ndo, " %s", tstr));
714cac3dcd5SXin LI     return;
715cac3dcd5SXin LI 
7163340d773SGleb Smirnoff  invalid:
7173340d773SGleb Smirnoff     ND_PRINT((ndo, "%s", istr));
718cac3dcd5SXin LI     return;
719cac3dcd5SXin LI }
720