]> The Tcpdump Group git mirrors - tcpdump/blob - print-pgm.c
Rename AF_INET{6} to AF_IP{6}.
[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 #define ND_LONGJMP_FROM_TCHECK
25 #include "netdissect.h"
26 #include "extract.h"
27 #include "addrtoname.h"
28 #include "addrtostr.h"
29
30 #include "ip.h"
31 #include "ip6.h"
32 #include "ipproto.h"
33 #include "af.h"
34
35 /*
36 * PGM header (RFC 3208)
37 */
38 struct pgm_header {
39 nd_uint16_t pgm_sport;
40 nd_uint16_t pgm_dport;
41 nd_uint8_t pgm_type;
42 nd_uint8_t pgm_options;
43 nd_uint16_t pgm_sum;
44 nd_byte pgm_gsid[6];
45 nd_uint16_t pgm_length;
46 };
47
48 struct pgm_spm {
49 nd_uint32_t pgms_seq;
50 nd_uint32_t pgms_trailseq;
51 nd_uint32_t pgms_leadseq;
52 nd_uint16_t pgms_nla_afi;
53 nd_uint16_t pgms_reserved;
54 /* ... uint8_t pgms_nla[0]; */
55 /* ... options */
56 };
57
58 struct pgm_nak {
59 nd_uint32_t pgmn_seq;
60 nd_uint16_t pgmn_source_afi;
61 nd_uint16_t pgmn_reserved;
62 /* ... uint8_t pgmn_source[0]; */
63 /* ... uint16_t pgmn_group_afi */
64 /* ... uint16_t pgmn_reserved2; */
65 /* ... uint8_t pgmn_group[0]; */
66 /* ... options */
67 };
68
69 struct pgm_ack {
70 nd_uint32_t pgma_rx_max_seq;
71 nd_uint32_t pgma_bitmap;
72 /* ... options */
73 };
74
75 struct pgm_poll {
76 nd_uint32_t pgmp_seq;
77 nd_uint16_t pgmp_round;
78 nd_uint16_t pgmp_subtype;
79 nd_uint16_t pgmp_nla_afi;
80 nd_uint16_t pgmp_reserved;
81 /* ... uint8_t pgmp_nla[0]; */
82 /* ... options */
83 };
84
85 struct pgm_polr {
86 nd_uint32_t pgmp_seq;
87 nd_uint16_t pgmp_round;
88 nd_uint16_t pgmp_reserved;
89 /* ... options */
90 };
91
92 struct pgm_data {
93 nd_uint32_t pgmd_seq;
94 nd_uint32_t pgmd_trailseq;
95 /* ... options */
96 };
97
98 typedef enum _pgm_type {
99 PGM_SPM = 0, /* source path message */
100 PGM_POLL = 1, /* POLL Request */
101 PGM_POLR = 2, /* POLL Response */
102 PGM_ODATA = 4, /* original data */
103 PGM_RDATA = 5, /* repair data */
104 PGM_NAK = 8, /* NAK */
105 PGM_NULLNAK = 9, /* Null NAK */
106 PGM_NCF = 10, /* NAK Confirmation */
107 PGM_ACK = 11, /* ACK for congestion control */
108 PGM_SPMR = 12, /* SPM request */
109 PGM_MAX = 255
110 } pgm_type;
111
112 #define PGM_OPT_BIT_PRESENT 0x01
113 #define PGM_OPT_BIT_NETWORK 0x02
114 #define PGM_OPT_BIT_VAR_PKTLEN 0x40
115 #define PGM_OPT_BIT_PARITY 0x80
116
117 #define PGM_OPT_LENGTH 0x00
118 #define PGM_OPT_FRAGMENT 0x01
119 #define PGM_OPT_NAK_LIST 0x02
120 #define PGM_OPT_JOIN 0x03
121 #define PGM_OPT_NAK_BO_IVL 0x04
122 #define PGM_OPT_NAK_BO_RNG 0x05
123
124 #define PGM_OPT_REDIRECT 0x07
125 #define PGM_OPT_PARITY_PRM 0x08
126 #define PGM_OPT_PARITY_GRP 0x09
127 #define PGM_OPT_CURR_TGSIZE 0x0A
128 #define PGM_OPT_NBR_UNREACH 0x0B
129 #define PGM_OPT_PATH_NLA 0x0C
130
131 #define PGM_OPT_SYN 0x0D
132 #define PGM_OPT_FIN 0x0E
133 #define PGM_OPT_RST 0x0F
134 #define PGM_OPT_CR 0x10
135 #define PGM_OPT_CRQST 0x11
136
137 #define PGM_OPT_PGMCC_DATA 0x12
138 #define PGM_OPT_PGMCC_FEEDBACK 0x13
139
140 #define PGM_OPT_MASK 0x7f
141
142 #define PGM_OPT_END 0x80 /* end of options marker */
143
144 #define PGM_MIN_OPT_LEN 4
145
146 void
147 pgm_print(netdissect_options *ndo,
148 const u_char *bp, u_int length,
149 const u_char *bp2)
150 {
151 const struct pgm_header *pgm;
152 const struct ip *ip;
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 if (!ND_TTEST_2(pgm->pgm_dport)) {
169 if (ip6) {
170 ND_PRINT("%s > %s:",
171 GET_IP6ADDR_STRING(ip6->ip6_src),
172 GET_IP6ADDR_STRING(ip6->ip6_dst));
173 } else {
174 ND_PRINT("%s > %s:",
175 GET_IPADDR_STRING(ip->ip_src),
176 GET_IPADDR_STRING(ip->ip_dst));
177 }
178 nd_trunc_longjmp(ndo);
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 GET_IP6ADDR_STRING(ip6->ip6_src),
188 tcpport_string(ndo, sport),
189 GET_IP6ADDR_STRING(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 GET_IPADDR_STRING(ip->ip_src),
199 tcpport_string(ndo, sport),
200 GET_IPADDR_STRING(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_IP:
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_IP6:
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 invalid;
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_IP:
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_IP6:
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 invalid;
276 break;
277 }
278
279 ivl = GET_BE_U_4(bp);
280 bp += sizeof(uint32_t);
281
282 rnd = GET_BE_U_4(bp);
283 bp += sizeof(uint32_t);
284
285 mask = GET_BE_U_4(bp);
286 bp += sizeof(uint32_t);
287
288 ND_PRINT("POLL seq %u round %u nla %s ivl %u rnd 0x%08x "
289 "mask 0x%08x", GET_BE_U_4(pgm_poll->pgmp_seq),
290 GET_BE_U_2(pgm_poll->pgmp_round), nla_buf, ivl, rnd,
291 mask);
292 break;
293 }
294 case PGM_POLR: {
295 const struct pgm_polr *polr_msg;
296
297 polr_msg = (const struct pgm_polr *)(pgm + 1);
298 ND_TCHECK_SIZE(polr_msg);
299 ND_PRINT("POLR seq %u round %u",
300 GET_BE_U_4(polr_msg->pgmp_seq),
301 GET_BE_U_2(polr_msg->pgmp_round));
302 bp = (const u_char *) (polr_msg + 1);
303 break;
304 }
305 case PGM_ODATA: {
306 const struct pgm_data *odata;
307
308 odata = (const struct pgm_data *)(pgm + 1);
309 ND_PRINT("ODATA trail %u seq %u",
310 GET_BE_U_4(odata->pgmd_trailseq),
311 GET_BE_U_4(odata->pgmd_seq));
312 bp = (const u_char *) (odata + 1);
313 break;
314 }
315
316 case PGM_RDATA: {
317 const struct pgm_data *rdata;
318
319 rdata = (const struct pgm_data *)(pgm + 1);
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_IP:
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_IP6:
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 invalid;
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_IP:
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_IP6:
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 invalid;
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_IP:
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_IP6:
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 invalid;
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_IP:
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_IP6:
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 invalid;
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_IP:
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_IP6:
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 invalid;
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 invalid:
825 nd_print_invalid(ndo);
826 }