GCC47: Add local modifications
[dragonfly.git] / contrib / tcpdump / print-pgm.c
1 /*
2  * Redistribution and use in source and binary forms, with or without
3  * modification, are permitted provided that: (1) source code
4  * distributions retain the above copyright notice and this paragraph
5  * in its entirety, and (2) distributions including binary code include
6  * the above copyright notice and this paragraph in its entirety in
7  * the documentation or other materials provided with the distribution.
8  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11  * FOR A PARTICULAR PURPOSE.
12  *
13  * Original code by Andy Heffernan (ahh@juniper.net)
14  */
15
16 #ifndef lint
17 static const char rcsid[] _U_ =
18     "@(#) $Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.5 2005-06-07 22:05:58 guy Exp $";
19 #endif
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <tcpdump-stdinc.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "interface.h"
32 #include "extract.h"
33 #include "addrtoname.h"
34
35 #include "ip.h"
36 #ifdef INET6
37 #include "ip6.h"
38 #endif
39 #include "ipproto.h"
40
41 /*
42  * PGM header (RFC 3208)
43  */
44 struct pgm_header {
45     u_int16_t   pgm_sport;
46     u_int16_t   pgm_dport;
47     u_int8_t    pgm_type;
48     u_int8_t    pgm_options;
49     u_int16_t   pgm_sum;
50     u_int8_t    pgm_gsid[6];
51     u_int16_t   pgm_length;
52 };
53
54 struct pgm_spm {
55     u_int32_t   pgms_seq;
56     u_int32_t   pgms_trailseq;
57     u_int32_t   pgms_leadseq;
58     u_int16_t   pgms_nla_afi;
59     u_int16_t   pgms_reserved;
60     /* ... u_int8_t     pgms_nla[0]; */
61     /* ... options */
62 };
63
64 struct pgm_nak {
65     u_int32_t   pgmn_seq;
66     u_int16_t   pgmn_source_afi;
67     u_int16_t   pgmn_reserved;
68     /* ... u_int8_t     pgmn_source[0]; */
69     /* ... u_int16_t    pgmn_group_afi */
70     /* ... u_int16_t    pgmn_reserved2; */
71     /* ... u_int8_t     pgmn_group[0]; */
72     /* ... options */
73 };
74
75 struct pgm_ack {
76     u_int32_t   pgma_rx_max_seq;
77     u_int32_t   pgma_bitmap;
78     /* ... options */
79 };
80
81 struct pgm_poll {
82     u_int32_t   pgmp_seq;
83     u_int16_t   pgmp_round;
84     u_int16_t   pgmp_reserved;
85     /* ... options */
86 };
87
88 struct pgm_polr {
89     u_int32_t   pgmp_seq;
90     u_int16_t   pgmp_round;
91     u_int16_t   pgmp_subtype;
92     u_int16_t   pgmp_nla_afi;
93     u_int16_t   pgmp_reserved;
94     /* ... u_int8_t     pgmp_nla[0]; */
95     /* ... options */
96 };
97
98 struct pgm_data {
99     u_int32_t   pgmd_seq;
100     u_int32_t   pgmd_trailseq;
101     /* ... options */
102 };
103
104 typedef enum _pgm_type {
105     PGM_SPM = 0,                /* source path message */
106     PGM_POLL = 1,               /* POLL Request */
107     PGM_POLR = 2,               /* POLL Response */
108     PGM_ODATA = 4,              /* original data */
109     PGM_RDATA = 5,              /* repair data */
110     PGM_NAK = 8,                /* NAK */
111     PGM_NULLNAK = 9,            /* Null NAK */
112     PGM_NCF = 10,               /* NAK Confirmation */
113     PGM_ACK = 11,               /* ACK for congestion control */
114     PGM_SPMR = 12,              /* SPM request */
115     PGM_MAX = 255
116 } pgm_type;
117
118 #define PGM_OPT_BIT_PRESENT     0x01
119 #define PGM_OPT_BIT_NETWORK     0x02
120 #define PGM_OPT_BIT_VAR_PKTLEN  0x40
121 #define PGM_OPT_BIT_PARITY      0x80
122
123 #define PGM_OPT_LENGTH          0x00
124 #define PGM_OPT_FRAGMENT        0x01
125 #define PGM_OPT_NAK_LIST        0x02
126 #define PGM_OPT_JOIN            0x03
127 #define PGM_OPT_NAK_BO_IVL      0x04
128 #define PGM_OPT_NAK_BO_RNG      0x05
129
130 #define PGM_OPT_REDIRECT        0x07
131 #define PGM_OPT_PARITY_PRM      0x08
132 #define PGM_OPT_PARITY_GRP      0x09
133 #define PGM_OPT_CURR_TGSIZE     0x0A
134 #define PGM_OPT_NBR_UNREACH     0x0B
135 #define PGM_OPT_PATH_NLA        0x0C
136
137 #define PGM_OPT_SYN             0x0D
138 #define PGM_OPT_FIN             0x0E
139 #define PGM_OPT_RST             0x0F
140 #define PGM_OPT_CR              0x10
141 #define PGM_OPT_CRQST           0x11
142
143 #define PGM_OPT_PGMCC_DATA      0x12
144 #define PGM_OPT_PGMCC_FEEDBACK  0x13
145      
146 #define PGM_OPT_MASK            0x7f
147
148 #define PGM_OPT_END             0x80    /* end of options marker */
149
150 #define PGM_MIN_OPT_LEN         4
151
152 #ifndef AFI_IP
153 #define AFI_IP          1
154 #define AFI_IP6         2
155 #endif
156
157 void
158 pgm_print(register const u_char *bp, register u_int length,
159           register const u_char *bp2)
160 {
161         register const struct pgm_header *pgm;
162         register const struct ip *ip;
163         register char ch;
164         u_int16_t sport, dport;
165         int addr_size;
166         const void *nla;
167         int nla_af;
168 #ifdef INET6
169         char nla_buf[INET6_ADDRSTRLEN];
170         register const struct ip6_hdr *ip6;
171 #else
172         char nla_buf[INET_ADDRSTRLEN];
173 #endif
174         u_int8_t opt_type, opt_len, flags1, flags2;
175         u_int32_t seq, opts_len, len, offset;
176
177         pgm = (struct pgm_header *)bp;
178         ip = (struct ip *)bp2;
179 #ifdef INET6
180         if (IP_V(ip) == 6)
181                 ip6 = (struct ip6_hdr *)bp2;
182         else
183                 ip6 = NULL;
184 #else /* INET6 */
185         if (IP_V(ip) == 6) {
186                 (void)printf("Can't handle IPv6");
187                 return;
188         }
189 #endif /* INET6 */
190         ch = '\0';
191         if (!TTEST(pgm->pgm_dport)) {
192 #ifdef INET6
193                 if (ip6) {
194                         (void)printf("%s > %s: [|pgm]",
195                                 ip6addr_string(&ip6->ip6_src),
196                                 ip6addr_string(&ip6->ip6_dst));
197                         return;
198                 } else
199 #endif /* INET6 */
200                 {
201                         (void)printf("%s > %s: [|pgm]",
202                                 ipaddr_string(&ip->ip_src),
203                                 ipaddr_string(&ip->ip_dst));
204                         return;
205                 }
206         }
207
208         sport = EXTRACT_16BITS(&pgm->pgm_sport);
209         dport = EXTRACT_16BITS(&pgm->pgm_dport);
210
211 #ifdef INET6
212         if (ip6) {
213                 if (ip6->ip6_nxt == IPPROTO_PGM) {
214                         (void)printf("%s.%s > %s.%s: ",
215                                 ip6addr_string(&ip6->ip6_src),
216                                 tcpport_string(sport),
217                                 ip6addr_string(&ip6->ip6_dst),
218                                 tcpport_string(dport));
219                 } else {
220                         (void)printf("%s > %s: ",
221                                 tcpport_string(sport), tcpport_string(dport));
222                 }
223         } else
224 #endif /*INET6*/
225         {
226                 if (ip->ip_p == IPPROTO_PGM) {
227                         (void)printf("%s.%s > %s.%s: ",
228                                 ipaddr_string(&ip->ip_src),
229                                 tcpport_string(sport),
230                                 ipaddr_string(&ip->ip_dst),
231                                 tcpport_string(dport));
232                 } else {
233                         (void)printf("%s > %s: ",
234                                 tcpport_string(sport), tcpport_string(dport));
235                 }
236         }
237
238         TCHECK(*pgm);
239
240         (void)printf("PGM, length %u", pgm->pgm_length);
241
242         if (!vflag)
243             return;
244
245         if (length > pgm->pgm_length)
246             length = pgm->pgm_length;
247
248         (void)printf(" 0x%02x%02x%02x%02x%02x%02x ",
249                      pgm->pgm_gsid[0],
250                      pgm->pgm_gsid[1],
251                      pgm->pgm_gsid[2],
252                      pgm->pgm_gsid[3],
253                      pgm->pgm_gsid[4],
254                      pgm->pgm_gsid[5]);
255         switch (pgm->pgm_type) {
256         case PGM_SPM: {
257             struct pgm_spm *spm;
258
259             spm = (struct pgm_spm *)(pgm + 1);
260             TCHECK(*spm);
261
262             switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) {
263             case AFI_IP:
264                 addr_size = sizeof(struct in_addr);
265                 nla_af = AF_INET;
266                 break;
267 #ifdef INET6
268             case AFI_IP6:
269                 addr_size = sizeof(struct in6_addr);
270                 nla_af = AF_INET6;
271                 break;
272 #endif
273             default:
274                 goto trunc;
275                 break;
276             }
277             bp = (u_char *) (spm + 1);
278             TCHECK2(*bp, addr_size);
279             nla = bp;
280             bp += addr_size;
281
282             inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
283             (void)printf("SPM seq %u trail %u lead %u nla %s",
284                          EXTRACT_32BITS(&spm->pgms_seq),
285                          EXTRACT_32BITS(&spm->pgms_trailseq),
286                          EXTRACT_32BITS(&spm->pgms_leadseq),
287                          nla_buf);
288             break;
289         }
290
291         case PGM_POLL: {
292             struct pgm_poll *poll;
293
294             poll = (struct pgm_poll *)(pgm + 1);
295             TCHECK(*poll);
296             (void)printf("POLL seq %u round %u",
297                          EXTRACT_32BITS(&poll->pgmp_seq),
298                          EXTRACT_16BITS(&poll->pgmp_round));
299             bp = (u_char *) (poll + 1);
300             break;
301         }
302         case PGM_POLR: {
303             struct pgm_polr *polr;
304             u_int32_t ivl, rnd, mask;
305
306             polr = (struct pgm_polr *)(pgm + 1);
307             TCHECK(*polr);
308
309             switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) {
310             case AFI_IP:
311                 addr_size = sizeof(struct in_addr);
312                 nla_af = AF_INET;
313                 break;
314 #ifdef INET6
315             case AFI_IP6:
316                 addr_size = sizeof(struct in6_addr);
317                 nla_af = AF_INET6;
318                 break;
319 #endif
320             default:
321                 goto trunc;
322                 break;
323             }
324             bp = (u_char *) (polr + 1);
325             TCHECK2(*bp, addr_size);
326             nla = bp;
327             bp += addr_size;
328
329             inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
330
331             TCHECK2(*bp, sizeof(u_int32_t));
332             ivl = EXTRACT_32BITS(bp);
333             bp += sizeof(u_int32_t);
334
335             TCHECK2(*bp, sizeof(u_int32_t));
336             rnd = EXTRACT_32BITS(bp);
337             bp += sizeof(u_int32_t);
338
339             TCHECK2(*bp, sizeof(u_int32_t));
340             mask = EXTRACT_32BITS(bp);
341             bp += sizeof(u_int32_t);
342
343             (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
344                          "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq),
345                          EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask);
346             break;
347         }
348         case PGM_ODATA: {
349             struct pgm_data *odata;
350
351             odata = (struct pgm_data *)(pgm + 1);
352             TCHECK(*odata);
353             (void)printf("ODATA trail %u seq %u",
354                          EXTRACT_32BITS(&odata->pgmd_trailseq),
355                          EXTRACT_32BITS(&odata->pgmd_seq));
356             bp = (u_char *) (odata + 1);
357             break;
358         }
359
360         case PGM_RDATA: {
361             struct pgm_data *rdata;
362
363             rdata = (struct pgm_data *)(pgm + 1);
364             TCHECK(*rdata);
365             (void)printf("RDATA trail %u seq %u",
366                          EXTRACT_32BITS(&rdata->pgmd_trailseq),
367                          EXTRACT_32BITS(&rdata->pgmd_seq));
368             bp = (u_char *) (rdata + 1);
369             break;
370         }
371
372         case PGM_NAK:
373         case PGM_NULLNAK:
374         case PGM_NCF: {
375             struct pgm_nak *nak;
376             const void *source, *group;
377             int source_af, group_af;
378 #ifdef INET6
379             char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
380 #else
381             char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN];
382 #endif
383
384             nak = (struct pgm_nak *)(pgm + 1);
385             TCHECK(*nak);
386
387             /*
388              * Skip past the source, saving info along the way
389              * and stopping if we don't have enough.
390              */
391             switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) {
392             case AFI_IP:
393                 addr_size = sizeof(struct in_addr);
394                 source_af = AF_INET;
395                 break;
396 #ifdef INET6
397             case AFI_IP6:
398                 addr_size = sizeof(struct in6_addr);
399                 source_af = AF_INET6;
400                 break;
401 #endif
402             default:
403                 goto trunc;
404                 break;
405             }
406             bp = (u_char *) (nak + 1);
407             TCHECK2(*bp, addr_size);
408             source = bp;
409             bp += addr_size;
410
411             /*
412              * Skip past the group, saving info along the way
413              * and stopping if we don't have enough.
414              */
415             switch (EXTRACT_16BITS(bp)) {
416             case AFI_IP:
417                 addr_size = sizeof(struct in_addr);
418                 group_af = AF_INET;
419                 break;
420 #ifdef INET6
421             case AFI_IP6:
422                 addr_size = sizeof(struct in6_addr);
423                 group_af = AF_INET6;
424                 break;
425 #endif
426             default:
427                 goto trunc;
428                 break;
429             }
430             bp += (2 * sizeof(u_int16_t));
431             TCHECK2(*bp, addr_size);
432             group = bp;
433             bp += addr_size;
434
435             /*
436              * Options decoding can go here.
437              */
438             inet_ntop(source_af, source, source_buf, sizeof(source_buf));
439             inet_ntop(group_af, group, group_buf, sizeof(group_buf));
440             switch (pgm->pgm_type) {
441                 case PGM_NAK:
442                     (void)printf("NAK ");
443                     break;
444                 case PGM_NULLNAK:
445                     (void)printf("NNAK ");
446                     break;
447                 case PGM_NCF:
448                     (void)printf("NCF ");
449                     break;
450                 default:
451                     break;
452             }
453             (void)printf("(%s -> %s), seq %u",
454                          source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq));
455             break;
456         }
457
458         case PGM_ACK: {
459             struct pgm_ack *ack;
460
461             ack = (struct pgm_ack *)(pgm + 1);
462             TCHECK(*ack);
463             (void)printf("ACK seq %u",
464                          EXTRACT_32BITS(&ack->pgma_rx_max_seq));
465             bp = (u_char *) (ack + 1);
466             break;
467         }
468
469         case PGM_SPMR:
470             (void)printf("SPMR");
471             break;
472
473         default:
474             (void)printf("UNKNOWN type %0x02x", pgm->pgm_type);
475             break;
476
477         }
478         if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) {      
479
480             /*
481              * make sure there's enough for the first option header
482              */
483             if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) {
484                 (void)printf("[|OPT]");
485                 return;
486             } 
487
488             /*
489              * That option header MUST be an OPT_LENGTH option
490              * (see the first paragraph of section 9.1 in RFC 3208).
491              */
492             opt_type = *bp++;
493             if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
494                 (void)printf("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
495                 return;
496             }
497             opt_len = *bp++;
498             if (opt_len != 4) {
499                 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
500                 return;
501             }
502             opts_len = EXTRACT_16BITS(bp);
503             if (opts_len < 4) {
504                 (void)printf("[Bad total option length %u < 4]", opts_len);
505                 return;
506             }
507             bp += sizeof(u_int16_t);
508             (void)printf(" OPTS LEN %d", opts_len);
509             opts_len -= 4;
510
511             while (opts_len) {
512                 if (opts_len < PGM_MIN_OPT_LEN) {
513                     (void)printf("[Total option length leaves no room for final option]");
514                     return;
515                 }
516                 opt_type = *bp++;
517                 opt_len = *bp++;
518                 if (opt_len < PGM_MIN_OPT_LEN) {
519                     (void)printf("[Bad option, length %u < %u]", opt_len,
520                         PGM_MIN_OPT_LEN);
521                     break;
522                 }
523                 if (opts_len < opt_len) {
524                     (void)printf("[Total option length leaves no room for final option]");
525                     return;
526                 }
527                 if (!TTEST2(*bp, opt_len - 2)) {
528                     (void)printf(" [|OPT]");
529                     return;
530                 } 
531
532                 switch (opt_type & PGM_OPT_MASK) {
533                 case PGM_OPT_LENGTH:
534                     if (opt_len != 4) {
535                         (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
536                         return;
537                     }
538                     (void)printf(" OPTS LEN (extra?) %d", EXTRACT_16BITS(bp));
539                     bp += sizeof(u_int16_t);
540                     opts_len -= 4;
541                     break;
542
543                 case PGM_OPT_FRAGMENT:
544                     if (opt_len != 16) {
545                         (void)printf("[Bad OPT_FRAGMENT option, length %u != 16]", opt_len);
546                         return;
547                     }
548                     flags1 = *bp++;
549                     flags2 = *bp++;
550                     seq = EXTRACT_32BITS(bp);
551                     bp += sizeof(u_int32_t);
552                     offset = EXTRACT_32BITS(bp);
553                     bp += sizeof(u_int32_t);
554                     len = EXTRACT_32BITS(bp);
555                     bp += sizeof(u_int32_t);
556                     (void)printf(" FRAG seq %u off %u len %u", seq, offset, len);
557                     opts_len -= 16;
558                     break;
559
560                 case PGM_OPT_NAK_LIST:
561                     flags1 = *bp++;
562                     flags2 = *bp++;
563                     opt_len -= sizeof(u_int32_t);       /* option header */
564                     (void)printf(" NAK LIST");
565                     while (opt_len) {
566                         if (opt_len < sizeof(u_int32_t)) {
567                             (void)printf("[Option length not a multiple of 4]");
568                             return;
569                         }
570                         TCHECK2(*bp, sizeof(u_int32_t));
571                         (void)printf(" %u", EXTRACT_32BITS(bp));
572                         bp += sizeof(u_int32_t);
573                         opt_len -= sizeof(u_int32_t);
574                         opts_len -= sizeof(u_int32_t);
575                     }
576                     break;
577
578                 case PGM_OPT_JOIN:
579                     if (opt_len != 8) {
580                         (void)printf("[Bad OPT_JOIN option, length %u != 8]", opt_len);
581                         return;
582                     }
583                     flags1 = *bp++;
584                     flags2 = *bp++;
585                     seq = EXTRACT_32BITS(bp);
586                     bp += sizeof(u_int32_t);
587                     (void)printf(" JOIN %u", seq);
588                     opts_len -= 8;
589                     break;
590
591                 case PGM_OPT_NAK_BO_IVL:
592                     if (opt_len != 12) {
593                         (void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len);
594                         return;
595                     }
596                     flags1 = *bp++;
597                     flags2 = *bp++;
598                     offset = EXTRACT_32BITS(bp);
599                     bp += sizeof(u_int32_t);
600                     seq = EXTRACT_32BITS(bp);
601                     bp += sizeof(u_int32_t);
602                     (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq);
603                     opts_len -= 12;
604                     break;
605
606                 case PGM_OPT_NAK_BO_RNG:
607                     if (opt_len != 12) {
608                         (void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len);
609                         return;
610                     }
611                     flags1 = *bp++;
612                     flags2 = *bp++;
613                     offset = EXTRACT_32BITS(bp);
614                     bp += sizeof(u_int32_t);
615                     seq = EXTRACT_32BITS(bp);
616                     bp += sizeof(u_int32_t);
617                     (void)printf(" BACKOFF max %u min %u", offset, seq);
618                     opts_len -= 12;
619                     break;
620
621                 case PGM_OPT_REDIRECT:
622                     flags1 = *bp++;
623                     flags2 = *bp++;
624                     switch (EXTRACT_16BITS(bp)) {
625                     case AFI_IP:
626                         addr_size = sizeof(struct in_addr);
627                         nla_af = AF_INET;
628                         break;
629 #ifdef INET6
630                     case AFI_IP6:
631                         addr_size = sizeof(struct in6_addr);
632                         nla_af = AF_INET6;
633                         break;
634 #endif
635                     default:
636                         goto trunc;
637                         break;
638                     }
639                     bp += (2 * sizeof(u_int16_t));
640                     if (opt_len != 4 + addr_size) {
641                         (void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len);
642                         return;
643                     }
644                     TCHECK2(*bp, addr_size);
645                     nla = bp;
646                     bp += addr_size;
647
648                     inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
649                     (void)printf(" REDIRECT %s",  (char *)nla);
650                     opts_len -= 4 + addr_size;
651                     break;
652
653                 case PGM_OPT_PARITY_PRM:
654                     if (opt_len != 8) {
655                         (void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len);
656                         return;
657                     }
658                     flags1 = *bp++;
659                     flags2 = *bp++;
660                     len = EXTRACT_32BITS(bp);
661                     bp += sizeof(u_int32_t);
662                     (void)printf(" PARITY MAXTGS %u", len);
663                     opts_len -= 8;
664                     break;
665
666                 case PGM_OPT_PARITY_GRP:
667                     if (opt_len != 8) {
668                         (void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len);
669                         return;
670                     }
671                     flags1 = *bp++;
672                     flags2 = *bp++;
673                     seq = EXTRACT_32BITS(bp);
674                     bp += sizeof(u_int32_t);
675                     (void)printf(" PARITY GROUP %u", seq);
676                     opts_len -= 8;
677                     break;
678
679                 case PGM_OPT_CURR_TGSIZE:
680                     if (opt_len != 8) {
681                         (void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len);
682                         return;
683                     }
684                     flags1 = *bp++;
685                     flags2 = *bp++;
686                     len = EXTRACT_32BITS(bp);
687                     bp += sizeof(u_int32_t);
688                     (void)printf(" PARITY ATGS %u", len);
689                     opts_len -= 8;
690                     break;
691
692                 case PGM_OPT_NBR_UNREACH:
693                     if (opt_len != 4) {
694                         (void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len);
695                         return;
696                     }
697                     flags1 = *bp++;
698                     flags2 = *bp++;
699                     (void)printf(" NBR_UNREACH");
700                     opts_len -= 4;
701                     break;
702
703                 case PGM_OPT_PATH_NLA:
704                     (void)printf(" PATH_NLA [%d]", opt_len);
705                     bp += opt_len;
706                     opts_len -= opt_len;
707                     break;
708
709                 case PGM_OPT_SYN:
710                     if (opt_len != 4) {
711                         (void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len);
712                         return;
713                     }
714                     flags1 = *bp++;
715                     flags2 = *bp++;
716                     (void)printf(" SYN");
717                     opts_len -= 4;
718                     break;
719
720                 case PGM_OPT_FIN:
721                     if (opt_len != 4) {
722                         (void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len);
723                         return;
724                     }
725                     flags1 = *bp++;
726                     flags2 = *bp++;
727                     (void)printf(" FIN");
728                     opts_len -= 4;
729                     break;
730
731                 case PGM_OPT_RST:
732                     if (opt_len != 4) {
733                         (void)printf("[Bad OPT_RST option, length %u != 4]", opt_len);
734                         return;
735                     }
736                     flags1 = *bp++;
737                     flags2 = *bp++;
738                     (void)printf(" RST");
739                     opts_len -= 4;
740                     break;
741
742                 case PGM_OPT_CR:
743                     (void)printf(" CR");
744                     bp += opt_len;
745                     opts_len -= opt_len;
746                     break;
747
748                 case PGM_OPT_CRQST:
749                     if (opt_len != 4) {
750                         (void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len);
751                         return;
752                     }
753                     flags1 = *bp++;
754                     flags2 = *bp++;
755                     (void)printf(" CRQST");
756                     opts_len -= 4;
757                     break;
758
759                 case PGM_OPT_PGMCC_DATA:
760                     flags1 = *bp++;
761                     flags2 = *bp++;
762                     offset = EXTRACT_32BITS(bp);
763                     bp += sizeof(u_int32_t);
764                     switch (EXTRACT_16BITS(bp)) {
765                     case AFI_IP:
766                         addr_size = sizeof(struct in_addr);
767                         nla_af = AF_INET;
768                         break;
769 #ifdef INET6
770                     case AFI_IP6:
771                         addr_size = sizeof(struct in6_addr);
772                         nla_af = AF_INET6;
773                         break;
774 #endif
775                     default:
776                         goto trunc;
777                         break;
778                     }
779                     bp += (2 * sizeof(u_int16_t));
780                     if (opt_len != 12 + addr_size) {
781                         (void)printf("[Bad OPT_PGMCC_DATA option, length %u != 12 + address size]", opt_len);
782                         return;
783                     }
784                     TCHECK2(*bp, addr_size);
785                     nla = bp;
786                     bp += addr_size;
787
788                     inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
789                     (void)printf(" PGMCC DATA %u %s", offset, (char*)nla);
790                     opts_len -= 16;
791                     break;
792
793                 case PGM_OPT_PGMCC_FEEDBACK:
794                     flags1 = *bp++;
795                     flags2 = *bp++;
796                     offset = EXTRACT_32BITS(bp);
797                     bp += sizeof(u_int32_t);
798                     switch (EXTRACT_16BITS(bp)) {
799                     case AFI_IP:
800                         addr_size = sizeof(struct in_addr);
801                         nla_af = AF_INET;
802                         break;
803 #ifdef INET6
804                     case AFI_IP6:
805                         addr_size = sizeof(struct in6_addr);
806                         nla_af = AF_INET6;
807                         break;
808 #endif
809                     default:
810                         goto trunc;
811                         break;
812                     }
813                     bp += (2 * sizeof(u_int16_t));
814                     if (opt_len != 12 + addr_size) {
815                         (void)printf("[Bad OPT_PGMCC_FEEDBACK option, length %u != 12 + address size]", opt_len);
816                         return;
817                     }
818                     TCHECK2(*bp, addr_size);
819                     nla = bp;
820                     bp += addr_size;
821
822                     inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
823                     (void)printf(" PGMCC FEEDBACK %u %s", offset, (char*)nla);
824                     opts_len -= 16;
825                     break;
826
827                 default:
828                     (void)printf(" OPT_%02X [%d] ", opt_type, opt_len);
829                     bp += opt_len;
830                     opts_len -= opt_len;
831                     break;
832                 }
833
834                 if (opt_type & PGM_OPT_END)
835                     break;
836              }
837         }
838
839         (void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length));
840
841         return;
842
843 trunc:
844         fputs("[|pgm]", stdout);
845         if (ch != '\0')
846                 putchar('>');
847 }