1/* 2 * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bruce M. Simpson. 16 * 4. Neither the name of Bruce M. Simpson nor the names of co- 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* \summary: Ad hoc On-Demand Distance Vector (AODV) Routing printer */ 34 35#ifdef HAVE_CONFIG_H 36#include <config.h> 37#endif 38 39#include "netdissect-stdinc.h" 40 41#include "netdissect.h" 42#include "addrtoname.h" 43#include "extract.h" 44 45/* 46 * RFC 3561 47 */ 48struct aodv_rreq { 49 nd_uint8_t rreq_type; /* AODV message type (1) */ 50 nd_uint8_t rreq_flags; /* various flags */ 51 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 52 nd_uint8_t rreq_hops; /* number of hops from originator */ 53 nd_uint32_t rreq_id; /* request ID */ 54 nd_ipv4 rreq_da; /* destination IPv4 address */ 55 nd_uint32_t rreq_ds; /* destination sequence number */ 56 nd_ipv4 rreq_oa; /* originator IPv4 address */ 57 nd_uint32_t rreq_os; /* originator sequence number */ 58}; 59struct aodv_rreq6 { 60 nd_uint8_t rreq_type; /* AODV message type (1) */ 61 nd_uint8_t rreq_flags; /* various flags */ 62 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 63 nd_uint8_t rreq_hops; /* number of hops from originator */ 64 nd_uint32_t rreq_id; /* request ID */ 65 nd_ipv6 rreq_da; /* destination IPv6 address */ 66 nd_uint32_t rreq_ds; /* destination sequence number */ 67 nd_ipv6 rreq_oa; /* originator IPv6 address */ 68 nd_uint32_t rreq_os; /* originator sequence number */ 69}; 70struct aodv_rreq6_draft_01 { 71 nd_uint8_t rreq_type; /* AODV message type (16) */ 72 nd_uint8_t rreq_flags; /* various flags */ 73 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 74 nd_uint8_t rreq_hops; /* number of hops from originator */ 75 nd_uint32_t rreq_id; /* request ID */ 76 nd_uint32_t rreq_ds; /* destination sequence number */ 77 nd_uint32_t rreq_os; /* originator sequence number */ 78 nd_ipv6 rreq_da; /* destination IPv6 address */ 79 nd_ipv6 rreq_oa; /* originator IPv6 address */ 80}; 81 82#define RREQ_JOIN 0x80 /* join (reserved for multicast */ 83#define RREQ_REPAIR 0x40 /* repair (reserved for multicast */ 84#define RREQ_GRAT 0x20 /* gratuitous RREP */ 85#define RREQ_DEST 0x10 /* destination only */ 86#define RREQ_UNKNOWN 0x08 /* unknown destination sequence num */ 87#define RREQ_FLAGS_MASK 0xF8 /* mask for rreq_flags */ 88 89struct aodv_rrep { 90 nd_uint8_t rrep_type; /* AODV message type (2) */ 91 nd_uint8_t rrep_flags; /* various flags */ 92 nd_uint8_t rrep_ps; /* prefix size */ 93 nd_uint8_t rrep_hops; /* number of hops from o to d */ 94 nd_ipv4 rrep_da; /* destination IPv4 address */ 95 nd_uint32_t rrep_ds; /* destination sequence number */ 96 nd_ipv4 rrep_oa; /* originator IPv4 address */ 97 nd_uint32_t rrep_life; /* lifetime of this route */ 98}; 99struct aodv_rrep6 { 100 nd_uint8_t rrep_type; /* AODV message type (2) */ 101 nd_uint8_t rrep_flags; /* various flags */ 102 nd_uint8_t rrep_ps; /* prefix size */ 103 nd_uint8_t rrep_hops; /* number of hops from o to d */ 104 nd_ipv6 rrep_da; /* destination IPv6 address */ 105 nd_uint32_t rrep_ds; /* destination sequence number */ 106 nd_ipv6 rrep_oa; /* originator IPv6 address */ 107 nd_uint32_t rrep_life; /* lifetime of this route */ 108}; 109struct aodv_rrep6_draft_01 { 110 nd_uint8_t rrep_type; /* AODV message type (17) */ 111 nd_uint8_t rrep_flags; /* various flags */ 112 nd_uint8_t rrep_ps; /* prefix size */ 113 nd_uint8_t rrep_hops; /* number of hops from o to d */ 114 nd_uint32_t rrep_ds; /* destination sequence number */ 115 nd_ipv6 rrep_da; /* destination IPv6 address */ 116 nd_ipv6 rrep_oa; /* originator IPv6 address */ 117 nd_uint32_t rrep_life; /* lifetime of this route */ 118}; 119 120#define RREP_REPAIR 0x80 /* repair (reserved for multicast */ 121#define RREP_ACK 0x40 /* acknowledgement required */ 122#define RREP_FLAGS_MASK 0xC0 /* mask for rrep_flags */ 123#define RREP_PREFIX_MASK 0x1F /* mask for prefix size */ 124 125struct rerr_unreach { 126 nd_ipv4 u_da; /* IPv4 address */ 127 nd_uint32_t u_ds; /* sequence number */ 128}; 129struct rerr_unreach6 { 130 nd_ipv6 u_da; /* IPv6 address */ 131 nd_uint32_t u_ds; /* sequence number */ 132}; 133struct rerr_unreach6_draft_01 { 134 nd_ipv6 u_da; /* IPv6 address */ 135 nd_uint32_t u_ds; /* sequence number */ 136}; 137 138struct aodv_rerr { 139 nd_uint8_t rerr_type; /* AODV message type (3 or 18) */ 140 nd_uint8_t rerr_flags; /* various flags */ 141 nd_uint8_t rerr_zero0; /* reserved, set to zero */ 142 nd_uint8_t rerr_dc; /* destination count */ 143}; 144 145#define RERR_NODELETE 0x80 /* don't delete the link */ 146#define RERR_FLAGS_MASK 0x80 /* mask for rerr_flags */ 147 148struct aodv_rrep_ack { 149 nd_uint8_t ra_type; 150 nd_uint8_t ra_zero0; 151}; 152 153#define AODV_RREQ 1 /* route request */ 154#define AODV_RREP 2 /* route response */ 155#define AODV_RERR 3 /* error report */ 156#define AODV_RREP_ACK 4 /* route response acknowledgement */ 157 158#define AODV_V6_DRAFT_01_RREQ 16 /* IPv6 route request */ 159#define AODV_V6_DRAFT_01_RREP 17 /* IPv6 route response */ 160#define AODV_V6_DRAFT_01_RERR 18 /* IPv6 error report */ 161#define AODV_V6_DRAFT_01_RREP_ACK 19 /* IPV6 route response acknowledgment */ 162 163struct aodv_ext { 164 nd_uint8_t type; /* extension type */ 165 nd_uint8_t length; /* extension length */ 166}; 167 168struct aodv_hello { 169 struct aodv_ext eh; /* extension header */ 170 nd_uint32_t interval; /* expect my next hello in 171 * (n) ms 172 * NOTE: this is not aligned */ 173}; 174 175#define AODV_EXT_HELLO 1 176 177static void 178aodv_extension(netdissect_options *ndo, 179 const struct aodv_ext *ep, u_int length) 180{ 181 const struct aodv_hello *ah; 182 183 ND_TCHECK_SIZE(ep); 184 switch (GET_U_1(ep->type)) { 185 case AODV_EXT_HELLO: 186 ah = (const struct aodv_hello *)(const void *)ep; 187 ND_TCHECK_SIZE(ah); 188 if (length < sizeof(struct aodv_hello)) 189 goto trunc; 190 if (GET_U_1(ep->length) < 4) { 191 ND_PRINT("\n\text HELLO - bad length %u", 192 GET_U_1(ep->length)); 193 break; 194 } 195 ND_PRINT("\n\text HELLO %u ms", 196 GET_BE_U_4(ah->interval)); 197 break; 198 199 default: 200 ND_PRINT("\n\text %u %u", GET_U_1(ep->type), 201 GET_U_1(ep->length)); 202 break; 203 } 204 return; 205 206trunc: 207 nd_print_trunc(ndo); 208} 209 210static void 211aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 212{ 213 u_int i; 214 const struct aodv_rreq *ap = (const struct aodv_rreq *)dat; 215 216 ND_TCHECK_SIZE(ap); 217 if (length < sizeof(*ap)) 218 goto trunc; 219 ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n" 220 "\tdst %s seq %u src %s seq %u", length, 221 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 222 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 223 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 224 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 225 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 226 GET_U_1(ap->rreq_hops), 227 GET_BE_U_4(ap->rreq_id), 228 GET_IPADDR_STRING(ap->rreq_da), 229 GET_BE_U_4(ap->rreq_ds), 230 GET_IPADDR_STRING(ap->rreq_oa), 231 GET_BE_U_4(ap->rreq_os)); 232 i = length - sizeof(*ap); 233 if (i >= sizeof(struct aodv_ext)) 234 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 235 return; 236 237trunc: 238 nd_print_trunc(ndo); 239} 240 241static void 242aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 243{ 244 u_int i; 245 const struct aodv_rrep *ap = (const struct aodv_rrep *)dat; 246 247 ND_TCHECK_SIZE(ap); 248 if (length < sizeof(*ap)) 249 goto trunc; 250 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 251 "\tdst %s dseq %u src %s %u ms", length, 252 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 253 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 254 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 255 GET_U_1(ap->rrep_hops), 256 GET_IPADDR_STRING(ap->rrep_da), 257 GET_BE_U_4(ap->rrep_ds), 258 GET_IPADDR_STRING(ap->rrep_oa), 259 GET_BE_U_4(ap->rrep_life)); 260 i = length - sizeof(*ap); 261 if (i >= sizeof(struct aodv_ext)) 262 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 263 return; 264 265trunc: 266 nd_print_trunc(ndo); 267} 268 269static void 270aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 271{ 272 u_int i, dc; 273 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 274 const struct rerr_unreach *dp; 275 276 ND_TCHECK_SIZE(ap); 277 if (length < sizeof(*ap)) 278 goto trunc; 279 ND_PRINT(" rerr %s [items %u] [%u]:", 280 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 281 GET_U_1(ap->rerr_dc), length); 282 dp = (const struct rerr_unreach *)(dat + sizeof(*ap)); 283 i = length - sizeof(*ap); 284 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 285 ND_TCHECK_SIZE(dp); 286 if (i < sizeof(*dp)) 287 goto trunc; 288 ND_PRINT(" {%s}(%u)", GET_IPADDR_STRING(dp->u_da), 289 GET_BE_U_4(dp->u_ds)); 290 dp++; 291 i -= sizeof(*dp); 292 } 293 return; 294 295trunc: 296 nd_print_trunc(ndo); 297} 298 299static void 300aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 301{ 302 u_int i; 303 const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat; 304 305 ND_TCHECK_SIZE(ap); 306 if (length < sizeof(*ap)) 307 goto trunc; 308 ND_PRINT(" v6 rreq %u %s%s%s%s%shops %u id 0x%08x\n" 309 "\tdst %s seq %u src %s seq %u", length, 310 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 311 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 312 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 313 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 314 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 315 GET_U_1(ap->rreq_hops), 316 GET_BE_U_4(ap->rreq_id), 317 GET_IP6ADDR_STRING(ap->rreq_da), 318 GET_BE_U_4(ap->rreq_ds), 319 GET_IP6ADDR_STRING(ap->rreq_oa), 320 GET_BE_U_4(ap->rreq_os)); 321 i = length - sizeof(*ap); 322 if (i >= sizeof(struct aodv_ext)) 323 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 324 return; 325 326trunc: 327 nd_print_trunc(ndo); 328} 329 330static void 331aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 332{ 333 u_int i; 334 const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat; 335 336 ND_TCHECK_SIZE(ap); 337 if (length < sizeof(*ap)) 338 goto trunc; 339 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 340 "\tdst %s dseq %u src %s %u ms", length, 341 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 342 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 343 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 344 GET_U_1(ap->rrep_hops), 345 GET_IP6ADDR_STRING(ap->rrep_da), 346 GET_BE_U_4(ap->rrep_ds), 347 GET_IP6ADDR_STRING(ap->rrep_oa), 348 GET_BE_U_4(ap->rrep_life)); 349 i = length - sizeof(*ap); 350 if (i >= sizeof(struct aodv_ext)) 351 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 352 return; 353 354trunc: 355 nd_print_trunc(ndo); 356} 357 358static void 359aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 360{ 361 u_int i, dc; 362 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 363 const struct rerr_unreach6 *dp6; 364 365 ND_TCHECK_SIZE(ap); 366 if (length < sizeof(*ap)) 367 goto trunc; 368 ND_PRINT(" rerr %s [items %u] [%u]:", 369 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 370 GET_U_1(ap->rerr_dc), length); 371 dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1); 372 i = length - sizeof(*ap); 373 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 374 ND_TCHECK_SIZE(dp6); 375 if (i < sizeof(*dp6)) 376 goto trunc; 377 ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da), 378 GET_BE_U_4(dp6->u_ds)); 379 dp6++; 380 i -= sizeof(*dp6); 381 } 382 return; 383 384trunc: 385 nd_print_trunc(ndo); 386} 387 388static void 389aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 390{ 391 u_int i; 392 const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat; 393 394 ND_TCHECK_SIZE(ap); 395 if (length < sizeof(*ap)) 396 goto trunc; 397 ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n" 398 "\tdst %s seq %u src %s seq %u", length, 399 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 400 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 401 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 402 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 403 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 404 GET_U_1(ap->rreq_hops), 405 GET_BE_U_4(ap->rreq_id), 406 GET_IP6ADDR_STRING(ap->rreq_da), 407 GET_BE_U_4(ap->rreq_ds), 408 GET_IP6ADDR_STRING(ap->rreq_oa), 409 GET_BE_U_4(ap->rreq_os)); 410 i = length - sizeof(*ap); 411 if (i >= sizeof(struct aodv_ext)) 412 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 413 return; 414 415trunc: 416 nd_print_trunc(ndo); 417} 418 419static void 420aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 421{ 422 u_int i; 423 const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat; 424 425 ND_TCHECK_SIZE(ap); 426 if (length < sizeof(*ap)) 427 goto trunc; 428 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 429 "\tdst %s dseq %u src %s %u ms", length, 430 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 431 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 432 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 433 GET_U_1(ap->rrep_hops), 434 GET_IP6ADDR_STRING(ap->rrep_da), 435 GET_BE_U_4(ap->rrep_ds), 436 GET_IP6ADDR_STRING(ap->rrep_oa), 437 GET_BE_U_4(ap->rrep_life)); 438 i = length - sizeof(*ap); 439 if (i >= sizeof(struct aodv_ext)) 440 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 441 return; 442 443trunc: 444 nd_print_trunc(ndo); 445} 446 447static void 448aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 449{ 450 u_int i, dc; 451 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 452 const struct rerr_unreach6_draft_01 *dp6; 453 454 ND_TCHECK_SIZE(ap); 455 if (length < sizeof(*ap)) 456 goto trunc; 457 ND_PRINT(" rerr %s [items %u] [%u]:", 458 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 459 GET_U_1(ap->rerr_dc), length); 460 dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1); 461 i = length - sizeof(*ap); 462 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 463 ND_TCHECK_SIZE(dp6); 464 if (i < sizeof(*dp6)) 465 goto trunc; 466 ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da), 467 GET_BE_U_4(dp6->u_ds)); 468 dp6++; 469 i -= sizeof(*dp6); 470 } 471 return; 472 473trunc: 474 nd_print_trunc(ndo); 475} 476 477void 478aodv_print(netdissect_options *ndo, 479 const u_char *dat, u_int length, int is_ip6) 480{ 481 uint8_t msg_type; 482 483 ndo->ndo_protocol = "aodv"; 484 /* 485 * The message type is the first byte; make sure we have it 486 * and then fetch it. 487 */ 488 msg_type = GET_U_1(dat); 489 ND_PRINT(" aodv"); 490 491 switch (msg_type) { 492 493 case AODV_RREQ: 494 if (is_ip6) 495 aodv_v6_rreq(ndo, dat, length); 496 else 497 aodv_rreq(ndo, dat, length); 498 break; 499 500 case AODV_RREP: 501 if (is_ip6) 502 aodv_v6_rrep(ndo, dat, length); 503 else 504 aodv_rrep(ndo, dat, length); 505 break; 506 507 case AODV_RERR: 508 if (is_ip6) 509 aodv_v6_rerr(ndo, dat, length); 510 else 511 aodv_rerr(ndo, dat, length); 512 break; 513 514 case AODV_RREP_ACK: 515 ND_PRINT(" rrep-ack %u", length); 516 break; 517 518 case AODV_V6_DRAFT_01_RREQ: 519 aodv_v6_draft_01_rreq(ndo, dat, length); 520 break; 521 522 case AODV_V6_DRAFT_01_RREP: 523 aodv_v6_draft_01_rrep(ndo, dat, length); 524 break; 525 526 case AODV_V6_DRAFT_01_RERR: 527 aodv_v6_draft_01_rerr(ndo, dat, length); 528 break; 529 530 case AODV_V6_DRAFT_01_RREP_ACK: 531 ND_PRINT(" rrep-ack %u", length); 532 break; 533 534 default: 535 ND_PRINT(" type %u %u", msg_type, length); 536 } 537} 538