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