Home | History | Annotate | Line # | Download | only in dist
      1  1.1  christos /*
      2  1.1  christos  * Copyright (c) 1998-2007 The TCPDUMP project
      3  1.1  christos  * Copyright (c) 2009  Florian Forster
      4  1.1  christos  *
      5  1.1  christos  * Redistribution and use in source and binary forms, with or without
      6  1.1  christos  * modification, are permitted provided that: (1) source code
      7  1.1  christos  * distributions retain the above copyright notice and this paragraph
      8  1.1  christos  * in its entirety, and (2) distributions including binary code include
      9  1.1  christos  * the above copyright notice and this paragraph in its entirety in
     10  1.1  christos  * the documentation or other materials provided with the distribution.
     11  1.1  christos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
     12  1.1  christos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     13  1.1  christos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     14  1.1  christos  * FOR A PARTICULAR PURPOSE.
     15  1.1  christos  *
     16  1.4  christos  * Original code by Hannes Gredler <hannes (at) gredler.at>
     17  1.1  christos  * IPv6 additions by Florian Forster <octo at verplant.org>
     18  1.1  christos  */
     19  1.1  christos 
     20  1.3       spz /* \summary: Optimized Link State Routing Protocol (OLSR) printer */
     21  1.3       spz 
     22  1.3       spz /* specification: RFC 3626 */
     23  1.3       spz 
     24  1.2  christos #include <sys/cdefs.h>
     25  1.2  christos #ifndef lint
     26  1.6  christos __RCSID("$NetBSD: print-olsr.c,v 1.6 2024/09/02 16:15:32 christos Exp $");
     27  1.2  christos #endif
     28  1.2  christos 
     29  1.5  christos #include <config.h>
     30  1.1  christos 
     31  1.5  christos #include "netdissect-stdinc.h"
     32  1.1  christos 
     33  1.2  christos #include "netdissect.h"
     34  1.1  christos #include "addrtoname.h"
     35  1.1  christos #include "extract.h"
     36  1.1  christos 
     37  1.1  christos /*
     38  1.1  christos  * RFC 3626 common header
     39  1.1  christos  *
     40  1.1  christos  *  0                   1                   2                   3
     41  1.1  christos  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     42  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     43  1.1  christos  * |         Packet Length         |    Packet Sequence Number     |
     44  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     45  1.1  christos  * |  Message Type |     Vtime     |         Message Size          |
     46  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     47  1.1  christos  * |                      Originator Address                       |
     48  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     49  1.1  christos  * |  Time To Live |   Hop Count   |    Message Sequence Number    |
     50  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     51  1.1  christos  * |                                                               |
     52  1.1  christos  * :                            MESSAGE                            :
     53  1.1  christos  * |                                                               |
     54  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     55  1.1  christos  * |  Message Type |     Vtime     |         Message Size          |
     56  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     57  1.1  christos  * |                      Originator Address                       |
     58  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     59  1.1  christos  * |  Time To Live |   Hop Count   |    Message Sequence Number    |
     60  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     61  1.1  christos  * |                                                               |
     62  1.1  christos  * :                            MESSAGE                            :
     63  1.1  christos  * |                                                               |
     64  1.1  christos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     65  1.1  christos  * :                                                               :
     66  1.1  christos  */
     67  1.1  christos 
     68  1.1  christos struct olsr_common {
     69  1.5  christos     nd_uint16_t packet_len;
     70  1.5  christos     nd_uint16_t packet_seq;
     71  1.1  christos };
     72  1.1  christos 
     73  1.1  christos #define OLSR_HELLO_MSG         1 /* rfc3626 */
     74  1.1  christos #define OLSR_TC_MSG            2 /* rfc3626 */
     75  1.1  christos #define OLSR_MID_MSG           3 /* rfc3626 */
     76  1.1  christos #define OLSR_HNA_MSG           4 /* rfc3626 */
     77  1.1  christos #define OLSR_POWERINFO_MSG   128
     78  1.1  christos #define OLSR_NAMESERVICE_MSG 130
     79  1.1  christos #define OLSR_HELLO_LQ_MSG    201 /* LQ extensions olsr.org */
     80  1.1  christos #define OLSR_TC_LQ_MSG       202 /* LQ extensions olsr.org */
     81  1.1  christos 
     82  1.2  christos static const struct tok olsr_msg_values[] = {
     83  1.1  christos     { OLSR_HELLO_MSG, "Hello" },
     84  1.1  christos     { OLSR_TC_MSG, "TC" },
     85  1.1  christos     { OLSR_MID_MSG, "MID" },
     86  1.1  christos     { OLSR_HNA_MSG, "HNA" },
     87  1.1  christos     { OLSR_POWERINFO_MSG, "Powerinfo" },
     88  1.1  christos     { OLSR_NAMESERVICE_MSG, "Nameservice" },
     89  1.1  christos     { OLSR_HELLO_LQ_MSG, "Hello-LQ" },
     90  1.1  christos     { OLSR_TC_LQ_MSG, "TC-LQ" },
     91  1.1  christos     { 0, NULL}
     92  1.1  christos };
     93  1.1  christos 
     94  1.1  christos struct olsr_msg4 {
     95  1.5  christos     nd_uint8_t  msg_type;
     96  1.5  christos     nd_uint8_t  vtime;
     97  1.5  christos     nd_uint16_t msg_len;
     98  1.5  christos     nd_ipv4     originator;
     99  1.5  christos     nd_uint8_t  ttl;
    100  1.5  christos     nd_uint8_t  hopcount;
    101  1.5  christos     nd_uint16_t msg_seq;
    102  1.1  christos };
    103  1.1  christos 
    104  1.1  christos struct olsr_msg6 {
    105  1.5  christos     nd_uint8_t  msg_type;
    106  1.5  christos     nd_uint8_t  vtime;
    107  1.5  christos     nd_uint16_t msg_len;
    108  1.5  christos     nd_ipv6     originator;
    109  1.5  christos     nd_uint8_t  ttl;
    110  1.5  christos     nd_uint8_t  hopcount;
    111  1.5  christos     nd_uint16_t msg_seq;
    112  1.1  christos };
    113  1.1  christos 
    114  1.1  christos struct olsr_hello {
    115  1.5  christos     nd_byte     res[2];
    116  1.5  christos     nd_uint8_t  htime;
    117  1.5  christos     nd_uint8_t  will;
    118  1.1  christos };
    119  1.1  christos 
    120  1.1  christos struct olsr_hello_link {
    121  1.5  christos     nd_uint8_t  link_code;
    122  1.5  christos     nd_byte     res;
    123  1.5  christos     nd_uint16_t len;
    124  1.1  christos };
    125  1.1  christos 
    126  1.1  christos struct olsr_tc {
    127  1.5  christos     nd_uint16_t ans_seq;
    128  1.5  christos     nd_byte     res[2];
    129  1.1  christos };
    130  1.1  christos 
    131  1.1  christos struct olsr_hna4 {
    132  1.5  christos     nd_ipv4 network;
    133  1.5  christos     nd_ipv4 mask;
    134  1.1  christos };
    135  1.1  christos 
    136  1.1  christos struct olsr_hna6 {
    137  1.5  christos     nd_ipv6 network;
    138  1.5  christos     nd_ipv6 mask;
    139  1.2  christos };
    140  1.2  christos 
    141  1.2  christos 
    142  1.2  christos /** gateway HNA flags */
    143  1.2  christos enum gateway_hna_flags {
    144  1.2  christos   GW_HNA_FLAG_LINKSPEED   = 1 << 0,
    145  1.2  christos   GW_HNA_FLAG_IPV4        = 1 << 1,
    146  1.2  christos   GW_HNA_FLAG_IPV4_NAT    = 1 << 2,
    147  1.2  christos   GW_HNA_FLAG_IPV6        = 1 << 3,
    148  1.2  christos   GW_HNA_FLAG_IPV6PREFIX  = 1 << 4
    149  1.2  christos };
    150  1.2  christos 
    151  1.2  christos /** gateway HNA field byte offsets in the netmask field of the HNA */
    152  1.2  christos enum gateway_hna_fields {
    153  1.2  christos   GW_HNA_PAD              = 0,
    154  1.2  christos   GW_HNA_FLAGS            = 1,
    155  1.2  christos   GW_HNA_UPLINK           = 2,
    156  1.2  christos   GW_HNA_DOWNLINK         = 3,
    157  1.2  christos   GW_HNA_V6PREFIXLEN      = 4,
    158  1.2  christos   GW_HNA_V6PREFIX         = 5
    159  1.1  christos };
    160  1.1  christos 
    161  1.1  christos 
    162  1.1  christos #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3)
    163  1.1  christos #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2)
    164  1.1  christos 
    165  1.2  christos static const struct tok olsr_link_type_values[] = {
    166  1.1  christos     { 0, "Unspecified" },
    167  1.1  christos     { 1, "Asymmetric" },
    168  1.1  christos     { 2, "Symmetric" },
    169  1.1  christos     { 3, "Lost" },
    170  1.1  christos     { 0, NULL}
    171  1.1  christos };
    172  1.1  christos 
    173  1.2  christos static const struct tok olsr_neighbor_type_values[] = {
    174  1.1  christos     { 0, "Not-Neighbor" },
    175  1.1  christos     { 1, "Symmetric" },
    176  1.1  christos     { 2, "Symmetric-MPR" },
    177  1.1  christos     { 0, NULL}
    178  1.1  christos };
    179  1.1  christos 
    180  1.1  christos struct olsr_lq_neighbor4 {
    181  1.5  christos     nd_ipv4     neighbor;
    182  1.5  christos     nd_uint8_t  link_quality;
    183  1.5  christos     nd_uint8_t  neighbor_link_quality;
    184  1.5  christos     nd_byte     res[2];
    185  1.1  christos };
    186  1.1  christos 
    187  1.1  christos struct olsr_lq_neighbor6 {
    188  1.5  christos     nd_ipv6     neighbor;
    189  1.5  christos     nd_uint8_t  link_quality;
    190  1.5  christos     nd_uint8_t  neighbor_link_quality;
    191  1.5  christos     nd_byte     res[2];
    192  1.1  christos };
    193  1.1  christos 
    194  1.2  christos #define MAX_SMARTGW_SPEED    320000000
    195  1.2  christos 
    196  1.2  christos /**
    197  1.2  christos  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
    198  1.2  christos  * to an uplink/downlink speed value
    199  1.2  christos  *
    200  1.2  christos  * @param value the encoded 1 byte transport value
    201  1.2  christos  * @return the uplink/downlink speed value (in kbit/s)
    202  1.2  christos  */
    203  1.2  christos static uint32_t deserialize_gw_speed(uint8_t value) {
    204  1.2  christos   uint32_t speed;
    205  1.2  christos   uint32_t exp;
    206  1.2  christos 
    207  1.2  christos   if (!value) {
    208  1.2  christos     return 0;
    209  1.2  christos   }
    210  1.2  christos 
    211  1.2  christos   if (value == UINT8_MAX) {
    212  1.2  christos     /* maximum value: also return maximum value */
    213  1.2  christos     return MAX_SMARTGW_SPEED;
    214  1.2  christos   }
    215  1.2  christos 
    216  1.2  christos   speed = (value >> 3) + 1;
    217  1.2  christos   exp = value & 7;
    218  1.2  christos 
    219  1.5  christos   while (exp != 0) {
    220  1.2  christos     speed *= 10;
    221  1.5  christos     exp--;
    222  1.2  christos   }
    223  1.2  christos   return speed;
    224  1.2  christos }
    225  1.2  christos 
    226  1.1  christos /*
    227  1.1  christos  * macro to convert the 8-bit mantissa/exponent to a double float
    228  1.1  christos  * taken from olsr.org.
    229  1.1  christos  */
    230  1.1  christos #define VTIME_SCALE_FACTOR    0.0625
    231  1.1  christos #define ME_TO_DOUBLE(me) \
    232  1.1  christos   (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F)))
    233  1.1  christos 
    234  1.1  christos /*
    235  1.1  christos  * print a neighbor list with LQ extensions.
    236  1.1  christos  */
    237  1.2  christos static int
    238  1.2  christos olsr_print_lq_neighbor4(netdissect_options *ndo,
    239  1.2  christos                         const u_char *msg_data, u_int hello_len)
    240  1.1  christos {
    241  1.2  christos     const struct olsr_lq_neighbor4 *lq_neighbor;
    242  1.1  christos 
    243  1.1  christos     while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {
    244  1.1  christos 
    245  1.2  christos         lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data;
    246  1.5  christos         ND_TCHECK_SIZE(lq_neighbor);
    247  1.2  christos 
    248  1.5  christos         ND_PRINT("\n\t      neighbor %s, link-quality %.2f%%"
    249  1.2  christos                ", neighbor-link-quality %.2f%%",
    250  1.5  christos                GET_IPADDR_STRING(lq_neighbor->neighbor),
    251  1.5  christos                ((double) GET_U_1(lq_neighbor->link_quality)/2.55),
    252  1.5  christos                ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55));
    253  1.1  christos 
    254  1.1  christos         msg_data += sizeof(struct olsr_lq_neighbor4);
    255  1.1  christos         hello_len -= sizeof(struct olsr_lq_neighbor4);
    256  1.1  christos     }
    257  1.2  christos     return (0);
    258  1.5  christos trunc:
    259  1.5  christos     return -1;
    260  1.1  christos }
    261  1.1  christos 
    262  1.2  christos static int
    263  1.2  christos olsr_print_lq_neighbor6(netdissect_options *ndo,
    264  1.2  christos                         const u_char *msg_data, u_int hello_len)
    265  1.1  christos {
    266  1.2  christos     const struct olsr_lq_neighbor6 *lq_neighbor;
    267  1.1  christos 
    268  1.1  christos     while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {
    269  1.1  christos 
    270  1.2  christos         lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data;
    271  1.5  christos         ND_TCHECK_SIZE(lq_neighbor);
    272  1.2  christos 
    273  1.5  christos         ND_PRINT("\n\t      neighbor %s, link-quality %.2f%%"
    274  1.2  christos                ", neighbor-link-quality %.2f%%",
    275  1.5  christos                GET_IP6ADDR_STRING(lq_neighbor->neighbor),
    276  1.5  christos                ((double) GET_U_1(lq_neighbor->link_quality)/2.55),
    277  1.5  christos                ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55));
    278  1.1  christos 
    279  1.1  christos         msg_data += sizeof(struct olsr_lq_neighbor6);
    280  1.1  christos         hello_len -= sizeof(struct olsr_lq_neighbor6);
    281  1.1  christos     }
    282  1.2  christos     return (0);
    283  1.5  christos trunc:
    284  1.5  christos     return -1;
    285  1.1  christos }
    286  1.1  christos 
    287  1.1  christos /*
    288  1.1  christos  * print a neighbor list.
    289  1.1  christos  */
    290  1.2  christos static int
    291  1.2  christos olsr_print_neighbor(netdissect_options *ndo,
    292  1.2  christos                     const u_char *msg_data, u_int hello_len)
    293  1.1  christos {
    294  1.1  christos     int neighbor;
    295  1.1  christos 
    296  1.5  christos     ND_PRINT("\n\t      neighbor\n\t\t");
    297  1.1  christos     neighbor = 1;
    298  1.1  christos 
    299  1.5  christos     while (hello_len >= sizeof(nd_ipv4)) {
    300  1.1  christos         /* print 4 neighbors per line */
    301  1.5  christos         ND_PRINT("%s%s", GET_IPADDR_STRING(msg_data),
    302  1.5  christos                neighbor % 4 == 0 ? "\n\t\t" : " ");
    303  1.1  christos 
    304  1.5  christos         msg_data += sizeof(nd_ipv4);
    305  1.5  christos         hello_len -= sizeof(nd_ipv4);
    306  1.1  christos     }
    307  1.2  christos     return (0);
    308  1.1  christos }
    309  1.1  christos 
    310  1.1  christos 
    311  1.1  christos void
    312  1.2  christos olsr_print(netdissect_options *ndo,
    313  1.2  christos            const u_char *pptr, u_int length, int is_ipv6)
    314  1.1  christos {
    315  1.1  christos     union {
    316  1.1  christos         const struct olsr_common *common;
    317  1.1  christos         const struct olsr_msg4 *msg4;
    318  1.1  christos         const struct olsr_msg6 *msg6;
    319  1.1  christos         const struct olsr_hello *hello;
    320  1.1  christos         const struct olsr_hello_link *hello_link;
    321  1.1  christos         const struct olsr_tc *tc;
    322  1.1  christos         const struct olsr_hna4 *hna;
    323  1.1  christos     } ptr;
    324  1.1  christos 
    325  1.1  christos     u_int msg_type, msg_len, msg_tlen, hello_len;
    326  1.2  christos     uint16_t name_entry_type, name_entry_len;
    327  1.1  christos     u_int name_entry_padding;
    328  1.2  christos     uint8_t link_type, neighbor_type;
    329  1.1  christos     const u_char *tptr, *msg_data;
    330  1.1  christos 
    331  1.5  christos     ndo->ndo_protocol = "olsr";
    332  1.1  christos     tptr = pptr;
    333  1.1  christos 
    334  1.5  christos     nd_print_protocol_caps(ndo);
    335  1.5  christos     ND_PRINT("v%u", (is_ipv6) ? 6 : 4);
    336  1.5  christos 
    337  1.1  christos     if (length < sizeof(struct olsr_common)) {
    338  1.1  christos         goto trunc;
    339  1.1  christos     }
    340  1.1  christos 
    341  1.5  christos     ND_TCHECK_LEN(tptr, sizeof(struct olsr_common));
    342  1.1  christos 
    343  1.2  christos     ptr.common = (const struct olsr_common *)tptr;
    344  1.5  christos     length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len));
    345  1.1  christos 
    346  1.5  christos     ND_PRINT(", seq 0x%04x, length %u",
    347  1.5  christos             GET_BE_U_2(ptr.common->packet_seq),
    348  1.5  christos             length);
    349  1.1  christos 
    350  1.1  christos     tptr += sizeof(struct olsr_common);
    351  1.1  christos 
    352  1.1  christos     /*
    353  1.1  christos      * In non-verbose mode, just print version.
    354  1.1  christos      */
    355  1.2  christos     if (ndo->ndo_vflag < 1) {
    356  1.1  christos         return;
    357  1.1  christos     }
    358  1.1  christos 
    359  1.1  christos     while (tptr < (pptr+length)) {
    360  1.1  christos         union
    361  1.1  christos         {
    362  1.2  christos             const struct olsr_msg4 *v4;
    363  1.2  christos             const struct olsr_msg6 *v6;
    364  1.1  christos         } msgptr;
    365  1.1  christos         int msg_len_valid = 0;
    366  1.1  christos 
    367  1.6  christos         if (is_ipv6) {
    368  1.5  christos             ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg6));
    369  1.2  christos             msgptr.v6 = (const struct olsr_msg6 *) tptr;
    370  1.5  christos             msg_type = GET_U_1(msgptr.v6->msg_type);
    371  1.5  christos             msg_len = GET_BE_U_2(msgptr.v6->msg_len);
    372  1.1  christos             if ((msg_len >= sizeof (struct olsr_msg6))
    373  1.1  christos                     && (msg_len <= length))
    374  1.1  christos                 msg_len_valid = 1;
    375  1.1  christos 
    376  1.1  christos             /* infinite loop check */
    377  1.1  christos             if (msg_type == 0 || msg_len == 0) {
    378  1.1  christos                 return;
    379  1.1  christos             }
    380  1.1  christos 
    381  1.5  christos             ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
    382  1.2  christos                     "\n\t  vtime %.3fs, msg-seq 0x%04x, length %u%s",
    383  1.1  christos                     tok2str(olsr_msg_values, "Unknown", msg_type),
    384  1.5  christos                     msg_type, GET_IP6ADDR_STRING(msgptr.v6->originator),
    385  1.5  christos                     GET_U_1(msgptr.v6->ttl),
    386  1.5  christos                     GET_U_1(msgptr.v6->hopcount),
    387  1.5  christos                     ME_TO_DOUBLE(GET_U_1(msgptr.v6->vtime)),
    388  1.5  christos                     GET_BE_U_2(msgptr.v6->msg_seq),
    389  1.5  christos                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
    390  1.2  christos             if (!msg_len_valid) {
    391  1.2  christos                 return;
    392  1.2  christos             }
    393  1.1  christos 
    394  1.1  christos             msg_tlen = msg_len - sizeof(struct olsr_msg6);
    395  1.1  christos             msg_data = tptr + sizeof(struct olsr_msg6);
    396  1.6  christos         } else {	/* (!is_ipv6) */
    397  1.5  christos             ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg4));
    398  1.2  christos             msgptr.v4 = (const struct olsr_msg4 *) tptr;
    399  1.5  christos             msg_type = GET_U_1(msgptr.v4->msg_type);
    400  1.5  christos             msg_len = GET_BE_U_2(msgptr.v4->msg_len);
    401  1.1  christos             if ((msg_len >= sizeof (struct olsr_msg4))
    402  1.1  christos                     && (msg_len <= length))
    403  1.1  christos                 msg_len_valid = 1;
    404  1.1  christos 
    405  1.1  christos             /* infinite loop check */
    406  1.1  christos             if (msg_type == 0 || msg_len == 0) {
    407  1.1  christos                 return;
    408  1.1  christos             }
    409  1.1  christos 
    410  1.5  christos             ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
    411  1.2  christos                     "\n\t  vtime %.3fs, msg-seq 0x%04x, length %u%s",
    412  1.1  christos                     tok2str(olsr_msg_values, "Unknown", msg_type),
    413  1.5  christos                     msg_type, GET_IPADDR_STRING(msgptr.v4->originator),
    414  1.5  christos                     GET_U_1(msgptr.v4->ttl),
    415  1.5  christos                     GET_U_1(msgptr.v4->hopcount),
    416  1.5  christos                     ME_TO_DOUBLE(GET_U_1(msgptr.v4->vtime)),
    417  1.5  christos                     GET_BE_U_2(msgptr.v4->msg_seq),
    418  1.5  christos                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
    419  1.2  christos             if (!msg_len_valid) {
    420  1.2  christos                 return;
    421  1.2  christos             }
    422  1.1  christos 
    423  1.1  christos             msg_tlen = msg_len - sizeof(struct olsr_msg4);
    424  1.1  christos             msg_data = tptr + sizeof(struct olsr_msg4);
    425  1.1  christos         }
    426  1.1  christos 
    427  1.1  christos         switch (msg_type) {
    428  1.1  christos         case OLSR_HELLO_MSG:
    429  1.1  christos         case OLSR_HELLO_LQ_MSG:
    430  1.2  christos             if (msg_tlen < sizeof(struct olsr_hello))
    431  1.1  christos                 goto trunc;
    432  1.5  christos             ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello));
    433  1.1  christos 
    434  1.2  christos             ptr.hello = (const struct olsr_hello *)msg_data;
    435  1.5  christos             ND_PRINT("\n\t  hello-time %.3fs, MPR willingness %u",
    436  1.5  christos                    ME_TO_DOUBLE(GET_U_1(ptr.hello->htime)),
    437  1.5  christos                    GET_U_1(ptr.hello->will));
    438  1.1  christos             msg_data += sizeof(struct olsr_hello);
    439  1.1  christos             msg_tlen -= sizeof(struct olsr_hello);
    440  1.1  christos 
    441  1.1  christos             while (msg_tlen >= sizeof(struct olsr_hello_link)) {
    442  1.1  christos                 int hello_len_valid = 0;
    443  1.1  christos 
    444  1.1  christos                 /*
    445  1.1  christos                  * link-type.
    446  1.1  christos                  */
    447  1.5  christos                 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello_link));
    448  1.1  christos 
    449  1.2  christos                 ptr.hello_link = (const struct olsr_hello_link *)msg_data;
    450  1.1  christos 
    451  1.5  christos                 hello_len = GET_BE_U_2(ptr.hello_link->len);
    452  1.5  christos                 link_type = OLSR_EXTRACT_LINK_TYPE(GET_U_1(ptr.hello_link->link_code));
    453  1.5  christos                 neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(GET_U_1(ptr.hello_link->link_code));
    454  1.1  christos 
    455  1.1  christos                 if ((hello_len <= msg_tlen)
    456  1.1  christos                         && (hello_len >= sizeof(struct olsr_hello_link)))
    457  1.1  christos                     hello_len_valid = 1;
    458  1.1  christos 
    459  1.5  christos                 ND_PRINT("\n\t    link-type %s, neighbor-type %s, len %u%s",
    460  1.1  christos                        tok2str(olsr_link_type_values, "Unknown", link_type),
    461  1.1  christos                        tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type),
    462  1.1  christos                        hello_len,
    463  1.5  christos                        (hello_len_valid == 0) ? " (invalid)" : "");
    464  1.1  christos 
    465  1.1  christos                 if (hello_len_valid == 0)
    466  1.1  christos                     break;
    467  1.1  christos 
    468  1.1  christos                 msg_data += sizeof(struct olsr_hello_link);
    469  1.1  christos                 msg_tlen -= sizeof(struct olsr_hello_link);
    470  1.1  christos                 hello_len -= sizeof(struct olsr_hello_link);
    471  1.1  christos 
    472  1.5  christos                 ND_TCHECK_LEN(msg_data, hello_len);
    473  1.1  christos                 if (msg_type == OLSR_HELLO_MSG) {
    474  1.2  christos                     if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1)
    475  1.2  christos                         goto trunc;
    476  1.1  christos                 } else {
    477  1.2  christos                     if (is_ipv6) {
    478  1.2  christos                         if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1)
    479  1.2  christos                             goto trunc;
    480  1.2  christos                     } else {
    481  1.2  christos                         if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1)
    482  1.2  christos                             goto trunc;
    483  1.2  christos                     }
    484  1.1  christos                 }
    485  1.1  christos 
    486  1.1  christos                 msg_data += hello_len;
    487  1.1  christos                 msg_tlen -= hello_len;
    488  1.1  christos             }
    489  1.1  christos             break;
    490  1.1  christos 
    491  1.1  christos         case OLSR_TC_MSG:
    492  1.1  christos         case OLSR_TC_LQ_MSG:
    493  1.2  christos             if (msg_tlen < sizeof(struct olsr_tc))
    494  1.1  christos                 goto trunc;
    495  1.5  christos             ND_TCHECK_LEN(msg_data, sizeof(struct olsr_tc));
    496  1.1  christos 
    497  1.2  christos             ptr.tc = (const struct olsr_tc *)msg_data;
    498  1.5  christos             ND_PRINT("\n\t    advertised neighbor seq 0x%04x",
    499  1.5  christos                    GET_BE_U_2(ptr.tc->ans_seq));
    500  1.1  christos             msg_data += sizeof(struct olsr_tc);
    501  1.1  christos             msg_tlen -= sizeof(struct olsr_tc);
    502  1.1  christos 
    503  1.1  christos             if (msg_type == OLSR_TC_MSG) {
    504  1.2  christos                 if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1)
    505  1.2  christos                     goto trunc;
    506  1.1  christos             } else {
    507  1.2  christos                 if (is_ipv6) {
    508  1.2  christos                     if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1)
    509  1.2  christos                         goto trunc;
    510  1.2  christos                 } else {
    511  1.2  christos                     if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1)
    512  1.2  christos                         goto trunc;
    513  1.2  christos                 }
    514  1.1  christos             }
    515  1.1  christos             break;
    516  1.1  christos 
    517  1.1  christos         case OLSR_MID_MSG:
    518  1.1  christos         {
    519  1.5  christos             u_int addr_size = (u_int)sizeof(nd_ipv4);
    520  1.1  christos 
    521  1.1  christos             if (is_ipv6)
    522  1.5  christos                 addr_size = (u_int)sizeof(nd_ipv6);
    523  1.1  christos 
    524  1.1  christos             while (msg_tlen >= addr_size) {
    525  1.5  christos                 ND_TCHECK_LEN(msg_data, addr_size);
    526  1.5  christos                 ND_PRINT("\n\t  interface address %s",
    527  1.5  christos                         is_ipv6 ? GET_IP6ADDR_STRING(msg_data) :
    528  1.5  christos                         GET_IPADDR_STRING(msg_data));
    529  1.1  christos 
    530  1.1  christos                 msg_data += addr_size;
    531  1.1  christos                 msg_tlen -= addr_size;
    532  1.1  christos             }
    533  1.1  christos             break;
    534  1.1  christos         }
    535  1.1  christos 
    536  1.1  christos         case OLSR_HNA_MSG:
    537  1.6  christos             if (is_ipv6) {
    538  1.1  christos                 int i = 0;
    539  1.2  christos 
    540  1.5  christos                 ND_PRINT("\n\t  Advertised networks (total %u)",
    541  1.5  christos                         (unsigned int) (msg_tlen / sizeof(struct olsr_hna6)));
    542  1.2  christos 
    543  1.1  christos                 while (msg_tlen >= sizeof(struct olsr_hna6)) {
    544  1.2  christos                     const struct olsr_hna6 *hna6;
    545  1.1  christos 
    546  1.5  christos                     ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna6));
    547  1.1  christos 
    548  1.2  christos                     hna6 = (const struct olsr_hna6 *)msg_data;
    549  1.1  christos 
    550  1.5  christos                     ND_PRINT("\n\t    #%i: %s/%u",
    551  1.5  christos                             i, GET_IP6ADDR_STRING(hna6->network),
    552  1.5  christos                             mask62plen (hna6->mask));
    553  1.1  christos 
    554  1.1  christos                     msg_data += sizeof(struct olsr_hna6);
    555  1.1  christos                     msg_tlen -= sizeof(struct olsr_hna6);
    556  1.1  christos                 }
    557  1.6  christos             } else {
    558  1.1  christos                 int col = 0;
    559  1.2  christos 
    560  1.5  christos                 ND_PRINT("\n\t  Advertised networks (total %u)",
    561  1.5  christos                         (unsigned int) (msg_tlen / sizeof(struct olsr_hna4)));
    562  1.2  christos 
    563  1.1  christos                 while (msg_tlen >= sizeof(struct olsr_hna4)) {
    564  1.5  christos                     ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna4));
    565  1.1  christos 
    566  1.2  christos                     ptr.hna = (const struct olsr_hna4 *)msg_data;
    567  1.1  christos 
    568  1.1  christos                     /* print 4 prefixes per line */
    569  1.2  christos                     if (!ptr.hna->network[0] && !ptr.hna->network[1] &&
    570  1.2  christos                         !ptr.hna->network[2] && !ptr.hna->network[3] &&
    571  1.2  christos                         !ptr.hna->mask[GW_HNA_PAD] &&
    572  1.2  christos                         ptr.hna->mask[GW_HNA_FLAGS]) {
    573  1.2  christos                             /* smart gateway */
    574  1.5  christos                             ND_PRINT("%sSmart-Gateway:%s%s%s%s%s %u/%u",
    575  1.2  christos                                 col == 0 ? "\n\t    " : ", ", /* indent */
    576  1.2  christos                                 /* sgw */
    577  1.2  christos                                 /* LINKSPEED */
    578  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    579  1.2  christos                                  GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "",
    580  1.2  christos                                 /* IPV4 */
    581  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    582  1.2  christos                                  GW_HNA_FLAG_IPV4) ? " IPV4" : "",
    583  1.2  christos                                 /* IPV4-NAT */
    584  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    585  1.2  christos                                  GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "",
    586  1.2  christos                                 /* IPV6 */
    587  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    588  1.2  christos                                  GW_HNA_FLAG_IPV6) ? " IPV6" : "",
    589  1.2  christos                                 /* IPv6PREFIX */
    590  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    591  1.2  christos                                  GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "",
    592  1.2  christos                                 /* uplink */
    593  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    594  1.2  christos                                  GW_HNA_FLAG_LINKSPEED) ?
    595  1.2  christos                                  deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0,
    596  1.2  christos                                 /* downlink */
    597  1.2  christos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
    598  1.2  christos                                  GW_HNA_FLAG_LINKSPEED) ?
    599  1.2  christos                                  deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0
    600  1.5  christos                                 );
    601  1.2  christos                     } else {
    602  1.2  christos                         /* normal route */
    603  1.5  christos                         ND_PRINT("%s%s/%u",
    604  1.2  christos                                 col == 0 ? "\n\t    " : ", ",
    605  1.5  christos                                 GET_IPADDR_STRING(ptr.hna->network),
    606  1.5  christos                                 mask2plen(GET_BE_U_4(ptr.hna->mask)));
    607  1.2  christos                     }
    608  1.1  christos 
    609  1.1  christos                     msg_data += sizeof(struct olsr_hna4);
    610  1.1  christos                     msg_tlen -= sizeof(struct olsr_hna4);
    611  1.1  christos 
    612  1.1  christos                     col = (col + 1) % 4;
    613  1.1  christos                 }
    614  1.1  christos             }
    615  1.1  christos             break;
    616  1.1  christos 
    617  1.1  christos         case OLSR_NAMESERVICE_MSG:
    618  1.1  christos         {
    619  1.4  christos             u_int name_entries;
    620  1.4  christos             u_int addr_size;
    621  1.4  christos             int name_entries_valid;
    622  1.1  christos             u_int i;
    623  1.1  christos 
    624  1.4  christos             if (msg_tlen < 4)
    625  1.4  christos                 goto trunc;
    626  1.4  christos 
    627  1.5  christos             name_entries = GET_BE_U_2(msg_data + 2);
    628  1.4  christos             addr_size = 4;
    629  1.1  christos             if (is_ipv6)
    630  1.1  christos                 addr_size = 16;
    631  1.1  christos 
    632  1.4  christos             name_entries_valid = 0;
    633  1.1  christos             if ((name_entries > 0)
    634  1.1  christos                     && ((name_entries * (4 + addr_size)) <= msg_tlen))
    635  1.1  christos                 name_entries_valid = 1;
    636  1.1  christos 
    637  1.5  christos             ND_PRINT("\n\t  Version %u, Entries %u%s",
    638  1.5  christos                    GET_BE_U_2(msg_data),
    639  1.5  christos                    name_entries, (name_entries_valid == 0) ? " (invalid)" : "");
    640  1.1  christos 
    641  1.1  christos             if (name_entries_valid == 0)
    642  1.1  christos                 break;
    643  1.1  christos 
    644  1.1  christos             msg_data += 4;
    645  1.1  christos             msg_tlen -= 4;
    646  1.1  christos 
    647  1.1  christos             for (i = 0; i < name_entries; i++) {
    648  1.1  christos                 int name_entry_len_valid = 0;
    649  1.1  christos 
    650  1.1  christos                 if (msg_tlen < 4)
    651  1.1  christos                     break;
    652  1.1  christos 
    653  1.5  christos                 name_entry_type = GET_BE_U_2(msg_data);
    654  1.5  christos                 name_entry_len = GET_BE_U_2(msg_data + 2);
    655  1.1  christos 
    656  1.1  christos                 msg_data += 4;
    657  1.1  christos                 msg_tlen -= 4;
    658  1.1  christos 
    659  1.1  christos                 if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen))
    660  1.1  christos                     name_entry_len_valid = 1;
    661  1.1  christos 
    662  1.5  christos                 ND_PRINT("\n\t    #%u: type %#06x, length %u%s",
    663  1.1  christos                         (unsigned int) i, name_entry_type,
    664  1.5  christos                         name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : "");
    665  1.1  christos 
    666  1.1  christos                 if (name_entry_len_valid == 0)
    667  1.1  christos                     break;
    668  1.1  christos 
    669  1.1  christos                 /* 32-bit alignment */
    670  1.1  christos                 name_entry_padding = 0;
    671  1.1  christos                 if (name_entry_len%4 != 0)
    672  1.1  christos                     name_entry_padding = 4-(name_entry_len%4);
    673  1.1  christos 
    674  1.1  christos                 if (msg_tlen < addr_size + name_entry_len + name_entry_padding)
    675  1.1  christos                     goto trunc;
    676  1.1  christos 
    677  1.5  christos                 ND_TCHECK_LEN(msg_data,
    678  1.5  christos                               addr_size + name_entry_len + name_entry_padding);
    679  1.1  christos 
    680  1.1  christos                 if (is_ipv6)
    681  1.5  christos                     ND_PRINT(", address %s, name \"",
    682  1.5  christos                             GET_IP6ADDR_STRING(msg_data));
    683  1.1  christos                 else
    684  1.5  christos                     ND_PRINT(", address %s, name \"",
    685  1.5  christos                             GET_IPADDR_STRING(msg_data));
    686  1.5  christos                 (void)nd_printn(ndo, msg_data + addr_size, name_entry_len, NULL);
    687  1.5  christos                 ND_PRINT("\"");
    688  1.1  christos 
    689  1.1  christos                 msg_data += addr_size + name_entry_len + name_entry_padding;
    690  1.1  christos                 msg_tlen -= addr_size + name_entry_len + name_entry_padding;
    691  1.1  christos             } /* for (i = 0; i < name_entries; i++) */
    692  1.1  christos             break;
    693  1.1  christos         } /* case OLSR_NAMESERVICE_MSG */
    694  1.1  christos 
    695  1.1  christos             /*
    696  1.1  christos              * FIXME those are the defined messages that lack a decoder
    697  1.1  christos              * you are welcome to contribute code ;-)
    698  1.1  christos              */
    699  1.1  christos         case OLSR_POWERINFO_MSG:
    700  1.1  christos         default:
    701  1.2  christos             print_unknown_data(ndo, msg_data, "\n\t    ", msg_tlen);
    702  1.1  christos             break;
    703  1.1  christos         } /* switch (msg_type) */
    704  1.1  christos         tptr += msg_len;
    705  1.1  christos     } /* while (tptr < (pptr+length)) */
    706  1.1  christos 
    707  1.1  christos     return;
    708  1.1  christos 
    709  1.1  christos  trunc:
    710  1.5  christos     nd_print_trunc(ndo);
    711  1.1  christos }
    712