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