10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1998-2007 The TCPDUMP project 30f74e101Schristos * Copyright (c) 2009 Florian Forster 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code 70f74e101Schristos * distributions retain the above copyright notice and this paragraph 80f74e101Schristos * in its entirety, and (2) distributions including binary code include 90f74e101Schristos * the above copyright notice and this paragraph in its entirety in 100f74e101Schristos * the documentation or other materials provided with the distribution. 110f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 120f74e101Schristos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 130f74e101Schristos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 140f74e101Schristos * FOR A PARTICULAR PURPOSE. 150f74e101Schristos * 1672c96ff3Schristos * Original code by Hannes Gredler <hannes@gredler.at> 170f74e101Schristos * IPv6 additions by Florian Forster <octo at verplant.org> 180f74e101Schristos */ 190f74e101Schristos 20dc860a36Sspz /* \summary: Optimized Link State Routing Protocol (OLSR) printer */ 21dc860a36Sspz 22dc860a36Sspz /* specification: RFC 3626 */ 23dc860a36Sspz 24fdccd7e4Schristos #include <sys/cdefs.h> 25fdccd7e4Schristos #ifndef lint 26*26ba0b50Schristos __RCSID("$NetBSD: print-olsr.c,v 1.6 2024/09/02 16:15:32 christos Exp $"); 27fdccd7e4Schristos #endif 28fdccd7e4Schristos 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 33784088dfSchristos #include "netdissect.h" 340f74e101Schristos #include "addrtoname.h" 350f74e101Schristos #include "extract.h" 360f74e101Schristos 370f74e101Schristos /* 380f74e101Schristos * RFC 3626 common header 390f74e101Schristos * 400f74e101Schristos * 0 1 2 3 410f74e101Schristos * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 420f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 430f74e101Schristos * | Packet Length | Packet Sequence Number | 440f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 450f74e101Schristos * | Message Type | Vtime | Message Size | 460f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 470f74e101Schristos * | Originator Address | 480f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 490f74e101Schristos * | Time To Live | Hop Count | Message Sequence Number | 500f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 510f74e101Schristos * | | 520f74e101Schristos * : MESSAGE : 530f74e101Schristos * | | 540f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 550f74e101Schristos * | Message Type | Vtime | Message Size | 560f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 570f74e101Schristos * | Originator Address | 580f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 590f74e101Schristos * | Time To Live | Hop Count | Message Sequence Number | 600f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 610f74e101Schristos * | | 620f74e101Schristos * : MESSAGE : 630f74e101Schristos * | | 640f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 650f74e101Schristos * : : 660f74e101Schristos */ 670f74e101Schristos 680f74e101Schristos struct olsr_common { 69c74ad251Schristos nd_uint16_t packet_len; 70c74ad251Schristos nd_uint16_t packet_seq; 710f74e101Schristos }; 720f74e101Schristos 730f74e101Schristos #define OLSR_HELLO_MSG 1 /* rfc3626 */ 740f74e101Schristos #define OLSR_TC_MSG 2 /* rfc3626 */ 750f74e101Schristos #define OLSR_MID_MSG 3 /* rfc3626 */ 760f74e101Schristos #define OLSR_HNA_MSG 4 /* rfc3626 */ 770f74e101Schristos #define OLSR_POWERINFO_MSG 128 780f74e101Schristos #define OLSR_NAMESERVICE_MSG 130 790f74e101Schristos #define OLSR_HELLO_LQ_MSG 201 /* LQ extensions olsr.org */ 800f74e101Schristos #define OLSR_TC_LQ_MSG 202 /* LQ extensions olsr.org */ 810f74e101Schristos 82026d7285Schristos static const struct tok olsr_msg_values[] = { 830f74e101Schristos { OLSR_HELLO_MSG, "Hello" }, 840f74e101Schristos { OLSR_TC_MSG, "TC" }, 850f74e101Schristos { OLSR_MID_MSG, "MID" }, 860f74e101Schristos { OLSR_HNA_MSG, "HNA" }, 870f74e101Schristos { OLSR_POWERINFO_MSG, "Powerinfo" }, 880f74e101Schristos { OLSR_NAMESERVICE_MSG, "Nameservice" }, 890f74e101Schristos { OLSR_HELLO_LQ_MSG, "Hello-LQ" }, 900f74e101Schristos { OLSR_TC_LQ_MSG, "TC-LQ" }, 910f74e101Schristos { 0, NULL} 920f74e101Schristos }; 930f74e101Schristos 940f74e101Schristos struct olsr_msg4 { 95c74ad251Schristos nd_uint8_t msg_type; 96c74ad251Schristos nd_uint8_t vtime; 97c74ad251Schristos nd_uint16_t msg_len; 98c74ad251Schristos nd_ipv4 originator; 99c74ad251Schristos nd_uint8_t ttl; 100c74ad251Schristos nd_uint8_t hopcount; 101c74ad251Schristos nd_uint16_t msg_seq; 1020f74e101Schristos }; 1030f74e101Schristos 1040f74e101Schristos struct olsr_msg6 { 105c74ad251Schristos nd_uint8_t msg_type; 106c74ad251Schristos nd_uint8_t vtime; 107c74ad251Schristos nd_uint16_t msg_len; 108c74ad251Schristos nd_ipv6 originator; 109c74ad251Schristos nd_uint8_t ttl; 110c74ad251Schristos nd_uint8_t hopcount; 111c74ad251Schristos nd_uint16_t msg_seq; 1120f74e101Schristos }; 1130f74e101Schristos 1140f74e101Schristos struct olsr_hello { 115c74ad251Schristos nd_byte res[2]; 116c74ad251Schristos nd_uint8_t htime; 117c74ad251Schristos nd_uint8_t will; 1180f74e101Schristos }; 1190f74e101Schristos 1200f74e101Schristos struct olsr_hello_link { 121c74ad251Schristos nd_uint8_t link_code; 122c74ad251Schristos nd_byte res; 123c74ad251Schristos nd_uint16_t len; 1240f74e101Schristos }; 1250f74e101Schristos 1260f74e101Schristos struct olsr_tc { 127c74ad251Schristos nd_uint16_t ans_seq; 128c74ad251Schristos nd_byte res[2]; 1290f74e101Schristos }; 1300f74e101Schristos 1310f74e101Schristos struct olsr_hna4 { 132c74ad251Schristos nd_ipv4 network; 133c74ad251Schristos nd_ipv4 mask; 1340f74e101Schristos }; 1350f74e101Schristos 1360f74e101Schristos struct olsr_hna6 { 137c74ad251Schristos nd_ipv6 network; 138c74ad251Schristos nd_ipv6 mask; 1390f74e101Schristos }; 1400f74e101Schristos 1410f74e101Schristos 142784088dfSchristos /** gateway HNA flags */ 143784088dfSchristos enum gateway_hna_flags { 144784088dfSchristos GW_HNA_FLAG_LINKSPEED = 1 << 0, 145784088dfSchristos GW_HNA_FLAG_IPV4 = 1 << 1, 146784088dfSchristos GW_HNA_FLAG_IPV4_NAT = 1 << 2, 147784088dfSchristos GW_HNA_FLAG_IPV6 = 1 << 3, 148784088dfSchristos GW_HNA_FLAG_IPV6PREFIX = 1 << 4 149784088dfSchristos }; 150784088dfSchristos 151784088dfSchristos /** gateway HNA field byte offsets in the netmask field of the HNA */ 152784088dfSchristos enum gateway_hna_fields { 153784088dfSchristos GW_HNA_PAD = 0, 154784088dfSchristos GW_HNA_FLAGS = 1, 155784088dfSchristos GW_HNA_UPLINK = 2, 156784088dfSchristos GW_HNA_DOWNLINK = 3, 157784088dfSchristos GW_HNA_V6PREFIXLEN = 4, 158784088dfSchristos GW_HNA_V6PREFIX = 5 159784088dfSchristos }; 160784088dfSchristos 161784088dfSchristos 1620f74e101Schristos #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3) 1630f74e101Schristos #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2) 1640f74e101Schristos 165026d7285Schristos static const struct tok olsr_link_type_values[] = { 1660f74e101Schristos { 0, "Unspecified" }, 1670f74e101Schristos { 1, "Asymmetric" }, 1680f74e101Schristos { 2, "Symmetric" }, 1690f74e101Schristos { 3, "Lost" }, 1700f74e101Schristos { 0, NULL} 1710f74e101Schristos }; 1720f74e101Schristos 173026d7285Schristos static const struct tok olsr_neighbor_type_values[] = { 1740f74e101Schristos { 0, "Not-Neighbor" }, 1750f74e101Schristos { 1, "Symmetric" }, 1760f74e101Schristos { 2, "Symmetric-MPR" }, 1770f74e101Schristos { 0, NULL} 1780f74e101Schristos }; 1790f74e101Schristos 1800f74e101Schristos struct olsr_lq_neighbor4 { 181c74ad251Schristos nd_ipv4 neighbor; 182c74ad251Schristos nd_uint8_t link_quality; 183c74ad251Schristos nd_uint8_t neighbor_link_quality; 184c74ad251Schristos nd_byte res[2]; 1850f74e101Schristos }; 1860f74e101Schristos 1870f74e101Schristos struct olsr_lq_neighbor6 { 188c74ad251Schristos nd_ipv6 neighbor; 189c74ad251Schristos nd_uint8_t link_quality; 190c74ad251Schristos nd_uint8_t neighbor_link_quality; 191c74ad251Schristos nd_byte res[2]; 1920f74e101Schristos }; 1930f74e101Schristos 194784088dfSchristos #define MAX_SMARTGW_SPEED 320000000 195784088dfSchristos 196784088dfSchristos /** 197784088dfSchristos * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent) 198784088dfSchristos * to an uplink/downlink speed value 199784088dfSchristos * 200784088dfSchristos * @param value the encoded 1 byte transport value 201784088dfSchristos * @return the uplink/downlink speed value (in kbit/s) 202784088dfSchristos */ 203784088dfSchristos static uint32_t deserialize_gw_speed(uint8_t value) { 204784088dfSchristos uint32_t speed; 205784088dfSchristos uint32_t exp; 206784088dfSchristos 207784088dfSchristos if (!value) { 208784088dfSchristos return 0; 209784088dfSchristos } 210784088dfSchristos 211784088dfSchristos if (value == UINT8_MAX) { 212784088dfSchristos /* maximum value: also return maximum value */ 213784088dfSchristos return MAX_SMARTGW_SPEED; 214784088dfSchristos } 215784088dfSchristos 216784088dfSchristos speed = (value >> 3) + 1; 217784088dfSchristos exp = value & 7; 218784088dfSchristos 219c74ad251Schristos while (exp != 0) { 220784088dfSchristos speed *= 10; 221c74ad251Schristos exp--; 222784088dfSchristos } 223784088dfSchristos return speed; 224784088dfSchristos } 225784088dfSchristos 2260f74e101Schristos /* 2270f74e101Schristos * macro to convert the 8-bit mantissa/exponent to a double float 2280f74e101Schristos * taken from olsr.org. 2290f74e101Schristos */ 2300f74e101Schristos #define VTIME_SCALE_FACTOR 0.0625 2310f74e101Schristos #define ME_TO_DOUBLE(me) \ 2320f74e101Schristos (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F))) 2330f74e101Schristos 2340f74e101Schristos /* 2350f74e101Schristos * print a neighbor list with LQ extensions. 2360f74e101Schristos */ 2373d25ea14Schristos static int 238c47fd378Schristos olsr_print_lq_neighbor4(netdissect_options *ndo, 239c47fd378Schristos const u_char *msg_data, u_int hello_len) 2400f74e101Schristos { 241784088dfSchristos const struct olsr_lq_neighbor4 *lq_neighbor; 2420f74e101Schristos 2430f74e101Schristos while (hello_len >= sizeof(struct olsr_lq_neighbor4)) { 2440f74e101Schristos 245784088dfSchristos lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data; 246c74ad251Schristos ND_TCHECK_SIZE(lq_neighbor); 2470f74e101Schristos 248c74ad251Schristos ND_PRINT("\n\t neighbor %s, link-quality %.2f%%" 249784088dfSchristos ", neighbor-link-quality %.2f%%", 250c74ad251Schristos GET_IPADDR_STRING(lq_neighbor->neighbor), 251c74ad251Schristos ((double) GET_U_1(lq_neighbor->link_quality)/2.55), 252c74ad251Schristos ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55)); 2530f74e101Schristos 2540f74e101Schristos msg_data += sizeof(struct olsr_lq_neighbor4); 2550f74e101Schristos hello_len -= sizeof(struct olsr_lq_neighbor4); 2560f74e101Schristos } 2573d25ea14Schristos return (0); 258c74ad251Schristos trunc: 259c74ad251Schristos return -1; 2600f74e101Schristos } 2610f74e101Schristos 2623d25ea14Schristos static int 263c47fd378Schristos olsr_print_lq_neighbor6(netdissect_options *ndo, 264c47fd378Schristos const u_char *msg_data, u_int hello_len) 2650f74e101Schristos { 266784088dfSchristos const struct olsr_lq_neighbor6 *lq_neighbor; 2670f74e101Schristos 2680f74e101Schristos while (hello_len >= sizeof(struct olsr_lq_neighbor6)) { 2690f74e101Schristos 270784088dfSchristos lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data; 271c74ad251Schristos ND_TCHECK_SIZE(lq_neighbor); 2720f74e101Schristos 273c74ad251Schristos ND_PRINT("\n\t neighbor %s, link-quality %.2f%%" 274784088dfSchristos ", neighbor-link-quality %.2f%%", 275c74ad251Schristos GET_IP6ADDR_STRING(lq_neighbor->neighbor), 276c74ad251Schristos ((double) GET_U_1(lq_neighbor->link_quality)/2.55), 277c74ad251Schristos ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55)); 2780f74e101Schristos 2790f74e101Schristos msg_data += sizeof(struct olsr_lq_neighbor6); 2800f74e101Schristos hello_len -= sizeof(struct olsr_lq_neighbor6); 2810f74e101Schristos } 2823d25ea14Schristos return (0); 283c74ad251Schristos trunc: 284c74ad251Schristos return -1; 2850f74e101Schristos } 2860f74e101Schristos 2870f74e101Schristos /* 2880f74e101Schristos * print a neighbor list. 2890f74e101Schristos */ 2903d25ea14Schristos static int 291c47fd378Schristos olsr_print_neighbor(netdissect_options *ndo, 292c47fd378Schristos const u_char *msg_data, u_int hello_len) 2930f74e101Schristos { 2940f74e101Schristos int neighbor; 2950f74e101Schristos 296c74ad251Schristos ND_PRINT("\n\t neighbor\n\t\t"); 2970f74e101Schristos neighbor = 1; 2980f74e101Schristos 299c74ad251Schristos while (hello_len >= sizeof(nd_ipv4)) { 3000f74e101Schristos /* print 4 neighbors per line */ 301c74ad251Schristos ND_PRINT("%s%s", GET_IPADDR_STRING(msg_data), 302c74ad251Schristos neighbor % 4 == 0 ? "\n\t\t" : " "); 3030f74e101Schristos 304c74ad251Schristos msg_data += sizeof(nd_ipv4); 305c74ad251Schristos hello_len -= sizeof(nd_ipv4); 3060f74e101Schristos } 3073d25ea14Schristos return (0); 3080f74e101Schristos } 3090f74e101Schristos 3100f74e101Schristos 3110f74e101Schristos void 312c47fd378Schristos olsr_print(netdissect_options *ndo, 313c47fd378Schristos const u_char *pptr, u_int length, int is_ipv6) 3140f74e101Schristos { 3150f74e101Schristos union { 3160f74e101Schristos const struct olsr_common *common; 3170f74e101Schristos const struct olsr_msg4 *msg4; 3180f74e101Schristos const struct olsr_msg6 *msg6; 3190f74e101Schristos const struct olsr_hello *hello; 3200f74e101Schristos const struct olsr_hello_link *hello_link; 3210f74e101Schristos const struct olsr_tc *tc; 3220f74e101Schristos const struct olsr_hna4 *hna; 3230f74e101Schristos } ptr; 3240f74e101Schristos 3250f74e101Schristos u_int msg_type, msg_len, msg_tlen, hello_len; 326c47fd378Schristos uint16_t name_entry_type, name_entry_len; 3270f74e101Schristos u_int name_entry_padding; 328c47fd378Schristos uint8_t link_type, neighbor_type; 3290f74e101Schristos const u_char *tptr, *msg_data; 3300f74e101Schristos 331c74ad251Schristos ndo->ndo_protocol = "olsr"; 3320f74e101Schristos tptr = pptr; 3330f74e101Schristos 334c74ad251Schristos nd_print_protocol_caps(ndo); 335c74ad251Schristos ND_PRINT("v%u", (is_ipv6) ? 6 : 4); 336c74ad251Schristos 3370f74e101Schristos if (length < sizeof(struct olsr_common)) { 3380f74e101Schristos goto trunc; 3390f74e101Schristos } 3400f74e101Schristos 341c74ad251Schristos ND_TCHECK_LEN(tptr, sizeof(struct olsr_common)); 3420f74e101Schristos 343784088dfSchristos ptr.common = (const struct olsr_common *)tptr; 344c74ad251Schristos length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len)); 3450f74e101Schristos 346c74ad251Schristos ND_PRINT(", seq 0x%04x, length %u", 347c74ad251Schristos GET_BE_U_2(ptr.common->packet_seq), 348c74ad251Schristos length); 3490f74e101Schristos 3500f74e101Schristos tptr += sizeof(struct olsr_common); 3510f74e101Schristos 3520f74e101Schristos /* 3530f74e101Schristos * In non-verbose mode, just print version. 3540f74e101Schristos */ 355c47fd378Schristos if (ndo->ndo_vflag < 1) { 3560f74e101Schristos return; 3570f74e101Schristos } 3580f74e101Schristos 3590f74e101Schristos while (tptr < (pptr+length)) { 3600f74e101Schristos union 3610f74e101Schristos { 362784088dfSchristos const struct olsr_msg4 *v4; 363784088dfSchristos const struct olsr_msg6 *v6; 3640f74e101Schristos } msgptr; 3650f74e101Schristos int msg_len_valid = 0; 3660f74e101Schristos 367*26ba0b50Schristos if (is_ipv6) { 368c74ad251Schristos ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg6)); 369784088dfSchristos msgptr.v6 = (const struct olsr_msg6 *) tptr; 370c74ad251Schristos msg_type = GET_U_1(msgptr.v6->msg_type); 371c74ad251Schristos msg_len = GET_BE_U_2(msgptr.v6->msg_len); 3720f74e101Schristos if ((msg_len >= sizeof (struct olsr_msg6)) 3730f74e101Schristos && (msg_len <= length)) 3740f74e101Schristos msg_len_valid = 1; 3750f74e101Schristos 3760f74e101Schristos /* infinite loop check */ 3770f74e101Schristos if (msg_type == 0 || msg_len == 0) { 3780f74e101Schristos return; 3790f74e101Schristos } 3800f74e101Schristos 381c74ad251Schristos ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 382784088dfSchristos "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 3830f74e101Schristos tok2str(olsr_msg_values, "Unknown", msg_type), 384c74ad251Schristos msg_type, GET_IP6ADDR_STRING(msgptr.v6->originator), 385c74ad251Schristos GET_U_1(msgptr.v6->ttl), 386c74ad251Schristos GET_U_1(msgptr.v6->hopcount), 387c74ad251Schristos ME_TO_DOUBLE(GET_U_1(msgptr.v6->vtime)), 388c74ad251Schristos GET_BE_U_2(msgptr.v6->msg_seq), 389c74ad251Schristos msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 3903d25ea14Schristos if (!msg_len_valid) { 3913d25ea14Schristos return; 3923d25ea14Schristos } 3930f74e101Schristos 3940f74e101Schristos msg_tlen = msg_len - sizeof(struct olsr_msg6); 3950f74e101Schristos msg_data = tptr + sizeof(struct olsr_msg6); 396*26ba0b50Schristos } else { /* (!is_ipv6) */ 397c74ad251Schristos ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg4)); 398784088dfSchristos msgptr.v4 = (const struct olsr_msg4 *) tptr; 399c74ad251Schristos msg_type = GET_U_1(msgptr.v4->msg_type); 400c74ad251Schristos msg_len = GET_BE_U_2(msgptr.v4->msg_len); 4010f74e101Schristos if ((msg_len >= sizeof (struct olsr_msg4)) 4020f74e101Schristos && (msg_len <= length)) 4030f74e101Schristos msg_len_valid = 1; 4040f74e101Schristos 4050f74e101Schristos /* infinite loop check */ 4060f74e101Schristos if (msg_type == 0 || msg_len == 0) { 4070f74e101Schristos return; 4080f74e101Schristos } 4090f74e101Schristos 410c74ad251Schristos ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 411784088dfSchristos "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 4120f74e101Schristos tok2str(olsr_msg_values, "Unknown", msg_type), 413c74ad251Schristos msg_type, GET_IPADDR_STRING(msgptr.v4->originator), 414c74ad251Schristos GET_U_1(msgptr.v4->ttl), 415c74ad251Schristos GET_U_1(msgptr.v4->hopcount), 416c74ad251Schristos ME_TO_DOUBLE(GET_U_1(msgptr.v4->vtime)), 417c74ad251Schristos GET_BE_U_2(msgptr.v4->msg_seq), 418c74ad251Schristos msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 4193d25ea14Schristos if (!msg_len_valid) { 4203d25ea14Schristos return; 4213d25ea14Schristos } 4220f74e101Schristos 4230f74e101Schristos msg_tlen = msg_len - sizeof(struct olsr_msg4); 4240f74e101Schristos msg_data = tptr + sizeof(struct olsr_msg4); 4250f74e101Schristos } 4260f74e101Schristos 4270f74e101Schristos switch (msg_type) { 4280f74e101Schristos case OLSR_HELLO_MSG: 4290f74e101Schristos case OLSR_HELLO_LQ_MSG: 4303d25ea14Schristos if (msg_tlen < sizeof(struct olsr_hello)) 4313d25ea14Schristos goto trunc; 432c74ad251Schristos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello)); 4330f74e101Schristos 434784088dfSchristos ptr.hello = (const struct olsr_hello *)msg_data; 435c74ad251Schristos ND_PRINT("\n\t hello-time %.3fs, MPR willingness %u", 436c74ad251Schristos ME_TO_DOUBLE(GET_U_1(ptr.hello->htime)), 437c74ad251Schristos GET_U_1(ptr.hello->will)); 4380f74e101Schristos msg_data += sizeof(struct olsr_hello); 4390f74e101Schristos msg_tlen -= sizeof(struct olsr_hello); 4400f74e101Schristos 4410f74e101Schristos while (msg_tlen >= sizeof(struct olsr_hello_link)) { 4420f74e101Schristos int hello_len_valid = 0; 4430f74e101Schristos 4440f74e101Schristos /* 4450f74e101Schristos * link-type. 4460f74e101Schristos */ 447c74ad251Schristos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello_link)); 4480f74e101Schristos 449784088dfSchristos ptr.hello_link = (const struct olsr_hello_link *)msg_data; 4500f74e101Schristos 451c74ad251Schristos hello_len = GET_BE_U_2(ptr.hello_link->len); 452c74ad251Schristos link_type = OLSR_EXTRACT_LINK_TYPE(GET_U_1(ptr.hello_link->link_code)); 453c74ad251Schristos neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(GET_U_1(ptr.hello_link->link_code)); 4540f74e101Schristos 4550f74e101Schristos if ((hello_len <= msg_tlen) 4560f74e101Schristos && (hello_len >= sizeof(struct olsr_hello_link))) 4570f74e101Schristos hello_len_valid = 1; 4580f74e101Schristos 459c74ad251Schristos ND_PRINT("\n\t link-type %s, neighbor-type %s, len %u%s", 4600f74e101Schristos tok2str(olsr_link_type_values, "Unknown", link_type), 4610f74e101Schristos tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type), 4620f74e101Schristos hello_len, 463c74ad251Schristos (hello_len_valid == 0) ? " (invalid)" : ""); 4640f74e101Schristos 4650f74e101Schristos if (hello_len_valid == 0) 4660f74e101Schristos break; 4670f74e101Schristos 4680f74e101Schristos msg_data += sizeof(struct olsr_hello_link); 4690f74e101Schristos msg_tlen -= sizeof(struct olsr_hello_link); 4700f74e101Schristos hello_len -= sizeof(struct olsr_hello_link); 4710f74e101Schristos 472c74ad251Schristos ND_TCHECK_LEN(msg_data, hello_len); 4730f74e101Schristos if (msg_type == OLSR_HELLO_MSG) { 4743d25ea14Schristos if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1) 4753d25ea14Schristos goto trunc; 4760f74e101Schristos } else { 4773d25ea14Schristos if (is_ipv6) { 4783d25ea14Schristos if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1) 4793d25ea14Schristos goto trunc; 480784088dfSchristos } else { 4813d25ea14Schristos if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1) 4823d25ea14Schristos goto trunc; 4833d25ea14Schristos } 4840f74e101Schristos } 4850f74e101Schristos 4860f74e101Schristos msg_data += hello_len; 4870f74e101Schristos msg_tlen -= hello_len; 4880f74e101Schristos } 4890f74e101Schristos break; 4900f74e101Schristos 4910f74e101Schristos case OLSR_TC_MSG: 4920f74e101Schristos case OLSR_TC_LQ_MSG: 4933d25ea14Schristos if (msg_tlen < sizeof(struct olsr_tc)) 4943d25ea14Schristos goto trunc; 495c74ad251Schristos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_tc)); 4960f74e101Schristos 497784088dfSchristos ptr.tc = (const struct olsr_tc *)msg_data; 498c74ad251Schristos ND_PRINT("\n\t advertised neighbor seq 0x%04x", 499c74ad251Schristos GET_BE_U_2(ptr.tc->ans_seq)); 5000f74e101Schristos msg_data += sizeof(struct olsr_tc); 5010f74e101Schristos msg_tlen -= sizeof(struct olsr_tc); 5020f74e101Schristos 5030f74e101Schristos if (msg_type == OLSR_TC_MSG) { 5043d25ea14Schristos if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1) 5053d25ea14Schristos goto trunc; 5060f74e101Schristos } else { 5073d25ea14Schristos if (is_ipv6) { 5083d25ea14Schristos if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1) 5093d25ea14Schristos goto trunc; 510784088dfSchristos } else { 5113d25ea14Schristos if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1) 5123d25ea14Schristos goto trunc; 5133d25ea14Schristos } 5140f74e101Schristos } 5150f74e101Schristos break; 5160f74e101Schristos 5170f74e101Schristos case OLSR_MID_MSG: 5180f74e101Schristos { 519c74ad251Schristos u_int addr_size = (u_int)sizeof(nd_ipv4); 5200f74e101Schristos 5210f74e101Schristos if (is_ipv6) 522c74ad251Schristos addr_size = (u_int)sizeof(nd_ipv6); 5230f74e101Schristos 5240f74e101Schristos while (msg_tlen >= addr_size) { 525c74ad251Schristos ND_TCHECK_LEN(msg_data, addr_size); 526c74ad251Schristos ND_PRINT("\n\t interface address %s", 527c74ad251Schristos is_ipv6 ? GET_IP6ADDR_STRING(msg_data) : 528c74ad251Schristos GET_IPADDR_STRING(msg_data)); 529c47fd378Schristos 5300f74e101Schristos msg_data += addr_size; 5310f74e101Schristos msg_tlen -= addr_size; 5320f74e101Schristos } 5330f74e101Schristos break; 5340f74e101Schristos } 5350f74e101Schristos 5360f74e101Schristos case OLSR_HNA_MSG: 537*26ba0b50Schristos if (is_ipv6) { 5380f74e101Schristos int i = 0; 539784088dfSchristos 540c74ad251Schristos ND_PRINT("\n\t Advertised networks (total %u)", 541c74ad251Schristos (unsigned int) (msg_tlen / sizeof(struct olsr_hna6))); 542784088dfSchristos 5430f74e101Schristos while (msg_tlen >= sizeof(struct olsr_hna6)) { 544784088dfSchristos const struct olsr_hna6 *hna6; 5450f74e101Schristos 546c74ad251Schristos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna6)); 5470f74e101Schristos 548784088dfSchristos hna6 = (const struct olsr_hna6 *)msg_data; 5490f74e101Schristos 550c74ad251Schristos ND_PRINT("\n\t #%i: %s/%u", 551c74ad251Schristos i, GET_IP6ADDR_STRING(hna6->network), 552c74ad251Schristos mask62plen (hna6->mask)); 5530f74e101Schristos 5540f74e101Schristos msg_data += sizeof(struct olsr_hna6); 5550f74e101Schristos msg_tlen -= sizeof(struct olsr_hna6); 5560f74e101Schristos } 557*26ba0b50Schristos } else { 5580f74e101Schristos int col = 0; 559784088dfSchristos 560c74ad251Schristos ND_PRINT("\n\t Advertised networks (total %u)", 561c74ad251Schristos (unsigned int) (msg_tlen / sizeof(struct olsr_hna4))); 562784088dfSchristos 5630f74e101Schristos while (msg_tlen >= sizeof(struct olsr_hna4)) { 564c74ad251Schristos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna4)); 5650f74e101Schristos 566784088dfSchristos ptr.hna = (const struct olsr_hna4 *)msg_data; 5670f74e101Schristos 5680f74e101Schristos /* print 4 prefixes per line */ 569784088dfSchristos if (!ptr.hna->network[0] && !ptr.hna->network[1] && 570784088dfSchristos !ptr.hna->network[2] && !ptr.hna->network[3] && 571784088dfSchristos !ptr.hna->mask[GW_HNA_PAD] && 572784088dfSchristos ptr.hna->mask[GW_HNA_FLAGS]) { 573784088dfSchristos /* smart gateway */ 574c74ad251Schristos ND_PRINT("%sSmart-Gateway:%s%s%s%s%s %u/%u", 575784088dfSchristos col == 0 ? "\n\t " : ", ", /* indent */ 576784088dfSchristos /* sgw */ 577784088dfSchristos /* LINKSPEED */ 578784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 579784088dfSchristos GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "", 580784088dfSchristos /* IPV4 */ 581784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 582784088dfSchristos GW_HNA_FLAG_IPV4) ? " IPV4" : "", 583784088dfSchristos /* IPV4-NAT */ 584784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 585784088dfSchristos GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "", 586784088dfSchristos /* IPV6 */ 587784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 588784088dfSchristos GW_HNA_FLAG_IPV6) ? " IPV6" : "", 589784088dfSchristos /* IPv6PREFIX */ 590784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 591784088dfSchristos GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "", 592784088dfSchristos /* uplink */ 593784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 594784088dfSchristos GW_HNA_FLAG_LINKSPEED) ? 595784088dfSchristos deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0, 596784088dfSchristos /* downlink */ 597784088dfSchristos (ptr.hna->mask[GW_HNA_FLAGS] & 598784088dfSchristos GW_HNA_FLAG_LINKSPEED) ? 599784088dfSchristos deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0 600c74ad251Schristos ); 601784088dfSchristos } else { 602784088dfSchristos /* normal route */ 603c74ad251Schristos ND_PRINT("%s%s/%u", 604c47fd378Schristos col == 0 ? "\n\t " : ", ", 605c74ad251Schristos GET_IPADDR_STRING(ptr.hna->network), 606c74ad251Schristos mask2plen(GET_BE_U_4(ptr.hna->mask))); 607784088dfSchristos } 6080f74e101Schristos 6090f74e101Schristos msg_data += sizeof(struct olsr_hna4); 6100f74e101Schristos msg_tlen -= sizeof(struct olsr_hna4); 6110f74e101Schristos 6120f74e101Schristos col = (col + 1) % 4; 6130f74e101Schristos } 6140f74e101Schristos } 6150f74e101Schristos break; 6160f74e101Schristos 6170f74e101Schristos case OLSR_NAMESERVICE_MSG: 6180f74e101Schristos { 61972c96ff3Schristos u_int name_entries; 62072c96ff3Schristos u_int addr_size; 62172c96ff3Schristos int name_entries_valid; 6220f74e101Schristos u_int i; 6230f74e101Schristos 6240f74e101Schristos if (msg_tlen < 4) 6250f74e101Schristos goto trunc; 6260f74e101Schristos 627c74ad251Schristos name_entries = GET_BE_U_2(msg_data + 2); 62872c96ff3Schristos addr_size = 4; 62972c96ff3Schristos if (is_ipv6) 63072c96ff3Schristos addr_size = 16; 63172c96ff3Schristos 63272c96ff3Schristos name_entries_valid = 0; 63372c96ff3Schristos if ((name_entries > 0) 63472c96ff3Schristos && ((name_entries * (4 + addr_size)) <= msg_tlen)) 63572c96ff3Schristos name_entries_valid = 1; 63672c96ff3Schristos 637c74ad251Schristos ND_PRINT("\n\t Version %u, Entries %u%s", 638c74ad251Schristos GET_BE_U_2(msg_data), 639c74ad251Schristos name_entries, (name_entries_valid == 0) ? " (invalid)" : ""); 6400f74e101Schristos 6410f74e101Schristos if (name_entries_valid == 0) 6420f74e101Schristos break; 6430f74e101Schristos 6440f74e101Schristos msg_data += 4; 6450f74e101Schristos msg_tlen -= 4; 6460f74e101Schristos 6470f74e101Schristos for (i = 0; i < name_entries; i++) { 6480f74e101Schristos int name_entry_len_valid = 0; 6490f74e101Schristos 6500f74e101Schristos if (msg_tlen < 4) 6510f74e101Schristos break; 6520f74e101Schristos 653c74ad251Schristos name_entry_type = GET_BE_U_2(msg_data); 654c74ad251Schristos name_entry_len = GET_BE_U_2(msg_data + 2); 6550f74e101Schristos 6560f74e101Schristos msg_data += 4; 6570f74e101Schristos msg_tlen -= 4; 6580f74e101Schristos 6590f74e101Schristos if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen)) 6600f74e101Schristos name_entry_len_valid = 1; 6610f74e101Schristos 662c74ad251Schristos ND_PRINT("\n\t #%u: type %#06x, length %u%s", 6630f74e101Schristos (unsigned int) i, name_entry_type, 664c74ad251Schristos name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : ""); 6650f74e101Schristos 6660f74e101Schristos if (name_entry_len_valid == 0) 6670f74e101Schristos break; 6680f74e101Schristos 6690f74e101Schristos /* 32-bit alignment */ 6700f74e101Schristos name_entry_padding = 0; 6710f74e101Schristos if (name_entry_len%4 != 0) 6720f74e101Schristos name_entry_padding = 4-(name_entry_len%4); 6730f74e101Schristos 6740f74e101Schristos if (msg_tlen < addr_size + name_entry_len + name_entry_padding) 6750f74e101Schristos goto trunc; 6760f74e101Schristos 677c74ad251Schristos ND_TCHECK_LEN(msg_data, 678c74ad251Schristos addr_size + name_entry_len + name_entry_padding); 6790f74e101Schristos 6800f74e101Schristos if (is_ipv6) 681c74ad251Schristos ND_PRINT(", address %s, name \"", 682c74ad251Schristos GET_IP6ADDR_STRING(msg_data)); 6830f74e101Schristos else 684c74ad251Schristos ND_PRINT(", address %s, name \"", 685c74ad251Schristos GET_IPADDR_STRING(msg_data)); 686c74ad251Schristos (void)nd_printn(ndo, msg_data + addr_size, name_entry_len, NULL); 687c74ad251Schristos ND_PRINT("\""); 6880f74e101Schristos 6890f74e101Schristos msg_data += addr_size + name_entry_len + name_entry_padding; 6900f74e101Schristos msg_tlen -= addr_size + name_entry_len + name_entry_padding; 6910f74e101Schristos } /* for (i = 0; i < name_entries; i++) */ 6920f74e101Schristos break; 6930f74e101Schristos } /* case OLSR_NAMESERVICE_MSG */ 6940f74e101Schristos 6950f74e101Schristos /* 6960f74e101Schristos * FIXME those are the defined messages that lack a decoder 6970f74e101Schristos * you are welcome to contribute code ;-) 6980f74e101Schristos */ 6990f74e101Schristos case OLSR_POWERINFO_MSG: 7000f74e101Schristos default: 701c47fd378Schristos print_unknown_data(ndo, msg_data, "\n\t ", msg_tlen); 7020f74e101Schristos break; 7030f74e101Schristos } /* switch (msg_type) */ 7040f74e101Schristos tptr += msg_len; 7050f74e101Schristos } /* while (tptr < (pptr+length)) */ 7060f74e101Schristos 7070f74e101Schristos return; 7080f74e101Schristos 7090f74e101Schristos trunc: 710c74ad251Schristos nd_print_trunc(ndo); 7110f74e101Schristos } 712