1 1.1 christos /* 2 1.1 christos * Copyright (c) 1998-2007 The TCPDUMP project 3 1.1 christos * Copyright (c) 2009 Florian Forster 4 1.1 christos * 5 1.1 christos * Redistribution and use in source and binary forms, with or without 6 1.1 christos * modification, are permitted provided that: (1) source code 7 1.1 christos * distributions retain the above copyright notice and this paragraph 8 1.1 christos * in its entirety, and (2) distributions including binary code include 9 1.1 christos * the above copyright notice and this paragraph in its entirety in 10 1.1 christos * the documentation or other materials provided with the distribution. 11 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 12 1.1 christos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 13 1.1 christos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 14 1.1 christos * FOR A PARTICULAR PURPOSE. 15 1.1 christos * 16 1.4 christos * Original code by Hannes Gredler <hannes (at) gredler.at> 17 1.1 christos * IPv6 additions by Florian Forster <octo at verplant.org> 18 1.1 christos */ 19 1.1 christos 20 1.3 spz /* \summary: Optimized Link State Routing Protocol (OLSR) printer */ 21 1.3 spz 22 1.3 spz /* specification: RFC 3626 */ 23 1.3 spz 24 1.2 christos #include <sys/cdefs.h> 25 1.2 christos #ifndef lint 26 1.6 christos __RCSID("$NetBSD: print-olsr.c,v 1.6 2024/09/02 16:15:32 christos Exp $"); 27 1.2 christos #endif 28 1.2 christos 29 1.5 christos #include <config.h> 30 1.1 christos 31 1.5 christos #include "netdissect-stdinc.h" 32 1.1 christos 33 1.2 christos #include "netdissect.h" 34 1.1 christos #include "addrtoname.h" 35 1.1 christos #include "extract.h" 36 1.1 christos 37 1.1 christos /* 38 1.1 christos * RFC 3626 common header 39 1.1 christos * 40 1.1 christos * 0 1 2 3 41 1.1 christos * 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 42 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43 1.1 christos * | Packet Length | Packet Sequence Number | 44 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 1.1 christos * | Message Type | Vtime | Message Size | 46 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 47 1.1 christos * | Originator Address | 48 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 49 1.1 christos * | Time To Live | Hop Count | Message Sequence Number | 50 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 51 1.1 christos * | | 52 1.1 christos * : MESSAGE : 53 1.1 christos * | | 54 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 55 1.1 christos * | Message Type | Vtime | Message Size | 56 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 1.1 christos * | Originator Address | 58 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 1.1 christos * | Time To Live | Hop Count | Message Sequence Number | 60 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61 1.1 christos * | | 62 1.1 christos * : MESSAGE : 63 1.1 christos * | | 64 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 1.1 christos * : : 66 1.1 christos */ 67 1.1 christos 68 1.1 christos struct olsr_common { 69 1.5 christos nd_uint16_t packet_len; 70 1.5 christos nd_uint16_t packet_seq; 71 1.1 christos }; 72 1.1 christos 73 1.1 christos #define OLSR_HELLO_MSG 1 /* rfc3626 */ 74 1.1 christos #define OLSR_TC_MSG 2 /* rfc3626 */ 75 1.1 christos #define OLSR_MID_MSG 3 /* rfc3626 */ 76 1.1 christos #define OLSR_HNA_MSG 4 /* rfc3626 */ 77 1.1 christos #define OLSR_POWERINFO_MSG 128 78 1.1 christos #define OLSR_NAMESERVICE_MSG 130 79 1.1 christos #define OLSR_HELLO_LQ_MSG 201 /* LQ extensions olsr.org */ 80 1.1 christos #define OLSR_TC_LQ_MSG 202 /* LQ extensions olsr.org */ 81 1.1 christos 82 1.2 christos static const struct tok olsr_msg_values[] = { 83 1.1 christos { OLSR_HELLO_MSG, "Hello" }, 84 1.1 christos { OLSR_TC_MSG, "TC" }, 85 1.1 christos { OLSR_MID_MSG, "MID" }, 86 1.1 christos { OLSR_HNA_MSG, "HNA" }, 87 1.1 christos { OLSR_POWERINFO_MSG, "Powerinfo" }, 88 1.1 christos { OLSR_NAMESERVICE_MSG, "Nameservice" }, 89 1.1 christos { OLSR_HELLO_LQ_MSG, "Hello-LQ" }, 90 1.1 christos { OLSR_TC_LQ_MSG, "TC-LQ" }, 91 1.1 christos { 0, NULL} 92 1.1 christos }; 93 1.1 christos 94 1.1 christos struct olsr_msg4 { 95 1.5 christos nd_uint8_t msg_type; 96 1.5 christos nd_uint8_t vtime; 97 1.5 christos nd_uint16_t msg_len; 98 1.5 christos nd_ipv4 originator; 99 1.5 christos nd_uint8_t ttl; 100 1.5 christos nd_uint8_t hopcount; 101 1.5 christos nd_uint16_t msg_seq; 102 1.1 christos }; 103 1.1 christos 104 1.1 christos struct olsr_msg6 { 105 1.5 christos nd_uint8_t msg_type; 106 1.5 christos nd_uint8_t vtime; 107 1.5 christos nd_uint16_t msg_len; 108 1.5 christos nd_ipv6 originator; 109 1.5 christos nd_uint8_t ttl; 110 1.5 christos nd_uint8_t hopcount; 111 1.5 christos nd_uint16_t msg_seq; 112 1.1 christos }; 113 1.1 christos 114 1.1 christos struct olsr_hello { 115 1.5 christos nd_byte res[2]; 116 1.5 christos nd_uint8_t htime; 117 1.5 christos nd_uint8_t will; 118 1.1 christos }; 119 1.1 christos 120 1.1 christos struct olsr_hello_link { 121 1.5 christos nd_uint8_t link_code; 122 1.5 christos nd_byte res; 123 1.5 christos nd_uint16_t len; 124 1.1 christos }; 125 1.1 christos 126 1.1 christos struct olsr_tc { 127 1.5 christos nd_uint16_t ans_seq; 128 1.5 christos nd_byte res[2]; 129 1.1 christos }; 130 1.1 christos 131 1.1 christos struct olsr_hna4 { 132 1.5 christos nd_ipv4 network; 133 1.5 christos nd_ipv4 mask; 134 1.1 christos }; 135 1.1 christos 136 1.1 christos struct olsr_hna6 { 137 1.5 christos nd_ipv6 network; 138 1.5 christos nd_ipv6 mask; 139 1.2 christos }; 140 1.2 christos 141 1.2 christos 142 1.2 christos /** gateway HNA flags */ 143 1.2 christos enum gateway_hna_flags { 144 1.2 christos GW_HNA_FLAG_LINKSPEED = 1 << 0, 145 1.2 christos GW_HNA_FLAG_IPV4 = 1 << 1, 146 1.2 christos GW_HNA_FLAG_IPV4_NAT = 1 << 2, 147 1.2 christos GW_HNA_FLAG_IPV6 = 1 << 3, 148 1.2 christos GW_HNA_FLAG_IPV6PREFIX = 1 << 4 149 1.2 christos }; 150 1.2 christos 151 1.2 christos /** gateway HNA field byte offsets in the netmask field of the HNA */ 152 1.2 christos enum gateway_hna_fields { 153 1.2 christos GW_HNA_PAD = 0, 154 1.2 christos GW_HNA_FLAGS = 1, 155 1.2 christos GW_HNA_UPLINK = 2, 156 1.2 christos GW_HNA_DOWNLINK = 3, 157 1.2 christos GW_HNA_V6PREFIXLEN = 4, 158 1.2 christos GW_HNA_V6PREFIX = 5 159 1.1 christos }; 160 1.1 christos 161 1.1 christos 162 1.1 christos #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3) 163 1.1 christos #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2) 164 1.1 christos 165 1.2 christos static const struct tok olsr_link_type_values[] = { 166 1.1 christos { 0, "Unspecified" }, 167 1.1 christos { 1, "Asymmetric" }, 168 1.1 christos { 2, "Symmetric" }, 169 1.1 christos { 3, "Lost" }, 170 1.1 christos { 0, NULL} 171 1.1 christos }; 172 1.1 christos 173 1.2 christos static const struct tok olsr_neighbor_type_values[] = { 174 1.1 christos { 0, "Not-Neighbor" }, 175 1.1 christos { 1, "Symmetric" }, 176 1.1 christos { 2, "Symmetric-MPR" }, 177 1.1 christos { 0, NULL} 178 1.1 christos }; 179 1.1 christos 180 1.1 christos struct olsr_lq_neighbor4 { 181 1.5 christos nd_ipv4 neighbor; 182 1.5 christos nd_uint8_t link_quality; 183 1.5 christos nd_uint8_t neighbor_link_quality; 184 1.5 christos nd_byte res[2]; 185 1.1 christos }; 186 1.1 christos 187 1.1 christos struct olsr_lq_neighbor6 { 188 1.5 christos nd_ipv6 neighbor; 189 1.5 christos nd_uint8_t link_quality; 190 1.5 christos nd_uint8_t neighbor_link_quality; 191 1.5 christos nd_byte res[2]; 192 1.1 christos }; 193 1.1 christos 194 1.2 christos #define MAX_SMARTGW_SPEED 320000000 195 1.2 christos 196 1.2 christos /** 197 1.2 christos * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent) 198 1.2 christos * to an uplink/downlink speed value 199 1.2 christos * 200 1.2 christos * @param value the encoded 1 byte transport value 201 1.2 christos * @return the uplink/downlink speed value (in kbit/s) 202 1.2 christos */ 203 1.2 christos static uint32_t deserialize_gw_speed(uint8_t value) { 204 1.2 christos uint32_t speed; 205 1.2 christos uint32_t exp; 206 1.2 christos 207 1.2 christos if (!value) { 208 1.2 christos return 0; 209 1.2 christos } 210 1.2 christos 211 1.2 christos if (value == UINT8_MAX) { 212 1.2 christos /* maximum value: also return maximum value */ 213 1.2 christos return MAX_SMARTGW_SPEED; 214 1.2 christos } 215 1.2 christos 216 1.2 christos speed = (value >> 3) + 1; 217 1.2 christos exp = value & 7; 218 1.2 christos 219 1.5 christos while (exp != 0) { 220 1.2 christos speed *= 10; 221 1.5 christos exp--; 222 1.2 christos } 223 1.2 christos return speed; 224 1.2 christos } 225 1.2 christos 226 1.1 christos /* 227 1.1 christos * macro to convert the 8-bit mantissa/exponent to a double float 228 1.1 christos * taken from olsr.org. 229 1.1 christos */ 230 1.1 christos #define VTIME_SCALE_FACTOR 0.0625 231 1.1 christos #define ME_TO_DOUBLE(me) \ 232 1.1 christos (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F))) 233 1.1 christos 234 1.1 christos /* 235 1.1 christos * print a neighbor list with LQ extensions. 236 1.1 christos */ 237 1.2 christos static int 238 1.2 christos olsr_print_lq_neighbor4(netdissect_options *ndo, 239 1.2 christos const u_char *msg_data, u_int hello_len) 240 1.1 christos { 241 1.2 christos const struct olsr_lq_neighbor4 *lq_neighbor; 242 1.1 christos 243 1.1 christos while (hello_len >= sizeof(struct olsr_lq_neighbor4)) { 244 1.1 christos 245 1.2 christos lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data; 246 1.5 christos ND_TCHECK_SIZE(lq_neighbor); 247 1.2 christos 248 1.5 christos ND_PRINT("\n\t neighbor %s, link-quality %.2f%%" 249 1.2 christos ", neighbor-link-quality %.2f%%", 250 1.5 christos GET_IPADDR_STRING(lq_neighbor->neighbor), 251 1.5 christos ((double) GET_U_1(lq_neighbor->link_quality)/2.55), 252 1.5 christos ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55)); 253 1.1 christos 254 1.1 christos msg_data += sizeof(struct olsr_lq_neighbor4); 255 1.1 christos hello_len -= sizeof(struct olsr_lq_neighbor4); 256 1.1 christos } 257 1.2 christos return (0); 258 1.5 christos trunc: 259 1.5 christos return -1; 260 1.1 christos } 261 1.1 christos 262 1.2 christos static int 263 1.2 christos olsr_print_lq_neighbor6(netdissect_options *ndo, 264 1.2 christos const u_char *msg_data, u_int hello_len) 265 1.1 christos { 266 1.2 christos const struct olsr_lq_neighbor6 *lq_neighbor; 267 1.1 christos 268 1.1 christos while (hello_len >= sizeof(struct olsr_lq_neighbor6)) { 269 1.1 christos 270 1.2 christos lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data; 271 1.5 christos ND_TCHECK_SIZE(lq_neighbor); 272 1.2 christos 273 1.5 christos ND_PRINT("\n\t neighbor %s, link-quality %.2f%%" 274 1.2 christos ", neighbor-link-quality %.2f%%", 275 1.5 christos GET_IP6ADDR_STRING(lq_neighbor->neighbor), 276 1.5 christos ((double) GET_U_1(lq_neighbor->link_quality)/2.55), 277 1.5 christos ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55)); 278 1.1 christos 279 1.1 christos msg_data += sizeof(struct olsr_lq_neighbor6); 280 1.1 christos hello_len -= sizeof(struct olsr_lq_neighbor6); 281 1.1 christos } 282 1.2 christos return (0); 283 1.5 christos trunc: 284 1.5 christos return -1; 285 1.1 christos } 286 1.1 christos 287 1.1 christos /* 288 1.1 christos * print a neighbor list. 289 1.1 christos */ 290 1.2 christos static int 291 1.2 christos olsr_print_neighbor(netdissect_options *ndo, 292 1.2 christos const u_char *msg_data, u_int hello_len) 293 1.1 christos { 294 1.1 christos int neighbor; 295 1.1 christos 296 1.5 christos ND_PRINT("\n\t neighbor\n\t\t"); 297 1.1 christos neighbor = 1; 298 1.1 christos 299 1.5 christos while (hello_len >= sizeof(nd_ipv4)) { 300 1.1 christos /* print 4 neighbors per line */ 301 1.5 christos ND_PRINT("%s%s", GET_IPADDR_STRING(msg_data), 302 1.5 christos neighbor % 4 == 0 ? "\n\t\t" : " "); 303 1.1 christos 304 1.5 christos msg_data += sizeof(nd_ipv4); 305 1.5 christos hello_len -= sizeof(nd_ipv4); 306 1.1 christos } 307 1.2 christos return (0); 308 1.1 christos } 309 1.1 christos 310 1.1 christos 311 1.1 christos void 312 1.2 christos olsr_print(netdissect_options *ndo, 313 1.2 christos const u_char *pptr, u_int length, int is_ipv6) 314 1.1 christos { 315 1.1 christos union { 316 1.1 christos const struct olsr_common *common; 317 1.1 christos const struct olsr_msg4 *msg4; 318 1.1 christos const struct olsr_msg6 *msg6; 319 1.1 christos const struct olsr_hello *hello; 320 1.1 christos const struct olsr_hello_link *hello_link; 321 1.1 christos const struct olsr_tc *tc; 322 1.1 christos const struct olsr_hna4 *hna; 323 1.1 christos } ptr; 324 1.1 christos 325 1.1 christos u_int msg_type, msg_len, msg_tlen, hello_len; 326 1.2 christos uint16_t name_entry_type, name_entry_len; 327 1.1 christos u_int name_entry_padding; 328 1.2 christos uint8_t link_type, neighbor_type; 329 1.1 christos const u_char *tptr, *msg_data; 330 1.1 christos 331 1.5 christos ndo->ndo_protocol = "olsr"; 332 1.1 christos tptr = pptr; 333 1.1 christos 334 1.5 christos nd_print_protocol_caps(ndo); 335 1.5 christos ND_PRINT("v%u", (is_ipv6) ? 6 : 4); 336 1.5 christos 337 1.1 christos if (length < sizeof(struct olsr_common)) { 338 1.1 christos goto trunc; 339 1.1 christos } 340 1.1 christos 341 1.5 christos ND_TCHECK_LEN(tptr, sizeof(struct olsr_common)); 342 1.1 christos 343 1.2 christos ptr.common = (const struct olsr_common *)tptr; 344 1.5 christos length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len)); 345 1.1 christos 346 1.5 christos ND_PRINT(", seq 0x%04x, length %u", 347 1.5 christos GET_BE_U_2(ptr.common->packet_seq), 348 1.5 christos length); 349 1.1 christos 350 1.1 christos tptr += sizeof(struct olsr_common); 351 1.1 christos 352 1.1 christos /* 353 1.1 christos * In non-verbose mode, just print version. 354 1.1 christos */ 355 1.2 christos if (ndo->ndo_vflag < 1) { 356 1.1 christos return; 357 1.1 christos } 358 1.1 christos 359 1.1 christos while (tptr < (pptr+length)) { 360 1.1 christos union 361 1.1 christos { 362 1.2 christos const struct olsr_msg4 *v4; 363 1.2 christos const struct olsr_msg6 *v6; 364 1.1 christos } msgptr; 365 1.1 christos int msg_len_valid = 0; 366 1.1 christos 367 1.6 christos if (is_ipv6) { 368 1.5 christos ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg6)); 369 1.2 christos msgptr.v6 = (const struct olsr_msg6 *) tptr; 370 1.5 christos msg_type = GET_U_1(msgptr.v6->msg_type); 371 1.5 christos msg_len = GET_BE_U_2(msgptr.v6->msg_len); 372 1.1 christos if ((msg_len >= sizeof (struct olsr_msg6)) 373 1.1 christos && (msg_len <= length)) 374 1.1 christos msg_len_valid = 1; 375 1.1 christos 376 1.1 christos /* infinite loop check */ 377 1.1 christos if (msg_type == 0 || msg_len == 0) { 378 1.1 christos return; 379 1.1 christos } 380 1.1 christos 381 1.5 christos ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 382 1.2 christos "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 383 1.1 christos tok2str(olsr_msg_values, "Unknown", msg_type), 384 1.5 christos msg_type, GET_IP6ADDR_STRING(msgptr.v6->originator), 385 1.5 christos GET_U_1(msgptr.v6->ttl), 386 1.5 christos GET_U_1(msgptr.v6->hopcount), 387 1.5 christos ME_TO_DOUBLE(GET_U_1(msgptr.v6->vtime)), 388 1.5 christos GET_BE_U_2(msgptr.v6->msg_seq), 389 1.5 christos msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 390 1.2 christos if (!msg_len_valid) { 391 1.2 christos return; 392 1.2 christos } 393 1.1 christos 394 1.1 christos msg_tlen = msg_len - sizeof(struct olsr_msg6); 395 1.1 christos msg_data = tptr + sizeof(struct olsr_msg6); 396 1.6 christos } else { /* (!is_ipv6) */ 397 1.5 christos ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg4)); 398 1.2 christos msgptr.v4 = (const struct olsr_msg4 *) tptr; 399 1.5 christos msg_type = GET_U_1(msgptr.v4->msg_type); 400 1.5 christos msg_len = GET_BE_U_2(msgptr.v4->msg_len); 401 1.1 christos if ((msg_len >= sizeof (struct olsr_msg4)) 402 1.1 christos && (msg_len <= length)) 403 1.1 christos msg_len_valid = 1; 404 1.1 christos 405 1.1 christos /* infinite loop check */ 406 1.1 christos if (msg_type == 0 || msg_len == 0) { 407 1.1 christos return; 408 1.1 christos } 409 1.1 christos 410 1.5 christos ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 411 1.2 christos "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 412 1.1 christos tok2str(olsr_msg_values, "Unknown", msg_type), 413 1.5 christos msg_type, GET_IPADDR_STRING(msgptr.v4->originator), 414 1.5 christos GET_U_1(msgptr.v4->ttl), 415 1.5 christos GET_U_1(msgptr.v4->hopcount), 416 1.5 christos ME_TO_DOUBLE(GET_U_1(msgptr.v4->vtime)), 417 1.5 christos GET_BE_U_2(msgptr.v4->msg_seq), 418 1.5 christos msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 419 1.2 christos if (!msg_len_valid) { 420 1.2 christos return; 421 1.2 christos } 422 1.1 christos 423 1.1 christos msg_tlen = msg_len - sizeof(struct olsr_msg4); 424 1.1 christos msg_data = tptr + sizeof(struct olsr_msg4); 425 1.1 christos } 426 1.1 christos 427 1.1 christos switch (msg_type) { 428 1.1 christos case OLSR_HELLO_MSG: 429 1.1 christos case OLSR_HELLO_LQ_MSG: 430 1.2 christos if (msg_tlen < sizeof(struct olsr_hello)) 431 1.1 christos goto trunc; 432 1.5 christos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello)); 433 1.1 christos 434 1.2 christos ptr.hello = (const struct olsr_hello *)msg_data; 435 1.5 christos ND_PRINT("\n\t hello-time %.3fs, MPR willingness %u", 436 1.5 christos ME_TO_DOUBLE(GET_U_1(ptr.hello->htime)), 437 1.5 christos GET_U_1(ptr.hello->will)); 438 1.1 christos msg_data += sizeof(struct olsr_hello); 439 1.1 christos msg_tlen -= sizeof(struct olsr_hello); 440 1.1 christos 441 1.1 christos while (msg_tlen >= sizeof(struct olsr_hello_link)) { 442 1.1 christos int hello_len_valid = 0; 443 1.1 christos 444 1.1 christos /* 445 1.1 christos * link-type. 446 1.1 christos */ 447 1.5 christos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello_link)); 448 1.1 christos 449 1.2 christos ptr.hello_link = (const struct olsr_hello_link *)msg_data; 450 1.1 christos 451 1.5 christos hello_len = GET_BE_U_2(ptr.hello_link->len); 452 1.5 christos link_type = OLSR_EXTRACT_LINK_TYPE(GET_U_1(ptr.hello_link->link_code)); 453 1.5 christos neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(GET_U_1(ptr.hello_link->link_code)); 454 1.1 christos 455 1.1 christos if ((hello_len <= msg_tlen) 456 1.1 christos && (hello_len >= sizeof(struct olsr_hello_link))) 457 1.1 christos hello_len_valid = 1; 458 1.1 christos 459 1.5 christos ND_PRINT("\n\t link-type %s, neighbor-type %s, len %u%s", 460 1.1 christos tok2str(olsr_link_type_values, "Unknown", link_type), 461 1.1 christos tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type), 462 1.1 christos hello_len, 463 1.5 christos (hello_len_valid == 0) ? " (invalid)" : ""); 464 1.1 christos 465 1.1 christos if (hello_len_valid == 0) 466 1.1 christos break; 467 1.1 christos 468 1.1 christos msg_data += sizeof(struct olsr_hello_link); 469 1.1 christos msg_tlen -= sizeof(struct olsr_hello_link); 470 1.1 christos hello_len -= sizeof(struct olsr_hello_link); 471 1.1 christos 472 1.5 christos ND_TCHECK_LEN(msg_data, hello_len); 473 1.1 christos if (msg_type == OLSR_HELLO_MSG) { 474 1.2 christos if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1) 475 1.2 christos goto trunc; 476 1.1 christos } else { 477 1.2 christos if (is_ipv6) { 478 1.2 christos if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1) 479 1.2 christos goto trunc; 480 1.2 christos } else { 481 1.2 christos if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1) 482 1.2 christos goto trunc; 483 1.2 christos } 484 1.1 christos } 485 1.1 christos 486 1.1 christos msg_data += hello_len; 487 1.1 christos msg_tlen -= hello_len; 488 1.1 christos } 489 1.1 christos break; 490 1.1 christos 491 1.1 christos case OLSR_TC_MSG: 492 1.1 christos case OLSR_TC_LQ_MSG: 493 1.2 christos if (msg_tlen < sizeof(struct olsr_tc)) 494 1.1 christos goto trunc; 495 1.5 christos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_tc)); 496 1.1 christos 497 1.2 christos ptr.tc = (const struct olsr_tc *)msg_data; 498 1.5 christos ND_PRINT("\n\t advertised neighbor seq 0x%04x", 499 1.5 christos GET_BE_U_2(ptr.tc->ans_seq)); 500 1.1 christos msg_data += sizeof(struct olsr_tc); 501 1.1 christos msg_tlen -= sizeof(struct olsr_tc); 502 1.1 christos 503 1.1 christos if (msg_type == OLSR_TC_MSG) { 504 1.2 christos if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1) 505 1.2 christos goto trunc; 506 1.1 christos } else { 507 1.2 christos if (is_ipv6) { 508 1.2 christos if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1) 509 1.2 christos goto trunc; 510 1.2 christos } else { 511 1.2 christos if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1) 512 1.2 christos goto trunc; 513 1.2 christos } 514 1.1 christos } 515 1.1 christos break; 516 1.1 christos 517 1.1 christos case OLSR_MID_MSG: 518 1.1 christos { 519 1.5 christos u_int addr_size = (u_int)sizeof(nd_ipv4); 520 1.1 christos 521 1.1 christos if (is_ipv6) 522 1.5 christos addr_size = (u_int)sizeof(nd_ipv6); 523 1.1 christos 524 1.1 christos while (msg_tlen >= addr_size) { 525 1.5 christos ND_TCHECK_LEN(msg_data, addr_size); 526 1.5 christos ND_PRINT("\n\t interface address %s", 527 1.5 christos is_ipv6 ? GET_IP6ADDR_STRING(msg_data) : 528 1.5 christos GET_IPADDR_STRING(msg_data)); 529 1.1 christos 530 1.1 christos msg_data += addr_size; 531 1.1 christos msg_tlen -= addr_size; 532 1.1 christos } 533 1.1 christos break; 534 1.1 christos } 535 1.1 christos 536 1.1 christos case OLSR_HNA_MSG: 537 1.6 christos if (is_ipv6) { 538 1.1 christos int i = 0; 539 1.2 christos 540 1.5 christos ND_PRINT("\n\t Advertised networks (total %u)", 541 1.5 christos (unsigned int) (msg_tlen / sizeof(struct olsr_hna6))); 542 1.2 christos 543 1.1 christos while (msg_tlen >= sizeof(struct olsr_hna6)) { 544 1.2 christos const struct olsr_hna6 *hna6; 545 1.1 christos 546 1.5 christos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna6)); 547 1.1 christos 548 1.2 christos hna6 = (const struct olsr_hna6 *)msg_data; 549 1.1 christos 550 1.5 christos ND_PRINT("\n\t #%i: %s/%u", 551 1.5 christos i, GET_IP6ADDR_STRING(hna6->network), 552 1.5 christos mask62plen (hna6->mask)); 553 1.1 christos 554 1.1 christos msg_data += sizeof(struct olsr_hna6); 555 1.1 christos msg_tlen -= sizeof(struct olsr_hna6); 556 1.1 christos } 557 1.6 christos } else { 558 1.1 christos int col = 0; 559 1.2 christos 560 1.5 christos ND_PRINT("\n\t Advertised networks (total %u)", 561 1.5 christos (unsigned int) (msg_tlen / sizeof(struct olsr_hna4))); 562 1.2 christos 563 1.1 christos while (msg_tlen >= sizeof(struct olsr_hna4)) { 564 1.5 christos ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna4)); 565 1.1 christos 566 1.2 christos ptr.hna = (const struct olsr_hna4 *)msg_data; 567 1.1 christos 568 1.1 christos /* print 4 prefixes per line */ 569 1.2 christos if (!ptr.hna->network[0] && !ptr.hna->network[1] && 570 1.2 christos !ptr.hna->network[2] && !ptr.hna->network[3] && 571 1.2 christos !ptr.hna->mask[GW_HNA_PAD] && 572 1.2 christos ptr.hna->mask[GW_HNA_FLAGS]) { 573 1.2 christos /* smart gateway */ 574 1.5 christos ND_PRINT("%sSmart-Gateway:%s%s%s%s%s %u/%u", 575 1.2 christos col == 0 ? "\n\t " : ", ", /* indent */ 576 1.2 christos /* sgw */ 577 1.2 christos /* LINKSPEED */ 578 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 579 1.2 christos GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "", 580 1.2 christos /* IPV4 */ 581 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 582 1.2 christos GW_HNA_FLAG_IPV4) ? " IPV4" : "", 583 1.2 christos /* IPV4-NAT */ 584 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 585 1.2 christos GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "", 586 1.2 christos /* IPV6 */ 587 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 588 1.2 christos GW_HNA_FLAG_IPV6) ? " IPV6" : "", 589 1.2 christos /* IPv6PREFIX */ 590 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 591 1.2 christos GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "", 592 1.2 christos /* uplink */ 593 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 594 1.2 christos GW_HNA_FLAG_LINKSPEED) ? 595 1.2 christos deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0, 596 1.2 christos /* downlink */ 597 1.2 christos (ptr.hna->mask[GW_HNA_FLAGS] & 598 1.2 christos GW_HNA_FLAG_LINKSPEED) ? 599 1.2 christos deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0 600 1.5 christos ); 601 1.2 christos } else { 602 1.2 christos /* normal route */ 603 1.5 christos ND_PRINT("%s%s/%u", 604 1.2 christos col == 0 ? "\n\t " : ", ", 605 1.5 christos GET_IPADDR_STRING(ptr.hna->network), 606 1.5 christos mask2plen(GET_BE_U_4(ptr.hna->mask))); 607 1.2 christos } 608 1.1 christos 609 1.1 christos msg_data += sizeof(struct olsr_hna4); 610 1.1 christos msg_tlen -= sizeof(struct olsr_hna4); 611 1.1 christos 612 1.1 christos col = (col + 1) % 4; 613 1.1 christos } 614 1.1 christos } 615 1.1 christos break; 616 1.1 christos 617 1.1 christos case OLSR_NAMESERVICE_MSG: 618 1.1 christos { 619 1.4 christos u_int name_entries; 620 1.4 christos u_int addr_size; 621 1.4 christos int name_entries_valid; 622 1.1 christos u_int i; 623 1.1 christos 624 1.4 christos if (msg_tlen < 4) 625 1.4 christos goto trunc; 626 1.4 christos 627 1.5 christos name_entries = GET_BE_U_2(msg_data + 2); 628 1.4 christos addr_size = 4; 629 1.1 christos if (is_ipv6) 630 1.1 christos addr_size = 16; 631 1.1 christos 632 1.4 christos name_entries_valid = 0; 633 1.1 christos if ((name_entries > 0) 634 1.1 christos && ((name_entries * (4 + addr_size)) <= msg_tlen)) 635 1.1 christos name_entries_valid = 1; 636 1.1 christos 637 1.5 christos ND_PRINT("\n\t Version %u, Entries %u%s", 638 1.5 christos GET_BE_U_2(msg_data), 639 1.5 christos name_entries, (name_entries_valid == 0) ? " (invalid)" : ""); 640 1.1 christos 641 1.1 christos if (name_entries_valid == 0) 642 1.1 christos break; 643 1.1 christos 644 1.1 christos msg_data += 4; 645 1.1 christos msg_tlen -= 4; 646 1.1 christos 647 1.1 christos for (i = 0; i < name_entries; i++) { 648 1.1 christos int name_entry_len_valid = 0; 649 1.1 christos 650 1.1 christos if (msg_tlen < 4) 651 1.1 christos break; 652 1.1 christos 653 1.5 christos name_entry_type = GET_BE_U_2(msg_data); 654 1.5 christos name_entry_len = GET_BE_U_2(msg_data + 2); 655 1.1 christos 656 1.1 christos msg_data += 4; 657 1.1 christos msg_tlen -= 4; 658 1.1 christos 659 1.1 christos if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen)) 660 1.1 christos name_entry_len_valid = 1; 661 1.1 christos 662 1.5 christos ND_PRINT("\n\t #%u: type %#06x, length %u%s", 663 1.1 christos (unsigned int) i, name_entry_type, 664 1.5 christos name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : ""); 665 1.1 christos 666 1.1 christos if (name_entry_len_valid == 0) 667 1.1 christos break; 668 1.1 christos 669 1.1 christos /* 32-bit alignment */ 670 1.1 christos name_entry_padding = 0; 671 1.1 christos if (name_entry_len%4 != 0) 672 1.1 christos name_entry_padding = 4-(name_entry_len%4); 673 1.1 christos 674 1.1 christos if (msg_tlen < addr_size + name_entry_len + name_entry_padding) 675 1.1 christos goto trunc; 676 1.1 christos 677 1.5 christos ND_TCHECK_LEN(msg_data, 678 1.5 christos addr_size + name_entry_len + name_entry_padding); 679 1.1 christos 680 1.1 christos if (is_ipv6) 681 1.5 christos ND_PRINT(", address %s, name \"", 682 1.5 christos GET_IP6ADDR_STRING(msg_data)); 683 1.1 christos else 684 1.5 christos ND_PRINT(", address %s, name \"", 685 1.5 christos GET_IPADDR_STRING(msg_data)); 686 1.5 christos (void)nd_printn(ndo, msg_data + addr_size, name_entry_len, NULL); 687 1.5 christos ND_PRINT("\""); 688 1.1 christos 689 1.1 christos msg_data += addr_size + name_entry_len + name_entry_padding; 690 1.1 christos msg_tlen -= addr_size + name_entry_len + name_entry_padding; 691 1.1 christos } /* for (i = 0; i < name_entries; i++) */ 692 1.1 christos break; 693 1.1 christos } /* case OLSR_NAMESERVICE_MSG */ 694 1.1 christos 695 1.1 christos /* 696 1.1 christos * FIXME those are the defined messages that lack a decoder 697 1.1 christos * you are welcome to contribute code ;-) 698 1.1 christos */ 699 1.1 christos case OLSR_POWERINFO_MSG: 700 1.1 christos default: 701 1.2 christos print_unknown_data(ndo, msg_data, "\n\t ", msg_tlen); 702 1.1 christos break; 703 1.1 christos } /* switch (msg_type) */ 704 1.1 christos tptr += msg_len; 705 1.1 christos } /* while (tptr < (pptr+length)) */ 706 1.1 christos 707 1.1 christos return; 708 1.1 christos 709 1.1 christos trunc: 710 1.5 christos nd_print_trunc(ndo); 711 1.1 christos } 712