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