]> The Tcpdump Group git mirrors - tcpdump/blob - print-pgm.c
Fix spaces
[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 uint8_t pgm_type_val;
153 uint16_t sport, dport;
154 u_int nla_afnum;
155 char nla_buf[INET6_ADDRSTRLEN];
156 const struct ip6_hdr *ip6;
157 uint8_t opt_type, opt_len;
158 uint32_t seq, opts_len, len, offset;
159
160 ndo->ndo_protocol = "pgm";
161 pgm = (const struct pgm_header *)bp;
162 ip = (const struct ip *)bp2;
163 if (IP_V(ip) == 6)
164 ip6 = (const struct ip6_hdr *)bp2;
165 else
166 ip6 = NULL;
167 if (!ND_TTEST_2(pgm->pgm_dport)) {
168 if (ip6) {
169 ND_PRINT("%s > %s:",
170 ip6addr_string(ndo, ip6->ip6_src),
171 ip6addr_string(ndo, ip6->ip6_dst));
172 } else {
173 ND_PRINT("%s > %s:",
174 ipaddr_string(ndo, ip->ip_src),
175 ipaddr_string(ndo, ip->ip_dst));
176 }
177 nd_print_trunc(ndo);
178 return;
179 }
180
181 sport = EXTRACT_BE_U_2(pgm->pgm_sport);
182 dport = EXTRACT_BE_U_2(pgm->pgm_dport);
183
184 if (ip6) {
185 if (EXTRACT_U_1(ip6->ip6_nxt) == IPPROTO_PGM) {
186 ND_PRINT("%s.%s > %s.%s: ",
187 ip6addr_string(ndo, ip6->ip6_src),
188 tcpport_string(ndo, sport),
189 ip6addr_string(ndo, ip6->ip6_dst),
190 tcpport_string(ndo, dport));
191 } else {
192 ND_PRINT("%s > %s: ",
193 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
194 }
195 } else {
196 if (EXTRACT_U_1(ip->ip_p) == IPPROTO_PGM) {
197 ND_PRINT("%s.%s > %s.%s: ",
198 ipaddr_string(ndo, ip->ip_src),
199 tcpport_string(ndo, sport),
200 ipaddr_string(ndo, ip->ip_dst),
201 tcpport_string(ndo, dport));
202 } else {
203 ND_PRINT("%s > %s: ",
204 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
205 }
206 }
207
208 ND_TCHECK_SIZE(pgm);
209
210 ND_PRINT("PGM, length %u", EXTRACT_BE_U_2(pgm->pgm_length));
211
212 if (!ndo->ndo_vflag)
213 return;
214
215 pgm_type_val = EXTRACT_U_1(pgm->pgm_type);
216 ND_PRINT(" 0x%02x%02x%02x%02x%02x%02x ",
217 pgm->pgm_gsid[0],
218 pgm->pgm_gsid[1],
219 pgm->pgm_gsid[2],
220 pgm->pgm_gsid[3],
221 pgm->pgm_gsid[4],
222 pgm->pgm_gsid[5]);
223 switch (pgm_type_val) {
224 case PGM_SPM: {
225 const struct pgm_spm *spm;
226
227 spm = (const struct pgm_spm *)(pgm + 1);
228 ND_TCHECK_SIZE(spm);
229 bp = (const u_char *) (spm + 1);
230
231 switch (EXTRACT_BE_U_2(spm->pgms_nla_afi)) {
232 case AFNUM_INET:
233 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
234 addrtostr(bp, nla_buf, sizeof(nla_buf));
235 bp += sizeof(nd_ipv4);
236 break;
237 case AFNUM_INET6:
238 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
239 addrtostr6(bp, nla_buf, sizeof(nla_buf));
240 bp += sizeof(nd_ipv6);
241 break;
242 default:
243 goto trunc;
244 break;
245 }
246
247 ND_PRINT("SPM seq %u trail %u lead %u nla %s",
248 EXTRACT_BE_U_4(spm->pgms_seq),
249 EXTRACT_BE_U_4(spm->pgms_trailseq),
250 EXTRACT_BE_U_4(spm->pgms_leadseq),
251 nla_buf);
252 break;
253 }
254
255 case PGM_POLL: {
256 const struct pgm_poll *poll_msg;
257
258 poll_msg = (const struct pgm_poll *)(pgm + 1);
259 ND_TCHECK_SIZE(poll_msg);
260 ND_PRINT("POLL seq %u round %u",
261 EXTRACT_BE_U_4(poll_msg->pgmp_seq),
262 EXTRACT_BE_U_2(poll_msg->pgmp_round));
263 bp = (const u_char *) (poll_msg + 1);
264 break;
265 }
266 case PGM_POLR: {
267 const struct pgm_polr *polr;
268 uint32_t ivl, rnd, mask;
269
270 polr = (const struct pgm_polr *)(pgm + 1);
271 ND_TCHECK_SIZE(polr);
272 bp = (const u_char *) (polr + 1);
273
274 switch (EXTRACT_BE_U_2(polr->pgmp_nla_afi)) {
275 case AFNUM_INET:
276 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
277 addrtostr(bp, nla_buf, sizeof(nla_buf));
278 bp += sizeof(nd_ipv4);
279 break;
280 case AFNUM_INET6:
281 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
282 addrtostr6(bp, nla_buf, sizeof(nla_buf));
283 bp += sizeof(nd_ipv6);
284 break;
285 default:
286 goto trunc;
287 break;
288 }
289
290 ND_TCHECK_LEN(bp, sizeof(uint32_t));
291 ivl = EXTRACT_BE_U_4(bp);
292 bp += sizeof(uint32_t);
293
294 ND_TCHECK_LEN(bp, sizeof(uint32_t));
295 rnd = EXTRACT_BE_U_4(bp);
296 bp += sizeof(uint32_t);
297
298 ND_TCHECK_LEN(bp, sizeof(uint32_t));
299 mask = EXTRACT_BE_U_4(bp);
300 bp += sizeof(uint32_t);
301
302 ND_PRINT("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
303 "mask 0x%08x", EXTRACT_BE_U_4(polr->pgmp_seq),
304 EXTRACT_BE_U_2(polr->pgmp_round), nla_buf, ivl, rnd, mask);
305 break;
306 }
307 case PGM_ODATA: {
308 const struct pgm_data *odata;
309
310 odata = (const struct pgm_data *)(pgm + 1);
311 ND_TCHECK_SIZE(odata);
312 ND_PRINT("ODATA trail %u seq %u",
313 EXTRACT_BE_U_4(odata->pgmd_trailseq),
314 EXTRACT_BE_U_4(odata->pgmd_seq));
315 bp = (const u_char *) (odata + 1);
316 break;
317 }
318
319 case PGM_RDATA: {
320 const struct pgm_data *rdata;
321
322 rdata = (const struct pgm_data *)(pgm + 1);
323 ND_TCHECK_SIZE(rdata);
324 ND_PRINT("RDATA trail %u seq %u",
325 EXTRACT_BE_U_4(rdata->pgmd_trailseq),
326 EXTRACT_BE_U_4(rdata->pgmd_seq));
327 bp = (const u_char *) (rdata + 1);
328 break;
329 }
330
331 case PGM_NAK:
332 case PGM_NULLNAK:
333 case PGM_NCF: {
334 const struct pgm_nak *nak;
335 char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
336
337 nak = (const struct pgm_nak *)(pgm + 1);
338 ND_TCHECK_SIZE(nak);
339 bp = (const u_char *) (nak + 1);
340
341 /*
342 * Skip past the source, saving info along the way
343 * and stopping if we don't have enough.
344 */
345 switch (EXTRACT_BE_U_2(nak->pgmn_source_afi)) {
346 case AFNUM_INET:
347 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
348 addrtostr(bp, source_buf, sizeof(source_buf));
349 bp += sizeof(nd_ipv4);
350 break;
351 case AFNUM_INET6:
352 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
353 addrtostr6(bp, source_buf, sizeof(source_buf));
354 bp += sizeof(nd_ipv6);
355 break;
356 default:
357 goto trunc;
358 break;
359 }
360
361 /*
362 * Skip past the group, saving info along the way
363 * and stopping if we don't have enough.
364 */
365 bp += (2 * sizeof(uint16_t));
366 ND_TCHECK_2(bp);
367 switch (EXTRACT_BE_U_2(bp)) {
368 case AFNUM_INET:
369 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
370 addrtostr(bp, group_buf, sizeof(group_buf));
371 bp += sizeof(nd_ipv4);
372 break;
373 case AFNUM_INET6:
374 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
375 addrtostr6(bp, group_buf, sizeof(group_buf));
376 bp += sizeof(nd_ipv6);
377 break;
378 default:
379 goto trunc;
380 break;
381 }
382
383 /*
384 * Options decoding can go here.
385 */
386 switch (pgm_type_val) {
387 case PGM_NAK:
388 ND_PRINT("NAK ");
389 break;
390 case PGM_NULLNAK:
391 ND_PRINT("NNAK ");
392 break;
393 case PGM_NCF:
394 ND_PRINT("NCF ");
395 break;
396 default:
397 break;
398 }
399 ND_PRINT("(%s -> %s), seq %u",
400 source_buf, group_buf, EXTRACT_BE_U_4(nak->pgmn_seq));
401 break;
402 }
403
404 case PGM_ACK: {
405 const struct pgm_ack *ack;
406
407 ack = (const struct pgm_ack *)(pgm + 1);
408 ND_TCHECK_SIZE(ack);
409 ND_PRINT("ACK seq %u",
410 EXTRACT_BE_U_4(ack->pgma_rx_max_seq));
411 bp = (const u_char *) (ack + 1);
412 break;
413 }
414
415 case PGM_SPMR:
416 ND_PRINT("SPMR");
417 break;
418
419 default:
420 ND_PRINT("UNKNOWN type 0x%02x", pgm_type_val);
421 break;
422
423 }
424 if (EXTRACT_U_1(pgm->pgm_options) & PGM_OPT_BIT_PRESENT) {
425
426 /*
427 * make sure there's enough for the first option header
428 */
429 ND_TCHECK_LEN(bp, PGM_MIN_OPT_LEN);
430
431 /*
432 * That option header MUST be an OPT_LENGTH option
433 * (see the first paragraph of section 9.1 in RFC 3208).
434 */
435 opt_type = EXTRACT_U_1(bp);
436 bp++;
437 if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
438 ND_PRINT("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
439 return;
440 }
441 opt_len = EXTRACT_U_1(bp);
442 bp++;
443 if (opt_len != 4) {
444 ND_PRINT("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
445 return;
446 }
447 opts_len = EXTRACT_BE_U_2(bp);
448 bp += sizeof(uint16_t);
449 if (opts_len < 4) {
450 ND_PRINT("[Bad total option length %u < 4]", opts_len);
451 return;
452 }
453 ND_PRINT(" OPTS LEN %u", opts_len);
454 opts_len -= 4;
455
456 while (opts_len) {
457 if (opts_len < PGM_MIN_OPT_LEN) {
458 ND_PRINT("[Total option length leaves no room for final option]");
459 return;
460 }
461 ND_TCHECK_2(bp);
462 opt_type = EXTRACT_U_1(bp);
463 bp++;
464 opt_len = EXTRACT_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", EXTRACT_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 = EXTRACT_BE_U_4(bp);
499 bp += 4;
500 offset = EXTRACT_BE_U_4(bp);
501 bp += 4;
502 len = EXTRACT_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_TCHECK_4(bp);
518 ND_PRINT(" %u", EXTRACT_BE_U_4(bp));
519 bp += 4;
520 opt_len -= 4;
521 opts_len -= 4;
522 }
523 break;
524
525 case PGM_OPT_JOIN:
526 #define PGM_OPT_JOIN_LEN (2+2+4)
527 if (opt_len != PGM_OPT_JOIN_LEN) {
528 ND_PRINT("[Bad OPT_JOIN option, length %u != %u]",
529 opt_len, PGM_OPT_JOIN_LEN);
530 return;
531 }
532 bp += 2;
533 seq = EXTRACT_BE_U_4(bp);
534 bp += 4;
535 ND_PRINT(" JOIN %u", seq);
536 opts_len -= PGM_OPT_JOIN_LEN;
537 break;
538
539 case PGM_OPT_NAK_BO_IVL:
540 #define PGM_OPT_NAK_BO_IVL_LEN (2+2+4+4)
541 if (opt_len != PGM_OPT_NAK_BO_IVL_LEN) {
542 ND_PRINT("[Bad OPT_NAK_BO_IVL option, length %u != %u]",
543 opt_len, PGM_OPT_NAK_BO_IVL_LEN);
544 return;
545 }
546 bp += 2;
547 offset = EXTRACT_BE_U_4(bp);
548 bp += 4;
549 seq = EXTRACT_BE_U_4(bp);
550 bp += 4;
551 ND_PRINT(" BACKOFF ivl %u ivlseq %u", offset, seq);
552 opts_len -= PGM_OPT_NAK_BO_IVL_LEN;
553 break;
554
555 case PGM_OPT_NAK_BO_RNG:
556 #define PGM_OPT_NAK_BO_RNG_LEN (2+2+4+4)
557 if (opt_len != PGM_OPT_NAK_BO_RNG_LEN) {
558 ND_PRINT("[Bad OPT_NAK_BO_RNG option, length %u != %u]",
559 opt_len, PGM_OPT_NAK_BO_RNG_LEN);
560 return;
561 }
562 bp += 2;
563 offset = EXTRACT_BE_U_4(bp);
564 bp += 4;
565 seq = EXTRACT_BE_U_4(bp);
566 bp += 4;
567 ND_PRINT(" BACKOFF max %u min %u", offset, seq);
568 opts_len -= PGM_OPT_NAK_BO_RNG_LEN;
569 break;
570
571 case PGM_OPT_REDIRECT:
572 #define PGM_OPT_REDIRECT_FIXED_LEN (2+2+2+2)
573 if (opt_len < PGM_OPT_REDIRECT_FIXED_LEN) {
574 ND_PRINT("[Bad OPT_REDIRECT option, length %u < %u]",
575 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
576 return;
577 }
578 bp += 2;
579 nla_afnum = EXTRACT_BE_U_2(bp);
580 bp += 2+2;
581 switch (nla_afnum) {
582 case AFNUM_INET:
583 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4)) {
584 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
585 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
586 return;
587 }
588 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
589 addrtostr(bp, nla_buf, sizeof(nla_buf));
590 bp += sizeof(nd_ipv4);
591 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4);
592 break;
593 case AFNUM_INET6:
594 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6)) {
595 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
596 PGM_OPT_REDIRECT_FIXED_LEN, opt_len);
597 return;
598 }
599 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
600 addrtostr6(bp, nla_buf, sizeof(nla_buf));
601 bp += sizeof(nd_ipv6);
602 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6);
603 break;
604 default:
605 goto trunc;
606 break;
607 }
608
609 ND_PRINT(" REDIRECT %s", nla_buf);
610 break;
611
612 case PGM_OPT_PARITY_PRM:
613 #define PGM_OPT_PARITY_PRM_LEN (2+2+4)
614 if (opt_len != PGM_OPT_PARITY_PRM_LEN) {
615 ND_PRINT("[Bad OPT_PARITY_PRM option, length %u != %u]",
616 opt_len, PGM_OPT_PARITY_PRM_LEN);
617 return;
618 }
619 bp += 2;
620 len = EXTRACT_BE_U_4(bp);
621 bp += 4;
622 ND_PRINT(" PARITY MAXTGS %u", len);
623 opts_len -= PGM_OPT_PARITY_PRM_LEN;
624 break;
625
626 case PGM_OPT_PARITY_GRP:
627 #define PGM_OPT_PARITY_GRP_LEN (2+2+4)
628 if (opt_len != PGM_OPT_PARITY_GRP_LEN) {
629 ND_PRINT("[Bad OPT_PARITY_GRP option, length %u != %u]",
630 opt_len, PGM_OPT_PARITY_GRP_LEN);
631 return;
632 }
633 bp += 2;
634 seq = EXTRACT_BE_U_4(bp);
635 bp += 4;
636 ND_PRINT(" PARITY GROUP %u", seq);
637 opts_len -= PGM_OPT_PARITY_GRP_LEN;
638 break;
639
640 case PGM_OPT_CURR_TGSIZE:
641 #define PGM_OPT_CURR_TGSIZE_LEN (2+2+4)
642 if (opt_len != PGM_OPT_CURR_TGSIZE_LEN) {
643 ND_PRINT("[Bad OPT_CURR_TGSIZE option, length %u != %u]",
644 opt_len, PGM_OPT_CURR_TGSIZE_LEN);
645 return;
646 }
647 bp += 2;
648 len = EXTRACT_BE_U_4(bp);
649 bp += 4;
650 ND_PRINT(" PARITY ATGS %u", len);
651 opts_len -= PGM_OPT_CURR_TGSIZE_LEN;
652 break;
653
654 case PGM_OPT_NBR_UNREACH:
655 #define PGM_OPT_NBR_UNREACH_LEN (2+2)
656 if (opt_len != PGM_OPT_NBR_UNREACH_LEN) {
657 ND_PRINT("[Bad OPT_NBR_UNREACH option, length %u != %u]",
658 opt_len, PGM_OPT_NBR_UNREACH_LEN);
659 return;
660 }
661 bp += 2;
662 ND_PRINT(" NBR_UNREACH");
663 opts_len -= PGM_OPT_NBR_UNREACH_LEN;
664 break;
665
666 case PGM_OPT_PATH_NLA:
667 ND_PRINT(" PATH_NLA [%u]", opt_len);
668 bp += opt_len;
669 opts_len -= opt_len;
670 break;
671
672 case PGM_OPT_SYN:
673 #define PGM_OPT_SYN_LEN (2+2)
674 if (opt_len != PGM_OPT_SYN_LEN) {
675 ND_PRINT("[Bad OPT_SYN option, length %u != %u]",
676 opt_len, PGM_OPT_SYN_LEN);
677 return;
678 }
679 bp += 2;
680 ND_PRINT(" SYN");
681 opts_len -= PGM_OPT_SYN_LEN;
682 break;
683
684 case PGM_OPT_FIN:
685 #define PGM_OPT_FIN_LEN (2+2)
686 if (opt_len != PGM_OPT_FIN_LEN) {
687 ND_PRINT("[Bad OPT_FIN option, length %u != %u]",
688 opt_len, PGM_OPT_FIN_LEN);
689 return;
690 }
691 bp += 2;
692 ND_PRINT(" FIN");
693 opts_len -= PGM_OPT_FIN_LEN;
694 break;
695
696 case PGM_OPT_RST:
697 #define PGM_OPT_RST_LEN (2+2)
698 if (opt_len != PGM_OPT_RST_LEN) {
699 ND_PRINT("[Bad OPT_RST option, length %u != %u]",
700 opt_len, PGM_OPT_RST_LEN);
701 return;
702 }
703 bp += 2;
704 ND_PRINT(" RST");
705 opts_len -= PGM_OPT_RST_LEN;
706 break;
707
708 case PGM_OPT_CR:
709 ND_PRINT(" CR");
710 bp += opt_len;
711 opts_len -= opt_len;
712 break;
713
714 case PGM_OPT_CRQST:
715 #define PGM_OPT_CRQST_LEN (2+2)
716 if (opt_len != PGM_OPT_CRQST_LEN) {
717 ND_PRINT("[Bad OPT_CRQST option, length %u != %u]",
718 opt_len, PGM_OPT_CRQST_LEN);
719 return;
720 }
721 bp += 2;
722 ND_PRINT(" CRQST");
723 opts_len -= PGM_OPT_CRQST_LEN;
724 break;
725
726 case PGM_OPT_PGMCC_DATA:
727 #define PGM_OPT_PGMCC_DATA_FIXED_LEN (2+2+4+2+2)
728 if (opt_len < PGM_OPT_PGMCC_DATA_FIXED_LEN) {
729 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u < %u]",
730 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
731 return;
732 }
733 bp += 2;
734 offset = EXTRACT_BE_U_4(bp);
735 bp += 4;
736 nla_afnum = EXTRACT_BE_U_2(bp);
737 bp += 2+2;
738 switch (nla_afnum) {
739 case AFNUM_INET:
740 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4)) {
741 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
742 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
743 return;
744 }
745 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
746 addrtostr(bp, nla_buf, sizeof(nla_buf));
747 bp += sizeof(nd_ipv4);
748 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4);
749 break;
750 case AFNUM_INET6:
751 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6)) {
752 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
753 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
754 return;
755 }
756 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
757 addrtostr6(bp, nla_buf, sizeof(nla_buf));
758 bp += sizeof(nd_ipv6);
759 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6);
760 break;
761 default:
762 goto trunc;
763 break;
764 }
765
766 ND_PRINT(" PGMCC DATA %u %s", offset, nla_buf);
767 break;
768
769 case PGM_OPT_PGMCC_FEEDBACK:
770 #define PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN (2+2+4+2+2)
771 if (opt_len < PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN) {
772 ND_PRINT("[Bad PGM_OPT_PGMCC_FEEDBACK option, length %u < %u]",
773 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
774 return;
775 }
776 bp += 2;
777 offset = EXTRACT_BE_U_4(bp);
778 bp += 4;
779 nla_afnum = EXTRACT_BE_U_2(bp);
780 bp += 2+2;
781 switch (nla_afnum) {
782 case AFNUM_INET:
783 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4)) {
784 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
785 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
786 return;
787 }
788 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
789 addrtostr(bp, nla_buf, sizeof(nla_buf));
790 bp += sizeof(nd_ipv4);
791 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4);
792 break;
793 case AFNUM_INET6:
794 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6)) {
795 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
796 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
797 return;
798 }
799 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
800 addrtostr6(bp, nla_buf, sizeof(nla_buf));
801 bp += sizeof(nd_ipv6);
802 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6);
803 break;
804 default:
805 goto trunc;
806 break;
807 }
808
809 ND_PRINT(" PGMCC FEEDBACK %u %s", offset, nla_buf);
810 break;
811
812 default:
813 ND_PRINT(" OPT_%02X [%u] ", opt_type, opt_len);
814 bp += opt_len;
815 opts_len -= opt_len;
816 break;
817 }
818
819 if (opt_type & PGM_OPT_END)
820 break;
821 }
822 }
823
824 ND_PRINT(" [%u]", length);
825 if (ndo->ndo_packettype == PT_PGM_ZMTP1 &&
826 (pgm_type_val == PGM_ODATA || pgm_type_val == PGM_RDATA))
827 zmtp1_datagram_print(ndo, bp,
828 EXTRACT_BE_U_2(pgm->pgm_length));
829
830 return;
831
832 trunc:
833 nd_print_trunc(ndo);
834 }