Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2007-2011 Grgoire 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 static const char tstr[] = "[|babel]";
     45 
     46 static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
     47 
     48 void
     49 babel_print(netdissect_options *ndo,
     50             const u_char *cp, u_int length)
     51 {
     52     ND_PRINT((ndo, "babel"));
     53 
     54     ND_TCHECK2(*cp, 4);
     55 
     56     if(cp[0] != 42) {
     57         ND_PRINT((ndo, " invalid header"));
     58         return;
     59     } else {
     60         ND_PRINT((ndo, " %d", cp[1]));
     61     }
     62 
     63     switch(cp[1]) {
     64     case 2:
     65         babel_print_v2(ndo, cp, length);
     66         break;
     67     default:
     68         ND_PRINT((ndo, " unknown version"));
     69         break;
     70     }
     71 
     72     return;
     73 
     74  trunc:
     75     ND_PRINT((ndo, " %s", tstr));
     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_REQUEST 9
     90 #define MESSAGE_MH_REQUEST 10
     91 #define MESSAGE_TSPC 11
     92 #define MESSAGE_HMAC 12
     93 #define MESSAGE_UPDATE_SRC_SPECIFIC 13
     94 #define MESSAGE_REQUEST_SRC_SPECIFIC 14
     95 #define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15
     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(const u_char *id)
    112 {
    113     static char buf[25];
    114     snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
    115              id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
    116     buf[24] = '\0';
    117     return buf;
    118 }
    119 
    120 static const unsigned char v4prefix[16] =
    121     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    122 
    123 static const char *
    124 format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
    125 {
    126     static char buf[50];
    127     if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
    128         snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
    129     else
    130         snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
    131     buf[49] = '\0';
    132     return buf;
    133 }
    134 
    135 static const char *
    136 format_address(netdissect_options *ndo, const u_char *prefix)
    137 {
    138     if(memcmp(prefix, v4prefix, 12) == 0)
    139         return ipaddr_string(ndo, prefix + 12);
    140     else
    141         return ip6addr_string(ndo, prefix);
    142 }
    143 
    144 static const char *
    145 format_interval(const uint16_t i)
    146 {
    147     static char buf[sizeof("000.00s")];
    148 
    149     if (i == 0)
    150         return "0.0s (bogus)";
    151     snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
    152     return buf;
    153 }
    154 
    155 static const char *
    156 format_interval_update(const uint16_t i)
    157 {
    158     return i == 0xFFFF ? "infinity" : format_interval(i);
    159 }
    160 
    161 static const char *
    162 format_timestamp(const uint32_t i)
    163 {
    164     static char buf[sizeof("0000.000000s")];
    165     snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
    166     return buf;
    167 }
    168 
    169 /* Return number of octets consumed from the input buffer (not the prefix length
    170  * in bytes), or -1 for encoding error. */
    171 static int
    172 network_prefix(int ae, int plen, unsigned int omitted,
    173                const unsigned char *p, const unsigned char *dp,
    174                unsigned int len, unsigned char *p_r)
    175 {
    176     unsigned pb;
    177     unsigned char prefix[16];
    178     int consumed = 0;
    179 
    180     if(plen >= 0)
    181         pb = (plen + 7) / 8;
    182     else if(ae == 1)
    183         pb = 4;
    184     else
    185         pb = 16;
    186 
    187     if(pb > 16)
    188         return -1;
    189 
    190     memset(prefix, 0, 16);
    191 
    192     switch(ae) {
    193     case 0: break;
    194     case 1:
    195         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
    196             return -1;
    197         memcpy(prefix, v4prefix, 12);
    198         if(omitted) {
    199             if (dp == NULL) return -1;
    200             memcpy(prefix, dp, 12 + omitted);
    201         }
    202         if(pb > omitted) {
    203             memcpy(prefix + 12 + omitted, p, pb - omitted);
    204             consumed = pb - omitted;
    205         }
    206         break;
    207     case 2:
    208         if(omitted > 16 || (pb > omitted && len < pb - omitted))
    209             return -1;
    210         if(omitted) {
    211             if (dp == NULL) return -1;
    212             memcpy(prefix, dp, omitted);
    213         }
    214         if(pb > omitted) {
    215             memcpy(prefix + omitted, p, pb - omitted);
    216             consumed = pb - omitted;
    217         }
    218         break;
    219     case 3:
    220         if(pb > 8 && len < pb - 8) return -1;
    221         prefix[0] = 0xfe;
    222         prefix[1] = 0x80;
    223         if(pb > 8) {
    224             memcpy(prefix + 8, p, pb - 8);
    225             consumed = pb - 8;
    226         }
    227         break;
    228     default:
    229         return -1;
    230     }
    231 
    232     memcpy(p_r, prefix, 16);
    233     return consumed;
    234 }
    235 
    236 static int
    237 network_address(int ae, const unsigned char *a, unsigned int len,
    238                 unsigned char *a_r)
    239 {
    240     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
    241 }
    242 
    243 /*
    244  * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
    245  * their encoding is similar to the encoding of TLVs, but the type namespace is
    246  * different:
    247  *
    248  * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
    249  * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
    250  * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
    251  *   data. Its body is a variable-length sequence of 8-bit unsigned integers,
    252  *   each representing per-hop number of interferring radio channel for the
    253  *   prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
    254  *   255 interferes with any other channel.
    255  * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
    256  *   neighbours. In the case of a Hello TLV, the body stores a 32-bits
    257  *   timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
    258  *   stored.
    259  *
    260  * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
    261  * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
    262  * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
    263  * The former would mean a lack of any claims about the interference, and the
    264  * latter would state that interference is definitely absent.
    265  * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
    266  * semantic of the sub-TLV is different in each case.
    267  */
    268 static void
    269 subtlvs_print(netdissect_options *ndo,
    270               const u_char *cp, const u_char *ep, const uint8_t tlv_type)
    271 {
    272     uint8_t subtype, sublen;
    273     const char *sep;
    274     uint32_t t1, t2;
    275 
    276     while (cp < ep) {
    277         subtype = *cp++;
    278         if(subtype == MESSAGE_SUB_PAD1) {
    279             ND_PRINT((ndo, " sub-pad1"));
    280             continue;
    281         }
    282         if(cp == ep)
    283             goto invalid;
    284         sublen = *cp++;
    285         if(cp + sublen > ep)
    286             goto invalid;
    287 
    288         switch(subtype) {
    289         case MESSAGE_SUB_PADN:
    290             ND_PRINT((ndo, " sub-padn"));
    291             cp += sublen;
    292             break;
    293         case MESSAGE_SUB_DIVERSITY:
    294             ND_PRINT((ndo, " sub-diversity"));
    295             if (sublen == 0) {
    296                 ND_PRINT((ndo, " empty"));
    297                 break;
    298             }
    299             sep = " ";
    300             while(sublen--) {
    301                 ND_PRINT((ndo, "%s%s", sep, tok2str(diversity_str, "%u", *cp++)));
    302                 sep = "-";
    303             }
    304             if(tlv_type != MESSAGE_UPDATE &&
    305                tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC)
    306                 ND_PRINT((ndo, " (bogus)"));
    307             break;
    308         case MESSAGE_SUB_TIMESTAMP:
    309             ND_PRINT((ndo, " sub-timestamp"));
    310             if(tlv_type == MESSAGE_HELLO) {
    311                 if(sublen < 4)
    312                     goto invalid;
    313                 t1 = EXTRACT_32BITS(cp);
    314                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
    315             } else if(tlv_type == MESSAGE_IHU) {
    316                 if(sublen < 8)
    317                     goto invalid;
    318                 t1 = EXTRACT_32BITS(cp);
    319                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
    320                 t2 = EXTRACT_32BITS(cp + 4);
    321                 ND_PRINT((ndo, "|%s", format_timestamp(t2)));
    322             } else
    323                 ND_PRINT((ndo, " (bogus)"));
    324             cp += sublen;
    325             break;
    326         default:
    327             ND_PRINT((ndo, " sub-unknown-0x%02x", subtype));
    328             cp += sublen;
    329         } /* switch */
    330     } /* while */
    331     return;
    332 
    333  invalid:
    334     ND_PRINT((ndo, "%s", istr));
    335 }
    336 
    337 #define ICHECK(i, l) \
    338 	if ((i) + (l) > bodylen || (i) + (l) > length) goto invalid;
    339 
    340 static void
    341 babel_print_v2(netdissect_options *ndo,
    342                const u_char *cp, u_int length)
    343 {
    344     u_int i;
    345     u_short bodylen;
    346     u_char v4_prefix[16] =
    347         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    348     u_char v6_prefix[16] = {0};
    349 
    350     ND_TCHECK2(*cp, 4);
    351     if (length < 4)
    352         goto invalid;
    353     bodylen = EXTRACT_16BITS(cp + 2);
    354     ND_PRINT((ndo, " (%u)", bodylen));
    355 
    356     /* Process the TLVs in the body */
    357     i = 0;
    358     while(i < bodylen) {
    359         const u_char *message;
    360         u_int type, len;
    361 
    362         message = cp + 4 + i;
    363 
    364         ND_TCHECK2(*message, 1);
    365         if((type = message[0]) == MESSAGE_PAD1) {
    366             ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
    367             i += 1;
    368             continue;
    369         }
    370 
    371         ND_TCHECK2(*message, 2);
    372         ICHECK(i, 2);
    373         len = message[1];
    374 
    375         ND_TCHECK2(*message, 2 + len);
    376         ICHECK(i, 2 + len);
    377 
    378         switch(type) {
    379         case MESSAGE_PADN: {
    380             if (!ndo->ndo_vflag)
    381                 ND_PRINT((ndo, " padN"));
    382             else
    383                 ND_PRINT((ndo, "\n\tPad %d", len + 2));
    384         }
    385             break;
    386 
    387         case MESSAGE_ACK_REQ: {
    388             u_short nonce, interval;
    389             if (!ndo->ndo_vflag)
    390                 ND_PRINT((ndo, " ack-req"));
    391             else {
    392                 ND_PRINT((ndo, "\n\tAcknowledgment Request "));
    393                 if(len < 6) goto invalid;
    394                 nonce = EXTRACT_16BITS(message + 4);
    395                 interval = EXTRACT_16BITS(message + 6);
    396                 ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
    397             }
    398         }
    399             break;
    400 
    401         case MESSAGE_ACK: {
    402             u_short nonce;
    403             if (!ndo->ndo_vflag)
    404                 ND_PRINT((ndo, " ack"));
    405             else {
    406                 ND_PRINT((ndo, "\n\tAcknowledgment "));
    407                 if(len < 2) goto invalid;
    408                 nonce = EXTRACT_16BITS(message + 2);
    409                 ND_PRINT((ndo, "%04x", nonce));
    410             }
    411         }
    412             break;
    413 
    414         case MESSAGE_HELLO:  {
    415             u_short seqno, interval;
    416             if (!ndo->ndo_vflag)
    417                 ND_PRINT((ndo, " hello"));
    418             else {
    419                 ND_PRINT((ndo, "\n\tHello "));
    420                 if(len < 6) goto invalid;
    421                 seqno = EXTRACT_16BITS(message + 4);
    422                 interval = EXTRACT_16BITS(message + 6);
    423                 ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
    424                 /* Extra data. */
    425                 if(len > 6)
    426                     subtlvs_print(ndo, message + 8, message + 2 + len, type);
    427             }
    428         }
    429             break;
    430 
    431         case MESSAGE_IHU: {
    432             unsigned short txcost, interval;
    433             if (!ndo->ndo_vflag)
    434                 ND_PRINT((ndo, " ihu"));
    435             else {
    436                 u_char address[16];
    437                 int rc;
    438                 ND_PRINT((ndo, "\n\tIHU "));
    439                 if(len < 6) goto invalid;
    440                 txcost = EXTRACT_16BITS(message + 4);
    441                 interval = EXTRACT_16BITS(message + 6);
    442                 rc = network_address(message[2], message + 8, len - 6, address);
    443                 if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
    444                 ND_PRINT((ndo, "%s txcost %u interval %s",
    445                        format_address(ndo, address), txcost, format_interval(interval)));
    446                 /* Extra data. */
    447                 if((u_int)rc < len - 6)
    448                     subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
    449                                   type);
    450             }
    451         }
    452             break;
    453 
    454         case MESSAGE_ROUTER_ID: {
    455             if (!ndo->ndo_vflag)
    456                 ND_PRINT((ndo, " router-id"));
    457             else {
    458                 ND_PRINT((ndo, "\n\tRouter Id"));
    459                 if(len < 10) goto invalid;
    460                 ND_PRINT((ndo, " %s", format_id(message + 4)));
    461             }
    462         }
    463             break;
    464 
    465         case MESSAGE_NH: {
    466             if (!ndo->ndo_vflag)
    467                 ND_PRINT((ndo, " nh"));
    468             else {
    469                 int rc;
    470                 u_char nh[16];
    471                 ND_PRINT((ndo, "\n\tNext Hop"));
    472                 if(len < 2) goto invalid;
    473                 rc = network_address(message[2], message + 4, len - 2, nh);
    474                 if(rc < 0) goto invalid;
    475                 ND_PRINT((ndo, " %s", format_address(ndo, nh)));
    476             }
    477         }
    478             break;
    479 
    480         case MESSAGE_UPDATE: {
    481             if (!ndo->ndo_vflag) {
    482                 ND_PRINT((ndo, " update"));
    483                 if(len < 1)
    484                     ND_PRINT((ndo, "/truncated"));
    485                 else
    486                     ND_PRINT((ndo, "%s%s%s",
    487                            (message[3] & 0x80) ? "/prefix": "",
    488                            (message[3] & 0x40) ? "/id" : "",
    489                            (message[3] & 0x3f) ? "/unknown" : ""));
    490             } else {
    491                 u_short interval, seqno, metric;
    492                 u_char plen;
    493                 int rc;
    494                 u_char prefix[16];
    495                 ND_PRINT((ndo, "\n\tUpdate"));
    496                 if(len < 10) goto invalid;
    497                 plen = message[4] + (message[2] == 1 ? 96 : 0);
    498                 rc = network_prefix(message[2], message[4], message[5],
    499                                     message + 12,
    500                                     message[2] == 1 ? v4_prefix : v6_prefix,
    501                                     len - 10, prefix);
    502                 if(rc < 0) goto invalid;
    503                 interval = EXTRACT_16BITS(message + 6);
    504                 seqno = EXTRACT_16BITS(message + 8);
    505                 metric = EXTRACT_16BITS(message + 10);
    506                 ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
    507                        (message[3] & 0x80) ? "/prefix": "",
    508                        (message[3] & 0x40) ? "/id" : "",
    509                        (message[3] & 0x3f) ? "/unknown" : "",
    510                        format_prefix(ndo, prefix, plen),
    511                        metric, seqno, format_interval_update(interval)));
    512                 if(message[3] & 0x80) {
    513                     if(message[2] == 1)
    514                         memcpy(v4_prefix, prefix, 16);
    515                     else
    516                         memcpy(v6_prefix, prefix, 16);
    517                 }
    518                 /* extra data? */
    519                 if((u_int)rc < len - 10)
    520                     subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
    521             }
    522         }
    523             break;
    524 
    525         case MESSAGE_REQUEST: {
    526             if (!ndo->ndo_vflag)
    527                 ND_PRINT((ndo, " request"));
    528             else {
    529                 int rc;
    530                 u_char prefix[16], plen;
    531                 ND_PRINT((ndo, "\n\tRequest "));
    532                 if(len < 2) goto invalid;
    533                 plen = message[3] + (message[2] == 1 ? 96 : 0);
    534                 rc = network_prefix(message[2], message[3], 0,
    535                                     message + 4, NULL, len - 2, prefix);
    536                 if(rc < 0) goto invalid;
    537                 ND_PRINT((ndo, "for %s",
    538                        message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
    539             }
    540         }
    541             break;
    542 
    543         case MESSAGE_MH_REQUEST : {
    544             if (!ndo->ndo_vflag)
    545                 ND_PRINT((ndo, " mh-request"));
    546             else {
    547                 int rc;
    548                 u_short seqno;
    549                 u_char prefix[16], plen;
    550                 ND_PRINT((ndo, "\n\tMH-Request "));
    551                 if(len < 14) goto invalid;
    552                 seqno = EXTRACT_16BITS(message + 4);
    553                 rc = network_prefix(message[2], message[3], 0,
    554                                     message + 16, NULL, len - 14, prefix);
    555                 if(rc < 0) goto invalid;
    556                 plen = message[3] + (message[2] == 1 ? 96 : 0);
    557                 ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
    558                        message[6], format_prefix(ndo, prefix, plen),
    559                        seqno, format_id(message + 8)));
    560             }
    561         }
    562             break;
    563         case MESSAGE_TSPC :
    564             if (!ndo->ndo_vflag)
    565                 ND_PRINT((ndo, " tspc"));
    566             else {
    567                 ND_PRINT((ndo, "\n\tTS/PC "));
    568                 if(len < 6) goto invalid;
    569                 ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
    570                        EXTRACT_16BITS(message + 2)));
    571             }
    572             break;
    573         case MESSAGE_HMAC : {
    574             if (!ndo->ndo_vflag)
    575                 ND_PRINT((ndo, " hmac"));
    576             else {
    577                 unsigned j;
    578                 ND_PRINT((ndo, "\n\tHMAC "));
    579                 if(len < 18) goto invalid;
    580                 ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
    581                 for (j = 0; j < len - 2; j++)
    582                     ND_PRINT((ndo, "%02X", message[4 + j]));
    583             }
    584         }
    585             break;
    586 
    587         case MESSAGE_UPDATE_SRC_SPECIFIC : {
    588             if(!ndo->ndo_vflag) {
    589                 ND_PRINT((ndo, " ss-update"));
    590             } else {
    591                 u_char prefix[16], src_prefix[16];
    592                 u_short interval, seqno, metric;
    593                 u_char ae, plen, src_plen, omitted;
    594                 int rc;
    595                 int parsed_len = 10;
    596                 ND_PRINT((ndo, "\n\tSS-Update"));
    597                 if(len < 10) goto invalid;
    598                 ae = message[2];
    599                 src_plen = message[3];
    600                 plen = message[4];
    601                 omitted = message[5];
    602                 interval = EXTRACT_16BITS(message + 6);
    603                 seqno = EXTRACT_16BITS(message + 8);
    604                 metric = EXTRACT_16BITS(message + 10);
    605                 rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
    606                                     ae == 1 ? v4_prefix : v6_prefix,
    607                                     len - parsed_len, prefix);
    608                 if(rc < 0) goto invalid;
    609                 if(ae == 1)
    610                     plen += 96;
    611                 parsed_len += rc;
    612                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
    613                                     NULL, len - parsed_len, src_prefix);
    614                 if(rc < 0) goto invalid;
    615                 if(ae == 1)
    616                     src_plen += 96;
    617                 parsed_len += rc;
    618 
    619                 ND_PRINT((ndo, " %s from", format_prefix(ndo, prefix, plen)));
    620                 ND_PRINT((ndo, " %s metric %u seqno %u interval %s",
    621                           format_prefix(ndo, src_prefix, src_plen),
    622                           metric, seqno, format_interval_update(interval)));
    623                 /* extra data? */
    624                 if((u_int)parsed_len < len)
    625                     subtlvs_print(ndo, message + 2 + parsed_len,
    626                                   message + 2 + len, type);
    627             }
    628         }
    629             break;
    630 
    631         case MESSAGE_REQUEST_SRC_SPECIFIC : {
    632             if(!ndo->ndo_vflag)
    633                 ND_PRINT((ndo, " ss-request"));
    634             else {
    635                 int rc, parsed_len = 3;
    636                 u_char ae, plen, src_plen, prefix[16], src_prefix[16];
    637                 ND_PRINT((ndo, "\n\tSS-Request "));
    638                 if(len < 3) goto invalid;
    639                 ae = message[2];
    640                 plen = message[3];
    641                 src_plen = message[4];
    642                 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
    643                                     NULL, len - parsed_len, prefix);
    644                 if(rc < 0) goto invalid;
    645                 if(ae == 1)
    646                     plen += 96;
    647                 parsed_len += rc;
    648                 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
    649                                     NULL, len - parsed_len, src_prefix);
    650                 if(rc < 0) goto invalid;
    651                 if(ae == 1)
    652                     src_plen += 96;
    653                 parsed_len += rc;
    654                 if(ae == 0) {
    655                     ND_PRINT((ndo, "for any"));
    656                 } else {
    657                     ND_PRINT((ndo, "for (%s, ", format_prefix(ndo, prefix, plen)));
    658                     ND_PRINT((ndo, "%s)", format_prefix(ndo, src_prefix, src_plen)));
    659                 }
    660             }
    661         }
    662             break;
    663 
    664         case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
    665             if(!ndo->ndo_vflag)
    666                 ND_PRINT((ndo, " ss-mh-request"));
    667             else {
    668                 int rc, parsed_len = 14;
    669                 u_short seqno;
    670                 u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
    671                 const u_char *router_id = NULL;
    672                 ND_PRINT((ndo, "\n\tSS-MH-Request "));
    673                 if(len < 14) goto invalid;
    674                 ae = message[2];
    675                 plen = message[3];
    676                 seqno = EXTRACT_16BITS(message + 4);
    677                 hopc = message[6];
    678                 src_plen = message[7];
    679                 router_id = message + 8;
    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                 ND_PRINT((ndo, "(%u hops) for (%s, ",
    692                           hopc, format_prefix(ndo, prefix, plen)));
    693                 ND_PRINT((ndo, "%s) seqno %u id %s",
    694                           format_prefix(ndo, src_prefix, src_plen),
    695                           seqno, format_id(router_id)));
    696             }
    697         }
    698             break;
    699 
    700         default:
    701             if (!ndo->ndo_vflag)
    702                 ND_PRINT((ndo, " unknown"));
    703             else
    704                 ND_PRINT((ndo, "\n\tUnknown message type %d", type));
    705         }
    706         i += len + 2;
    707     }
    708     return;
    709 
    710  trunc:
    711     ND_PRINT((ndo, " %s", tstr));
    712     return;
    713 
    714  invalid:
    715     ND_PRINT((ndo, "%s", istr));
    716     return;
    717 }
    718