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