Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / tcpdump / print-pgm.c
blob3342ec06ae2e81efcaf03211018d83851f93cca2
1 /* $NetBSD$ */
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
15 * Original code by Andy Heffernan (ahh@juniper.net)
18 #include <sys/cdefs.h>
19 #ifndef lint
20 #if 0
21 static const char rcsid[] _U_ =
22 "@(#) Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.1.2.5 2005/06/07 22:06:16 guy Exp";
23 #else
24 __RCSID("$NetBSD: tcpdump2rcsid.ex,v 1.1 2001/06/25 20:09:58 itojun Exp $");
25 #endif
26 #endif
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
32 #include <tcpdump-stdinc.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
38 #include "interface.h"
39 #include "extract.h"
40 #include "addrtoname.h"
42 #include "ip.h"
43 #ifdef INET6
44 #include "ip6.h"
45 #endif
46 #include "ipproto.h"
49 * PGM header (RFC 3208)
51 struct pgm_header {
52 u_int16_t pgm_sport;
53 u_int16_t pgm_dport;
54 u_int8_t pgm_type;
55 u_int8_t pgm_options;
56 u_int16_t pgm_sum;
57 u_int8_t pgm_gsid[6];
58 u_int16_t pgm_length;
61 struct pgm_spm {
62 u_int32_t pgms_seq;
63 u_int32_t pgms_trailseq;
64 u_int32_t pgms_leadseq;
65 u_int16_t pgms_nla_afi;
66 u_int16_t pgms_reserved;
67 /* ... u_int8_t pgms_nla[0]; */
68 /* ... options */
71 struct pgm_nak {
72 u_int32_t pgmn_seq;
73 u_int16_t pgmn_source_afi;
74 u_int16_t pgmn_reserved;
75 /* ... u_int8_t pgmn_source[0]; */
76 /* ... u_int16_t pgmn_group_afi */
77 /* ... u_int16_t pgmn_reserved2; */
78 /* ... u_int8_t pgmn_group[0]; */
79 /* ... options */
82 struct pgm_poll {
83 u_int32_t pgmp_seq;
84 u_int16_t pgmp_round;
85 u_int16_t pgmp_reserved;
86 /* ... options */
89 struct pgm_polr {
90 u_int32_t pgmp_seq;
91 u_int16_t pgmp_round;
92 u_int16_t pgmp_subtype;
93 u_int16_t pgmp_nla_afi;
94 u_int16_t pgmp_reserved;
95 /* ... u_int8_t pgmp_nla[0]; */
96 /* ... options */
99 struct pgm_data {
100 u_int32_t pgmd_seq;
101 u_int32_t pgmd_trailseq;
102 /* ... options */
105 typedef enum _pgm_type {
106 PGM_SPM = 0, /* source path message */
107 PGM_POLL = 1, /* POLL Request */
108 PGM_POLR = 2, /* POLL Response */
109 PGM_ODATA = 4, /* original data */
110 PGM_RDATA = 5, /* repair data */
111 PGM_NAK = 8, /* NAK */
112 PGM_NULLNAK = 9, /* Null NAK */
113 PGM_NCF = 10, /* NAK Confirmation */
114 PGM_ACK = 11, /* ACK for congestion control */
115 PGM_SPMR = 12, /* SPM request */
116 PGM_MAX = 255
117 } pgm_type;
119 #define PGM_OPT_BIT_PRESENT 0x01
120 #define PGM_OPT_BIT_NETWORK 0x02
121 #define PGM_OPT_BIT_VAR_PKTLEN 0x40
122 #define PGM_OPT_BIT_PARITY 0x80
124 #define PGM_OPT_LENGTH 0x00
125 #define PGM_OPT_FRAGMENT 0x01
126 #define PGM_OPT_NAK_LIST 0x02
127 #define PGM_OPT_JOIN 0x03
128 #define PGM_OPT_NAK_BO_IVL 0x04
129 #define PGM_OPT_NAK_BO_RNG 0x05
131 #define PGM_OPT_REDIRECT 0x07
132 #define PGM_OPT_PARITY_PRM 0x08
133 #define PGM_OPT_PARITY_GRP 0x09
134 #define PGM_OPT_CURR_TGSIZE 0x0A
135 #define PGM_OPT_NBR_UNREACH 0x0B
136 #define PGM_OPT_PATH_NLA 0x0C
138 #define PGM_OPT_SYN 0x0D
139 #define PGM_OPT_FIN 0x0E
140 #define PGM_OPT_RST 0x0F
141 #define PGM_OPT_CR 0x10
142 #define PGM_OPT_CRQST 0x11
144 #define PGM_OPT_MASK 0x7f
146 #define PGM_OPT_END 0x80 /* end of options marker */
148 #define PGM_MIN_OPT_LEN 4
150 #ifndef AFI_IP
151 #define AFI_IP 1
152 #define AFI_IP6 2
153 #endif
155 void
156 pgm_print(register const u_char *bp, register u_int length,
157 register const u_char *bp2)
159 register const struct pgm_header *pgm;
160 register const struct ip *ip;
161 register char ch;
162 u_int16_t sport, dport;
163 int addr_size;
164 const void *nla;
165 int nla_af;
166 #ifdef INET6
167 char nla_buf[INET6_ADDRSTRLEN];
168 register const struct ip6_hdr *ip6;
169 #else
170 char nla_buf[INET_ADDRSTRLEN];
171 #endif
172 u_int8_t opt_type, opt_len, flags1, flags2;
173 u_int32_t seq, opts_len, len, offset;
175 pgm = (struct pgm_header *)bp;
176 ip = (struct ip *)bp2;
177 #ifdef INET6
178 if (IP_V(ip) == 6)
179 ip6 = (struct ip6_hdr *)bp2;
180 else
181 ip6 = NULL;
182 #else /* INET6 */
183 if (IP_V(ip) == 6) {
184 (void)printf("Can't handle IPv6");
185 return;
187 #endif /* INET6 */
188 ch = '\0';
189 if (!TTEST(pgm->pgm_dport)) {
190 #ifdef INET6
191 if (ip6) {
192 (void)printf("%s > %s: [|pgm]",
193 ip6addr_string(&ip6->ip6_src),
194 ip6addr_string(&ip6->ip6_dst));
195 return;
196 } else
197 #endif /* INET6 */
199 (void)printf("%s > %s: [|pgm]",
200 ipaddr_string(&ip->ip_src),
201 ipaddr_string(&ip->ip_dst));
202 return;
206 sport = EXTRACT_16BITS(&pgm->pgm_sport);
207 dport = EXTRACT_16BITS(&pgm->pgm_dport);
209 #ifdef INET6
210 if (ip6) {
211 if (ip6->ip6_nxt == IPPROTO_PGM) {
212 (void)printf("%s.%s > %s.%s: ",
213 ip6addr_string(&ip6->ip6_src),
214 tcpport_string(sport),
215 ip6addr_string(&ip6->ip6_dst),
216 tcpport_string(dport));
217 } else {
218 (void)printf("%s > %s: ",
219 tcpport_string(sport), tcpport_string(dport));
221 } else
222 #endif /*INET6*/
224 if (ip->ip_p == IPPROTO_PGM) {
225 (void)printf("%s.%s > %s.%s: ",
226 ipaddr_string(&ip->ip_src),
227 tcpport_string(sport),
228 ipaddr_string(&ip->ip_dst),
229 tcpport_string(dport));
230 } else {
231 (void)printf("%s > %s: ",
232 tcpport_string(sport), tcpport_string(dport));
236 TCHECK(*pgm);
238 (void)printf("PGM, length %u", pgm->pgm_length);
240 if (!vflag)
241 return;
243 if (length > pgm->pgm_length)
244 length = pgm->pgm_length;
246 (void)printf(" 0x%02x%02x%02x%02x%02x%02x ",
247 pgm->pgm_gsid[0],
248 pgm->pgm_gsid[1],
249 pgm->pgm_gsid[2],
250 pgm->pgm_gsid[3],
251 pgm->pgm_gsid[4],
252 pgm->pgm_gsid[5]);
253 switch (pgm->pgm_type) {
254 case PGM_SPM: {
255 struct pgm_spm *spm;
257 spm = (struct pgm_spm *)(pgm + 1);
258 TCHECK(*spm);
260 switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) {
261 case AFI_IP:
262 addr_size = sizeof(struct in_addr);
263 nla_af = AF_INET;
264 break;
265 #ifdef INET6
266 case AFI_IP6:
267 addr_size = sizeof(struct in6_addr);
268 nla_af = AF_INET6;
269 break;
270 #endif
271 default:
272 goto trunc;
273 break;
275 bp = (u_char *) (spm + 1);
276 TCHECK2(*bp, addr_size);
277 nla = bp;
278 bp += addr_size;
280 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
281 (void)printf("SPM seq %u trail %u lead %u nla %s",
282 EXTRACT_32BITS(&spm->pgms_seq),
283 EXTRACT_32BITS(&spm->pgms_trailseq),
284 EXTRACT_32BITS(&spm->pgms_leadseq),
285 nla_buf);
286 break;
289 case PGM_POLL: {
290 struct pgm_poll *poll;
292 poll = (struct pgm_poll *)(pgm + 1);
293 TCHECK(*poll);
294 (void)printf("POLL seq %u round %u",
295 EXTRACT_32BITS(&poll->pgmp_seq),
296 EXTRACT_16BITS(&poll->pgmp_round));
297 bp = (u_char *) (poll + 1);
298 break;
300 case PGM_POLR: {
301 struct pgm_polr *polr;
302 u_int32_t ivl, rnd, mask;
304 polr = (struct pgm_polr *)(pgm + 1);
305 TCHECK(*polr);
307 switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) {
308 case AFI_IP:
309 addr_size = sizeof(struct in_addr);
310 nla_af = AF_INET;
311 break;
312 #ifdef INET6
313 case AFI_IP6:
314 addr_size = sizeof(struct in6_addr);
315 nla_af = AF_INET6;
316 break;
317 #endif
318 default:
319 goto trunc;
320 break;
322 bp = (u_char *) (polr + 1);
323 TCHECK2(*bp, addr_size);
324 nla = bp;
325 bp += addr_size;
327 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
329 TCHECK2(*bp, sizeof(u_int32_t));
330 ivl = EXTRACT_32BITS(bp);
331 bp += sizeof(u_int32_t);
333 TCHECK2(*bp, sizeof(u_int32_t));
334 rnd = EXTRACT_32BITS(bp);
335 bp += sizeof(u_int32_t);
337 TCHECK2(*bp, sizeof(u_int32_t));
338 mask = EXTRACT_32BITS(bp);
339 bp += sizeof(u_int32_t);
341 (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
342 "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq),
343 EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask);
344 break;
346 case PGM_ODATA: {
347 struct pgm_data *odata;
349 odata = (struct pgm_data *)(pgm + 1);
350 TCHECK(*odata);
351 (void)printf("ODATA trail %u seq %u",
352 EXTRACT_32BITS(&odata->pgmd_trailseq),
353 EXTRACT_32BITS(&odata->pgmd_seq));
354 bp = (u_char *) (odata + 1);
355 break;
358 case PGM_RDATA: {
359 struct pgm_data *rdata;
361 rdata = (struct pgm_data *)(pgm + 1);
362 TCHECK(*rdata);
363 (void)printf("RDATA trail %u seq %u",
364 EXTRACT_32BITS(&rdata->pgmd_trailseq),
365 EXTRACT_32BITS(&rdata->pgmd_seq));
366 bp = (u_char *) (rdata + 1);
367 break;
370 case PGM_NAK:
371 case PGM_NULLNAK:
372 case PGM_NCF: {
373 struct pgm_nak *nak;
374 const void *source, *group;
375 int source_af, group_af;
376 #ifdef INET6
377 char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
378 #else
379 char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN];
380 #endif
382 nak = (struct pgm_nak *)(pgm + 1);
383 TCHECK(*nak);
386 * Skip past the source, saving info along the way
387 * and stopping if we don't have enough.
389 switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) {
390 case AFI_IP:
391 addr_size = sizeof(struct in_addr);
392 source_af = AF_INET;
393 break;
394 #ifdef INET6
395 case AFI_IP6:
396 addr_size = sizeof(struct in6_addr);
397 source_af = AF_INET6;
398 break;
399 #endif
400 default:
401 goto trunc;
402 break;
404 bp = (u_char *) (nak + 1);
405 TCHECK2(*bp, addr_size);
406 source = bp;
407 bp += addr_size;
410 * Skip past the group, saving info along the way
411 * and stopping if we don't have enough.
413 switch (EXTRACT_16BITS(bp)) {
414 case AFI_IP:
415 addr_size = sizeof(struct in_addr);
416 group_af = AF_INET;
417 break;
418 #ifdef INET6
419 case AFI_IP6:
420 addr_size = sizeof(struct in6_addr);
421 group_af = AF_INET6;
422 break;
423 #endif
424 default:
425 goto trunc;
426 break;
428 bp += (2 * sizeof(u_int16_t));
429 TCHECK2(*bp, addr_size);
430 group = bp;
431 bp += addr_size;
434 * Options decoding can go here.
436 inet_ntop(source_af, source, source_buf, sizeof(source_buf));
437 inet_ntop(group_af, group, group_buf, sizeof(group_buf));
438 switch (pgm->pgm_type) {
439 case PGM_NAK:
440 (void)printf("NAK ");
441 break;
442 case PGM_NULLNAK:
443 (void)printf("NNAK ");
444 break;
445 case PGM_NCF:
446 (void)printf("NCF ");
447 break;
448 default:
449 break;
451 (void)printf("(%s -> %s), seq %u",
452 source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq));
453 break;
456 case PGM_SPMR:
457 (void)printf("SPMR");
458 break;
460 default:
461 (void)printf("UNKNOWN type %0x02x", pgm->pgm_type);
462 break;
465 if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) {
468 * make sure there's enough for the first option header
470 if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) {
471 (void)printf("[|OPT]");
472 return;
476 * That option header MUST be an OPT_LENGTH option
477 * (see the first paragraph of section 9.1 in RFC 3208).
479 opt_type = *bp++;
480 if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
481 (void)printf("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
482 return;
484 opt_len = *bp++;
485 if (opt_len != 4) {
486 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
487 return;
489 opts_len = EXTRACT_16BITS(bp);
490 if (opts_len < 4) {
491 (void)printf("[Bad total option length %u < 4]", opts_len);
492 return;
494 bp += sizeof(u_int16_t);
495 (void)printf(" OPTS LEN %d", opts_len);
496 opts_len -= 4;
498 while (opts_len) {
499 if (opts_len < PGM_MIN_OPT_LEN) {
500 (void)printf("[Total option length leaves no room for final option]");
501 return;
503 opt_type = *bp++;
504 opt_len = *bp++;
505 if (opt_len < PGM_MIN_OPT_LEN) {
506 (void)printf("[Bad option, length %u < %u]", opt_len,
507 PGM_MIN_OPT_LEN);
508 break;
510 if (opts_len < opt_len) {
511 (void)printf("[Total option length leaves no room for final option]");
512 return;
514 if (!TTEST2(*bp, opt_len - 2)) {
515 (void)printf(" [|OPT]");
516 return;
519 switch (opt_type & PGM_OPT_MASK) {
520 case PGM_OPT_LENGTH:
521 if (opt_len != 4) {
522 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
523 return;
525 (void)printf(" OPTS LEN (extra?) %d", EXTRACT_16BITS(bp));
526 bp += sizeof(u_int16_t);
527 opts_len -= 4;
528 break;
530 case PGM_OPT_FRAGMENT:
531 if (opt_len != 16) {
532 (void)printf("[Bad OPT_FRAGMENT option, length %u != 16]", opt_len);
533 return;
535 flags1 = *bp++;
536 flags2 = *bp++;
537 seq = EXTRACT_32BITS(bp);
538 bp += sizeof(u_int32_t);
539 offset = EXTRACT_32BITS(bp);
540 bp += sizeof(u_int32_t);
541 len = EXTRACT_32BITS(bp);
542 bp += sizeof(u_int32_t);
543 (void)printf(" FRAG seq %u off %u len %u", seq, offset, len);
544 opts_len -= 16;
545 break;
547 case PGM_OPT_NAK_LIST:
548 flags1 = *bp++;
549 flags2 = *bp++;
550 opt_len -= sizeof(u_int32_t); /* option header */
551 (void)printf(" NAK LIST");
552 while (opt_len) {
553 if (opt_len < sizeof(u_int32_t)) {
554 (void)printf("[Option length not a multiple of 4]");
555 return;
557 TCHECK2(*bp, sizeof(u_int32_t));
558 (void)printf(" %u", EXTRACT_32BITS(bp));
559 bp += sizeof(u_int32_t);
560 opt_len -= sizeof(u_int32_t);
561 opts_len -= sizeof(u_int32_t);
563 break;
565 case PGM_OPT_JOIN:
566 if (opt_len != 8) {
567 (void)printf("[Bad OPT_JOIN option, length %u != 8]", opt_len);
568 return;
570 flags1 = *bp++;
571 flags2 = *bp++;
572 seq = EXTRACT_32BITS(bp);
573 bp += sizeof(u_int32_t);
574 (void)printf(" JOIN %u", seq);
575 opts_len -= 8;
576 break;
578 case PGM_OPT_NAK_BO_IVL:
579 if (opt_len != 12) {
580 (void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len);
581 return;
583 flags1 = *bp++;
584 flags2 = *bp++;
585 offset = EXTRACT_32BITS(bp);
586 bp += sizeof(u_int32_t);
587 seq = EXTRACT_32BITS(bp);
588 bp += sizeof(u_int32_t);
589 (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq);
590 opts_len -= 12;
591 break;
593 case PGM_OPT_NAK_BO_RNG:
594 if (opt_len != 12) {
595 (void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len);
596 return;
598 flags1 = *bp++;
599 flags2 = *bp++;
600 offset = EXTRACT_32BITS(bp);
601 bp += sizeof(u_int32_t);
602 seq = EXTRACT_32BITS(bp);
603 bp += sizeof(u_int32_t);
604 (void)printf(" BACKOFF max %u min %u", offset, seq);
605 opts_len -= 12;
606 break;
608 case PGM_OPT_REDIRECT:
609 flags1 = *bp++;
610 flags2 = *bp++;
611 switch (EXTRACT_16BITS(bp)) {
612 case AFI_IP:
613 addr_size = sizeof(struct in_addr);
614 nla_af = AF_INET;
615 break;
616 #ifdef INET6
617 case AFI_IP6:
618 addr_size = sizeof(struct in6_addr);
619 nla_af = AF_INET6;
620 break;
621 #endif
622 default:
623 goto trunc;
624 break;
626 bp += (2 * sizeof(u_int16_t));
627 if (opt_len != 4 + addr_size) {
628 (void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len);
629 return;
631 TCHECK2(*bp, addr_size);
632 nla = bp;
633 bp += addr_size;
635 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
636 (void)printf(" REDIRECT %s", (char *)nla);
637 opts_len -= 4 + addr_size;
638 break;
640 case PGM_OPT_PARITY_PRM:
641 if (opt_len != 8) {
642 (void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len);
643 return;
645 flags1 = *bp++;
646 flags2 = *bp++;
647 len = EXTRACT_32BITS(bp);
648 bp += sizeof(u_int32_t);
649 (void)printf(" PARITY MAXTGS %u", len);
650 opts_len -= 8;
651 break;
653 case PGM_OPT_PARITY_GRP:
654 if (opt_len != 8) {
655 (void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len);
656 return;
658 flags1 = *bp++;
659 flags2 = *bp++;
660 seq = EXTRACT_32BITS(bp);
661 bp += sizeof(u_int32_t);
662 (void)printf(" PARITY GROUP %u", seq);
663 opts_len -= 8;
664 break;
666 case PGM_OPT_CURR_TGSIZE:
667 if (opt_len != 8) {
668 (void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len);
669 return;
671 flags1 = *bp++;
672 flags2 = *bp++;
673 len = EXTRACT_32BITS(bp);
674 bp += sizeof(u_int32_t);
675 (void)printf(" PARITY ATGS %u", len);
676 opts_len -= 8;
677 break;
679 case PGM_OPT_NBR_UNREACH:
680 if (opt_len != 4) {
681 (void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len);
682 return;
684 flags1 = *bp++;
685 flags2 = *bp++;
686 (void)printf(" NBR_UNREACH");
687 opts_len -= 4;
688 break;
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;
696 case PGM_OPT_SYN:
697 if (opt_len != 4) {
698 (void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len);
699 return;
701 flags1 = *bp++;
702 flags2 = *bp++;
703 (void)printf(" SYN");
704 opts_len -= 4;
705 break;
707 case PGM_OPT_FIN:
708 if (opt_len != 4) {
709 (void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len);
710 return;
712 flags1 = *bp++;
713 flags2 = *bp++;
714 (void)printf(" FIN");
715 opts_len -= 4;
716 break;
718 case PGM_OPT_RST:
719 if (opt_len != 4) {
720 (void)printf("[Bad OPT_RST option, length %u != 4]", opt_len);
721 return;
723 flags1 = *bp++;
724 flags2 = *bp++;
725 (void)printf(" RST");
726 opts_len -= 4;
727 break;
729 case PGM_OPT_CR:
730 (void)printf(" CR");
731 bp += opt_len;
732 opts_len -= opt_len;
733 break;
735 case PGM_OPT_CRQST:
736 if (opt_len != 4) {
737 (void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len);
738 return;
740 flags1 = *bp++;
741 flags2 = *bp++;
742 (void)printf(" CRQST");
743 opts_len -= 4;
744 break;
746 default:
747 (void)printf(" OPT_%02X [%d] ", opt_type, opt_len);
748 bp += opt_len;
749 opts_len -= opt_len;
750 break;
753 if (opt_type & PGM_OPT_END)
754 break;
758 (void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length));
760 return;
762 trunc:
763 fputs("[|pgm]", stdout);
764 if (ch != '\0')
765 putchar('>');