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