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 struct aodv_rreq { 47 uint8_t rreq_type; /* AODV message type (1) */ 48 uint8_t rreq_flags; /* various flags */ 49 uint8_t rreq_zero0; /* reserved, set to zero */ 50 uint8_t rreq_hops; /* number of hops from originator */ 51 uint32_t rreq_id; /* request ID */ 52 uint32_t rreq_da; /* destination IPv4 address */ 53 uint32_t rreq_ds; /* destination sequence number */ 54 uint32_t rreq_oa; /* originator IPv4 address */ 55 uint32_t rreq_os; /* originator sequence number */ 56 }; 57 struct aodv_rreq6 { 58 uint8_t rreq_type; /* AODV message type (1) */ 59 uint8_t rreq_flags; /* various flags */ 60 uint8_t rreq_zero0; /* reserved, set to zero */ 61 uint8_t rreq_hops; /* number of hops from originator */ 62 uint32_t rreq_id; /* request ID */ 63 struct in6_addr rreq_da; /* destination IPv6 address */ 64 uint32_t rreq_ds; /* destination sequence number */ 65 struct in6_addr rreq_oa; /* originator IPv6 address */ 66 uint32_t rreq_os; /* originator sequence number */ 67 }; 68 struct aodv_rreq6_draft_01 { 69 uint8_t rreq_type; /* AODV message type (16) */ 70 uint8_t rreq_flags; /* various flags */ 71 uint8_t rreq_zero0; /* reserved, set to zero */ 72 uint8_t rreq_hops; /* number of hops from originator */ 73 uint32_t rreq_id; /* request ID */ 74 uint32_t rreq_ds; /* destination sequence number */ 75 uint32_t rreq_os; /* originator sequence number */ 76 struct in6_addr rreq_da; /* destination IPv6 address */ 77 struct in6_addr rreq_oa; /* originator IPv6 address */ 78 }; 79 80 #define RREQ_JOIN 0x80 /* join (reserved for multicast */ 81 #define RREQ_REPAIR 0x40 /* repair (reserved for multicast */ 82 #define RREQ_GRAT 0x20 /* gratuitous RREP */ 83 #define RREQ_DEST 0x10 /* destination only */ 84 #define RREQ_UNKNOWN 0x08 /* unknown destination sequence num */ 85 #define RREQ_FLAGS_MASK 0xF8 /* mask for rreq_flags */ 86 87 struct aodv_rrep { 88 uint8_t rrep_type; /* AODV message type (2) */ 89 uint8_t rrep_flags; /* various flags */ 90 uint8_t rrep_ps; /* prefix size */ 91 uint8_t rrep_hops; /* number of hops from o to d */ 92 uint32_t rrep_da; /* destination IPv4 address */ 93 uint32_t rrep_ds; /* destination sequence number */ 94 uint32_t rrep_oa; /* originator IPv4 address */ 95 uint32_t rrep_life; /* lifetime of this route */ 96 }; 97 struct aodv_rrep6 { 98 uint8_t rrep_type; /* AODV message type (2) */ 99 uint8_t rrep_flags; /* various flags */ 100 uint8_t rrep_ps; /* prefix size */ 101 uint8_t rrep_hops; /* number of hops from o to d */ 102 struct in6_addr rrep_da; /* destination IPv6 address */ 103 uint32_t rrep_ds; /* destination sequence number */ 104 struct in6_addr rrep_oa; /* originator IPv6 address */ 105 uint32_t rrep_life; /* lifetime of this route */ 106 }; 107 struct aodv_rrep6_draft_01 { 108 uint8_t rrep_type; /* AODV message type (17) */ 109 uint8_t rrep_flags; /* various flags */ 110 uint8_t rrep_ps; /* prefix size */ 111 uint8_t rrep_hops; /* number of hops from o to d */ 112 uint32_t rrep_ds; /* destination sequence number */ 113 struct in6_addr rrep_da; /* destination IPv6 address */ 114 struct in6_addr rrep_oa; /* originator IPv6 address */ 115 uint32_t rrep_life; /* lifetime of this route */ 116 }; 117 118 #define RREP_REPAIR 0x80 /* repair (reserved for multicast */ 119 #define RREP_ACK 0x40 /* acknowledgement required */ 120 #define RREP_FLAGS_MASK 0xC0 /* mask for rrep_flags */ 121 #define RREP_PREFIX_MASK 0x1F /* mask for prefix size */ 122 123 struct rerr_unreach { 124 uint32_t u_da; /* IPv4 address */ 125 uint32_t u_ds; /* sequence number */ 126 }; 127 struct rerr_unreach6 { 128 struct in6_addr u_da; /* IPv6 address */ 129 uint32_t u_ds; /* sequence number */ 130 }; 131 struct rerr_unreach6_draft_01 { 132 struct in6_addr u_da; /* IPv6 address */ 133 uint32_t u_ds; /* sequence number */ 134 }; 135 136 struct aodv_rerr { 137 uint8_t rerr_type; /* AODV message type (3 or 18) */ 138 uint8_t rerr_flags; /* various flags */ 139 uint8_t rerr_zero0; /* reserved, set to zero */ 140 uint8_t rerr_dc; /* destination count */ 141 }; 142 143 #define RERR_NODELETE 0x80 /* don't delete the link */ 144 #define RERR_FLAGS_MASK 0x80 /* mask for rerr_flags */ 145 146 struct aodv_rrep_ack { 147 uint8_t ra_type; 148 uint8_t ra_zero0; 149 }; 150 151 #define AODV_RREQ 1 /* route request */ 152 #define AODV_RREP 2 /* route response */ 153 #define AODV_RERR 3 /* error report */ 154 #define AODV_RREP_ACK 4 /* route response acknowledgement */ 155 156 #define AODV_V6_DRAFT_01_RREQ 16 /* IPv6 route request */ 157 #define AODV_V6_DRAFT_01_RREP 17 /* IPv6 route response */ 158 #define AODV_V6_DRAFT_01_RERR 18 /* IPv6 error report */ 159 #define AODV_V6_DRAFT_01_RREP_ACK 19 /* IPV6 route response acknowledgment */ 160 161 struct aodv_ext { 162 uint8_t type; /* extension type */ 163 uint8_t length; /* extension length */ 164 }; 165 166 struct aodv_hello { 167 struct aodv_ext eh; /* extension header */ 168 uint8_t interval[4]; /* expect my next hello in 169 * (n) ms 170 * NOTE: this is not aligned */ 171 }; 172 173 #define AODV_EXT_HELLO 1 174 175 static void 176 aodv_extension(netdissect_options *ndo, 177 const struct aodv_ext *ep, u_int length) 178 { 179 const struct aodv_hello *ah; 180 181 switch (ep->type) { 182 case AODV_EXT_HELLO: 183 ah = (const struct aodv_hello *)(const void *)ep; 184 ND_TCHECK(*ah); 185 if (length < sizeof(struct aodv_hello)) 186 goto trunc; 187 ND_PRINT((ndo, "\n\text HELLO %ld ms", 188 (unsigned long)EXTRACT_32BITS(&ah->interval))); 189 break; 190 191 default: 192 ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length)); 193 break; 194 } 195 return; 196 197 trunc: 198 ND_PRINT((ndo, " [|hello]")); 199 } 200 201 static void 202 aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 203 { 204 u_int i; 205 const struct aodv_rreq *ap = (const struct aodv_rreq *)dat; 206 207 ND_TCHECK(*ap); 208 if (length < sizeof(*ap)) 209 goto trunc; 210 ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" 211 "\tdst %s seq %lu src %s seq %lu", length, 212 ap->rreq_type & RREQ_JOIN ? "[J]" : "", 213 ap->rreq_type & RREQ_REPAIR ? "[R]" : "", 214 ap->rreq_type & RREQ_GRAT ? "[G]" : "", 215 ap->rreq_type & RREQ_DEST ? "[D]" : "", 216 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", 217 ap->rreq_hops, 218 (unsigned long)EXTRACT_32BITS(&ap->rreq_id), 219 ipaddr_string(ndo, &ap->rreq_da), 220 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), 221 ipaddr_string(ndo, &ap->rreq_oa), 222 (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); 223 i = length - sizeof(*ap); 224 if (i >= sizeof(struct aodv_ext)) 225 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 226 return; 227 228 trunc: 229 ND_PRINT((ndo, " [|rreq")); 230 } 231 232 static void 233 aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 234 { 235 u_int i; 236 const struct aodv_rrep *ap = (const struct aodv_rrep *)dat; 237 238 ND_TCHECK(*ap); 239 if (length < sizeof(*ap)) 240 goto trunc; 241 ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" 242 "\tdst %s dseq %lu src %s %lu ms", length, 243 ap->rrep_type & RREP_REPAIR ? "[R]" : "", 244 ap->rrep_type & RREP_ACK ? "[A] " : " ", 245 ap->rrep_ps & RREP_PREFIX_MASK, 246 ap->rrep_hops, 247 ipaddr_string(ndo, &ap->rrep_da), 248 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), 249 ipaddr_string(ndo, &ap->rrep_oa), 250 (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); 251 i = length - sizeof(*ap); 252 if (i >= sizeof(struct aodv_ext)) 253 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 254 return; 255 256 trunc: 257 ND_PRINT((ndo, " [|rreq")); 258 } 259 260 static void 261 aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 262 { 263 u_int i, dc; 264 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 265 const struct rerr_unreach *dp; 266 267 ND_TCHECK(*ap); 268 if (length < sizeof(*ap)) 269 goto trunc; 270 ND_PRINT((ndo, " rerr %s [items %u] [%u]:", 271 ap->rerr_flags & RERR_NODELETE ? "[D]" : "", 272 ap->rerr_dc, length)); 273 dp = (const struct rerr_unreach *)(dat + sizeof(*ap)); 274 i = length - sizeof(*ap); 275 for (dc = ap->rerr_dc; dc != 0; dc--) { 276 ND_TCHECK(*dp); 277 if (i < sizeof(*dp)) 278 goto trunc; 279 ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da), 280 (unsigned long)EXTRACT_32BITS(&dp->u_ds))); 281 dp++; 282 i -= sizeof(*dp); 283 } 284 return; 285 286 trunc: 287 ND_PRINT((ndo, "[|rerr]")); 288 } 289 290 static void 291 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 292 { 293 u_int i; 294 const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat; 295 296 ND_TCHECK(*ap); 297 if (length < sizeof(*ap)) 298 goto trunc; 299 ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n" 300 "\tdst %s seq %lu src %s seq %lu", length, 301 ap->rreq_type & RREQ_JOIN ? "[J]" : "", 302 ap->rreq_type & RREQ_REPAIR ? "[R]" : "", 303 ap->rreq_type & RREQ_GRAT ? "[G]" : "", 304 ap->rreq_type & RREQ_DEST ? "[D]" : "", 305 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", 306 ap->rreq_hops, 307 (unsigned long)EXTRACT_32BITS(&ap->rreq_id), 308 ip6addr_string(ndo, &ap->rreq_da), 309 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), 310 ip6addr_string(ndo, &ap->rreq_oa), 311 (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); 312 i = length - sizeof(*ap); 313 if (i >= sizeof(struct aodv_ext)) 314 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 315 return; 316 317 trunc: 318 ND_PRINT((ndo, " [|rreq")); 319 } 320 321 static void 322 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 323 { 324 u_int i; 325 const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat; 326 327 ND_TCHECK(*ap); 328 if (length < sizeof(*ap)) 329 goto trunc; 330 ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" 331 "\tdst %s dseq %lu src %s %lu ms", length, 332 ap->rrep_type & RREP_REPAIR ? "[R]" : "", 333 ap->rrep_type & RREP_ACK ? "[A] " : " ", 334 ap->rrep_ps & RREP_PREFIX_MASK, 335 ap->rrep_hops, 336 ip6addr_string(ndo, &ap->rrep_da), 337 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), 338 ip6addr_string(ndo, &ap->rrep_oa), 339 (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); 340 i = length - sizeof(*ap); 341 if (i >= sizeof(struct aodv_ext)) 342 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 343 return; 344 345 trunc: 346 ND_PRINT((ndo, " [|rreq")); 347 } 348 349 static void 350 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 351 { 352 u_int i, dc; 353 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 354 const struct rerr_unreach6 *dp6; 355 356 ND_TCHECK(*ap); 357 if (length < sizeof(*ap)) 358 goto trunc; 359 ND_PRINT((ndo, " rerr %s [items %u] [%u]:", 360 ap->rerr_flags & RERR_NODELETE ? "[D]" : "", 361 ap->rerr_dc, length)); 362 dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1); 363 i = length - sizeof(*ap); 364 for (dc = ap->rerr_dc; dc != 0; dc--) { 365 ND_TCHECK(*dp6); 366 if (i < sizeof(*dp6)) 367 goto trunc; 368 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), 369 (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); 370 dp6++; 371 i -= sizeof(*dp6); 372 } 373 return; 374 375 trunc: 376 ND_PRINT((ndo, "[|rerr]")); 377 } 378 379 static void 380 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 381 { 382 u_int i; 383 const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat; 384 385 ND_TCHECK(*ap); 386 if (length < sizeof(*ap)) 387 goto trunc; 388 ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" 389 "\tdst %s seq %lu src %s seq %lu", length, 390 ap->rreq_type & RREQ_JOIN ? "[J]" : "", 391 ap->rreq_type & RREQ_REPAIR ? "[R]" : "", 392 ap->rreq_type & RREQ_GRAT ? "[G]" : "", 393 ap->rreq_type & RREQ_DEST ? "[D]" : "", 394 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", 395 ap->rreq_hops, 396 (unsigned long)EXTRACT_32BITS(&ap->rreq_id), 397 ip6addr_string(ndo, &ap->rreq_da), 398 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), 399 ip6addr_string(ndo, &ap->rreq_oa), 400 (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); 401 i = length - sizeof(*ap); 402 if (i >= sizeof(struct aodv_ext)) 403 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 404 return; 405 406 trunc: 407 ND_PRINT((ndo, " [|rreq")); 408 } 409 410 static void 411 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 412 { 413 u_int i; 414 const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat; 415 416 ND_TCHECK(*ap); 417 if (length < sizeof(*ap)) 418 goto trunc; 419 ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" 420 "\tdst %s dseq %lu src %s %lu ms", length, 421 ap->rrep_type & RREP_REPAIR ? "[R]" : "", 422 ap->rrep_type & RREP_ACK ? "[A] " : " ", 423 ap->rrep_ps & RREP_PREFIX_MASK, 424 ap->rrep_hops, 425 ip6addr_string(ndo, &ap->rrep_da), 426 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), 427 ip6addr_string(ndo, &ap->rrep_oa), 428 (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); 429 i = length - sizeof(*ap); 430 if (i >= sizeof(struct aodv_ext)) 431 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 432 return; 433 434 trunc: 435 ND_PRINT((ndo, " [|rreq")); 436 } 437 438 static void 439 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 440 { 441 u_int i, dc; 442 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 443 const struct rerr_unreach6_draft_01 *dp6; 444 445 ND_TCHECK(*ap); 446 if (length < sizeof(*ap)) 447 goto trunc; 448 ND_PRINT((ndo, " rerr %s [items %u] [%u]:", 449 ap->rerr_flags & RERR_NODELETE ? "[D]" : "", 450 ap->rerr_dc, length)); 451 dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1); 452 i = length - sizeof(*ap); 453 for (dc = ap->rerr_dc; dc != 0; dc--) { 454 ND_TCHECK(*dp6); 455 if (i < sizeof(*dp6)) 456 goto trunc; 457 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), 458 (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); 459 dp6++; 460 i -= sizeof(*dp6); 461 } 462 return; 463 464 trunc: 465 ND_PRINT((ndo, "[|rerr]")); 466 } 467 468 void 469 aodv_print(netdissect_options *ndo, 470 const u_char *dat, u_int length, int is_ip6) 471 { 472 uint8_t msg_type; 473 474 /* 475 * The message type is the first byte; make sure we have it 476 * and then fetch it. 477 */ 478 ND_TCHECK(*dat); 479 msg_type = *dat; 480 ND_PRINT((ndo, " aodv")); 481 482 switch (msg_type) { 483 484 case AODV_RREQ: 485 if (is_ip6) 486 aodv_v6_rreq(ndo, dat, length); 487 else 488 aodv_rreq(ndo, dat, length); 489 break; 490 491 case AODV_RREP: 492 if (is_ip6) 493 aodv_v6_rrep(ndo, dat, length); 494 else 495 aodv_rrep(ndo, dat, length); 496 break; 497 498 case AODV_RERR: 499 if (is_ip6) 500 aodv_v6_rerr(ndo, dat, length); 501 else 502 aodv_rerr(ndo, dat, length); 503 break; 504 505 case AODV_RREP_ACK: 506 ND_PRINT((ndo, " rrep-ack %u", length)); 507 break; 508 509 case AODV_V6_DRAFT_01_RREQ: 510 aodv_v6_draft_01_rreq(ndo, dat, length); 511 break; 512 513 case AODV_V6_DRAFT_01_RREP: 514 aodv_v6_draft_01_rrep(ndo, dat, length); 515 break; 516 517 case AODV_V6_DRAFT_01_RERR: 518 aodv_v6_draft_01_rerr(ndo, dat, length); 519 break; 520 521 case AODV_V6_DRAFT_01_RREP_ACK: 522 ND_PRINT((ndo, " rrep-ack %u", length)); 523 break; 524 525 default: 526 ND_PRINT((ndo, " type %u %u", msg_type, length)); 527 } 528 return; 529 530 trunc: 531 ND_PRINT((ndo, " [|aodv]")); 532 } 533