xref: /netbsd-src/external/bsd/tcpdump/dist/print-olsr.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1998-2007 The TCPDUMP project
30f74e101Schristos  * Copyright (c) 2009  Florian Forster
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code
70f74e101Schristos  * distributions retain the above copyright notice and this paragraph
80f74e101Schristos  * in its entirety, and (2) distributions including binary code include
90f74e101Schristos  * the above copyright notice and this paragraph in its entirety in
100f74e101Schristos  * the documentation or other materials provided with the distribution.
110f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
120f74e101Schristos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
130f74e101Schristos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
140f74e101Schristos  * FOR A PARTICULAR PURPOSE.
150f74e101Schristos  *
1672c96ff3Schristos  * Original code by Hannes Gredler <hannes@gredler.at>
170f74e101Schristos  * IPv6 additions by Florian Forster <octo at verplant.org>
180f74e101Schristos  */
190f74e101Schristos 
20dc860a36Sspz /* \summary: Optimized Link State Routing Protocol (OLSR) printer */
21dc860a36Sspz 
22dc860a36Sspz /* specification: RFC 3626 */
23dc860a36Sspz 
24fdccd7e4Schristos #include <sys/cdefs.h>
25fdccd7e4Schristos #ifndef lint
26*26ba0b50Schristos __RCSID("$NetBSD: print-olsr.c,v 1.6 2024/09/02 16:15:32 christos Exp $");
27fdccd7e4Schristos #endif
28fdccd7e4Schristos 
29c74ad251Schristos #include <config.h>
300f74e101Schristos 
31c74ad251Schristos #include "netdissect-stdinc.h"
320f74e101Schristos 
33784088dfSchristos #include "netdissect.h"
340f74e101Schristos #include "addrtoname.h"
350f74e101Schristos #include "extract.h"
360f74e101Schristos 
370f74e101Schristos /*
380f74e101Schristos  * RFC 3626 common header
390f74e101Schristos  *
400f74e101Schristos  *  0                   1                   2                   3
410f74e101Schristos  *  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
420f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
430f74e101Schristos  * |         Packet Length         |    Packet Sequence Number     |
440f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
450f74e101Schristos  * |  Message Type |     Vtime     |         Message Size          |
460f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
470f74e101Schristos  * |                      Originator Address                       |
480f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
490f74e101Schristos  * |  Time To Live |   Hop Count   |    Message Sequence Number    |
500f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510f74e101Schristos  * |                                                               |
520f74e101Schristos  * :                            MESSAGE                            :
530f74e101Schristos  * |                                                               |
540f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
550f74e101Schristos  * |  Message Type |     Vtime     |         Message Size          |
560f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570f74e101Schristos  * |                      Originator Address                       |
580f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590f74e101Schristos  * |  Time To Live |   Hop Count   |    Message Sequence Number    |
600f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
610f74e101Schristos  * |                                                               |
620f74e101Schristos  * :                            MESSAGE                            :
630f74e101Schristos  * |                                                               |
640f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
650f74e101Schristos  * :                                                               :
660f74e101Schristos  */
670f74e101Schristos 
680f74e101Schristos struct olsr_common {
69c74ad251Schristos     nd_uint16_t packet_len;
70c74ad251Schristos     nd_uint16_t packet_seq;
710f74e101Schristos };
720f74e101Schristos 
730f74e101Schristos #define OLSR_HELLO_MSG         1 /* rfc3626 */
740f74e101Schristos #define OLSR_TC_MSG            2 /* rfc3626 */
750f74e101Schristos #define OLSR_MID_MSG           3 /* rfc3626 */
760f74e101Schristos #define OLSR_HNA_MSG           4 /* rfc3626 */
770f74e101Schristos #define OLSR_POWERINFO_MSG   128
780f74e101Schristos #define OLSR_NAMESERVICE_MSG 130
790f74e101Schristos #define OLSR_HELLO_LQ_MSG    201 /* LQ extensions olsr.org */
800f74e101Schristos #define OLSR_TC_LQ_MSG       202 /* LQ extensions olsr.org */
810f74e101Schristos 
82026d7285Schristos static const struct tok olsr_msg_values[] = {
830f74e101Schristos     { OLSR_HELLO_MSG, "Hello" },
840f74e101Schristos     { OLSR_TC_MSG, "TC" },
850f74e101Schristos     { OLSR_MID_MSG, "MID" },
860f74e101Schristos     { OLSR_HNA_MSG, "HNA" },
870f74e101Schristos     { OLSR_POWERINFO_MSG, "Powerinfo" },
880f74e101Schristos     { OLSR_NAMESERVICE_MSG, "Nameservice" },
890f74e101Schristos     { OLSR_HELLO_LQ_MSG, "Hello-LQ" },
900f74e101Schristos     { OLSR_TC_LQ_MSG, "TC-LQ" },
910f74e101Schristos     { 0, NULL}
920f74e101Schristos };
930f74e101Schristos 
940f74e101Schristos struct olsr_msg4 {
95c74ad251Schristos     nd_uint8_t  msg_type;
96c74ad251Schristos     nd_uint8_t  vtime;
97c74ad251Schristos     nd_uint16_t msg_len;
98c74ad251Schristos     nd_ipv4     originator;
99c74ad251Schristos     nd_uint8_t  ttl;
100c74ad251Schristos     nd_uint8_t  hopcount;
101c74ad251Schristos     nd_uint16_t msg_seq;
1020f74e101Schristos };
1030f74e101Schristos 
1040f74e101Schristos struct olsr_msg6 {
105c74ad251Schristos     nd_uint8_t  msg_type;
106c74ad251Schristos     nd_uint8_t  vtime;
107c74ad251Schristos     nd_uint16_t msg_len;
108c74ad251Schristos     nd_ipv6     originator;
109c74ad251Schristos     nd_uint8_t  ttl;
110c74ad251Schristos     nd_uint8_t  hopcount;
111c74ad251Schristos     nd_uint16_t msg_seq;
1120f74e101Schristos };
1130f74e101Schristos 
1140f74e101Schristos struct olsr_hello {
115c74ad251Schristos     nd_byte     res[2];
116c74ad251Schristos     nd_uint8_t  htime;
117c74ad251Schristos     nd_uint8_t  will;
1180f74e101Schristos };
1190f74e101Schristos 
1200f74e101Schristos struct olsr_hello_link {
121c74ad251Schristos     nd_uint8_t  link_code;
122c74ad251Schristos     nd_byte     res;
123c74ad251Schristos     nd_uint16_t len;
1240f74e101Schristos };
1250f74e101Schristos 
1260f74e101Schristos struct olsr_tc {
127c74ad251Schristos     nd_uint16_t ans_seq;
128c74ad251Schristos     nd_byte     res[2];
1290f74e101Schristos };
1300f74e101Schristos 
1310f74e101Schristos struct olsr_hna4 {
132c74ad251Schristos     nd_ipv4 network;
133c74ad251Schristos     nd_ipv4 mask;
1340f74e101Schristos };
1350f74e101Schristos 
1360f74e101Schristos struct olsr_hna6 {
137c74ad251Schristos     nd_ipv6 network;
138c74ad251Schristos     nd_ipv6 mask;
1390f74e101Schristos };
1400f74e101Schristos 
1410f74e101Schristos 
142784088dfSchristos /** gateway HNA flags */
143784088dfSchristos enum gateway_hna_flags {
144784088dfSchristos   GW_HNA_FLAG_LINKSPEED   = 1 << 0,
145784088dfSchristos   GW_HNA_FLAG_IPV4        = 1 << 1,
146784088dfSchristos   GW_HNA_FLAG_IPV4_NAT    = 1 << 2,
147784088dfSchristos   GW_HNA_FLAG_IPV6        = 1 << 3,
148784088dfSchristos   GW_HNA_FLAG_IPV6PREFIX  = 1 << 4
149784088dfSchristos };
150784088dfSchristos 
151784088dfSchristos /** gateway HNA field byte offsets in the netmask field of the HNA */
152784088dfSchristos enum gateway_hna_fields {
153784088dfSchristos   GW_HNA_PAD              = 0,
154784088dfSchristos   GW_HNA_FLAGS            = 1,
155784088dfSchristos   GW_HNA_UPLINK           = 2,
156784088dfSchristos   GW_HNA_DOWNLINK         = 3,
157784088dfSchristos   GW_HNA_V6PREFIXLEN      = 4,
158784088dfSchristos   GW_HNA_V6PREFIX         = 5
159784088dfSchristos };
160784088dfSchristos 
161784088dfSchristos 
1620f74e101Schristos #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3)
1630f74e101Schristos #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2)
1640f74e101Schristos 
165026d7285Schristos static const struct tok olsr_link_type_values[] = {
1660f74e101Schristos     { 0, "Unspecified" },
1670f74e101Schristos     { 1, "Asymmetric" },
1680f74e101Schristos     { 2, "Symmetric" },
1690f74e101Schristos     { 3, "Lost" },
1700f74e101Schristos     { 0, NULL}
1710f74e101Schristos };
1720f74e101Schristos 
173026d7285Schristos static const struct tok olsr_neighbor_type_values[] = {
1740f74e101Schristos     { 0, "Not-Neighbor" },
1750f74e101Schristos     { 1, "Symmetric" },
1760f74e101Schristos     { 2, "Symmetric-MPR" },
1770f74e101Schristos     { 0, NULL}
1780f74e101Schristos };
1790f74e101Schristos 
1800f74e101Schristos struct olsr_lq_neighbor4 {
181c74ad251Schristos     nd_ipv4     neighbor;
182c74ad251Schristos     nd_uint8_t  link_quality;
183c74ad251Schristos     nd_uint8_t  neighbor_link_quality;
184c74ad251Schristos     nd_byte     res[2];
1850f74e101Schristos };
1860f74e101Schristos 
1870f74e101Schristos struct olsr_lq_neighbor6 {
188c74ad251Schristos     nd_ipv6     neighbor;
189c74ad251Schristos     nd_uint8_t  link_quality;
190c74ad251Schristos     nd_uint8_t  neighbor_link_quality;
191c74ad251Schristos     nd_byte     res[2];
1920f74e101Schristos };
1930f74e101Schristos 
194784088dfSchristos #define MAX_SMARTGW_SPEED    320000000
195784088dfSchristos 
196784088dfSchristos /**
197784088dfSchristos  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
198784088dfSchristos  * to an uplink/downlink speed value
199784088dfSchristos  *
200784088dfSchristos  * @param value the encoded 1 byte transport value
201784088dfSchristos  * @return the uplink/downlink speed value (in kbit/s)
202784088dfSchristos  */
203784088dfSchristos static uint32_t deserialize_gw_speed(uint8_t value) {
204784088dfSchristos   uint32_t speed;
205784088dfSchristos   uint32_t exp;
206784088dfSchristos 
207784088dfSchristos   if (!value) {
208784088dfSchristos     return 0;
209784088dfSchristos   }
210784088dfSchristos 
211784088dfSchristos   if (value == UINT8_MAX) {
212784088dfSchristos     /* maximum value: also return maximum value */
213784088dfSchristos     return MAX_SMARTGW_SPEED;
214784088dfSchristos   }
215784088dfSchristos 
216784088dfSchristos   speed = (value >> 3) + 1;
217784088dfSchristos   exp = value & 7;
218784088dfSchristos 
219c74ad251Schristos   while (exp != 0) {
220784088dfSchristos     speed *= 10;
221c74ad251Schristos     exp--;
222784088dfSchristos   }
223784088dfSchristos   return speed;
224784088dfSchristos }
225784088dfSchristos 
2260f74e101Schristos /*
2270f74e101Schristos  * macro to convert the 8-bit mantissa/exponent to a double float
2280f74e101Schristos  * taken from olsr.org.
2290f74e101Schristos  */
2300f74e101Schristos #define VTIME_SCALE_FACTOR    0.0625
2310f74e101Schristos #define ME_TO_DOUBLE(me) \
2320f74e101Schristos   (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F)))
2330f74e101Schristos 
2340f74e101Schristos /*
2350f74e101Schristos  * print a neighbor list with LQ extensions.
2360f74e101Schristos  */
2373d25ea14Schristos static int
238c47fd378Schristos olsr_print_lq_neighbor4(netdissect_options *ndo,
239c47fd378Schristos                         const u_char *msg_data, u_int hello_len)
2400f74e101Schristos {
241784088dfSchristos     const struct olsr_lq_neighbor4 *lq_neighbor;
2420f74e101Schristos 
2430f74e101Schristos     while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {
2440f74e101Schristos 
245784088dfSchristos         lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data;
246c74ad251Schristos         ND_TCHECK_SIZE(lq_neighbor);
2470f74e101Schristos 
248c74ad251Schristos         ND_PRINT("\n\t      neighbor %s, link-quality %.2f%%"
249784088dfSchristos                ", neighbor-link-quality %.2f%%",
250c74ad251Schristos                GET_IPADDR_STRING(lq_neighbor->neighbor),
251c74ad251Schristos                ((double) GET_U_1(lq_neighbor->link_quality)/2.55),
252c74ad251Schristos                ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55));
2530f74e101Schristos 
2540f74e101Schristos         msg_data += sizeof(struct olsr_lq_neighbor4);
2550f74e101Schristos         hello_len -= sizeof(struct olsr_lq_neighbor4);
2560f74e101Schristos     }
2573d25ea14Schristos     return (0);
258c74ad251Schristos trunc:
259c74ad251Schristos     return -1;
2600f74e101Schristos }
2610f74e101Schristos 
2623d25ea14Schristos static int
263c47fd378Schristos olsr_print_lq_neighbor6(netdissect_options *ndo,
264c47fd378Schristos                         const u_char *msg_data, u_int hello_len)
2650f74e101Schristos {
266784088dfSchristos     const struct olsr_lq_neighbor6 *lq_neighbor;
2670f74e101Schristos 
2680f74e101Schristos     while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {
2690f74e101Schristos 
270784088dfSchristos         lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data;
271c74ad251Schristos         ND_TCHECK_SIZE(lq_neighbor);
2720f74e101Schristos 
273c74ad251Schristos         ND_PRINT("\n\t      neighbor %s, link-quality %.2f%%"
274784088dfSchristos                ", neighbor-link-quality %.2f%%",
275c74ad251Schristos                GET_IP6ADDR_STRING(lq_neighbor->neighbor),
276c74ad251Schristos                ((double) GET_U_1(lq_neighbor->link_quality)/2.55),
277c74ad251Schristos                ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55));
2780f74e101Schristos 
2790f74e101Schristos         msg_data += sizeof(struct olsr_lq_neighbor6);
2800f74e101Schristos         hello_len -= sizeof(struct olsr_lq_neighbor6);
2810f74e101Schristos     }
2823d25ea14Schristos     return (0);
283c74ad251Schristos trunc:
284c74ad251Schristos     return -1;
2850f74e101Schristos }
2860f74e101Schristos 
2870f74e101Schristos /*
2880f74e101Schristos  * print a neighbor list.
2890f74e101Schristos  */
2903d25ea14Schristos static int
291c47fd378Schristos olsr_print_neighbor(netdissect_options *ndo,
292c47fd378Schristos                     const u_char *msg_data, u_int hello_len)
2930f74e101Schristos {
2940f74e101Schristos     int neighbor;
2950f74e101Schristos 
296c74ad251Schristos     ND_PRINT("\n\t      neighbor\n\t\t");
2970f74e101Schristos     neighbor = 1;
2980f74e101Schristos 
299c74ad251Schristos     while (hello_len >= sizeof(nd_ipv4)) {
3000f74e101Schristos         /* print 4 neighbors per line */
301c74ad251Schristos         ND_PRINT("%s%s", GET_IPADDR_STRING(msg_data),
302c74ad251Schristos                neighbor % 4 == 0 ? "\n\t\t" : " ");
3030f74e101Schristos 
304c74ad251Schristos         msg_data += sizeof(nd_ipv4);
305c74ad251Schristos         hello_len -= sizeof(nd_ipv4);
3060f74e101Schristos     }
3073d25ea14Schristos     return (0);
3080f74e101Schristos }
3090f74e101Schristos 
3100f74e101Schristos 
3110f74e101Schristos void
312c47fd378Schristos olsr_print(netdissect_options *ndo,
313c47fd378Schristos            const u_char *pptr, u_int length, int is_ipv6)
3140f74e101Schristos {
3150f74e101Schristos     union {
3160f74e101Schristos         const struct olsr_common *common;
3170f74e101Schristos         const struct olsr_msg4 *msg4;
3180f74e101Schristos         const struct olsr_msg6 *msg6;
3190f74e101Schristos         const struct olsr_hello *hello;
3200f74e101Schristos         const struct olsr_hello_link *hello_link;
3210f74e101Schristos         const struct olsr_tc *tc;
3220f74e101Schristos         const struct olsr_hna4 *hna;
3230f74e101Schristos     } ptr;
3240f74e101Schristos 
3250f74e101Schristos     u_int msg_type, msg_len, msg_tlen, hello_len;
326c47fd378Schristos     uint16_t name_entry_type, name_entry_len;
3270f74e101Schristos     u_int name_entry_padding;
328c47fd378Schristos     uint8_t link_type, neighbor_type;
3290f74e101Schristos     const u_char *tptr, *msg_data;
3300f74e101Schristos 
331c74ad251Schristos     ndo->ndo_protocol = "olsr";
3320f74e101Schristos     tptr = pptr;
3330f74e101Schristos 
334c74ad251Schristos     nd_print_protocol_caps(ndo);
335c74ad251Schristos     ND_PRINT("v%u", (is_ipv6) ? 6 : 4);
336c74ad251Schristos 
3370f74e101Schristos     if (length < sizeof(struct olsr_common)) {
3380f74e101Schristos         goto trunc;
3390f74e101Schristos     }
3400f74e101Schristos 
341c74ad251Schristos     ND_TCHECK_LEN(tptr, sizeof(struct olsr_common));
3420f74e101Schristos 
343784088dfSchristos     ptr.common = (const struct olsr_common *)tptr;
344c74ad251Schristos     length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len));
3450f74e101Schristos 
346c74ad251Schristos     ND_PRINT(", seq 0x%04x, length %u",
347c74ad251Schristos             GET_BE_U_2(ptr.common->packet_seq),
348c74ad251Schristos             length);
3490f74e101Schristos 
3500f74e101Schristos     tptr += sizeof(struct olsr_common);
3510f74e101Schristos 
3520f74e101Schristos     /*
3530f74e101Schristos      * In non-verbose mode, just print version.
3540f74e101Schristos      */
355c47fd378Schristos     if (ndo->ndo_vflag < 1) {
3560f74e101Schristos         return;
3570f74e101Schristos     }
3580f74e101Schristos 
3590f74e101Schristos     while (tptr < (pptr+length)) {
3600f74e101Schristos         union
3610f74e101Schristos         {
362784088dfSchristos             const struct olsr_msg4 *v4;
363784088dfSchristos             const struct olsr_msg6 *v6;
3640f74e101Schristos         } msgptr;
3650f74e101Schristos         int msg_len_valid = 0;
3660f74e101Schristos 
367*26ba0b50Schristos         if (is_ipv6) {
368c74ad251Schristos             ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg6));
369784088dfSchristos             msgptr.v6 = (const struct olsr_msg6 *) tptr;
370c74ad251Schristos             msg_type = GET_U_1(msgptr.v6->msg_type);
371c74ad251Schristos             msg_len = GET_BE_U_2(msgptr.v6->msg_len);
3720f74e101Schristos             if ((msg_len >= sizeof (struct olsr_msg6))
3730f74e101Schristos                     && (msg_len <= length))
3740f74e101Schristos                 msg_len_valid = 1;
3750f74e101Schristos 
3760f74e101Schristos             /* infinite loop check */
3770f74e101Schristos             if (msg_type == 0 || msg_len == 0) {
3780f74e101Schristos                 return;
3790f74e101Schristos             }
3800f74e101Schristos 
381c74ad251Schristos             ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
382784088dfSchristos                     "\n\t  vtime %.3fs, msg-seq 0x%04x, length %u%s",
3830f74e101Schristos                     tok2str(olsr_msg_values, "Unknown", msg_type),
384c74ad251Schristos                     msg_type, GET_IP6ADDR_STRING(msgptr.v6->originator),
385c74ad251Schristos                     GET_U_1(msgptr.v6->ttl),
386c74ad251Schristos                     GET_U_1(msgptr.v6->hopcount),
387c74ad251Schristos                     ME_TO_DOUBLE(GET_U_1(msgptr.v6->vtime)),
388c74ad251Schristos                     GET_BE_U_2(msgptr.v6->msg_seq),
389c74ad251Schristos                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
3903d25ea14Schristos             if (!msg_len_valid) {
3913d25ea14Schristos                 return;
3923d25ea14Schristos             }
3930f74e101Schristos 
3940f74e101Schristos             msg_tlen = msg_len - sizeof(struct olsr_msg6);
3950f74e101Schristos             msg_data = tptr + sizeof(struct olsr_msg6);
396*26ba0b50Schristos         } else {	/* (!is_ipv6) */
397c74ad251Schristos             ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg4));
398784088dfSchristos             msgptr.v4 = (const struct olsr_msg4 *) tptr;
399c74ad251Schristos             msg_type = GET_U_1(msgptr.v4->msg_type);
400c74ad251Schristos             msg_len = GET_BE_U_2(msgptr.v4->msg_len);
4010f74e101Schristos             if ((msg_len >= sizeof (struct olsr_msg4))
4020f74e101Schristos                     && (msg_len <= length))
4030f74e101Schristos                 msg_len_valid = 1;
4040f74e101Schristos 
4050f74e101Schristos             /* infinite loop check */
4060f74e101Schristos             if (msg_type == 0 || msg_len == 0) {
4070f74e101Schristos                 return;
4080f74e101Schristos             }
4090f74e101Schristos 
410c74ad251Schristos             ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
411784088dfSchristos                     "\n\t  vtime %.3fs, msg-seq 0x%04x, length %u%s",
4120f74e101Schristos                     tok2str(olsr_msg_values, "Unknown", msg_type),
413c74ad251Schristos                     msg_type, GET_IPADDR_STRING(msgptr.v4->originator),
414c74ad251Schristos                     GET_U_1(msgptr.v4->ttl),
415c74ad251Schristos                     GET_U_1(msgptr.v4->hopcount),
416c74ad251Schristos                     ME_TO_DOUBLE(GET_U_1(msgptr.v4->vtime)),
417c74ad251Schristos                     GET_BE_U_2(msgptr.v4->msg_seq),
418c74ad251Schristos                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
4193d25ea14Schristos             if (!msg_len_valid) {
4203d25ea14Schristos                 return;
4213d25ea14Schristos             }
4220f74e101Schristos 
4230f74e101Schristos             msg_tlen = msg_len - sizeof(struct olsr_msg4);
4240f74e101Schristos             msg_data = tptr + sizeof(struct olsr_msg4);
4250f74e101Schristos         }
4260f74e101Schristos 
4270f74e101Schristos         switch (msg_type) {
4280f74e101Schristos         case OLSR_HELLO_MSG:
4290f74e101Schristos         case OLSR_HELLO_LQ_MSG:
4303d25ea14Schristos             if (msg_tlen < sizeof(struct olsr_hello))
4313d25ea14Schristos                 goto trunc;
432c74ad251Schristos             ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello));
4330f74e101Schristos 
434784088dfSchristos             ptr.hello = (const struct olsr_hello *)msg_data;
435c74ad251Schristos             ND_PRINT("\n\t  hello-time %.3fs, MPR willingness %u",
436c74ad251Schristos                    ME_TO_DOUBLE(GET_U_1(ptr.hello->htime)),
437c74ad251Schristos                    GET_U_1(ptr.hello->will));
4380f74e101Schristos             msg_data += sizeof(struct olsr_hello);
4390f74e101Schristos             msg_tlen -= sizeof(struct olsr_hello);
4400f74e101Schristos 
4410f74e101Schristos             while (msg_tlen >= sizeof(struct olsr_hello_link)) {
4420f74e101Schristos                 int hello_len_valid = 0;
4430f74e101Schristos 
4440f74e101Schristos                 /*
4450f74e101Schristos                  * link-type.
4460f74e101Schristos                  */
447c74ad251Schristos                 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello_link));
4480f74e101Schristos 
449784088dfSchristos                 ptr.hello_link = (const struct olsr_hello_link *)msg_data;
4500f74e101Schristos 
451c74ad251Schristos                 hello_len = GET_BE_U_2(ptr.hello_link->len);
452c74ad251Schristos                 link_type = OLSR_EXTRACT_LINK_TYPE(GET_U_1(ptr.hello_link->link_code));
453c74ad251Schristos                 neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(GET_U_1(ptr.hello_link->link_code));
4540f74e101Schristos 
4550f74e101Schristos                 if ((hello_len <= msg_tlen)
4560f74e101Schristos                         && (hello_len >= sizeof(struct olsr_hello_link)))
4570f74e101Schristos                     hello_len_valid = 1;
4580f74e101Schristos 
459c74ad251Schristos                 ND_PRINT("\n\t    link-type %s, neighbor-type %s, len %u%s",
4600f74e101Schristos                        tok2str(olsr_link_type_values, "Unknown", link_type),
4610f74e101Schristos                        tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type),
4620f74e101Schristos                        hello_len,
463c74ad251Schristos                        (hello_len_valid == 0) ? " (invalid)" : "");
4640f74e101Schristos 
4650f74e101Schristos                 if (hello_len_valid == 0)
4660f74e101Schristos                     break;
4670f74e101Schristos 
4680f74e101Schristos                 msg_data += sizeof(struct olsr_hello_link);
4690f74e101Schristos                 msg_tlen -= sizeof(struct olsr_hello_link);
4700f74e101Schristos                 hello_len -= sizeof(struct olsr_hello_link);
4710f74e101Schristos 
472c74ad251Schristos                 ND_TCHECK_LEN(msg_data, hello_len);
4730f74e101Schristos                 if (msg_type == OLSR_HELLO_MSG) {
4743d25ea14Schristos                     if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1)
4753d25ea14Schristos                         goto trunc;
4760f74e101Schristos                 } else {
4773d25ea14Schristos                     if (is_ipv6) {
4783d25ea14Schristos                         if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1)
4793d25ea14Schristos                             goto trunc;
480784088dfSchristos                     } else {
4813d25ea14Schristos                         if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1)
4823d25ea14Schristos                             goto trunc;
4833d25ea14Schristos                     }
4840f74e101Schristos                 }
4850f74e101Schristos 
4860f74e101Schristos                 msg_data += hello_len;
4870f74e101Schristos                 msg_tlen -= hello_len;
4880f74e101Schristos             }
4890f74e101Schristos             break;
4900f74e101Schristos 
4910f74e101Schristos         case OLSR_TC_MSG:
4920f74e101Schristos         case OLSR_TC_LQ_MSG:
4933d25ea14Schristos             if (msg_tlen < sizeof(struct olsr_tc))
4943d25ea14Schristos                 goto trunc;
495c74ad251Schristos             ND_TCHECK_LEN(msg_data, sizeof(struct olsr_tc));
4960f74e101Schristos 
497784088dfSchristos             ptr.tc = (const struct olsr_tc *)msg_data;
498c74ad251Schristos             ND_PRINT("\n\t    advertised neighbor seq 0x%04x",
499c74ad251Schristos                    GET_BE_U_2(ptr.tc->ans_seq));
5000f74e101Schristos             msg_data += sizeof(struct olsr_tc);
5010f74e101Schristos             msg_tlen -= sizeof(struct olsr_tc);
5020f74e101Schristos 
5030f74e101Schristos             if (msg_type == OLSR_TC_MSG) {
5043d25ea14Schristos                 if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1)
5053d25ea14Schristos                     goto trunc;
5060f74e101Schristos             } else {
5073d25ea14Schristos                 if (is_ipv6) {
5083d25ea14Schristos                     if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1)
5093d25ea14Schristos                         goto trunc;
510784088dfSchristos                 } else {
5113d25ea14Schristos                     if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1)
5123d25ea14Schristos                         goto trunc;
5133d25ea14Schristos                 }
5140f74e101Schristos             }
5150f74e101Schristos             break;
5160f74e101Schristos 
5170f74e101Schristos         case OLSR_MID_MSG:
5180f74e101Schristos         {
519c74ad251Schristos             u_int addr_size = (u_int)sizeof(nd_ipv4);
5200f74e101Schristos 
5210f74e101Schristos             if (is_ipv6)
522c74ad251Schristos                 addr_size = (u_int)sizeof(nd_ipv6);
5230f74e101Schristos 
5240f74e101Schristos             while (msg_tlen >= addr_size) {
525c74ad251Schristos                 ND_TCHECK_LEN(msg_data, addr_size);
526c74ad251Schristos                 ND_PRINT("\n\t  interface address %s",
527c74ad251Schristos                         is_ipv6 ? GET_IP6ADDR_STRING(msg_data) :
528c74ad251Schristos                         GET_IPADDR_STRING(msg_data));
529c47fd378Schristos 
5300f74e101Schristos                 msg_data += addr_size;
5310f74e101Schristos                 msg_tlen -= addr_size;
5320f74e101Schristos             }
5330f74e101Schristos             break;
5340f74e101Schristos         }
5350f74e101Schristos 
5360f74e101Schristos         case OLSR_HNA_MSG:
537*26ba0b50Schristos             if (is_ipv6) {
5380f74e101Schristos                 int i = 0;
539784088dfSchristos 
540c74ad251Schristos                 ND_PRINT("\n\t  Advertised networks (total %u)",
541c74ad251Schristos                         (unsigned int) (msg_tlen / sizeof(struct olsr_hna6)));
542784088dfSchristos 
5430f74e101Schristos                 while (msg_tlen >= sizeof(struct olsr_hna6)) {
544784088dfSchristos                     const struct olsr_hna6 *hna6;
5450f74e101Schristos 
546c74ad251Schristos                     ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna6));
5470f74e101Schristos 
548784088dfSchristos                     hna6 = (const struct olsr_hna6 *)msg_data;
5490f74e101Schristos 
550c74ad251Schristos                     ND_PRINT("\n\t    #%i: %s/%u",
551c74ad251Schristos                             i, GET_IP6ADDR_STRING(hna6->network),
552c74ad251Schristos                             mask62plen (hna6->mask));
5530f74e101Schristos 
5540f74e101Schristos                     msg_data += sizeof(struct olsr_hna6);
5550f74e101Schristos                     msg_tlen -= sizeof(struct olsr_hna6);
5560f74e101Schristos                 }
557*26ba0b50Schristos             } else {
5580f74e101Schristos                 int col = 0;
559784088dfSchristos 
560c74ad251Schristos                 ND_PRINT("\n\t  Advertised networks (total %u)",
561c74ad251Schristos                         (unsigned int) (msg_tlen / sizeof(struct olsr_hna4)));
562784088dfSchristos 
5630f74e101Schristos                 while (msg_tlen >= sizeof(struct olsr_hna4)) {
564c74ad251Schristos                     ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna4));
5650f74e101Schristos 
566784088dfSchristos                     ptr.hna = (const struct olsr_hna4 *)msg_data;
5670f74e101Schristos 
5680f74e101Schristos                     /* print 4 prefixes per line */
569784088dfSchristos                     if (!ptr.hna->network[0] && !ptr.hna->network[1] &&
570784088dfSchristos                         !ptr.hna->network[2] && !ptr.hna->network[3] &&
571784088dfSchristos                         !ptr.hna->mask[GW_HNA_PAD] &&
572784088dfSchristos                         ptr.hna->mask[GW_HNA_FLAGS]) {
573784088dfSchristos                             /* smart gateway */
574c74ad251Schristos                             ND_PRINT("%sSmart-Gateway:%s%s%s%s%s %u/%u",
575784088dfSchristos                                 col == 0 ? "\n\t    " : ", ", /* indent */
576784088dfSchristos                                 /* sgw */
577784088dfSchristos                                 /* LINKSPEED */
578784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
579784088dfSchristos                                  GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "",
580784088dfSchristos                                 /* IPV4 */
581784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
582784088dfSchristos                                  GW_HNA_FLAG_IPV4) ? " IPV4" : "",
583784088dfSchristos                                 /* IPV4-NAT */
584784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
585784088dfSchristos                                  GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "",
586784088dfSchristos                                 /* IPV6 */
587784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
588784088dfSchristos                                  GW_HNA_FLAG_IPV6) ? " IPV6" : "",
589784088dfSchristos                                 /* IPv6PREFIX */
590784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
591784088dfSchristos                                  GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "",
592784088dfSchristos                                 /* uplink */
593784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
594784088dfSchristos                                  GW_HNA_FLAG_LINKSPEED) ?
595784088dfSchristos                                  deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0,
596784088dfSchristos                                 /* downlink */
597784088dfSchristos                                 (ptr.hna->mask[GW_HNA_FLAGS] &
598784088dfSchristos                                  GW_HNA_FLAG_LINKSPEED) ?
599784088dfSchristos                                  deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0
600c74ad251Schristos                                 );
601784088dfSchristos                     } else {
602784088dfSchristos                         /* normal route */
603c74ad251Schristos                         ND_PRINT("%s%s/%u",
604c47fd378Schristos                                 col == 0 ? "\n\t    " : ", ",
605c74ad251Schristos                                 GET_IPADDR_STRING(ptr.hna->network),
606c74ad251Schristos                                 mask2plen(GET_BE_U_4(ptr.hna->mask)));
607784088dfSchristos                     }
6080f74e101Schristos 
6090f74e101Schristos                     msg_data += sizeof(struct olsr_hna4);
6100f74e101Schristos                     msg_tlen -= sizeof(struct olsr_hna4);
6110f74e101Schristos 
6120f74e101Schristos                     col = (col + 1) % 4;
6130f74e101Schristos                 }
6140f74e101Schristos             }
6150f74e101Schristos             break;
6160f74e101Schristos 
6170f74e101Schristos         case OLSR_NAMESERVICE_MSG:
6180f74e101Schristos         {
61972c96ff3Schristos             u_int name_entries;
62072c96ff3Schristos             u_int addr_size;
62172c96ff3Schristos             int name_entries_valid;
6220f74e101Schristos             u_int i;
6230f74e101Schristos 
6240f74e101Schristos             if (msg_tlen < 4)
6250f74e101Schristos                 goto trunc;
6260f74e101Schristos 
627c74ad251Schristos             name_entries = GET_BE_U_2(msg_data + 2);
62872c96ff3Schristos             addr_size = 4;
62972c96ff3Schristos             if (is_ipv6)
63072c96ff3Schristos                 addr_size = 16;
63172c96ff3Schristos 
63272c96ff3Schristos             name_entries_valid = 0;
63372c96ff3Schristos             if ((name_entries > 0)
63472c96ff3Schristos                     && ((name_entries * (4 + addr_size)) <= msg_tlen))
63572c96ff3Schristos                 name_entries_valid = 1;
63672c96ff3Schristos 
637c74ad251Schristos             ND_PRINT("\n\t  Version %u, Entries %u%s",
638c74ad251Schristos                    GET_BE_U_2(msg_data),
639c74ad251Schristos                    name_entries, (name_entries_valid == 0) ? " (invalid)" : "");
6400f74e101Schristos 
6410f74e101Schristos             if (name_entries_valid == 0)
6420f74e101Schristos                 break;
6430f74e101Schristos 
6440f74e101Schristos             msg_data += 4;
6450f74e101Schristos             msg_tlen -= 4;
6460f74e101Schristos 
6470f74e101Schristos             for (i = 0; i < name_entries; i++) {
6480f74e101Schristos                 int name_entry_len_valid = 0;
6490f74e101Schristos 
6500f74e101Schristos                 if (msg_tlen < 4)
6510f74e101Schristos                     break;
6520f74e101Schristos 
653c74ad251Schristos                 name_entry_type = GET_BE_U_2(msg_data);
654c74ad251Schristos                 name_entry_len = GET_BE_U_2(msg_data + 2);
6550f74e101Schristos 
6560f74e101Schristos                 msg_data += 4;
6570f74e101Schristos                 msg_tlen -= 4;
6580f74e101Schristos 
6590f74e101Schristos                 if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen))
6600f74e101Schristos                     name_entry_len_valid = 1;
6610f74e101Schristos 
662c74ad251Schristos                 ND_PRINT("\n\t    #%u: type %#06x, length %u%s",
6630f74e101Schristos                         (unsigned int) i, name_entry_type,
664c74ad251Schristos                         name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : "");
6650f74e101Schristos 
6660f74e101Schristos                 if (name_entry_len_valid == 0)
6670f74e101Schristos                     break;
6680f74e101Schristos 
6690f74e101Schristos                 /* 32-bit alignment */
6700f74e101Schristos                 name_entry_padding = 0;
6710f74e101Schristos                 if (name_entry_len%4 != 0)
6720f74e101Schristos                     name_entry_padding = 4-(name_entry_len%4);
6730f74e101Schristos 
6740f74e101Schristos                 if (msg_tlen < addr_size + name_entry_len + name_entry_padding)
6750f74e101Schristos                     goto trunc;
6760f74e101Schristos 
677c74ad251Schristos                 ND_TCHECK_LEN(msg_data,
678c74ad251Schristos                               addr_size + name_entry_len + name_entry_padding);
6790f74e101Schristos 
6800f74e101Schristos                 if (is_ipv6)
681c74ad251Schristos                     ND_PRINT(", address %s, name \"",
682c74ad251Schristos                             GET_IP6ADDR_STRING(msg_data));
6830f74e101Schristos                 else
684c74ad251Schristos                     ND_PRINT(", address %s, name \"",
685c74ad251Schristos                             GET_IPADDR_STRING(msg_data));
686c74ad251Schristos                 (void)nd_printn(ndo, msg_data + addr_size, name_entry_len, NULL);
687c74ad251Schristos                 ND_PRINT("\"");
6880f74e101Schristos 
6890f74e101Schristos                 msg_data += addr_size + name_entry_len + name_entry_padding;
6900f74e101Schristos                 msg_tlen -= addr_size + name_entry_len + name_entry_padding;
6910f74e101Schristos             } /* for (i = 0; i < name_entries; i++) */
6920f74e101Schristos             break;
6930f74e101Schristos         } /* case OLSR_NAMESERVICE_MSG */
6940f74e101Schristos 
6950f74e101Schristos             /*
6960f74e101Schristos              * FIXME those are the defined messages that lack a decoder
6970f74e101Schristos              * you are welcome to contribute code ;-)
6980f74e101Schristos              */
6990f74e101Schristos         case OLSR_POWERINFO_MSG:
7000f74e101Schristos         default:
701c47fd378Schristos             print_unknown_data(ndo, msg_data, "\n\t    ", msg_tlen);
7020f74e101Schristos             break;
7030f74e101Schristos         } /* switch (msg_type) */
7040f74e101Schristos         tptr += msg_len;
7050f74e101Schristos     } /* while (tptr < (pptr+length)) */
7060f74e101Schristos 
7070f74e101Schristos     return;
7080f74e101Schristos 
7090f74e101Schristos  trunc:
710c74ad251Schristos     nd_print_trunc(ndo);
7110f74e101Schristos }
712