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