]> The Tcpdump Group git mirrors - tcpdump/blob - print-pgm.c
from Andy Heffernan <[email protected]>:
[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.1.2.1 2005-05-20 21:15:47 hannes 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 #include "ip6.h"
37 #include "ipproto.h"
38
39 /*
40 * PGM header (RFC 3208)
41 */
42 struct pgm_header {
43 u_int16_t pgm_sport;
44 u_int16_t pgm_dport;
45 u_int8_t pgm_type;
46 u_int8_t pgm_options;
47 u_int16_t pgm_sum;
48 u_int8_t pgm_gsid[6];
49 u_int16_t pgm_length;
50 };
51
52 struct pgm_spm {
53 u_int32_t pgms_seq;
54 u_int32_t pgms_trailseq;
55 u_int32_t pgms_leadseq;
56 u_int16_t pgms_nla_afi;
57 u_int16_t pgms_reserved;
58 u_int8_t pgms_nla[0];
59 /* ... options */
60 };
61
62 struct pgm_nak {
63 u_int32_t pgmn_seq;
64 u_int16_t pgmn_source_afi;
65 u_int16_t pgmn_reserved;
66 u_int8_t pgmn_source[0];
67 /* ... u_int16_t pgmn_group_afi */
68 /* ... u_int16_t pgmn_reserved2; */
69 /* ... u_int8_t pgmn_group[0]; */
70 /* ... options */
71 };
72
73 struct pgm_poll {
74 u_int32_t pgmp_seq;
75 u_int16_t pgmp_round;
76 u_int16_t pgmp_reserved;
77 /* ... options */
78 };
79
80 struct pgm_polr {
81 u_int32_t pgmp_seq;
82 u_int16_t pgmp_round;
83 u_int16_t pgmp_subtype;
84 u_int16_t pgmp_nla_afi;
85 u_int16_t pgmp_reserved;
86 u_int8_t pgmp_nla[0];
87 /* ... options */
88 };
89
90 struct pgm_data {
91 u_int32_t pgmd_seq;
92 u_int32_t pgmd_trailseq;
93 /* ... options */
94 };
95
96 typedef enum _pgm_type {
97 PGM_SPM = 0, /* source path message */
98 PGM_POLL = 1, /* POLL Request */
99 PGM_POLR = 2, /* POLL Response */
100 PGM_ODATA = 4, /* original data */
101 PGM_RDATA = 5, /* repair data */
102 PGM_NAK = 8, /* NAK */
103 PGM_NULLNAK = 9, /* Null NAK */
104 PGM_NCF = 10, /* NAK Confirmation */
105 PGM_ACK = 11, /* ACK for congestion control */
106 PGM_SPMR = 12, /* SPM request */
107 PGM_MAX = 255
108 } pgm_type;
109
110 #define PGM_OPT_BIT_PRESENT 0x01
111 #define PGM_OPT_BIT_NETWORK 0x02
112 #define PGM_OPT_BIT_VAR_PKTLEN 0x40
113 #define PGM_OPT_BIT_PARITY 0x80
114
115 #define PGM_OPT_LENGTH 0x00
116 #define PGM_OPT_FRAGMENT 0x01
117 #define PGM_OPT_NAK_LIST 0x02
118 #define PGM_OPT_JOIN 0x03
119 #define PGM_OPT_NAK_BO_IVL 0x04
120 #define PGM_OPT_NAK_BO_RNG 0x05
121
122 #define PGM_OPT_REDIRECT 0x07
123 #define PGM_OPT_PARITY_PRM 0x08
124 #define PGM_OPT_PARITY_GRP 0x09
125 #define PGM_OPT_CURR_TGSIZE 0x0A
126 #define PGM_OPT_NBR_UNREACH 0x0B
127 #define PGM_OPT_PATH_NLA 0x0C
128
129 #define PGM_OPT_SYN 0x0D
130 #define PGM_OPT_FIN 0x0E
131 #define PGM_OPT_RST 0x0F
132 #define PGM_OPT_CR 0x10
133 #define PGM_OPT_CRQST 0x11
134
135 #define PGM_OPT_MASK 0x7f
136
137 #define PGM_OPT_END 0x80 /* end of options marker */
138
139 #define PGM_MIN_OPT_LEN 4
140
141 #ifndef AFI_IP
142 #define AFI_IP 1
143 #define AFI_IP6 2
144 #endif
145
146 void
147 pgm_print(register const u_char *bp, register u_int length,
148 register const u_char *bp2)
149 {
150 register const struct pgm_header *pgm;
151 register const struct ip *ip;
152 register char ch;
153 u_int16_t sport, dport;
154 int addr_size;
155 const void *nla;
156 int nla_af;
157 char nla_buf[INET6_ADDRSTRLEN];
158 #ifdef INET6
159 register const struct ip6_hdr *ip6;
160 #endif
161
162 pgm = (struct pgm_header *)bp;
163 ip = (struct ip *)bp2;
164 #ifdef INET6
165 if (IP_V(ip) == 6)
166 ip6 = (struct ip6_hdr *)bp2;
167 else
168 ip6 = NULL;
169 #endif /*INET6*/
170 ch = '\0';
171 if (!TTEST(pgm->pgm_dport)) {
172 #ifdef INET6
173 if (ip6) {
174 (void)printf("%s > %s: [|pgm]",
175 ip6addr_string(&ip6->ip6_src),
176 ip6addr_string(&ip6->ip6_dst));
177 return;
178 } else
179 #endif /* INET6 */
180 {
181 (void)printf("%s > %s: [|pgm]",
182 ipaddr_string(&ip->ip_src),
183 ipaddr_string(&ip->ip_dst));
184 return;
185 }
186 }
187
188 sport = EXTRACT_16BITS(&pgm->pgm_sport);
189 dport = EXTRACT_16BITS(&pgm->pgm_dport);
190
191 #ifdef INET6
192 if (ip6) {
193 if (ip6->ip6_nxt == IPPROTO_PGM) {
194 (void)printf("%s.%s > %s.%s: ",
195 ip6addr_string(&ip6->ip6_src),
196 tcpport_string(sport),
197 ip6addr_string(&ip6->ip6_dst),
198 tcpport_string(dport));
199 } else {
200 (void)printf("%s > %s: ",
201 tcpport_string(sport), tcpport_string(dport));
202 }
203 } else
204 #endif /*INET6*/
205 {
206 if (ip->ip_p == IPPROTO_PGM) {
207 (void)printf("%s.%s > %s.%s: ",
208 ipaddr_string(&ip->ip_src),
209 tcpport_string(sport),
210 ipaddr_string(&ip->ip_dst),
211 tcpport_string(dport));
212 } else {
213 (void)printf("%s > %s: ",
214 tcpport_string(sport), tcpport_string(dport));
215 }
216 }
217
218 TCHECK(*pgm);
219
220 (void)printf("PGM, length %u", pgm->pgm_length);
221
222 if (!vflag)
223 return;
224
225 if (length > pgm->pgm_length)
226 length = pgm->pgm_length;
227
228 (void)printf(" 0x%02x%02x%02x%02x%02x%02x ",
229 pgm->pgm_gsid[0],
230 pgm->pgm_gsid[1],
231 pgm->pgm_gsid[2],
232 pgm->pgm_gsid[3],
233 pgm->pgm_gsid[4],
234 pgm->pgm_gsid[5]);
235 switch (pgm->pgm_type) {
236 case PGM_SPM: {
237 struct pgm_spm *spm;
238
239 spm = (struct pgm_spm *)(pgm + 1);
240 TCHECK(*spm);
241
242 switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) {
243 case AFI_IP:
244 addr_size = sizeof(struct in_addr);
245 nla_af = AF_INET;
246 break;
247 case AFI_IP6:
248 addr_size = sizeof(struct in6_addr);
249 nla_af = AF_INET6;
250 break;
251 default:
252 goto trunc;
253 break;
254 }
255 bp = (u_char *) (spm + 1);
256 TCHECK2(*bp, addr_size);
257 nla = bp;
258 bp += addr_size;
259
260 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
261 (void)printf("SPM seq %u trail %u lead %u nla %s",
262 EXTRACT_32BITS(&spm->pgms_seq),
263 EXTRACT_32BITS(&spm->pgms_trailseq),
264 EXTRACT_32BITS(&spm->pgms_leadseq),
265 nla_buf);
266 break;
267 }
268
269 case PGM_POLL: {
270 struct pgm_poll *poll;
271
272 poll = (struct pgm_poll *)(pgm + 1);
273 TCHECK(*poll);
274 (void)printf("POLL seq %u round %u",
275 EXTRACT_32BITS(&poll->pgmp_seq),
276 EXTRACT_16BITS(&poll->pgmp_round));
277 break;
278 }
279 case PGM_POLR: {
280 struct pgm_polr *polr;
281 u_int32_t ivl, rnd, mask;
282
283 polr = (struct pgm_polr *)(pgm + 1);
284 TCHECK(*polr);
285
286 switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) {
287 case AFI_IP:
288 addr_size = sizeof(struct in_addr);
289 nla_af = AF_INET;
290 break;
291 case AFI_IP6:
292 addr_size = sizeof(struct in6_addr);
293 nla_af = AF_INET6;
294 break;
295 default:
296 goto trunc;
297 break;
298 }
299 bp = (u_char *) (polr + 1);
300 TCHECK2(*bp, addr_size);
301 nla = bp;
302 bp += addr_size;
303
304 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
305
306 TCHECK2(*bp, sizeof(u_int32_t));
307 ivl = EXTRACT_32BITS(*(u_int32_t *)bp);
308 bp += sizeof(u_int32_t);
309
310 TCHECK2(*bp, sizeof(u_int32_t));
311 rnd = EXTRACT_32BITS(*(u_int32_t *)bp);
312 bp += sizeof(u_int32_t);
313
314 TCHECK2(*bp, sizeof(u_int32_t));
315 mask = EXTRACT_32BITS(*(u_int32_t *)bp);
316 bp += sizeof(u_int32_t);
317
318 (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
319 "mask 0x%08x", EXTRACT_32BITS(polr->pgmp_seq),
320 EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask);
321 break;
322 }
323 case PGM_ODATA: {
324 struct pgm_data *odata;
325
326 odata = (struct pgm_data *)(pgm + 1);
327 TCHECK(*odata);
328 (void)printf("ODATA trail %u seq %u",
329 EXTRACT_32BITS(odata->pgmd_trailseq), EXTRACT_32BITS(odata->pgmd_seq));
330 break;
331 }
332
333 case PGM_RDATA: {
334 struct pgm_data *rdata;
335
336 rdata = (struct pgm_data *)(pgm + 1);
337 TCHECK(*rdata);
338 (void)printf("RDATA trail %u seq %u",
339 EXTRACT_32BITS(rdata->pgmd_trailseq), EXTRACT_32BITS(rdata->pgmd_seq));
340 break;
341 }
342
343 case PGM_NAK:
344 case PGM_NULLNAK:
345 case PGM_NCF: {
346 struct pgm_nak *nak;
347 const void *source, *group;
348 int source_af, group_af;
349 char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
350
351 nak = (struct pgm_nak *)(pgm + 1);
352 TCHECK(*nak);
353
354 /*
355 * Skip past the source, saving info along the way
356 * and stopping if we don't have enough.
357 */
358 switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) {
359 case AFI_IP:
360 addr_size = sizeof(struct in_addr);
361 source_af = AF_INET;
362 break;
363 case AFI_IP6:
364 addr_size = sizeof(struct in6_addr);
365 source_af = AF_INET6;
366 break;
367 default:
368 goto trunc;
369 break;
370 }
371 bp = (u_char *) (nak + 1);
372 TCHECK2(*bp, addr_size);
373 source = bp;
374 bp += addr_size;
375
376 /*
377 * Skip past the group, saving info along the way
378 * and stopping if we don't have enough.
379 */
380 switch (EXTRACT_16BITS(bp)) {
381 case AFI_IP:
382 addr_size = sizeof(struct in_addr);
383 group_af = AF_INET;
384 break;
385 case AFI_IP6:
386 addr_size = sizeof(struct in6_addr);
387 group_af = AF_INET6;
388 break;
389 default:
390 goto trunc;
391 break;
392 }
393 bp += (2 * sizeof(u_int16_t));
394 TCHECK2(*bp, addr_size);
395 group = bp;
396 bp += addr_size;
397
398 /*
399 * Options decoding can go here.
400 */
401 inet_ntop(source_af, source, source_buf, sizeof(source_buf));
402 inet_ntop(group_af, group, group_buf, sizeof(group_buf));
403 switch (pgm->pgm_type) {
404 case PGM_NAK:
405 (void)printf("NAK ");
406 break;
407 case PGM_NULLNAK:
408 (void)printf("NNAK ");
409 break;
410 case PGM_NCF:
411 (void)printf("NCF ");
412 break;
413 default:
414 break;
415 }
416 (void)printf("(%s -> %s), seq %u",
417 source_buf, group_buf, EXTRACT_32BITS(nak->pgmn_seq));
418 break;
419 }
420
421 case PGM_SPMR:
422 (void)printf("SPMR");
423 break;
424
425 default:
426 (void)printf("UNKNOWN type %0x02x", pgm->pgm_type);
427 break;
428
429 }
430 if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) {
431
432 /*
433 * make sure there's enough for the first option header
434 */
435 if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) {
436 (void)printf("[|OPT]");
437 return;
438 }
439 while (TTEST2(*bp, PGM_MIN_OPT_LEN)) {
440 u_int8_t opt_type, opt_len, flags1, flags2;
441 u_int32_t seq, len, offset;
442
443 opt_type = *bp++;
444 opt_len = *bp++;
445
446 switch (opt_type & PGM_OPT_MASK) {
447 case PGM_OPT_LENGTH:
448 len = EXTRACT_16BITS(bp);
449 bp += sizeof(u_int16_t);
450 (void)printf(" OPT[%d] %d", opt_len, len);
451 break;
452
453 case PGM_OPT_FRAGMENT:
454 flags1 = *bp++;
455 flags2 = *bp++;
456 seq = EXTRACT_32BITS(*(u_int32_t *)bp);
457 bp += sizeof(u_int32_t);
458 offset = EXTRACT_32BITS(*(u_int32_t *)bp);
459 bp += sizeof(u_int32_t);
460 len = EXTRACT_32BITS(*(u_int32_t *)bp);
461 bp += sizeof(u_int32_t);
462 (void)printf(" FRAG seq %u off %u len %u", seq, offset, len);
463 break;
464
465 case PGM_OPT_NAK_LIST:
466 flags1 = *bp++;
467 flags2 = *bp++;
468 opt_len -= sizeof(u_int32_t); /* option header */
469 (void)printf(" NAK LIST");
470 while (opt_len) {
471 TCHECK2(*bp, sizeof(u_int32_t));
472 (void)printf(" %u", EXTRACT_32BITS(*(u_int32_t *)bp));
473 bp += sizeof(u_int32_t);
474 opt_len -= sizeof(u_int32_t);
475 }
476 break;
477
478 case PGM_OPT_JOIN:
479 flags1 = *bp++;
480 flags2 = *bp++;
481 seq = EXTRACT_32BITS(*(u_int32_t *)bp);
482 bp += sizeof(u_int32_t);
483 (void)printf(" JOIN %u", seq);
484 break;
485
486 case PGM_OPT_NAK_BO_IVL:
487 flags1 = *bp++;
488 flags2 = *bp++;
489 offset = EXTRACT_32BITS(*(u_int32_t *)bp);
490 bp += sizeof(u_int32_t);
491 seq = EXTRACT_32BITS(*(u_int32_t *)bp);
492 bp += sizeof(u_int32_t);
493 (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq);
494 break;
495
496 case PGM_OPT_NAK_BO_RNG:
497 flags1 = *bp++;
498 flags2 = *bp++;
499 offset = EXTRACT_32BITS(*(u_int32_t *)bp);
500 bp += sizeof(u_int32_t);
501 seq = EXTRACT_32BITS(*(u_int32_t *)bp);
502 bp += sizeof(u_int32_t);
503 (void)printf(" BACKOFF max %u min %u", offset, seq);
504 break;
505
506 case PGM_OPT_REDIRECT:
507 flags1 = *bp++;
508 flags2 = *bp++;
509 switch (EXTRACT_16BITS(bp)) {
510 case AFI_IP:
511 addr_size = sizeof(struct in_addr);
512 nla_af = AF_INET;
513 break;
514 case AFI_IP6:
515 addr_size = sizeof(struct in6_addr);
516 nla_af = AF_INET6;
517 break;
518 default:
519 goto trunc;
520 break;
521 }
522 bp += (2 * sizeof(u_int16_t));
523 TCHECK2(*bp, addr_size);
524 nla = bp;
525 bp += addr_size;
526
527 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
528 (void)printf(" REDIRECT %s", (char *)nla);
529 break;
530
531 case PGM_OPT_PARITY_PRM:
532 flags1 = *bp++;
533 flags2 = *bp++;
534 len = EXTRACT_32BITS(*(u_int32_t *)bp);
535 bp += sizeof(u_int32_t);
536 (void)printf(" PARITY MAXTGS %u", len);
537 break;
538
539 case PGM_OPT_PARITY_GRP:
540 flags1 = *bp++;
541 flags2 = *bp++;
542 seq = EXTRACT_32BITS(*(u_int32_t *)bp);
543 bp += sizeof(u_int32_t);
544 (void)printf(" PARITY GROUP %u", seq);
545 break;
546
547 case PGM_OPT_CURR_TGSIZE:
548 flags1 = *bp++;
549 flags2 = *bp++;
550 len = EXTRACT_32BITS(*(u_int32_t *)bp);
551 bp += sizeof(u_int32_t);
552 (void)printf(" PARITY ATGS %u", len);
553 break;
554
555 case PGM_OPT_NBR_UNREACH:
556 flags1 = *bp++;
557 flags2 = *bp++;
558 (void)printf(" NBR_UNREACH");
559 break;
560
561 case PGM_OPT_PATH_NLA:
562 (void)printf(" PATH_NLA [%d]", opt_len);
563 bp += opt_len;
564 break;
565
566 case PGM_OPT_SYN:
567 flags1 = *bp++;
568 flags2 = *bp++;
569 (void)printf(" SYN");
570 break;
571
572 case PGM_OPT_FIN:
573 flags1 = *bp++;
574 flags2 = *bp++;
575 (void)printf(" FIN");
576 break;
577
578 case PGM_OPT_RST:
579 flags1 = *bp++;
580 flags2 = *bp++;
581 (void)printf(" RST");
582 break;
583
584 case PGM_OPT_CR:
585 (void)printf(" CR");
586 bp += opt_len;
587 break;
588
589 case PGM_OPT_CRQST:
590 flags1 = *bp++;
591 flags2 = *bp++;
592 (void)printf(" CRQST");
593 break;
594
595 default:
596 if (!TTEST2(*bp, opt_len)) {
597 (void)printf(" [|OPT]");
598 return;
599 }
600 (void)printf(" OPT_%02X [%d] ", opt_type, opt_len);
601 bp += opt_len;
602 break;
603 }
604
605 if (opt_type & PGM_OPT_END)
606 break;
607 }
608 }
609
610 (void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length));
611
612 return;
613
614 trunc:
615 fputs("[|pgm]", stdout);
616 if (ch != '\0')
617 putchar('>');
618 }