]> The Tcpdump Group git mirrors - tcpdump/blob - print-babel.c
Merge pull request #492 from vel21ripn/nflog-print
[tcpdump] / print-babel.c
1 /*
2 * Copyright (c) 2007-2011 Grégoire Henry, Juliusz Chroboczek
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the project nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /* \summary: Babel Routing Protocol printer */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include "netdissect-stdinc.h"
36
37 #include <stdio.h>
38 #include <string.h>
39
40 #include "netdissect.h"
41 #include "addrtoname.h"
42 #include "extract.h"
43
44
45 static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
46
47 void
48 babel_print(netdissect_options *ndo,
49 const u_char *cp, u_int length)
50 {
51 ndo->ndo_protocol = "babel";
52 ND_PRINT("babel");
53
54 ND_TCHECK_4(cp);
55
56 if(GET_U_1(cp) != 42) {
57 ND_PRINT(" invalid header");
58 return;
59 } else {
60 ND_PRINT(" %u", GET_U_1(cp + 1));
61 }
62
63 switch(GET_U_1(cp + 1)) {
64 case 2:
65 babel_print_v2(ndo, cp, length);
66 break;
67 default:
68 ND_PRINT(" unknown version");
69 break;
70 }
71
72 return;
73
74 trunc:
75 nd_print_trunc(ndo);
76 return;
77 }
78
79 /* TLVs */
80 #define MESSAGE_PAD1 0
81 #define MESSAGE_PADN 1
82 #define MESSAGE_ACK_REQ 2
83 #define MESSAGE_ACK 3
84 #define MESSAGE_HELLO 4
85 #define MESSAGE_IHU 5
86 #define MESSAGE_ROUTER_ID 6
87 #define MESSAGE_NH 7
88 #define MESSAGE_UPDATE 8
89 #define MESSAGE_ROUTE_REQUEST 9
90 #define MESSAGE_SEQNO_REQUEST 10
91 #define MESSAGE_TSPC 11
92 #define MESSAGE_HMAC 12
93 #define MESSAGE_UPDATE_SRC_SPECIFIC 13 /* last appearance in draft-boutier-babel-source-specific-01 */
94 #define MESSAGE_REQUEST_SRC_SPECIFIC 14 /* idem */
95 #define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15 /* idem */
96
97 /* sub-TLVs */
98 #define MESSAGE_SUB_PAD1 0
99 #define MESSAGE_SUB_PADN 1
100 #define MESSAGE_SUB_DIVERSITY 2
101 #define MESSAGE_SUB_TIMESTAMP 3
102
103 /* Diversity sub-TLV channel codes */
104 static const struct tok diversity_str[] = {
105 { 0, "reserved" },
106 { 255, "all" },
107 { 0, NULL }
108 };
109
110 static const char *
111 format_id(netdissect_options *ndo, const u_char *id)
112 {
113 static char buf[25];
114 snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
115 GET_U_1(id), GET_U_1(id + 1), GET_U_1(id + 2),
116 GET_U_1(id + 3), GET_U_1(id + 4), GET_U_1(id + 5),
117 GET_U_1(id + 6), GET_U_1(id + 7));
118 buf[24] = '\0';
119 return buf;
120 }
121
122 static const unsigned char v4prefix[16] =
123 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
124
125 static const char *
126 format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
127 {
128 static char buf[50];
129
130 /*
131 * prefix points to a buffer on the stack into which the prefix has
132 * been placed, so we can't use GET_IPADDR_STRING() or
133 * GET_IP6ADDR_STRING() on it.
134 */
135 if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
136 snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
137 else
138 snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
139 buf[49] = '\0';
140 return buf;
141 }
142
143 static const char *
144 format_address(netdissect_options *ndo, const u_char *prefix)
145 {
146 /*
147 * prefix points to a buffer on the stack into which the prefix has
148 * been placed, so we can't use GET_IPADDR_STRING() or
149 * GET_IP6ADDR_STRING() on it.
150 */
151 if(memcmp(prefix, v4prefix, 12) == 0)
152 return ipaddr_string(ndo, prefix + 12);
153 else
154 return ip6addr_string(ndo, prefix);
155 }
156
157 static const char *
158 format_interval(const uint16_t i)
159 {
160 static char buf[sizeof("000.00s")];
161
162 if (i == 0)
163 return "0.0s (bogus)";
164 snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
165 return buf;
166 }
167
168 static const char *
169 format_interval_update(const uint16_t i)
170 {
171 return i == 0xFFFF ? "infinity" : format_interval(i);
172 }
173
174 static const char *
175 format_timestamp(const uint32_t i)
176 {
177 static char buf[sizeof("0000.000000s")];
178 snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
179 return buf;
180 }
181
182 /* Return number of octets consumed from the input buffer (not the prefix length
183 * in bytes), or -1 for encoding error. */
184 static int
185 network_prefix(int ae, int plen, unsigned int omitted,
186 const unsigned char *p, const unsigned char *dp,
187 unsigned int len, unsigned char *p_r)
188 {
189 unsigned pb;
190 unsigned char prefix[16];
191 int consumed = 0;
192
193 if(plen >= 0)
194 pb = (plen + 7) / 8;
195 else if(ae == 1)
196 pb = 4;
197 else
198 pb = 16;
199
200 if(pb > 16)
201 return -1;
202
203 memset(prefix, 0, 16);
204
205 switch(ae) {
206 case 0: break;
207 case 1:
208 if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
209 return -1;
210 memcpy(prefix, v4prefix, 12);
211 if(omitted) {
212 if (dp == NULL) return -1;
213 memcpy(prefix, dp, 12 + omitted);
214 }
215 if(pb > omitted) {
216 memcpy(prefix + 12 + omitted, p, pb - omitted);
217 consumed = pb - omitted;
218 }
219 break;
220 case 2:
221 if(omitted > 16 || (pb > omitted && len < pb - omitted))
222 return -1;
223 if(omitted) {
224 if (dp == NULL) return -1;
225 memcpy(prefix, dp, omitted);
226 }
227 if(pb > omitted) {
228 memcpy(prefix + omitted, p, pb - omitted);
229 consumed = pb - omitted;
230 }
231 break;
232 case 3:
233 if(pb > 8 && len < pb - 8) return -1;
234 prefix[0] = 0xfe;
235 prefix[1] = 0x80;
236 if(pb > 8) {
237 memcpy(prefix + 8, p, pb - 8);
238 consumed = pb - 8;
239 }
240 break;
241 default:
242 return -1;
243 }
244
245 memcpy(p_r, prefix, 16);
246 return consumed;
247 }
248
249 static int
250 network_address(int ae, const unsigned char *a, unsigned int len,
251 unsigned char *a_r)
252 {
253 return network_prefix(ae, -1, 0, a, NULL, len, a_r);
254 }
255
256 /*
257 * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
258 * their encoding is similar to the encoding of TLVs, but the type namespace is
259 * different:
260 *
261 * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
262 * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
263 * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
264 * data. Its body is a variable-length sequence of 8-bit unsigned integers,
265 * each representing per-hop number of interfering radio channel for the
266 * prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
267 * 255 interferes with any other channel.
268 * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
269 * neighbours. In the case of a Hello TLV, the body stores a 32-bits
270 * timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
271 * stored.
272 *
273 * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
274 * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
275 * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
276 * The former would mean a lack of any claims about the interference, and the
277 * latter would state that interference is definitely absent.
278 * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
279 * semantic of the sub-TLV is different in each case.
280 */
281 static void
282 subtlvs_print(netdissect_options *ndo,
283 const u_char *cp, const u_char *ep, const uint8_t tlv_type)
284 {
285 uint8_t subtype, sublen;
286 const char *sep;
287 uint32_t t1, t2;
288
289 while (cp < ep) {
290 subtype = GET_U_1(cp);
291 cp++;
292 if(subtype == MESSAGE_SUB_PAD1) {
293 ND_PRINT(" sub-pad1");
294 continue;
295 }
296 if(cp == ep)
297 goto invalid;
298 sublen = GET_U_1(cp);
299 cp++;
300 if(cp + sublen > ep)
301 goto invalid;
302
303 switch(subtype) {
304 case MESSAGE_SUB_PADN:
305 ND_PRINT(" sub-padn");
306 cp += sublen;
307 break;
308 case MESSAGE_SUB_DIVERSITY:
309 ND_PRINT(" sub-diversity");
310 if (sublen == 0) {
311 ND_PRINT(" empty");
312 break;
313 }
314 sep = " ";
315 while (sublen) {
316 ND_PRINT("%s%s", sep,
317 tok2str(diversity_str, "%u", GET_U_1(cp)));
318 cp++;
319 sep = "-";
320 sublen--;
321 }
322 if(tlv_type != MESSAGE_UPDATE &&
323 tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC)
324 ND_PRINT(" (bogus)");
325 break;
326 case MESSAGE_SUB_TIMESTAMP:
327 ND_PRINT(" sub-timestamp");
328 if(tlv_type == MESSAGE_HELLO) {
329 if(sublen < 4)
330 goto invalid;
331 t1 = GET_BE_U_4(cp);
332 ND_PRINT(" %s", format_timestamp(t1));
333 } else if(tlv_type == MESSAGE_IHU) {
334 if(sublen < 8)
335 goto invalid;
336 t1 = GET_BE_U_4(cp);
337 ND_PRINT(" %s", format_timestamp(t1));
338 t2 = GET_BE_U_4(cp + 4);
339 ND_PRINT("|%s", format_timestamp(t2));
340 } else
341 ND_PRINT(" (bogus)");
342 cp += sublen;
343 break;
344 default:
345 ND_PRINT(" sub-unknown-0x%02x", subtype);
346 cp += sublen;
347 } /* switch */
348 } /* while */
349 return;
350
351 invalid:
352 nd_print_invalid(ndo);
353 }
354
355 #define ICHECK(i, l) \
356 if ((i) + (l) > bodylen || (i) + (l) > length) goto invalid;
357
358 static void
359 babel_print_v2(netdissect_options *ndo,
360 const u_char *cp, u_int length)
361 {
362 u_int i;
363 u_short bodylen;
364 u_char v4_prefix[16] =
365 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
366 u_char v6_prefix[16] = {0};
367
368 ND_TCHECK_4(cp);
369 if (length < 4)
370 goto invalid;
371 bodylen = GET_BE_U_2(cp + 2);
372 ND_PRINT(" (%u)", bodylen);
373 if (4U + bodylen > length)
374 goto invalid;
375
376 /* Process the TLVs in the body */
377 i = 0;
378 while(i < bodylen) {
379 const u_char *message;
380 uint8_t type;
381 u_int len;
382
383 message = cp + 4 + i;
384
385 ND_TCHECK_1(message);
386 if((type = GET_U_1(message)) == MESSAGE_PAD1) {
387 ND_PRINT(ndo->ndo_vflag ? "\n\tPad 1" : " pad1");
388 i += 1;
389 continue;
390 }
391
392 ND_TCHECK_2(message);
393 ICHECK(i, 2);
394 len = GET_U_1(message + 1);
395
396 ND_TCHECK_LEN(message, 2 + len);
397 ICHECK(i, 2 + len);
398
399 switch(type) {
400 case MESSAGE_PADN: {
401 if (!ndo->ndo_vflag)
402 ND_PRINT(" padN");
403 else
404 ND_PRINT("\n\tPad %u", len + 2);
405 }
406 break;
407
408 case MESSAGE_ACK_REQ: {
409 u_short nonce, interval;
410 if (!ndo->ndo_vflag)
411 ND_PRINT(" ack-req");
412 else {
413 ND_PRINT("\n\tAcknowledgment Request ");
414 if(len < 6) goto invalid;
415 nonce = GET_BE_U_2(message + 4);
416 interval = GET_BE_U_2(message + 6);
417 ND_PRINT("%04x %s", nonce, format_interval(interval));
418 }
419 }
420 break;
421
422 case MESSAGE_ACK: {
423 u_short nonce;
424 if (!ndo->ndo_vflag)
425 ND_PRINT(" ack");
426 else {
427 ND_PRINT("\n\tAcknowledgment ");
428 if(len < 2) goto invalid;
429 nonce = GET_BE_U_2(message + 2);
430 ND_PRINT("%04x", nonce);
431 }
432 }
433 break;
434
435 case MESSAGE_HELLO: {
436 u_short seqno, interval;
437 if (!ndo->ndo_vflag)
438 ND_PRINT(" hello");
439 else {
440 ND_PRINT("\n\tHello ");
441 if(len < 6) goto invalid;
442 seqno = GET_BE_U_2(message + 4);
443 interval = GET_BE_U_2(message + 6);
444 ND_PRINT("seqno %u interval %s", seqno, format_interval(interval));
445 /* Extra data. */
446 if(len > 6)
447 subtlvs_print(ndo, message + 8, message + 2 + len, type);
448 }
449 }
450 break;
451
452 case MESSAGE_IHU: {
453 unsigned short rxcost, interval;
454 if (!ndo->ndo_vflag)
455 ND_PRINT(" ihu");
456 else {
457 u_char address[16];
458 u_char ae;
459 int rc;
460 ND_PRINT("\n\tIHU ");
461 if(len < 6) goto invalid;
462 rxcost = GET_BE_U_2(message + 4);
463 interval = GET_BE_U_2(message + 6);
464 ae = GET_U_1(message + 2);
465 rc = network_address(ae, message + 8,
466 len - 6, address);
467 if(rc < 0) { nd_print_trunc(ndo); break; }
468 ND_PRINT("%s rxcost %u interval %s",
469 ae == 0 ? "any" : format_address(ndo, address),
470 rxcost, format_interval(interval));
471 /* Extra data. */
472 if((u_int)rc < len - 6)
473 subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
474 type);
475 }
476 }
477 break;
478
479 case MESSAGE_ROUTER_ID: {
480 if (!ndo->ndo_vflag)
481 ND_PRINT(" router-id");
482 else {
483 ND_PRINT("\n\tRouter Id");
484 if(len < 10) goto invalid;
485 ND_PRINT(" %s", format_id(ndo, message + 4));
486 }
487 }
488 break;
489
490 case MESSAGE_NH: {
491 if (!ndo->ndo_vflag)
492 ND_PRINT(" nh");
493 else {
494 int rc;
495 u_char ae;
496 u_char nh[16];
497 ND_PRINT("\n\tNext Hop");
498 if(len < 2) goto invalid;
499 ae = GET_U_1(message + 2);
500 rc = network_address(ae, message + 4,
501 len - 2, nh);
502 if(rc < 0) goto invalid;
503 ND_PRINT(" %s", ae == 0 ? "invalid AE 0" : format_address(ndo, nh));
504 }
505 }
506 break;
507
508 case MESSAGE_UPDATE: {
509 if (!ndo->ndo_vflag) {
510 ND_PRINT(" update");
511 if(len < 10)
512 goto invalid;
513 else
514 ND_PRINT("%s%s%s",
515 (GET_U_1(message + 3) & 0x80) ? "/prefix": "",
516 (GET_U_1(message + 3) & 0x40) ? "/id" : "",
517 (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "");
518 } else {
519 u_short interval, seqno, metric;
520 u_char ae, plen;
521 int rc;
522 u_char prefix[16];
523 ND_PRINT("\n\tUpdate");
524 if(len < 10) goto invalid;
525 ae = GET_U_1(message + 2);
526 plen = GET_U_1(message + 4) + (GET_U_1(message + 2) == 1 ? 96 : 0);
527 rc = network_prefix(ae,
528 GET_U_1(message + 4),
529 GET_U_1(message + 5),
530 message + 12,
531 GET_U_1(message + 2) == 1 ? v4_prefix : v6_prefix,
532 len - 10, prefix);
533 if(rc < 0) goto invalid;
534 interval = GET_BE_U_2(message + 6);
535 seqno = GET_BE_U_2(message + 8);
536 metric = GET_BE_U_2(message + 10);
537 ND_PRINT("%s%s%s %s metric %u seqno %u interval %s",
538 (GET_U_1(message + 3) & 0x80) ? "/prefix": "",
539 (GET_U_1(message + 3) & 0x40) ? "/id" : "",
540 (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "",
541 ae == 0 ? "any" : format_prefix(ndo, prefix, plen),
542 metric, seqno, format_interval_update(interval));
543 if(GET_U_1(message + 3) & 0x80) {
544 if(GET_U_1(message + 2) == 1)
545 memcpy(v4_prefix, prefix, 16);
546 else
547 memcpy(v6_prefix, prefix, 16);
548 }
549 /* extra data? */
550 if((u_int)rc < len - 10)
551 subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
552 }
553 }
554 break;
555
556 case MESSAGE_ROUTE_REQUEST: {
557 if (!ndo->ndo_vflag)
558 ND_PRINT(" route-request");
559 else {
560 int rc;
561 u_char prefix[16], ae, plen;
562 ND_PRINT("\n\tRoute Request ");
563 if(len < 2) goto invalid;
564 ae = GET_U_1(message + 2);
565 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0);
566 rc = network_prefix(ae,
567 GET_U_1(message + 3), 0,
568 message + 4, NULL, len - 2, prefix);
569 if(rc < 0) goto invalid;
570 ND_PRINT("for %s",
571 ae == 0 ? "any" : format_prefix(ndo, prefix, plen));
572 }
573 }
574 break;
575
576 case MESSAGE_SEQNO_REQUEST : {
577 if (!ndo->ndo_vflag)
578 ND_PRINT(" seqno-request");
579 else {
580 int rc;
581 u_short seqno;
582 u_char prefix[16], ae, plen;
583 ND_PRINT("\n\tSeqno Request ");
584 if(len < 14) goto invalid;
585 ae = GET_U_1(message + 2);
586 seqno = GET_BE_U_2(message + 4);
587 rc = network_prefix(ae,
588 GET_U_1(message + 3), 0,
589 message + 16, NULL, len - 14, prefix);
590 if(rc < 0) goto invalid;
591 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0);
592 ND_PRINT("(%u hops) for %s seqno %u id %s",
593 GET_U_1(message + 6),
594 ae == 0 ? "invalid AE 0" : format_prefix(ndo, prefix, plen),
595 seqno, format_id(ndo, message + 8));
596 }
597 }
598 break;
599 case MESSAGE_TSPC :
600 if (!ndo->ndo_vflag)
601 ND_PRINT(" tspc");
602 else {
603 ND_PRINT("\n\tTS/PC ");
604 if(len < 6) goto invalid;
605 ND_PRINT("timestamp %u packetcounter %u",
606 GET_BE_U_4(message + 4),
607 GET_BE_U_2(message + 2));
608 }
609 break;
610 case MESSAGE_HMAC : {
611 if (!ndo->ndo_vflag)
612 ND_PRINT(" hmac");
613 else {
614 unsigned j;
615 ND_PRINT("\n\tHMAC ");
616 if(len < 18) goto invalid;
617 ND_PRINT("key-id %u digest-%u ", GET_BE_U_2(message + 2),
618 len - 2);
619 for (j = 0; j < len - 2; j++)
620 ND_PRINT("%02X", GET_U_1(message + j + 4));
621 }
622 }
623 break;
624
625 case MESSAGE_UPDATE_SRC_SPECIFIC : {
626 if(!ndo->ndo_vflag) {
627 ND_PRINT(" ss-update");
628 } else {
629 u_char prefix[16], src_prefix[16];
630 u_short interval, seqno, metric;
631 u_char ae, plen, src_plen, omitted;
632 int rc;
633 int parsed_len = 10;
634 ND_PRINT("\n\tSS-Update");
635 if(len < 10) goto invalid;
636 ae = GET_U_1(message + 2);
637 src_plen = GET_U_1(message + 3);
638 plen = GET_U_1(message + 4);
639 omitted = GET_U_1(message + 5);
640 interval = GET_BE_U_2(message + 6);
641 seqno = GET_BE_U_2(message + 8);
642 metric = GET_BE_U_2(message + 10);
643 rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
644 ae == 1 ? v4_prefix : v6_prefix,
645 len - parsed_len, prefix);
646 if(rc < 0) goto invalid;
647 if(ae == 1)
648 plen += 96;
649 parsed_len += rc;
650 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
651 NULL, len - parsed_len, src_prefix);
652 if(rc < 0) goto invalid;
653 if(ae == 1)
654 src_plen += 96;
655 parsed_len += rc;
656
657 ND_PRINT(" %s from", format_prefix(ndo, prefix, plen));
658 ND_PRINT(" %s metric %u seqno %u interval %s",
659 format_prefix(ndo, src_prefix, src_plen),
660 metric, seqno, format_interval_update(interval));
661 /* extra data? */
662 if((u_int)parsed_len < len)
663 subtlvs_print(ndo, message + 2 + parsed_len,
664 message + 2 + len, type);
665 }
666 }
667 break;
668
669 case MESSAGE_REQUEST_SRC_SPECIFIC : {
670 if(!ndo->ndo_vflag)
671 ND_PRINT(" ss-request");
672 else {
673 int rc, parsed_len = 3;
674 u_char ae, plen, src_plen, prefix[16], src_prefix[16];
675 ND_PRINT("\n\tSS-Request ");
676 if(len < 3) goto invalid;
677 ae = GET_U_1(message + 2);
678 plen = GET_U_1(message + 3);
679 src_plen = GET_U_1(message + 4);
680 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
681 NULL, len - parsed_len, prefix);
682 if(rc < 0) goto invalid;
683 if(ae == 1)
684 plen += 96;
685 parsed_len += rc;
686 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
687 NULL, len - parsed_len, src_prefix);
688 if(rc < 0) goto invalid;
689 if(ae == 1)
690 src_plen += 96;
691 parsed_len += rc;
692 if(ae == 0) {
693 ND_PRINT("for any");
694 } else {
695 ND_PRINT("for (%s, ", format_prefix(ndo, prefix, plen));
696 ND_PRINT("%s)", format_prefix(ndo, src_prefix, src_plen));
697 }
698 }
699 }
700 break;
701
702 case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
703 if(!ndo->ndo_vflag)
704 ND_PRINT(" ss-mh-request");
705 else {
706 int rc, parsed_len = 14;
707 u_short seqno;
708 u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
709 const u_char *router_id = NULL;
710 ND_PRINT("\n\tSS-MH-Request ");
711 if(len < 14) goto invalid;
712 ae = GET_U_1(message + 2);
713 plen = GET_U_1(message + 3);
714 seqno = GET_BE_U_2(message + 4);
715 hopc = GET_U_1(message + 6);
716 src_plen = GET_U_1(message + 7);
717 router_id = message + 8;
718 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
719 NULL, len - parsed_len, prefix);
720 if(rc < 0) goto invalid;
721 if(ae == 1)
722 plen += 96;
723 parsed_len += rc;
724 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
725 NULL, len - parsed_len, src_prefix);
726 if(rc < 0) goto invalid;
727 if(ae == 1)
728 src_plen += 96;
729 ND_PRINT("(%u hops) for (%s, ",
730 hopc, format_prefix(ndo, prefix, plen));
731 ND_PRINT("%s) seqno %u id %s",
732 format_prefix(ndo, src_prefix, src_plen),
733 seqno, format_id(ndo, router_id));
734 }
735 }
736 break;
737
738 default:
739 if (!ndo->ndo_vflag)
740 ND_PRINT(" unknown");
741 else
742 ND_PRINT("\n\tUnknown message type %u", type);
743 }
744 i += len + 2;
745 }
746 return;
747
748 trunc:
749 nd_print_trunc(ndo);
750 return;
751
752 invalid:
753 nd_print_invalid(ndo);
754 return;
755 }