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