Example #1
0
static void
babel_print_v2(const u_char *cp, u_int length) {
    u_int i;
    u_short bodylen;
    u_char v4_prefix[16] =
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    u_char v6_prefix[16] = {0};

    TCHECK2(*cp, 4);
    if (length < 4)
        goto corrupt;
    bodylen = EXTRACT_16BITS(cp + 2);
    printf(" (%u)", bodylen);

    /* Process the TLVs in the body */
    i = 0;
    while(i < bodylen) {
        const u_char *message;
        u_char type, len;

        message = cp + 4 + i;
        TCHECK2(*message, 2);
        ICHECK(i, 2);
        type = message[0];
        len = message[1];

        TCHECK2(*message, 2 + len);
        ICHECK(i, 2 + len);

        switch(type) {
        case MESSAGE_PAD1: {
            if(!vflag)
                printf(" pad1");
            else
                printf("\n\tPad 1");
        }
            break;

        case MESSAGE_PADN: {
            if(!vflag)
                printf(" padN");
            else
                printf("\n\tPad %d", len + 2);
        }
            break;

        case MESSAGE_ACK_REQ: {
            u_short nonce, interval;
            if(!vflag)
                printf(" ack-req");
            else {
                printf("\n\tAcknowledgment Request ");
                if(len < 6) goto corrupt;
                nonce = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                printf("%04x %d", nonce, interval);
            }
        }
            break;

        case MESSAGE_ACK: {
            u_short nonce;
            if(!vflag)
                printf(" ack");
            else {
                printf("\n\tAcknowledgment ");
                if(len < 2) goto corrupt;
                nonce = EXTRACT_16BITS(message + 2);
                printf("%04x", nonce);
            }
        }
            break;

        case MESSAGE_HELLO:  {
            u_short seqno, interval;
            if(!vflag)
                printf(" hello");
            else {
                printf("\n\tHello ");
                if(len < 6) goto corrupt;
                seqno = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                printf("seqno %u interval %u", seqno, interval);
            }
        }
            break;

        case MESSAGE_IHU: {
            unsigned short txcost, interval;
            if(!vflag)
                printf(" ihu");
            else {
                u_char address[16];
                int rc;
                printf("\n\tIHU ");
                if(len < 6) goto corrupt;
                txcost = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                rc = network_address(message[2], message + 8, len - 6, address);
                if(rc < 0) { printf("[|babel]"); break; }
                printf("%s txcost %u interval %d",
                       format_address(address), txcost, interval);
            }
        }
            break;

        case MESSAGE_ROUTER_ID: {
            if(!vflag)
                printf(" router-id");
            else {
                printf("\n\tRouter Id");
                if(len < 10) goto corrupt;
                printf(" %s", format_id(message + 4));
            }
        }
            break;

        case MESSAGE_NH: {
            if(!vflag)
                printf(" nh");
            else {
                int rc;
                u_char nh[16];
                printf("\n\tNext Hop");
                if(len < 2) goto corrupt;
                rc = network_address(message[2], message + 4, len - 2, nh);
                if(rc < 0) goto corrupt;
                printf(" %s", format_address(nh));
            }
        }
            break;

        case MESSAGE_UPDATE: {
            if(!vflag) {
                printf(" update");
                if(len < 1)
                    printf("/truncated");
                else
                    printf("%s%s%s",
                           (message[3] & 0x80) ? "/prefix": "",
                           (message[3] & 0x40) ? "/id" : "",
                           (message[3] & 0x3f) ? "/unknown" : "");
            } else {
                u_short interval, seqno, metric;
                u_char plen;
                int rc;
                u_char prefix[16];
                printf("\n\tUpdate");
                if(len < 10) goto corrupt;
                plen = message[4] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[4], message[5],
                                    message + 12,
                                    message[2] == 1 ? v4_prefix : v6_prefix,
                                    len - 10, prefix);
                if(rc < 0) goto corrupt;
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                printf("%s%s%s %s metric %u seqno %u interval %u",
                       (message[3] & 0x80) ? "/prefix": "",
                       (message[3] & 0x40) ? "/id" : "",
                       (message[3] & 0x3f) ? "/unknown" : "",
                       format_prefix(prefix, plen),
                       metric, seqno, interval);
                if(message[3] & 0x80) {
                    if(message[2] == 1)
                        memcpy(v4_prefix, prefix, 16);
                    else
                        memcpy(v6_prefix, prefix, 16);
                }
            }
        }
            break;

        case MESSAGE_REQUEST: {
            if(!vflag)
                printf(" request");
            else {
                int rc;
                u_char prefix[16], plen;
                printf("\n\tRequest ");
                if(len < 2) goto corrupt;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 4, NULL, len - 2, prefix);
                if(rc < 0) goto corrupt;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                printf("for %s",
                       message[2] == 0 ? "any" : format_prefix(prefix, plen));
            }
        }
            break;

        case MESSAGE_MH_REQUEST : {
            if(!vflag)
                printf(" mh-request");
            else {
                int rc;
                u_short seqno;
                u_char prefix[16], plen;
                printf("\n\tMH-Request ");
                if(len < 14) goto corrupt;
                seqno = EXTRACT_16BITS(message + 4);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 16, NULL, len - 14, prefix);
                if(rc < 0) goto corrupt;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                printf("(%u hops) for %s seqno %u id %s",
                       message[6], format_prefix(prefix, plen),
                       seqno, format_id(message + 8));
            }
        }
            break;
        default:
            if(!vflag)
                printf(" unknown");
            else
                printf("\n\tUnknown message type %d", type);
        }
        i += len + 2;
    }
    return;

 trunc:
    printf(" [|babel]");
    return;

 corrupt:
    printf(" (corrupt)");
    return;
}
Example #2
0
static int
network_address(int ae, const unsigned char *a, unsigned int len,
                unsigned char *a_r)
{
    return network_prefix(ae, -1, 0, a, NULL, len, a_r);
}
static int
dissect_babel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
    proto_item *ti;
    unsigned char v4_prefix[16] = {0}, v6_prefix[16] = {0};
    int i = 0;
    proto_tree *babel_tree = NULL;
    guint8 version;
    guint16 bodylen;

    if(tvb_length(tvb) < 4)
        return 0;

    if(tvb_get_guint8(tvb, 0) != 42)
        return 0;
    version = tvb_get_guint8(tvb, 1);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "Babel");
    col_set_str(pinfo->cinfo, COL_INFO, "Babel");

    if(version != 2) {
        col_add_fstr(pinfo->cinfo, COL_INFO, "Version %u", version);
        return 2;
    }

    if(tree) {
        ti = proto_tree_add_item(tree, proto_babel, tvb, 0, -1, ENC_NA);
        babel_tree = proto_item_add_subtree(ti, ett_babel);

        proto_tree_add_item(babel_tree, hf_babel_magic, tvb, 0, 1, ENC_NA);
        proto_tree_add_item(babel_tree, hf_babel_version, tvb, 1, 1, ENC_NA);
        proto_tree_add_item(babel_tree, hf_babel_bodylen,
                            tvb, 2, 2, ENC_BIG_ENDIAN);
    }

    bodylen = tvb_get_ntohs(tvb, 2);

    i = 0;
    while(i < bodylen) {
        guint8 type, len = 0, total_length;
        proto_tree *message_tree = NULL;
        int message = 4 + i;

        type = tvb_get_guint8(tvb, message);
        if(type == MESSAGE_PAD1)
            total_length = 1;
        else {
            len = tvb_get_guint8(tvb, message + 1);
            total_length = len + 2;
        }

        col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
                        val_to_str(type, messages, "unknown"));

        ti = proto_tree_add_uint_format(babel_tree, hf_babel_message,
                                        tvb, message, total_length, type,
                                        "Message %s (%u)",
                                        val_to_str(type, messages,
                                                "unknown"),
                                        type);

        if(tree) {
            message_tree = proto_item_add_subtree(ti, ett_message);
            proto_tree_add_item(message_tree, hf_babel_message_type,
                                tvb, message, 1, ENC_NA);
        }

        if(type == MESSAGE_PAD1) {
            i++;
            continue;
        }

        if(tree) {
            proto_tree_add_item(message_tree, hf_babel_message_length,
                                tvb, message + 1, 1, ENC_BIG_ENDIAN);

            if(type == MESSAGE_PADN) {
            } else if(type == MESSAGE_ACK_REQ) {
                proto_tree_add_item(message_tree, hf_babel_message_nonce,
                                    tvb, message + 4, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(message_tree, hf_babel_message_interval,
                                    tvb, message + 6, 2, ENC_BIG_ENDIAN);
            } else if(type == MESSAGE_ACK) {
                proto_tree_add_item(message_tree, hf_babel_message_nonce,
                                    tvb, message + 2, 2, ENC_BIG_ENDIAN);
            } else if(type == MESSAGE_HELLO) {
                proto_tree_add_item(message_tree, hf_babel_message_seqno,
                                    tvb, message + 4, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(message_tree, hf_babel_message_interval,
                                    tvb, message + 6, 2, ENC_BIG_ENDIAN);
            } else if(type == MESSAGE_IHU) {
                proto_tree *subtree;
                unsigned char address[16];
                int rc =
                    network_address(tvb_get_guint8(tvb, message + 2),
                                    tvb_get_ptr(tvb, message + 8, len - 6),
                                    len - 6,
                                    address);
                proto_tree_add_item(message_tree, hf_babel_message_rxcost,
                                    tvb, message + 4, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(message_tree, hf_babel_message_interval,
                                    tvb, message + 6, 2, ENC_BIG_ENDIAN);
                ti = proto_tree_add_text(message_tree,
                                         tvb, message + 4, len - 2,
                                         "Address: %s",
                                         format_address(rc < 0 ?
                                                        NULL : address));
                subtree = proto_item_add_subtree(ti, ett_subtree);
                proto_tree_add_item(subtree, hf_babel_message_ae,
                                    tvb, message + 2, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_prefix,
                                    tvb, message + 4, len - 2, ENC_NA);
            } else if(type == MESSAGE_ROUTER_ID) {
                proto_tree_add_item(message_tree, hf_babel_message_routerid,
                                    tvb, message + 4, 8, ENC_NA);
            } else if(type == MESSAGE_NH) {
                proto_tree *subtree;
                unsigned char nh[16];
                int rc =
                    network_address(tvb_get_guint8(tvb, message + 2),
                                    tvb_get_ptr(tvb, message + 4, len - 2),
                                    len - 2,
                                    nh);
                ti = proto_tree_add_text(message_tree,
                                         tvb, message + 4, len - 2,
                                         "NH: %s",
                                         format_address(rc < 0 ? NULL : nh));
                subtree = proto_item_add_subtree(ti, ett_subtree);
                proto_tree_add_item(subtree, hf_babel_message_ae,
                                    tvb, message + 2, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_prefix,
                                    tvb, message + 4, len - 2, ENC_NA);
            } else if(type == MESSAGE_UPDATE) {
                proto_tree *subtree;
                unsigned char p[16];
                guint8 ae = tvb_get_guint8(tvb, message + 2);
                guint8 flags = tvb_get_guint8(tvb, message + 3);
                guint8 plen = tvb_get_guint8(tvb, message + 4);
                int rc =
                    network_prefix(ae, plen,
                                   tvb_get_guint8(tvb, message + 5),
                                   tvb_get_ptr(tvb, message + 12, len - 10),
                                   ae == 1 ? v4_prefix : v6_prefix,
                                   len - 10, p);
                if(rc >= 0 && (flags & 0x80)) {
                    if(ae == 1)
                        memcpy(v4_prefix, p, 16);
                    else
                        memcpy(v6_prefix, p, 16);
                }

                proto_tree_add_item(message_tree, hf_babel_message_flags,
                                    tvb, message + 3, 1, ENC_NA);
                proto_tree_add_item(message_tree, hf_babel_message_interval,
                                    tvb, message + 6, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(message_tree, hf_babel_message_seqno,
                                    tvb, message + 8, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(message_tree, hf_babel_message_metric,
                                    tvb, message + 10, 2, ENC_BIG_ENDIAN);
                ti = proto_tree_add_text(message_tree,
                                         tvb, message + 12, len - 10,
                                         "Prefix: %s",
                                         format_prefix(rc < 0 ? NULL : p,
                                                       plen));
                subtree = proto_item_add_subtree(ti, ett_subtree);
                proto_tree_add_item(subtree, hf_babel_message_ae,
                                    tvb, message + 2, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_plen,
                                    tvb, message + 4, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_omitted,
                                    tvb, message + 5, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_prefix,
                                    tvb, message + 12, len - 10, ENC_NA);
            } else if(type == MESSAGE_REQUEST) {
                proto_tree *subtree;
                unsigned char p[16];
                guint8 plen = tvb_get_guint8(tvb, message + 3);
                int rc =
                    network_prefix(tvb_get_guint8(tvb, message + 2), plen,
                                   0,
                                   tvb_get_ptr(tvb, message + 4, len - 2),
                                   NULL,
                                   len - 2, p);
                ti = proto_tree_add_text(message_tree,
                                         tvb, message + 4, len - 2,
                                         "Prefix: %s",
                                         format_prefix(rc < 0 ? NULL : p,
                                                       plen));
                subtree = proto_item_add_subtree(ti, ett_subtree);
                proto_tree_add_item(subtree, hf_babel_message_ae,
                                    tvb, message + 2, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_plen,
                                    tvb, message + 3, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_prefix,
                                    tvb, message + 4, len - 2, ENC_NA);
            } else if(type == MESSAGE_MH_REQUEST) {
                proto_tree *subtree;
                unsigned char p[16];
                guint8 plen = tvb_get_guint8(tvb, message + 3);
                int rc =
                    network_prefix(tvb_get_guint8(tvb, message + 2), plen,
                                   0,
                                   tvb_get_ptr(tvb, message + 16, len - 14),
                                   NULL,
                                   len - 14, p);
                proto_tree_add_item(message_tree, hf_babel_message_seqno,
                                    tvb, message + 4, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item(message_tree, hf_babel_message_hopcount,
                                    tvb, message + 6, 1, ENC_NA);
                proto_tree_add_item(message_tree, hf_babel_message_routerid,
                                    tvb, message + 8, 8, ENC_NA);
                ti = proto_tree_add_text(message_tree,
                                         tvb, message + 16, len - 14,
                                         "Prefix: %s",
                                         format_prefix(rc < 0 ? NULL : p,
                                                       plen));
                subtree = proto_item_add_subtree(ti, ett_subtree);
                proto_tree_add_item(subtree, hf_babel_message_ae,
                                    tvb, message + 2, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_plen,
                                    tvb, message + 3, 1, ENC_NA);
                proto_tree_add_item(subtree, hf_babel_message_prefix,
                                    tvb, message + 16, len - 14, ENC_NA);
            }
        }
        i += len + 2;
    }
    return i;
}
Example #4
0
static int
network_address(int ae, tvbuff_t *tvb, int offset, unsigned int len,
                unsigned char *a_r)
{
    return network_prefix(ae, -1, 0, tvb, offset, NULL, len, a_r);
}
Example #5
0
static void
babel_print_v2(netdissect_options *ndo,
               const u_char *cp, u_int length)
{
    u_int i;
    u_short bodylen;
    u_char v4_prefix[16] =
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    u_char v6_prefix[16] = {0};

    ND_TCHECK2(*cp, 4);
    if (length < 4)
        goto corrupt;
    bodylen = EXTRACT_16BITS(cp + 2);
    ND_PRINT((ndo, " (%u)", bodylen));

    /* Process the TLVs in the body */
    i = 0;
    while(i < bodylen) {
        const u_char *message;
        u_int type, len;

        message = cp + 4 + i;

        ND_TCHECK2(*message, 1);
        if((type = message[0]) == MESSAGE_PAD1) {
            ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
            i += 1;
            continue;
        }

        ND_TCHECK2(*message, 2);
        ICHECK(i, 2);
        len = message[1];

        ND_TCHECK2(*message, 2 + len);
        ICHECK(i, 2 + len);

        switch(type) {
        case MESSAGE_PADN: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " padN"));
            else
                ND_PRINT((ndo, "\n\tPad %d", len + 2));
        }
            break;

        case MESSAGE_ACK_REQ: {
            u_short nonce, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ack-req"));
            else {
                ND_PRINT((ndo, "\n\tAcknowledgment Request "));
                if(len < 6) goto corrupt;
                nonce = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
            }
        }
            break;

        case MESSAGE_ACK: {
            u_short nonce;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ack"));
            else {
                ND_PRINT((ndo, "\n\tAcknowledgment "));
                if(len < 2) goto corrupt;
                nonce = EXTRACT_16BITS(message + 2);
                ND_PRINT((ndo, "%04x", nonce));
            }
        }
            break;

        case MESSAGE_HELLO:  {
            u_short seqno, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " hello"));
            else {
                ND_PRINT((ndo, "\n\tHello "));
                if(len < 6) goto corrupt;
                seqno = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
                /* Extra data. */
                if(len > 6)
                    subtlvs_print(ndo, message + 8, message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_IHU: {
            unsigned short txcost, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ihu"));
            else {
                u_char address[16];
                int rc;
                ND_PRINT((ndo, "\n\tIHU "));
                if(len < 6) goto corrupt;
                txcost = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                rc = network_address(message[2], message + 8, len - 6, address);
                if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
                ND_PRINT((ndo, "%s txcost %u interval %s",
                       format_address(ndo, address), txcost, format_interval(interval)));
                /* Extra data. */
                if((u_int)rc < len - 6)
                    subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
                                  type);
            }
        }
            break;

        case MESSAGE_ROUTER_ID: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " router-id"));
            else {
                ND_PRINT((ndo, "\n\tRouter Id"));
                if(len < 10) goto corrupt;
                ND_PRINT((ndo, " %s", format_id(message + 4)));
            }
        }
            break;

        case MESSAGE_NH: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " nh"));
            else {
                int rc;
                u_char nh[16];
                ND_PRINT((ndo, "\n\tNext Hop"));
                if(len < 2) goto corrupt;
                rc = network_address(message[2], message + 4, len - 2, nh);
                if(rc < 0) goto corrupt;
                ND_PRINT((ndo, " %s", format_address(ndo, nh)));
            }
        }
            break;

        case MESSAGE_UPDATE: {
            if (!ndo->ndo_vflag) {
                ND_PRINT((ndo, " update"));
                if(len < 1)
                    ND_PRINT((ndo, "/truncated"));
                else
                    ND_PRINT((ndo, "%s%s%s",
                           (message[3] & 0x80) ? "/prefix": "",
                           (message[3] & 0x40) ? "/id" : "",
                           (message[3] & 0x3f) ? "/unknown" : ""));
            } else {
                u_short interval, seqno, metric;
                u_char plen;
                int rc;
                u_char prefix[16];
                ND_PRINT((ndo, "\n\tUpdate"));
                if(len < 10) goto corrupt;
                plen = message[4] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[4], message[5],
                                    message + 12,
                                    message[2] == 1 ? v4_prefix : v6_prefix,
                                    len - 10, prefix);
                if(rc < 0) goto corrupt;
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
                       (message[3] & 0x80) ? "/prefix": "",
                       (message[3] & 0x40) ? "/id" : "",
                       (message[3] & 0x3f) ? "/unknown" : "",
                       format_prefix(ndo, prefix, plen),
                       metric, seqno, format_interval_update(interval)));
                if(message[3] & 0x80) {
                    if(message[2] == 1)
                        memcpy(v4_prefix, prefix, 16);
                    else
                        memcpy(v6_prefix, prefix, 16);
                }
                /* extra data? */
                if((u_int)rc < len - 10)
                    subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_REQUEST: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " request"));
            else {
                int rc;
                u_char prefix[16], plen;
                ND_PRINT((ndo, "\n\tRequest "));
                if(len < 2) goto corrupt;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 4, NULL, len - 2, prefix);
                if(rc < 0) goto corrupt;
                ND_PRINT((ndo, "for %s",
                       message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
            }
        }
            break;

        case MESSAGE_MH_REQUEST : {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " mh-request"));
            else {
                int rc;
                u_short seqno;
                u_char prefix[16], plen;
                ND_PRINT((ndo, "\n\tMH-Request "));
                if(len < 14) goto corrupt;
                seqno = EXTRACT_16BITS(message + 4);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 16, NULL, len - 14, prefix);
                if(rc < 0) goto corrupt;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
                       message[6], format_prefix(ndo, prefix, plen),
                       seqno, format_id(message + 8)));
            }
        }
            break;
        case MESSAGE_TSPC :
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " tspc"));
            else {
                ND_PRINT((ndo, "\n\tTS/PC "));
                if(len < 6) goto corrupt;
                ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
                       EXTRACT_16BITS(message + 2)));
            }
            break;
        case MESSAGE_HMAC : {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " hmac"));
            else {
                unsigned j;
                ND_PRINT((ndo, "\n\tHMAC "));
                if(len < 18) goto corrupt;
                ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
                for (j = 0; j < len - 2; j++)
                    ND_PRINT((ndo, "%02X", message[4 + j]));
            }
        }
            break;

        case MESSAGE_UPDATE_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag) {
                ND_PRINT((ndo, " ss-update"));
            } else {
                u_char prefix[16], src_prefix[16];
                u_short interval, seqno, metric;
                u_char ae, plen, src_plen, omitted;
                int rc;
                int parsed_len = 10;
                ND_PRINT((ndo, "\n\tSS-Update"));
                if(len < 10) goto corrupt;
                ae = message[2];
                src_plen = message[3];
                plen = message[4];
                omitted = message[5];
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
                                    ae == 1 ? v4_prefix : v6_prefix,
                                    len - parsed_len, prefix);
                if(rc < 0) goto corrupt;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto corrupt;
                if(ae == 1)
                    src_plen += 96;
                parsed_len += rc;

                ND_PRINT((ndo, " %s from", format_prefix(ndo, prefix, plen)));
                ND_PRINT((ndo, " %s metric %u seqno %u interval %s",
                          format_prefix(ndo, src_prefix, src_plen),
                          metric, seqno, format_interval_update(interval)));
                /* extra data? */
                if((u_int)parsed_len < len)
                    subtlvs_print(ndo, message + 2 + parsed_len,
                                  message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_REQUEST_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag)
                ND_PRINT((ndo, " ss-request"));
            else {
                int rc, parsed_len = 3;
                u_char ae, plen, src_plen, prefix[16], src_prefix[16];
                ND_PRINT((ndo, "\n\tSS-Request "));
                if(len < 3) goto corrupt;
                ae = message[2];
                plen = message[3];
                src_plen = message[4];
                rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, prefix);
                if(rc < 0) goto corrupt;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto corrupt;
                if(ae == 1)
                    src_plen += 96;
                parsed_len += rc;
                if(ae == 0) {
                    ND_PRINT((ndo, "for any"));
                } else {
                    ND_PRINT((ndo, "for (%s, ", format_prefix(ndo, prefix, plen)));
                    ND_PRINT((ndo, "%s)", format_prefix(ndo, src_prefix, src_plen)));
                }
            }
        }
            break;

        case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag)
                ND_PRINT((ndo, " ss-mh-request"));
            else {
                int rc, parsed_len = 14;
                u_short seqno;
                u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
                const u_char *router_id = NULL;
                ND_PRINT((ndo, "\n\tSS-MH-Request "));
                if(len < 14) goto corrupt;
                ae = message[2];
                plen = message[3];
                seqno = EXTRACT_16BITS(message + 4);
                hopc = message[6];
                src_plen = message[7];
                router_id = message + 8;
                rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, prefix);
                if(rc < 0) goto corrupt;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto corrupt;
                if(ae == 1)
                    src_plen += 96;
                ND_PRINT((ndo, "(%u hops) for (%s, ",
                          hopc, format_prefix(ndo, prefix, plen)));
                ND_PRINT((ndo, "%s) seqno %u id %s",
                          format_prefix(ndo, src_prefix, src_plen),
                          seqno, format_id(router_id)));
            }
        }
            break;

        default:
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " unknown"));
            else
                ND_PRINT((ndo, "\n\tUnknown message type %d", type));
        }
        i += len + 2;
    }
    return;

 trunc:
    ND_PRINT((ndo, " %s", tstr));
    return;

 corrupt:
    ND_PRINT((ndo, " (corrupt)"));
    return;
}