"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-olsr.c" (7 Jun 2021, 23861 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "print-olsr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

    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@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     nd_uint16_t packet_len;
   67     nd_uint16_t packet_seq;
   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     nd_uint8_t  msg_type;
   93     nd_uint8_t  vtime;
   94     nd_uint16_t msg_len;
   95     nd_ipv4     originator;
   96     nd_uint8_t  ttl;
   97     nd_uint8_t  hopcount;
   98     nd_uint16_t msg_seq;
   99 };
  100 
  101 struct olsr_msg6 {
  102     nd_uint8_t  msg_type;
  103     nd_uint8_t  vtime;
  104     nd_uint16_t msg_len;
  105     nd_ipv6     originator;
  106     nd_uint8_t  ttl;
  107     nd_uint8_t  hopcount;
  108     nd_uint16_t msg_seq;
  109 };
  110 
  111 struct olsr_hello {
  112     nd_byte     res[2];
  113     nd_uint8_t  htime;
  114     nd_uint8_t  will;
  115 };
  116 
  117 struct olsr_hello_link {
  118     nd_uint8_t  link_code;
  119     nd_byte     res;
  120     nd_uint16_t len;
  121 };
  122 
  123 struct olsr_tc {
  124     nd_uint16_t ans_seq;
  125     nd_byte     res[2];
  126 };
  127 
  128 struct olsr_hna4 {
  129     nd_ipv4 network;
  130     nd_ipv4 mask;
  131 };
  132 
  133 struct olsr_hna6 {
  134     nd_ipv6 network;
  135     nd_ipv6 mask;
  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     nd_ipv4     neighbor;
  179     nd_uint8_t  link_quality;
  180     nd_uint8_t  neighbor_link_quality;
  181     nd_byte     res[2];
  182 };
  183 
  184 struct olsr_lq_neighbor6 {
  185     nd_ipv6     neighbor;
  186     nd_uint8_t  link_quality;
  187     nd_uint8_t  neighbor_link_quality;
  188     nd_byte     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     exp--;
  219   }
  220   return speed;
  221 }
  222 
  223 /*
  224  * macro to convert the 8-bit mantissa/exponent to a double float
  225  * taken from olsr.org.
  226  */
  227 #define VTIME_SCALE_FACTOR    0.0625
  228 #define ME_TO_DOUBLE(me) \
  229   (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F)))
  230 
  231 /*
  232  * print a neighbor list with LQ extensions.
  233  */
  234 static int
  235 olsr_print_lq_neighbor4(netdissect_options *ndo,
  236                         const u_char *msg_data, u_int hello_len)
  237 {
  238     const struct olsr_lq_neighbor4 *lq_neighbor;
  239 
  240     while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {
  241 
  242         lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data;
  243         ND_TCHECK_SIZE(lq_neighbor);
  244 
  245         ND_PRINT("\n\t      neighbor %s, link-quality %.2f%%"
  246                ", neighbor-link-quality %.2f%%",
  247                GET_IPADDR_STRING(lq_neighbor->neighbor),
  248                ((double) GET_U_1(lq_neighbor->link_quality)/2.55),
  249                ((double) GET_U_1(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 trunc:
  256     return -1;
  257 }
  258 
  259 static int
  260 olsr_print_lq_neighbor6(netdissect_options *ndo,
  261                         const u_char *msg_data, u_int hello_len)
  262 {
  263     const struct olsr_lq_neighbor6 *lq_neighbor;
  264 
  265     while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {
  266 
  267         lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data;
  268         ND_TCHECK_SIZE(lq_neighbor);
  269 
  270         ND_PRINT("\n\t      neighbor %s, link-quality %.2f%%"
  271                ", neighbor-link-quality %.2f%%",
  272                GET_IP6ADDR_STRING(lq_neighbor->neighbor),
  273                ((double) GET_U_1(lq_neighbor->link_quality)/2.55),
  274                ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55));
  275 
  276         msg_data += sizeof(struct olsr_lq_neighbor6);
  277         hello_len -= sizeof(struct olsr_lq_neighbor6);
  278     }
  279     return (0);
  280 trunc:
  281     return -1;
  282 }
  283 
  284 /*
  285  * print a neighbor list.
  286  */
  287 static int
  288 olsr_print_neighbor(netdissect_options *ndo,
  289                     const u_char *msg_data, u_int hello_len)
  290 {
  291     int neighbor;
  292 
  293     ND_PRINT("\n\t      neighbor\n\t\t");
  294     neighbor = 1;
  295 
  296     while (hello_len >= sizeof(nd_ipv4)) {
  297         /* print 4 neighbors per line */
  298         ND_PRINT("%s%s", GET_IPADDR_STRING(msg_data),
  299                neighbor % 4 == 0 ? "\n\t\t" : " ");
  300 
  301         msg_data += sizeof(nd_ipv4);
  302         hello_len -= sizeof(nd_ipv4);
  303     }
  304     return (0);
  305 }
  306 
  307 
  308 void
  309 olsr_print(netdissect_options *ndo,
  310            const u_char *pptr, u_int length, int is_ipv6)
  311 {
  312     union {
  313         const struct olsr_common *common;
  314         const struct olsr_msg4 *msg4;
  315         const struct olsr_msg6 *msg6;
  316         const struct olsr_hello *hello;
  317         const struct olsr_hello_link *hello_link;
  318         const struct olsr_tc *tc;
  319         const struct olsr_hna4 *hna;
  320     } ptr;
  321 
  322     u_int msg_type, msg_len, msg_tlen, hello_len;
  323     uint16_t name_entry_type, name_entry_len;
  324     u_int name_entry_padding;
  325     uint8_t link_type, neighbor_type;
  326     const u_char *tptr, *msg_data;
  327 
  328     ndo->ndo_protocol = "olsr";
  329     tptr = pptr;
  330 
  331     nd_print_protocol_caps(ndo);
  332     ND_PRINT("v%u", (is_ipv6) ? 6 : 4);
  333 
  334     if (length < sizeof(struct olsr_common)) {
  335         goto trunc;
  336     }
  337 
  338     ND_TCHECK_LEN(tptr, sizeof(struct olsr_common));
  339 
  340     ptr.common = (const struct olsr_common *)tptr;
  341     length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len));
  342 
  343     ND_PRINT(", seq 0x%04x, length %u",
  344             GET_BE_U_2(ptr.common->packet_seq),
  345             length);
  346 
  347     tptr += sizeof(struct olsr_common);
  348 
  349     /*
  350      * In non-verbose mode, just print version.
  351      */
  352     if (ndo->ndo_vflag < 1) {
  353         return;
  354     }
  355 
  356     while (tptr < (pptr+length)) {
  357         union
  358         {
  359             const struct olsr_msg4 *v4;
  360             const struct olsr_msg6 *v6;
  361         } msgptr;
  362         int msg_len_valid = 0;
  363 
  364         if (is_ipv6)
  365         {
  366             ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg6));
  367             msgptr.v6 = (const struct olsr_msg6 *) tptr;
  368             msg_type = GET_U_1(msgptr.v6->msg_type);
  369             msg_len = GET_BE_U_2(msgptr.v6->msg_len);
  370             if ((msg_len >= sizeof (struct olsr_msg6))
  371                     && (msg_len <= length))
  372                 msg_len_valid = 1;
  373 
  374             /* infinite loop check */
  375             if (msg_type == 0 || msg_len == 0) {
  376                 return;
  377             }
  378 
  379             ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
  380                     "\n\t  vtime %.3fs, msg-seq 0x%04x, length %u%s",
  381                     tok2str(olsr_msg_values, "Unknown", msg_type),
  382                     msg_type, GET_IP6ADDR_STRING(msgptr.v6->originator),
  383                     GET_U_1(msgptr.v6->ttl),
  384                     GET_U_1(msgptr.v6->hopcount),
  385                     ME_TO_DOUBLE(GET_U_1(msgptr.v6->vtime)),
  386                     GET_BE_U_2(msgptr.v6->msg_seq),
  387                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
  388             if (!msg_len_valid) {
  389                 return;
  390             }
  391 
  392             msg_tlen = msg_len - sizeof(struct olsr_msg6);
  393             msg_data = tptr + sizeof(struct olsr_msg6);
  394         }
  395         else /* (!is_ipv6) */
  396         {
  397             ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg4));
  398             msgptr.v4 = (const struct olsr_msg4 *) tptr;
  399             msg_type = GET_U_1(msgptr.v4->msg_type);
  400             msg_len = GET_BE_U_2(msgptr.v4->msg_len);
  401             if ((msg_len >= sizeof (struct olsr_msg4))
  402                     && (msg_len <= length))
  403                 msg_len_valid = 1;
  404 
  405             /* infinite loop check */
  406             if (msg_type == 0 || msg_len == 0) {
  407                 return;
  408             }
  409 
  410             ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
  411                     "\n\t  vtime %.3fs, msg-seq 0x%04x, length %u%s",
  412                     tok2str(olsr_msg_values, "Unknown", msg_type),
  413                     msg_type, GET_IPADDR_STRING(msgptr.v4->originator),
  414                     GET_U_1(msgptr.v4->ttl),
  415                     GET_U_1(msgptr.v4->hopcount),
  416                     ME_TO_DOUBLE(GET_U_1(msgptr.v4->vtime)),
  417                     GET_BE_U_2(msgptr.v4->msg_seq),
  418                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
  419             if (!msg_len_valid) {
  420                 return;
  421             }
  422 
  423             msg_tlen = msg_len - sizeof(struct olsr_msg4);
  424             msg_data = tptr + sizeof(struct olsr_msg4);
  425         }
  426 
  427         switch (msg_type) {
  428         case OLSR_HELLO_MSG:
  429         case OLSR_HELLO_LQ_MSG:
  430             if (msg_tlen < sizeof(struct olsr_hello))
  431                 goto trunc;
  432             ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello));
  433 
  434             ptr.hello = (const struct olsr_hello *)msg_data;
  435             ND_PRINT("\n\t  hello-time %.3fs, MPR willingness %u",
  436                    ME_TO_DOUBLE(GET_U_1(ptr.hello->htime)),
  437                    GET_U_1(ptr.hello->will));
  438             msg_data += sizeof(struct olsr_hello);
  439             msg_tlen -= sizeof(struct olsr_hello);
  440 
  441             while (msg_tlen >= sizeof(struct olsr_hello_link)) {
  442                 int hello_len_valid = 0;
  443 
  444                 /*
  445                  * link-type.
  446                  */
  447                 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello_link));
  448 
  449                 ptr.hello_link = (const struct olsr_hello_link *)msg_data;
  450 
  451                 hello_len = GET_BE_U_2(ptr.hello_link->len);
  452                 link_type = OLSR_EXTRACT_LINK_TYPE(GET_U_1(ptr.hello_link->link_code));
  453                 neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(GET_U_1(ptr.hello_link->link_code));
  454 
  455                 if ((hello_len <= msg_tlen)
  456                         && (hello_len >= sizeof(struct olsr_hello_link)))
  457                     hello_len_valid = 1;
  458 
  459                 ND_PRINT("\n\t    link-type %s, neighbor-type %s, len %u%s",
  460                        tok2str(olsr_link_type_values, "Unknown", link_type),
  461                        tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type),
  462                        hello_len,
  463                        (hello_len_valid == 0) ? " (invalid)" : "");
  464 
  465                 if (hello_len_valid == 0)
  466                     break;
  467 
  468                 msg_data += sizeof(struct olsr_hello_link);
  469                 msg_tlen -= sizeof(struct olsr_hello_link);
  470                 hello_len -= sizeof(struct olsr_hello_link);
  471 
  472                 ND_TCHECK_LEN(msg_data, hello_len);
  473                 if (msg_type == OLSR_HELLO_MSG) {
  474                     if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1)
  475                         goto trunc;
  476                 } else {
  477                     if (is_ipv6) {
  478                         if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1)
  479                             goto trunc;
  480                     } else {
  481                         if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1)
  482                             goto trunc;
  483                     }
  484                 }
  485 
  486                 msg_data += hello_len;
  487                 msg_tlen -= hello_len;
  488             }
  489             break;
  490 
  491         case OLSR_TC_MSG:
  492         case OLSR_TC_LQ_MSG:
  493             if (msg_tlen < sizeof(struct olsr_tc))
  494                 goto trunc;
  495             ND_TCHECK_LEN(msg_data, sizeof(struct olsr_tc));
  496 
  497             ptr.tc = (const struct olsr_tc *)msg_data;
  498             ND_PRINT("\n\t    advertised neighbor seq 0x%04x",
  499                    GET_BE_U_2(ptr.tc->ans_seq));
  500             msg_data += sizeof(struct olsr_tc);
  501             msg_tlen -= sizeof(struct olsr_tc);
  502 
  503             if (msg_type == OLSR_TC_MSG) {
  504                 if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1)
  505                     goto trunc;
  506             } else {
  507                 if (is_ipv6) {
  508                     if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1)
  509                         goto trunc;
  510                 } else {
  511                     if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1)
  512                         goto trunc;
  513                 }
  514             }
  515             break;
  516 
  517         case OLSR_MID_MSG:
  518         {
  519             u_int addr_size = (u_int)sizeof(nd_ipv4);
  520 
  521             if (is_ipv6)
  522                 addr_size = (u_int)sizeof(nd_ipv6);
  523 
  524             while (msg_tlen >= addr_size) {
  525                 ND_TCHECK_LEN(msg_data, addr_size);
  526                 ND_PRINT("\n\t  interface address %s",
  527                         is_ipv6 ? GET_IP6ADDR_STRING(msg_data) :
  528                         GET_IPADDR_STRING(msg_data));
  529 
  530                 msg_data += addr_size;
  531                 msg_tlen -= addr_size;
  532             }
  533             break;
  534         }
  535 
  536         case OLSR_HNA_MSG:
  537             if (is_ipv6)
  538             {
  539                 int i = 0;
  540 
  541                 ND_PRINT("\n\t  Advertised networks (total %u)",
  542                         (unsigned int) (msg_tlen / sizeof(struct olsr_hna6)));
  543 
  544                 while (msg_tlen >= sizeof(struct olsr_hna6)) {
  545                     const struct olsr_hna6 *hna6;
  546 
  547                     ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna6));
  548 
  549                     hna6 = (const struct olsr_hna6 *)msg_data;
  550 
  551                     ND_PRINT("\n\t    #%i: %s/%u",
  552                             i, GET_IP6ADDR_STRING(hna6->network),
  553                             mask62plen (hna6->mask));
  554 
  555                     msg_data += sizeof(struct olsr_hna6);
  556                     msg_tlen -= sizeof(struct olsr_hna6);
  557                 }
  558             }
  559             else
  560             {
  561                 int col = 0;
  562 
  563                 ND_PRINT("\n\t  Advertised networks (total %u)",
  564                         (unsigned int) (msg_tlen / sizeof(struct olsr_hna4)));
  565 
  566                 while (msg_tlen >= sizeof(struct olsr_hna4)) {
  567                     ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna4));
  568 
  569                     ptr.hna = (const struct olsr_hna4 *)msg_data;
  570 
  571                     /* print 4 prefixes per line */
  572                     if (!ptr.hna->network[0] && !ptr.hna->network[1] &&
  573                         !ptr.hna->network[2] && !ptr.hna->network[3] &&
  574                         !ptr.hna->mask[GW_HNA_PAD] &&
  575                         ptr.hna->mask[GW_HNA_FLAGS]) {
  576                             /* smart gateway */
  577                             ND_PRINT("%sSmart-Gateway:%s%s%s%s%s %u/%u",
  578                                 col == 0 ? "\n\t    " : ", ", /* indent */
  579                                 /* sgw */
  580                                 /* LINKSPEED */
  581                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  582                                  GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "",
  583                                 /* IPV4 */
  584                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  585                                  GW_HNA_FLAG_IPV4) ? " IPV4" : "",
  586                                 /* IPV4-NAT */
  587                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  588                                  GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "",
  589                                 /* IPV6 */
  590                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  591                                  GW_HNA_FLAG_IPV6) ? " IPV6" : "",
  592                                 /* IPv6PREFIX */
  593                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  594                                  GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "",
  595                                 /* uplink */
  596                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  597                                  GW_HNA_FLAG_LINKSPEED) ?
  598                                  deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0,
  599                                 /* downlink */
  600                                 (ptr.hna->mask[GW_HNA_FLAGS] &
  601                                  GW_HNA_FLAG_LINKSPEED) ?
  602                                  deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0
  603                                 );
  604                     } else {
  605                         /* normal route */
  606                         ND_PRINT("%s%s/%u",
  607                                 col == 0 ? "\n\t    " : ", ",
  608                                 GET_IPADDR_STRING(ptr.hna->network),
  609                                 mask2plen(GET_BE_U_4(ptr.hna->mask)));
  610                     }
  611 
  612                     msg_data += sizeof(struct olsr_hna4);
  613                     msg_tlen -= sizeof(struct olsr_hna4);
  614 
  615                     col = (col + 1) % 4;
  616                 }
  617             }
  618             break;
  619 
  620         case OLSR_NAMESERVICE_MSG:
  621         {
  622             u_int name_entries;
  623             u_int addr_size;
  624             int name_entries_valid;
  625             u_int i;
  626 
  627             if (msg_tlen < 4)
  628                 goto trunc;
  629 
  630             name_entries = GET_BE_U_2(msg_data + 2);
  631             addr_size = 4;
  632             if (is_ipv6)
  633                 addr_size = 16;
  634 
  635             name_entries_valid = 0;
  636             if ((name_entries > 0)
  637                     && ((name_entries * (4 + addr_size)) <= msg_tlen))
  638                 name_entries_valid = 1;
  639 
  640             ND_PRINT("\n\t  Version %u, Entries %u%s",
  641                    GET_BE_U_2(msg_data),
  642                    name_entries, (name_entries_valid == 0) ? " (invalid)" : "");
  643 
  644             if (name_entries_valid == 0)
  645                 break;
  646 
  647             msg_data += 4;
  648             msg_tlen -= 4;
  649 
  650             for (i = 0; i < name_entries; i++) {
  651                 int name_entry_len_valid = 0;
  652 
  653                 if (msg_tlen < 4)
  654                     break;
  655 
  656                 name_entry_type = GET_BE_U_2(msg_data);
  657                 name_entry_len = GET_BE_U_2(msg_data + 2);
  658 
  659                 msg_data += 4;
  660                 msg_tlen -= 4;
  661 
  662                 if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen))
  663                     name_entry_len_valid = 1;
  664 
  665                 ND_PRINT("\n\t    #%u: type %#06x, length %u%s",
  666                         (unsigned int) i, name_entry_type,
  667                         name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : "");
  668 
  669                 if (name_entry_len_valid == 0)
  670                     break;
  671 
  672                 /* 32-bit alignment */
  673                 name_entry_padding = 0;
  674                 if (name_entry_len%4 != 0)
  675                     name_entry_padding = 4-(name_entry_len%4);
  676 
  677                 if (msg_tlen < addr_size + name_entry_len + name_entry_padding)
  678                     goto trunc;
  679 
  680                 ND_TCHECK_LEN(msg_data,
  681                               addr_size + name_entry_len + name_entry_padding);
  682 
  683                 if (is_ipv6)
  684                     ND_PRINT(", address %s, name \"",
  685                             GET_IP6ADDR_STRING(msg_data));
  686                 else
  687                     ND_PRINT(", address %s, name \"",
  688                             GET_IPADDR_STRING(msg_data));
  689                 (void)nd_printn(ndo, msg_data + addr_size, name_entry_len, NULL);
  690                 ND_PRINT("\"");
  691 
  692                 msg_data += addr_size + name_entry_len + name_entry_padding;
  693                 msg_tlen -= addr_size + name_entry_len + name_entry_padding;
  694             } /* for (i = 0; i < name_entries; i++) */
  695             break;
  696         } /* case OLSR_NAMESERVICE_MSG */
  697 
  698             /*
  699              * FIXME those are the defined messages that lack a decoder
  700              * you are welcome to contribute code ;-)
  701              */
  702         case OLSR_POWERINFO_MSG:
  703         default:
  704             print_unknown_data(ndo, msg_data, "\n\t    ", msg_tlen);
  705             break;
  706         } /* switch (msg_type) */
  707         tptr += msg_len;
  708     } /* while (tptr < (pptr+length)) */
  709 
  710     return;
  711 
  712  trunc:
  713     nd_print_trunc(ndo);
  714 }