blob: b6138c6fdd4a6d76314381eee68b5095eb847914 [file] [log] [blame]
The Android Open Source Project2949f582009-03-03 19:30:46 -08001/*
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
17static const char rcsid[] _U_ =
JP Abgrall53f17a92014-02-12 14:02:41 -080018 "@(#) $Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.5 2005-06-07 22:05:58 guy Exp $";
The Android Open Source Project2949f582009-03-03 19:30:46 -080019#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 */
44struct 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
54struct 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
64struct 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
JP Abgrall53f17a92014-02-12 14:02:41 -080075struct pgm_ack {
76 u_int32_t pgma_rx_max_seq;
77 u_int32_t pgma_bitmap;
78 /* ... options */
79};
80
The Android Open Source Project2949f582009-03-03 19:30:46 -080081struct pgm_poll {
82 u_int32_t pgmp_seq;
83 u_int16_t pgmp_round;
84 u_int16_t pgmp_reserved;
85 /* ... options */
86};
87
88struct 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
98struct pgm_data {
99 u_int32_t pgmd_seq;
100 u_int32_t pgmd_trailseq;
101 /* ... options */
102};
103
104typedef 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
JP Abgrall53f17a92014-02-12 14:02:41 -0800142
143#define PGM_OPT_PGMCC_DATA 0x12
144#define PGM_OPT_PGMCC_FEEDBACK 0x13
The Android Open Source Project2949f582009-03-03 19:30:46 -0800145
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
157void
158pgm_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
JP Abgrall53f17a92014-02-12 14:02:41 -0800174 u_int8_t opt_type, opt_len;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800175 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
JP Abgrall53f17a92014-02-12 14:02:41 -0800240 (void)printf("PGM, length %u", EXTRACT_16BITS(&pgm->pgm_length));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800241
242 if (!vflag)
243 return;
244
The Android Open Source Project2949f582009-03-03 19:30:46 -0800245 (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
JP Abgrall53f17a92014-02-12 14:02:41 -0800455 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
The Android Open Source Project2949f582009-03-03 19:30:46 -0800466 case PGM_SPMR:
467 (void)printf("SPMR");
468 break;
469
470 default:
JP Abgrall53f17a92014-02-12 14:02:41 -0800471 (void)printf("UNKNOWN type 0x%02x", pgm->pgm_type);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800472 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 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800545 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800546 seq = EXTRACT_32BITS(bp);
547 bp += sizeof(u_int32_t);
548 offset = EXTRACT_32BITS(bp);
549 bp += sizeof(u_int32_t);
550 len = EXTRACT_32BITS(bp);
551 bp += sizeof(u_int32_t);
552 (void)printf(" FRAG seq %u off %u len %u", seq, offset, len);
553 opts_len -= 16;
554 break;
555
556 case PGM_OPT_NAK_LIST:
JP Abgrall53f17a92014-02-12 14:02:41 -0800557 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800558 opt_len -= sizeof(u_int32_t); /* option header */
559 (void)printf(" NAK LIST");
560 while (opt_len) {
561 if (opt_len < sizeof(u_int32_t)) {
562 (void)printf("[Option length not a multiple of 4]");
563 return;
564 }
565 TCHECK2(*bp, sizeof(u_int32_t));
566 (void)printf(" %u", EXTRACT_32BITS(bp));
567 bp += sizeof(u_int32_t);
568 opt_len -= sizeof(u_int32_t);
569 opts_len -= sizeof(u_int32_t);
570 }
571 break;
572
573 case PGM_OPT_JOIN:
574 if (opt_len != 8) {
575 (void)printf("[Bad OPT_JOIN option, length %u != 8]", opt_len);
576 return;
577 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800578 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800579 seq = EXTRACT_32BITS(bp);
580 bp += sizeof(u_int32_t);
581 (void)printf(" JOIN %u", seq);
582 opts_len -= 8;
583 break;
584
585 case PGM_OPT_NAK_BO_IVL:
586 if (opt_len != 12) {
587 (void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len);
588 return;
589 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800590 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800591 offset = EXTRACT_32BITS(bp);
592 bp += sizeof(u_int32_t);
593 seq = EXTRACT_32BITS(bp);
594 bp += sizeof(u_int32_t);
595 (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq);
596 opts_len -= 12;
597 break;
598
599 case PGM_OPT_NAK_BO_RNG:
600 if (opt_len != 12) {
601 (void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len);
602 return;
603 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800604 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800605 offset = EXTRACT_32BITS(bp);
606 bp += sizeof(u_int32_t);
607 seq = EXTRACT_32BITS(bp);
608 bp += sizeof(u_int32_t);
609 (void)printf(" BACKOFF max %u min %u", offset, seq);
610 opts_len -= 12;
611 break;
612
613 case PGM_OPT_REDIRECT:
JP Abgrall53f17a92014-02-12 14:02:41 -0800614 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800615 switch (EXTRACT_16BITS(bp)) {
616 case AFI_IP:
617 addr_size = sizeof(struct in_addr);
618 nla_af = AF_INET;
619 break;
620#ifdef INET6
621 case AFI_IP6:
622 addr_size = sizeof(struct in6_addr);
623 nla_af = AF_INET6;
624 break;
625#endif
626 default:
627 goto trunc;
628 break;
629 }
630 bp += (2 * sizeof(u_int16_t));
631 if (opt_len != 4 + addr_size) {
632 (void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len);
633 return;
634 }
635 TCHECK2(*bp, addr_size);
636 nla = bp;
637 bp += addr_size;
638
639 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
640 (void)printf(" REDIRECT %s", (char *)nla);
641 opts_len -= 4 + addr_size;
642 break;
643
644 case PGM_OPT_PARITY_PRM:
645 if (opt_len != 8) {
646 (void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len);
647 return;
648 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800649 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800650 len = EXTRACT_32BITS(bp);
651 bp += sizeof(u_int32_t);
652 (void)printf(" PARITY MAXTGS %u", len);
653 opts_len -= 8;
654 break;
655
656 case PGM_OPT_PARITY_GRP:
657 if (opt_len != 8) {
658 (void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len);
659 return;
660 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800661 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800662 seq = EXTRACT_32BITS(bp);
663 bp += sizeof(u_int32_t);
664 (void)printf(" PARITY GROUP %u", seq);
665 opts_len -= 8;
666 break;
667
668 case PGM_OPT_CURR_TGSIZE:
669 if (opt_len != 8) {
670 (void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len);
671 return;
672 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800673 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800674 len = EXTRACT_32BITS(bp);
675 bp += sizeof(u_int32_t);
676 (void)printf(" PARITY ATGS %u", len);
677 opts_len -= 8;
678 break;
679
680 case PGM_OPT_NBR_UNREACH:
681 if (opt_len != 4) {
682 (void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len);
683 return;
684 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800685 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800686 (void)printf(" NBR_UNREACH");
687 opts_len -= 4;
688 break;
689
690 case PGM_OPT_PATH_NLA:
691 (void)printf(" PATH_NLA [%d]", opt_len);
692 bp += opt_len;
693 opts_len -= opt_len;
694 break;
695
696 case PGM_OPT_SYN:
697 if (opt_len != 4) {
698 (void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len);
699 return;
700 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800701 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800702 (void)printf(" SYN");
703 opts_len -= 4;
704 break;
705
706 case PGM_OPT_FIN:
707 if (opt_len != 4) {
708 (void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len);
709 return;
710 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800711 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800712 (void)printf(" FIN");
713 opts_len -= 4;
714 break;
715
716 case PGM_OPT_RST:
717 if (opt_len != 4) {
718 (void)printf("[Bad OPT_RST option, length %u != 4]", opt_len);
719 return;
720 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800721 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800722 (void)printf(" RST");
723 opts_len -= 4;
724 break;
725
726 case PGM_OPT_CR:
727 (void)printf(" CR");
728 bp += opt_len;
729 opts_len -= opt_len;
730 break;
731
732 case PGM_OPT_CRQST:
733 if (opt_len != 4) {
734 (void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len);
735 return;
736 }
JP Abgrall53f17a92014-02-12 14:02:41 -0800737 bp += 2;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800738 (void)printf(" CRQST");
739 opts_len -= 4;
740 break;
741
JP Abgrall53f17a92014-02-12 14:02:41 -0800742 case PGM_OPT_PGMCC_DATA:
743 bp += 2;
744 offset = EXTRACT_32BITS(bp);
745 bp += sizeof(u_int32_t);
746 switch (EXTRACT_16BITS(bp)) {
747 case AFI_IP:
748 addr_size = sizeof(struct in_addr);
749 nla_af = AF_INET;
750 break;
751#ifdef INET6
752 case AFI_IP6:
753 addr_size = sizeof(struct in6_addr);
754 nla_af = AF_INET6;
755 break;
756#endif
757 default:
758 goto trunc;
759 break;
760 }
761 bp += (2 * sizeof(u_int16_t));
762 if (opt_len != 12 + addr_size) {
763 (void)printf("[Bad OPT_PGMCC_DATA option, length %u != 12 + address size]", opt_len);
764 return;
765 }
766 TCHECK2(*bp, addr_size);
767 nla = bp;
768 bp += addr_size;
769
770 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
771 (void)printf(" PGMCC DATA %u %s", offset, (char*)nla);
772 opts_len -= 16;
773 break;
774
775 case PGM_OPT_PGMCC_FEEDBACK:
776 bp += 2;
777 offset = EXTRACT_32BITS(bp);
778 bp += sizeof(u_int32_t);
779 switch (EXTRACT_16BITS(bp)) {
780 case AFI_IP:
781 addr_size = sizeof(struct in_addr);
782 nla_af = AF_INET;
783 break;
784#ifdef INET6
785 case AFI_IP6:
786 addr_size = sizeof(struct in6_addr);
787 nla_af = AF_INET6;
788 break;
789#endif
790 default:
791 goto trunc;
792 break;
793 }
794 bp += (2 * sizeof(u_int16_t));
795 if (opt_len != 12 + addr_size) {
796 (void)printf("[Bad OPT_PGMCC_FEEDBACK option, length %u != 12 + address size]", opt_len);
797 return;
798 }
799 TCHECK2(*bp, addr_size);
800 nla = bp;
801 bp += addr_size;
802
803 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
804 (void)printf(" PGMCC FEEDBACK %u %s", offset, (char*)nla);
805 opts_len -= 16;
806 break;
807
The Android Open Source Project2949f582009-03-03 19:30:46 -0800808 default:
809 (void)printf(" OPT_%02X [%d] ", opt_type, opt_len);
810 bp += opt_len;
811 opts_len -= opt_len;
812 break;
813 }
814
815 if (opt_type & PGM_OPT_END)
816 break;
817 }
818 }
819
JP Abgrall53f17a92014-02-12 14:02:41 -0800820 (void)printf(" [%u]", length);
821 if (packettype == PT_PGM_ZMTP1 &&
822 (pgm->pgm_type == PGM_ODATA || pgm->pgm_type == PGM_RDATA))
823 zmtp1_print_datagram(bp, EXTRACT_16BITS(&pgm->pgm_length));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800824
825 return;
826
827trunc:
828 fputs("[|pgm]", stdout);
829 if (ch != '\0')
830 putchar('>');
831}