]> The Tcpdump Group git mirrors - tcpdump/blob - print-pgm.c
Add more nd_print_trunc() calls
[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:",
172 ip6addr_string(ndo, ip6->ip6_src),
173 ip6addr_string(ndo, ip6->ip6_dst));
174 } else {
175 ND_PRINT("%s > %s:",
176 ipaddr_string(ndo, ip->ip_src),
177 ipaddr_string(ndo, ip->ip_dst));
178 }
179 nd_print_trunc(ndo);
180 return;
181 }
182
183 sport = EXTRACT_BE_U_2(pgm->pgm_sport);
184 dport = EXTRACT_BE_U_2(pgm->pgm_dport);
185
186 if (ip6) {
187 if (EXTRACT_U_1(ip6->ip6_nxt) == IPPROTO_PGM) {
188 ND_PRINT("%s.%s > %s.%s: ",
189 ip6addr_string(ndo, ip6->ip6_src),
190 tcpport_string(ndo, sport),
191 ip6addr_string(ndo, ip6->ip6_dst),
192 tcpport_string(ndo, dport));
193 } else {
194 ND_PRINT("%s > %s: ",
195 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
196 }
197 } else {
198 if (EXTRACT_U_1(ip->ip_p) == IPPROTO_PGM) {
199 ND_PRINT("%s.%s > %s.%s: ",
200 ipaddr_string(ndo, ip->ip_src),
201 tcpport_string(ndo, sport),
202 ipaddr_string(ndo, ip->ip_dst),
203 tcpport_string(ndo, dport));
204 } else {
205 ND_PRINT("%s > %s: ",
206 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
207 }
208 }
209
210 ND_TCHECK_SIZE(pgm);
211
212 ND_PRINT("PGM, length %u", EXTRACT_BE_U_2(pgm->pgm_length));
213
214 if (!ndo->ndo_vflag)
215 return;
216
217 pgm_type_val = EXTRACT_U_1(pgm->pgm_type);
218 ND_PRINT(" 0x%02x%02x%02x%02x%02x%02x ",
219 pgm->pgm_gsid[0],
220 pgm->pgm_gsid[1],
221 pgm->pgm_gsid[2],
222 pgm->pgm_gsid[3],
223 pgm->pgm_gsid[4],
224 pgm->pgm_gsid[5]);
225 switch (pgm_type_val) {
226 case PGM_SPM: {
227 const struct pgm_spm *spm;
228
229 spm = (const struct pgm_spm *)(pgm + 1);
230 ND_TCHECK_SIZE(spm);
231 bp = (const u_char *) (spm + 1);
232
233 switch (EXTRACT_BE_U_2(spm->pgms_nla_afi)) {
234 case AFNUM_INET:
235 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
236 addrtostr(bp, nla_buf, sizeof(nla_buf));
237 bp += sizeof(nd_ipv4);
238 break;
239 case AFNUM_INET6:
240 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
241 addrtostr6(bp, nla_buf, sizeof(nla_buf));
242 bp += sizeof(nd_ipv6);
243 break;
244 default:
245 goto trunc;
246 break;
247 }
248
249 ND_PRINT("SPM seq %u trail %u lead %u nla %s",
250 EXTRACT_BE_U_4(spm->pgms_seq),
251 EXTRACT_BE_U_4(spm->pgms_trailseq),
252 EXTRACT_BE_U_4(spm->pgms_leadseq),
253 nla_buf);
254 break;
255 }
256
257 case PGM_POLL: {
258 const struct pgm_poll *poll_msg;
259
260 poll_msg = (const struct pgm_poll *)(pgm + 1);
261 ND_TCHECK_SIZE(poll_msg);
262 ND_PRINT("POLL seq %u round %u",
263 EXTRACT_BE_U_4(poll_msg->pgmp_seq),
264 EXTRACT_BE_U_2(poll_msg->pgmp_round));
265 bp = (const u_char *) (poll_msg + 1);
266 break;
267 }
268 case PGM_POLR: {
269 const struct pgm_polr *polr;
270 uint32_t ivl, rnd, mask;
271
272 polr = (const struct pgm_polr *)(pgm + 1);
273 ND_TCHECK_SIZE(polr);
274 bp = (const u_char *) (polr + 1);
275
276 switch (EXTRACT_BE_U_2(polr->pgmp_nla_afi)) {
277 case AFNUM_INET:
278 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
279 addrtostr(bp, nla_buf, sizeof(nla_buf));
280 bp += sizeof(nd_ipv4);
281 break;
282 case AFNUM_INET6:
283 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
284 addrtostr6(bp, nla_buf, sizeof(nla_buf));
285 bp += sizeof(nd_ipv6);
286 break;
287 default:
288 goto trunc;
289 break;
290 }
291
292 ND_TCHECK_LEN(bp, sizeof(uint32_t));
293 ivl = EXTRACT_BE_U_4(bp);
294 bp += sizeof(uint32_t);
295
296 ND_TCHECK_LEN(bp, sizeof(uint32_t));
297 rnd = EXTRACT_BE_U_4(bp);
298 bp += sizeof(uint32_t);
299
300 ND_TCHECK_LEN(bp, sizeof(uint32_t));
301 mask = EXTRACT_BE_U_4(bp);
302 bp += sizeof(uint32_t);
303
304 ND_PRINT("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
305 "mask 0x%08x", EXTRACT_BE_U_4(polr->pgmp_seq),
306 EXTRACT_BE_U_2(polr->pgmp_round), nla_buf, ivl, rnd, mask);
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 EXTRACT_BE_U_4(odata->pgmd_trailseq),
316 EXTRACT_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 EXTRACT_BE_U_4(rdata->pgmd_trailseq),
328 EXTRACT_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 (EXTRACT_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 ND_TCHECK_2(bp);
369 switch (EXTRACT_BE_U_2(bp)) {
370 case AFNUM_INET:
371 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
372 addrtostr(bp, group_buf, sizeof(group_buf));
373 bp += sizeof(nd_ipv4);
374 break;
375 case AFNUM_INET6:
376 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
377 addrtostr6(bp, group_buf, sizeof(group_buf));
378 bp += sizeof(nd_ipv6);
379 break;
380 default:
381 goto trunc;
382 break;
383 }
384
385 /*
386 * Options decoding can go here.
387 */
388 switch (pgm_type_val) {
389 case PGM_NAK:
390 ND_PRINT("NAK ");
391 break;
392 case PGM_NULLNAK:
393 ND_PRINT("NNAK ");
394 break;
395 case PGM_NCF:
396 ND_PRINT("NCF ");
397 break;
398 default:
399 break;
400 }
401 ND_PRINT("(%s -> %s), seq %u",
402 source_buf, group_buf, EXTRACT_BE_U_4(nak->pgmn_seq));
403 break;
404 }
405
406 case PGM_ACK: {
407 const struct pgm_ack *ack;
408
409 ack = (const struct pgm_ack *)(pgm + 1);
410 ND_TCHECK_SIZE(ack);
411 ND_PRINT("ACK seq %u",
412 EXTRACT_BE_U_4(ack->pgma_rx_max_seq));
413 bp = (const u_char *) (ack + 1);
414 break;
415 }
416
417 case PGM_SPMR:
418 ND_PRINT("SPMR");
419 break;
420
421 default:
422 ND_PRINT("UNKNOWN type 0x%02x", pgm_type_val);
423 break;
424
425 }
426 if (EXTRACT_U_1(pgm->pgm_options) & PGM_OPT_BIT_PRESENT) {
427
428 /*
429 * make sure there's enough for the first option header
430 */
431 if (!ND_TTEST_LEN(bp, PGM_MIN_OPT_LEN)) {
432 nd_print_trunc(ndo);
433 return;
434 }
435
436 /*
437 * That option header MUST be an OPT_LENGTH option
438 * (see the first paragraph of section 9.1 in RFC 3208).
439 */
440 opt_type = EXTRACT_U_1(bp);
441 bp++;
442 if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
443 ND_PRINT("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
444 return;
445 }
446 opt_len = EXTRACT_U_1(bp);
447 bp++;
448 if (opt_len != 4) {
449 ND_PRINT("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
450 return;
451 }
452 opts_len = EXTRACT_BE_U_2(bp);
453 bp += sizeof(uint16_t);
454 if (opts_len < 4) {
455 ND_PRINT("[Bad total option length %u < 4]", opts_len);
456 return;
457 }
458 ND_PRINT(" OPTS LEN %u", opts_len);
459 opts_len -= 4;
460
461 while (opts_len) {
462 if (opts_len < PGM_MIN_OPT_LEN) {
463 ND_PRINT("[Total option length leaves no room for final option]");
464 return;
465 }
466 if (!ND_TTEST_2(bp)) {
467 nd_print_trunc(ndo);
468 return;
469 }
470 opt_type = EXTRACT_U_1(bp);
471 bp++;
472 opt_len = EXTRACT_U_1(bp);
473 bp++;
474 if (opt_len < PGM_MIN_OPT_LEN) {
475 ND_PRINT("[Bad option, length %u < %u]", opt_len,
476 PGM_MIN_OPT_LEN);
477 break;
478 }
479 if (opts_len < opt_len) {
480 ND_PRINT("[Total option length leaves no room for final option]");
481 return;
482 }
483 if (!ND_TTEST_LEN(bp, opt_len - 2)) {
484 nd_print_trunc(ndo);
485 return;
486 }
487
488 switch (opt_type & PGM_OPT_MASK) {
489 case PGM_OPT_LENGTH:
490 #define PGM_OPT_LENGTH_LEN (2+2)
491 if (opt_len != PGM_OPT_LENGTH_LEN) {
492 ND_PRINT("[Bad OPT_LENGTH option, length %u != %u]",
493 opt_len, PGM_OPT_LENGTH_LEN);
494 return;
495 }
496 ND_PRINT(" OPTS LEN (extra?) %u", EXTRACT_BE_U_2(bp));
497 bp += 2;
498 opts_len -= PGM_OPT_LENGTH_LEN;
499 break;
500
501 case PGM_OPT_FRAGMENT:
502 #define PGM_OPT_FRAGMENT_LEN (2+2+4+4+4)
503 if (opt_len != PGM_OPT_FRAGMENT_LEN) {
504 ND_PRINT("[Bad OPT_FRAGMENT option, length %u != %u]",
505 opt_len, PGM_OPT_FRAGMENT_LEN);
506 return;
507 }
508 bp += 2;
509 seq = EXTRACT_BE_U_4(bp);
510 bp += 4;
511 offset = EXTRACT_BE_U_4(bp);
512 bp += 4;
513 len = EXTRACT_BE_U_4(bp);
514 bp += 4;
515 ND_PRINT(" FRAG seq %u off %u len %u", seq, offset, len);
516 opts_len -= PGM_OPT_FRAGMENT_LEN;
517 break;
518
519 case PGM_OPT_NAK_LIST:
520 bp += 2;
521 opt_len -= 4; /* option header */
522 ND_PRINT(" NAK LIST");
523 while (opt_len) {
524 if (opt_len < 4) {
525 ND_PRINT("[Option length not a multiple of 4]");
526 return;
527 }
528 ND_TCHECK_4(bp);
529 ND_PRINT(" %u", EXTRACT_BE_U_4(bp));
530 bp += 4;
531 opt_len -= 4;
532 opts_len -= 4;
533 }
534 break;
535
536 case PGM_OPT_JOIN:
537 #define PGM_OPT_JOIN_LEN (2+2+4)
538 if (opt_len != PGM_OPT_JOIN_LEN) {
539 ND_PRINT("[Bad OPT_JOIN option, length %u != %u]",
540 opt_len, PGM_OPT_JOIN_LEN);
541 return;
542 }
543 bp += 2;
544 seq = EXTRACT_BE_U_4(bp);
545 bp += 4;
546 ND_PRINT(" JOIN %u", seq);
547 opts_len -= PGM_OPT_JOIN_LEN;
548 break;
549
550 case PGM_OPT_NAK_BO_IVL:
551 #define PGM_OPT_NAK_BO_IVL_LEN (2+2+4+4)
552 if (opt_len != PGM_OPT_NAK_BO_IVL_LEN) {
553 ND_PRINT("[Bad OPT_NAK_BO_IVL option, length %u != %u]",
554 opt_len, PGM_OPT_NAK_BO_IVL_LEN);
555 return;
556 }
557 bp += 2;
558 offset = EXTRACT_BE_U_4(bp);
559 bp += 4;
560 seq = EXTRACT_BE_U_4(bp);
561 bp += 4;
562 ND_PRINT(" BACKOFF ivl %u ivlseq %u", offset, seq);
563 opts_len -= PGM_OPT_NAK_BO_IVL_LEN;
564 break;
565
566 case PGM_OPT_NAK_BO_RNG:
567 #define PGM_OPT_NAK_BO_RNG_LEN (2+2+4+4)
568 if (opt_len != PGM_OPT_NAK_BO_RNG_LEN) {
569 ND_PRINT("[Bad OPT_NAK_BO_RNG option, length %u != %u]",
570 opt_len, PGM_OPT_NAK_BO_RNG_LEN);
571 return;
572 }
573 bp += 2;
574 offset = EXTRACT_BE_U_4(bp);
575 bp += 4;
576 seq = EXTRACT_BE_U_4(bp);
577 bp += 4;
578 ND_PRINT(" BACKOFF max %u min %u", offset, seq);
579 opts_len -= PGM_OPT_NAK_BO_RNG_LEN;
580 break;
581
582 case PGM_OPT_REDIRECT:
583 #define PGM_OPT_REDIRECT_FIXED_LEN (2+2+2+2)
584 if (opt_len < PGM_OPT_REDIRECT_FIXED_LEN) {
585 ND_PRINT("[Bad OPT_REDIRECT option, length %u < %u]",
586 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
587 return;
588 }
589 bp += 2;
590 nla_afnum = EXTRACT_BE_U_2(bp);
591 bp += 2+2;
592 switch (nla_afnum) {
593 case AFNUM_INET:
594 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4)) {
595 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
596 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
597 return;
598 }
599 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
600 addrtostr(bp, nla_buf, sizeof(nla_buf));
601 bp += sizeof(nd_ipv4);
602 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4);
603 break;
604 case AFNUM_INET6:
605 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6)) {
606 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
607 PGM_OPT_REDIRECT_FIXED_LEN, opt_len);
608 return;
609 }
610 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
611 addrtostr6(bp, nla_buf, sizeof(nla_buf));
612 bp += sizeof(nd_ipv6);
613 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6);
614 break;
615 default:
616 goto trunc;
617 break;
618 }
619
620 ND_PRINT(" REDIRECT %s", nla_buf);
621 break;
622
623 case PGM_OPT_PARITY_PRM:
624 #define PGM_OPT_PARITY_PRM_LEN (2+2+4)
625 if (opt_len != PGM_OPT_PARITY_PRM_LEN) {
626 ND_PRINT("[Bad OPT_PARITY_PRM option, length %u != %u]",
627 opt_len, PGM_OPT_PARITY_PRM_LEN);
628 return;
629 }
630 bp += 2;
631 len = EXTRACT_BE_U_4(bp);
632 bp += 4;
633 ND_PRINT(" PARITY MAXTGS %u", len);
634 opts_len -= PGM_OPT_PARITY_PRM_LEN;
635 break;
636
637 case PGM_OPT_PARITY_GRP:
638 #define PGM_OPT_PARITY_GRP_LEN (2+2+4)
639 if (opt_len != PGM_OPT_PARITY_GRP_LEN) {
640 ND_PRINT("[Bad OPT_PARITY_GRP option, length %u != %u]",
641 opt_len, PGM_OPT_PARITY_GRP_LEN);
642 return;
643 }
644 bp += 2;
645 seq = EXTRACT_BE_U_4(bp);
646 bp += 4;
647 ND_PRINT(" PARITY GROUP %u", seq);
648 opts_len -= PGM_OPT_PARITY_GRP_LEN;
649 break;
650
651 case PGM_OPT_CURR_TGSIZE:
652 #define PGM_OPT_CURR_TGSIZE_LEN (2+2+4)
653 if (opt_len != PGM_OPT_CURR_TGSIZE_LEN) {
654 ND_PRINT("[Bad OPT_CURR_TGSIZE option, length %u != %u]",
655 opt_len, PGM_OPT_CURR_TGSIZE_LEN);
656 return;
657 }
658 bp += 2;
659 len = EXTRACT_BE_U_4(bp);
660 bp += 4;
661 ND_PRINT(" PARITY ATGS %u", len);
662 opts_len -= PGM_OPT_CURR_TGSIZE_LEN;
663 break;
664
665 case PGM_OPT_NBR_UNREACH:
666 #define PGM_OPT_NBR_UNREACH_LEN (2+2)
667 if (opt_len != PGM_OPT_NBR_UNREACH_LEN) {
668 ND_PRINT("[Bad OPT_NBR_UNREACH option, length %u != %u]",
669 opt_len, PGM_OPT_NBR_UNREACH_LEN);
670 return;
671 }
672 bp += 2;
673 ND_PRINT(" NBR_UNREACH");
674 opts_len -= PGM_OPT_NBR_UNREACH_LEN;
675 break;
676
677 case PGM_OPT_PATH_NLA:
678 ND_PRINT(" PATH_NLA [%u]", opt_len);
679 bp += opt_len;
680 opts_len -= opt_len;
681 break;
682
683 case PGM_OPT_SYN:
684 #define PGM_OPT_SYN_LEN (2+2)
685 if (opt_len != PGM_OPT_SYN_LEN) {
686 ND_PRINT("[Bad OPT_SYN option, length %u != %u]",
687 opt_len, PGM_OPT_SYN_LEN);
688 return;
689 }
690 bp += 2;
691 ND_PRINT(" SYN");
692 opts_len -= PGM_OPT_SYN_LEN;
693 break;
694
695 case PGM_OPT_FIN:
696 #define PGM_OPT_FIN_LEN (2+2)
697 if (opt_len != PGM_OPT_FIN_LEN) {
698 ND_PRINT("[Bad OPT_FIN option, length %u != %u]",
699 opt_len, PGM_OPT_FIN_LEN);
700 return;
701 }
702 bp += 2;
703 ND_PRINT(" FIN");
704 opts_len -= PGM_OPT_FIN_LEN;
705 break;
706
707 case PGM_OPT_RST:
708 #define PGM_OPT_RST_LEN (2+2)
709 if (opt_len != PGM_OPT_RST_LEN) {
710 ND_PRINT("[Bad OPT_RST option, length %u != %u]",
711 opt_len, PGM_OPT_RST_LEN);
712 return;
713 }
714 bp += 2;
715 ND_PRINT(" RST");
716 opts_len -= PGM_OPT_RST_LEN;
717 break;
718
719 case PGM_OPT_CR:
720 ND_PRINT(" CR");
721 bp += opt_len;
722 opts_len -= opt_len;
723 break;
724
725 case PGM_OPT_CRQST:
726 #define PGM_OPT_CRQST_LEN (2+2)
727 if (opt_len != PGM_OPT_CRQST_LEN) {
728 ND_PRINT("[Bad OPT_CRQST option, length %u != %u]",
729 opt_len, PGM_OPT_CRQST_LEN);
730 return;
731 }
732 bp += 2;
733 ND_PRINT(" CRQST");
734 opts_len -= PGM_OPT_CRQST_LEN;
735 break;
736
737 case PGM_OPT_PGMCC_DATA:
738 #define PGM_OPT_PGMCC_DATA_FIXED_LEN (2+2+4+2+2)
739 if (opt_len < PGM_OPT_PGMCC_DATA_FIXED_LEN) {
740 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u < %u]",
741 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
742 return;
743 }
744 bp += 2;
745 offset = EXTRACT_BE_U_4(bp);
746 bp += 4;
747 nla_afnum = EXTRACT_BE_U_2(bp);
748 bp += 2+2;
749 switch (nla_afnum) {
750 case AFNUM_INET:
751 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4)) {
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_ipv4));
757 addrtostr(bp, nla_buf, sizeof(nla_buf));
758 bp += sizeof(nd_ipv4);
759 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4);
760 break;
761 case AFNUM_INET6:
762 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6)) {
763 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
764 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
765 return;
766 }
767 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
768 addrtostr6(bp, nla_buf, sizeof(nla_buf));
769 bp += sizeof(nd_ipv6);
770 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6);
771 break;
772 default:
773 goto trunc;
774 break;
775 }
776
777 ND_PRINT(" PGMCC DATA %u %s", offset, nla_buf);
778 break;
779
780 case PGM_OPT_PGMCC_FEEDBACK:
781 #define PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN (2+2+4+2+2)
782 if (opt_len < PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN) {
783 ND_PRINT("[Bad PGM_OPT_PGMCC_FEEDBACK option, length %u < %u]",
784 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
785 return;
786 }
787 bp += 2;
788 offset = EXTRACT_BE_U_4(bp);
789 bp += 4;
790 nla_afnum = EXTRACT_BE_U_2(bp);
791 bp += 2+2;
792 switch (nla_afnum) {
793 case AFNUM_INET:
794 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4)) {
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_ipv4));
800 addrtostr(bp, nla_buf, sizeof(nla_buf));
801 bp += sizeof(nd_ipv4);
802 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4);
803 break;
804 case AFNUM_INET6:
805 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6)) {
806 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
807 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
808 return;
809 }
810 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
811 addrtostr6(bp, nla_buf, sizeof(nla_buf));
812 bp += sizeof(nd_ipv6);
813 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6);
814 break;
815 default:
816 goto trunc;
817 break;
818 }
819
820 ND_PRINT(" PGMCC FEEDBACK %u %s", offset, nla_buf);
821 break;
822
823 default:
824 ND_PRINT(" OPT_%02X [%u] ", opt_type, opt_len);
825 bp += opt_len;
826 opts_len -= opt_len;
827 break;
828 }
829
830 if (opt_type & PGM_OPT_END)
831 break;
832 }
833 }
834
835 ND_PRINT(" [%u]", length);
836 if (ndo->ndo_packettype == PT_PGM_ZMTP1 &&
837 (pgm_type_val == PGM_ODATA || pgm_type_val == PGM_RDATA))
838 zmtp1_datagram_print(ndo, bp,
839 EXTRACT_BE_U_2(pgm->pgm_length));
840
841 return;
842
843 trunc:
844 nd_print_trunc(ndo);
845 if (ch != '\0')
846 ND_PRINT(">");
847 }