]> The Tcpdump Group git mirrors - tcpdump/blob - print-pgm.c
Fix a warning
[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_subtype;
78 nd_uint16_t pgmp_nla_afi;
79 nd_uint16_t pgmp_reserved;
80 /* ... uint8_t pgmp_nla[0]; */
81 /* ... options */
82 };
83
84 struct pgm_polr {
85 nd_uint32_t pgmp_seq;
86 nd_uint16_t pgmp_round;
87 nd_uint16_t pgmp_reserved;
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 = GET_BE_U_2(pgm->pgm_sport);
182 dport = GET_BE_U_2(pgm->pgm_dport);
183
184 if (ip6) {
185 if (GET_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 (GET_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", GET_BE_U_2(pgm->pgm_length));
211
212 if (!ndo->ndo_vflag)
213 return;
214
215 pgm_type_val = GET_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 (GET_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 GET_BE_U_4(spm->pgms_seq),
249 GET_BE_U_4(spm->pgms_trailseq),
250 GET_BE_U_4(spm->pgms_leadseq),
251 nla_buf);
252 break;
253 }
254
255 case PGM_POLL: {
256 const struct pgm_poll *pgm_poll;
257 uint32_t ivl, rnd, mask;
258
259 pgm_poll = (const struct pgm_poll *)(pgm + 1);
260 ND_TCHECK_SIZE(pgm_poll);
261 bp = (const u_char *) (pgm_poll + 1);
262
263 switch (GET_BE_U_2(pgm_poll->pgmp_nla_afi)) {
264 case AFNUM_INET:
265 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
266 addrtostr(bp, nla_buf, sizeof(nla_buf));
267 bp += sizeof(nd_ipv4);
268 break;
269 case AFNUM_INET6:
270 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
271 addrtostr6(bp, nla_buf, sizeof(nla_buf));
272 bp += sizeof(nd_ipv6);
273 break;
274 default:
275 goto trunc;
276 break;
277 }
278
279 ND_TCHECK_LEN(bp, sizeof(uint32_t));
280 ivl = GET_BE_U_4(bp);
281 bp += sizeof(uint32_t);
282
283 ND_TCHECK_LEN(bp, sizeof(uint32_t));
284 rnd = GET_BE_U_4(bp);
285 bp += sizeof(uint32_t);
286
287 ND_TCHECK_LEN(bp, sizeof(uint32_t));
288 mask = GET_BE_U_4(bp);
289 bp += sizeof(uint32_t);
290
291 ND_PRINT("POLL seq %u round %u nla %s ivl %u rnd 0x%08x "
292 "mask 0x%08x", GET_BE_U_4(pgm_poll->pgmp_seq),
293 GET_BE_U_2(pgm_poll->pgmp_round), nla_buf, ivl, rnd,
294 mask);
295 break;
296 }
297 case PGM_POLR: {
298 const struct pgm_polr *polr_msg;
299
300 polr_msg = (const struct pgm_polr *)(pgm + 1);
301 ND_TCHECK_SIZE(polr_msg);
302 ND_PRINT("POLR seq %u round %u",
303 GET_BE_U_4(polr_msg->pgmp_seq),
304 GET_BE_U_2(polr_msg->pgmp_round));
305 bp = (const u_char *) (polr_msg + 1);
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 GET_BE_U_4(odata->pgmd_trailseq),
315 GET_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 GET_BE_U_4(rdata->pgmd_trailseq),
327 GET_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 (GET_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 (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 ND_TCHECK_2(bp);
463 opt_type = GET_U_1(bp);
464 bp++;
465 opt_len = GET_U_1(bp);
466 bp++;
467 if (opt_len < PGM_MIN_OPT_LEN) {
468 ND_PRINT("[Bad option, length %u < %u]", opt_len,
469 PGM_MIN_OPT_LEN);
470 break;
471 }
472 if (opts_len < opt_len) {
473 ND_PRINT("[Total option length leaves no room for final option]");
474 return;
475 }
476 ND_TCHECK_LEN(bp, opt_len - 2);
477
478 switch (opt_type & PGM_OPT_MASK) {
479 case PGM_OPT_LENGTH:
480 #define PGM_OPT_LENGTH_LEN (2+2)
481 if (opt_len != PGM_OPT_LENGTH_LEN) {
482 ND_PRINT("[Bad OPT_LENGTH option, length %u != %u]",
483 opt_len, PGM_OPT_LENGTH_LEN);
484 return;
485 }
486 ND_PRINT(" OPTS LEN (extra?) %u", GET_BE_U_2(bp));
487 bp += 2;
488 opts_len -= PGM_OPT_LENGTH_LEN;
489 break;
490
491 case PGM_OPT_FRAGMENT:
492 #define PGM_OPT_FRAGMENT_LEN (2+2+4+4+4)
493 if (opt_len != PGM_OPT_FRAGMENT_LEN) {
494 ND_PRINT("[Bad OPT_FRAGMENT option, length %u != %u]",
495 opt_len, PGM_OPT_FRAGMENT_LEN);
496 return;
497 }
498 bp += 2;
499 seq = GET_BE_U_4(bp);
500 bp += 4;
501 offset = GET_BE_U_4(bp);
502 bp += 4;
503 len = GET_BE_U_4(bp);
504 bp += 4;
505 ND_PRINT(" FRAG seq %u off %u len %u", seq, offset, len);
506 opts_len -= PGM_OPT_FRAGMENT_LEN;
507 break;
508
509 case PGM_OPT_NAK_LIST:
510 bp += 2;
511 opt_len -= 4; /* option header */
512 ND_PRINT(" NAK LIST");
513 while (opt_len) {
514 if (opt_len < 4) {
515 ND_PRINT("[Option length not a multiple of 4]");
516 return;
517 }
518 ND_TCHECK_4(bp);
519 ND_PRINT(" %u", GET_BE_U_4(bp));
520 bp += 4;
521 opt_len -= 4;
522 opts_len -= 4;
523 }
524 break;
525
526 case PGM_OPT_JOIN:
527 #define PGM_OPT_JOIN_LEN (2+2+4)
528 if (opt_len != PGM_OPT_JOIN_LEN) {
529 ND_PRINT("[Bad OPT_JOIN option, length %u != %u]",
530 opt_len, PGM_OPT_JOIN_LEN);
531 return;
532 }
533 bp += 2;
534 seq = GET_BE_U_4(bp);
535 bp += 4;
536 ND_PRINT(" JOIN %u", seq);
537 opts_len -= PGM_OPT_JOIN_LEN;
538 break;
539
540 case PGM_OPT_NAK_BO_IVL:
541 #define PGM_OPT_NAK_BO_IVL_LEN (2+2+4+4)
542 if (opt_len != PGM_OPT_NAK_BO_IVL_LEN) {
543 ND_PRINT("[Bad OPT_NAK_BO_IVL option, length %u != %u]",
544 opt_len, PGM_OPT_NAK_BO_IVL_LEN);
545 return;
546 }
547 bp += 2;
548 offset = GET_BE_U_4(bp);
549 bp += 4;
550 seq = GET_BE_U_4(bp);
551 bp += 4;
552 ND_PRINT(" BACKOFF ivl %u ivlseq %u", offset, seq);
553 opts_len -= PGM_OPT_NAK_BO_IVL_LEN;
554 break;
555
556 case PGM_OPT_NAK_BO_RNG:
557 #define PGM_OPT_NAK_BO_RNG_LEN (2+2+4+4)
558 if (opt_len != PGM_OPT_NAK_BO_RNG_LEN) {
559 ND_PRINT("[Bad OPT_NAK_BO_RNG option, length %u != %u]",
560 opt_len, PGM_OPT_NAK_BO_RNG_LEN);
561 return;
562 }
563 bp += 2;
564 offset = GET_BE_U_4(bp);
565 bp += 4;
566 seq = GET_BE_U_4(bp);
567 bp += 4;
568 ND_PRINT(" BACKOFF max %u min %u", offset, seq);
569 opts_len -= PGM_OPT_NAK_BO_RNG_LEN;
570 break;
571
572 case PGM_OPT_REDIRECT:
573 #define PGM_OPT_REDIRECT_FIXED_LEN (2+2+2+2)
574 if (opt_len < PGM_OPT_REDIRECT_FIXED_LEN) {
575 ND_PRINT("[Bad OPT_REDIRECT option, length %u < %u]",
576 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
577 return;
578 }
579 bp += 2;
580 nla_afnum = GET_BE_U_2(bp);
581 bp += 2+2;
582 switch (nla_afnum) {
583 case AFNUM_INET:
584 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4)) {
585 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
586 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
587 return;
588 }
589 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
590 addrtostr(bp, nla_buf, sizeof(nla_buf));
591 bp += sizeof(nd_ipv4);
592 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4);
593 break;
594 case AFNUM_INET6:
595 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6)) {
596 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
597 PGM_OPT_REDIRECT_FIXED_LEN, opt_len);
598 return;
599 }
600 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
601 addrtostr6(bp, nla_buf, sizeof(nla_buf));
602 bp += sizeof(nd_ipv6);
603 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6);
604 break;
605 default:
606 goto trunc;
607 break;
608 }
609
610 ND_PRINT(" REDIRECT %s", nla_buf);
611 break;
612
613 case PGM_OPT_PARITY_PRM:
614 #define PGM_OPT_PARITY_PRM_LEN (2+2+4)
615 if (opt_len != PGM_OPT_PARITY_PRM_LEN) {
616 ND_PRINT("[Bad OPT_PARITY_PRM option, length %u != %u]",
617 opt_len, PGM_OPT_PARITY_PRM_LEN);
618 return;
619 }
620 bp += 2;
621 len = GET_BE_U_4(bp);
622 bp += 4;
623 ND_PRINT(" PARITY MAXTGS %u", len);
624 opts_len -= PGM_OPT_PARITY_PRM_LEN;
625 break;
626
627 case PGM_OPT_PARITY_GRP:
628 #define PGM_OPT_PARITY_GRP_LEN (2+2+4)
629 if (opt_len != PGM_OPT_PARITY_GRP_LEN) {
630 ND_PRINT("[Bad OPT_PARITY_GRP option, length %u != %u]",
631 opt_len, PGM_OPT_PARITY_GRP_LEN);
632 return;
633 }
634 bp += 2;
635 seq = GET_BE_U_4(bp);
636 bp += 4;
637 ND_PRINT(" PARITY GROUP %u", seq);
638 opts_len -= PGM_OPT_PARITY_GRP_LEN;
639 break;
640
641 case PGM_OPT_CURR_TGSIZE:
642 #define PGM_OPT_CURR_TGSIZE_LEN (2+2+4)
643 if (opt_len != PGM_OPT_CURR_TGSIZE_LEN) {
644 ND_PRINT("[Bad OPT_CURR_TGSIZE option, length %u != %u]",
645 opt_len, PGM_OPT_CURR_TGSIZE_LEN);
646 return;
647 }
648 bp += 2;
649 len = GET_BE_U_4(bp);
650 bp += 4;
651 ND_PRINT(" PARITY ATGS %u", len);
652 opts_len -= PGM_OPT_CURR_TGSIZE_LEN;
653 break;
654
655 case PGM_OPT_NBR_UNREACH:
656 #define PGM_OPT_NBR_UNREACH_LEN (2+2)
657 if (opt_len != PGM_OPT_NBR_UNREACH_LEN) {
658 ND_PRINT("[Bad OPT_NBR_UNREACH option, length %u != %u]",
659 opt_len, PGM_OPT_NBR_UNREACH_LEN);
660 return;
661 }
662 bp += 2;
663 ND_PRINT(" NBR_UNREACH");
664 opts_len -= PGM_OPT_NBR_UNREACH_LEN;
665 break;
666
667 case PGM_OPT_PATH_NLA:
668 ND_PRINT(" PATH_NLA [%u]", opt_len);
669 bp += opt_len;
670 opts_len -= opt_len;
671 break;
672
673 case PGM_OPT_SYN:
674 #define PGM_OPT_SYN_LEN (2+2)
675 if (opt_len != PGM_OPT_SYN_LEN) {
676 ND_PRINT("[Bad OPT_SYN option, length %u != %u]",
677 opt_len, PGM_OPT_SYN_LEN);
678 return;
679 }
680 bp += 2;
681 ND_PRINT(" SYN");
682 opts_len -= PGM_OPT_SYN_LEN;
683 break;
684
685 case PGM_OPT_FIN:
686 #define PGM_OPT_FIN_LEN (2+2)
687 if (opt_len != PGM_OPT_FIN_LEN) {
688 ND_PRINT("[Bad OPT_FIN option, length %u != %u]",
689 opt_len, PGM_OPT_FIN_LEN);
690 return;
691 }
692 bp += 2;
693 ND_PRINT(" FIN");
694 opts_len -= PGM_OPT_FIN_LEN;
695 break;
696
697 case PGM_OPT_RST:
698 #define PGM_OPT_RST_LEN (2+2)
699 if (opt_len != PGM_OPT_RST_LEN) {
700 ND_PRINT("[Bad OPT_RST option, length %u != %u]",
701 opt_len, PGM_OPT_RST_LEN);
702 return;
703 }
704 bp += 2;
705 ND_PRINT(" RST");
706 opts_len -= PGM_OPT_RST_LEN;
707 break;
708
709 case PGM_OPT_CR:
710 ND_PRINT(" CR");
711 bp += opt_len;
712 opts_len -= opt_len;
713 break;
714
715 case PGM_OPT_CRQST:
716 #define PGM_OPT_CRQST_LEN (2+2)
717 if (opt_len != PGM_OPT_CRQST_LEN) {
718 ND_PRINT("[Bad OPT_CRQST option, length %u != %u]",
719 opt_len, PGM_OPT_CRQST_LEN);
720 return;
721 }
722 bp += 2;
723 ND_PRINT(" CRQST");
724 opts_len -= PGM_OPT_CRQST_LEN;
725 break;
726
727 case PGM_OPT_PGMCC_DATA:
728 #define PGM_OPT_PGMCC_DATA_FIXED_LEN (2+2+4+2+2)
729 if (opt_len < PGM_OPT_PGMCC_DATA_FIXED_LEN) {
730 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u < %u]",
731 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
732 return;
733 }
734 bp += 2;
735 offset = GET_BE_U_4(bp);
736 bp += 4;
737 nla_afnum = GET_BE_U_2(bp);
738 bp += 2+2;
739 switch (nla_afnum) {
740 case AFNUM_INET:
741 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4)) {
742 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
743 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
744 return;
745 }
746 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
747 addrtostr(bp, nla_buf, sizeof(nla_buf));
748 bp += sizeof(nd_ipv4);
749 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4);
750 break;
751 case AFNUM_INET6:
752 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6)) {
753 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
754 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
755 return;
756 }
757 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
758 addrtostr6(bp, nla_buf, sizeof(nla_buf));
759 bp += sizeof(nd_ipv6);
760 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6);
761 break;
762 default:
763 goto trunc;
764 break;
765 }
766
767 ND_PRINT(" PGMCC DATA %u %s", offset, nla_buf);
768 break;
769
770 case PGM_OPT_PGMCC_FEEDBACK:
771 #define PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN (2+2+4+2+2)
772 if (opt_len < PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN) {
773 ND_PRINT("[Bad PGM_OPT_PGMCC_FEEDBACK option, length %u < %u]",
774 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
775 return;
776 }
777 bp += 2;
778 offset = GET_BE_U_4(bp);
779 bp += 4;
780 nla_afnum = GET_BE_U_2(bp);
781 bp += 2+2;
782 switch (nla_afnum) {
783 case AFNUM_INET:
784 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4)) {
785 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
786 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
787 return;
788 }
789 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
790 addrtostr(bp, nla_buf, sizeof(nla_buf));
791 bp += sizeof(nd_ipv4);
792 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4);
793 break;
794 case AFNUM_INET6:
795 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6)) {
796 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
797 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
798 return;
799 }
800 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
801 addrtostr6(bp, nla_buf, sizeof(nla_buf));
802 bp += sizeof(nd_ipv6);
803 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6);
804 break;
805 default:
806 goto trunc;
807 break;
808 }
809
810 ND_PRINT(" PGMCC FEEDBACK %u %s", offset, nla_buf);
811 break;
812
813 default:
814 ND_PRINT(" OPT_%02X [%u] ", opt_type, opt_len);
815 bp += opt_len;
816 opts_len -= opt_len;
817 break;
818 }
819
820 if (opt_type & PGM_OPT_END)
821 break;
822 }
823 }
824
825 ND_PRINT(" [%u]", length);
826 if (ndo->ndo_packettype == PT_PGM_ZMTP1 &&
827 (pgm_type_val == PGM_ODATA || pgm_type_val == PGM_RDATA))
828 zmtp1_datagram_print(ndo, bp,
829 GET_BE_U_2(pgm->pgm_length));
830
831 return;
832
833 trunc:
834 nd_print_trunc(ndo);
835 }