4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
31 #include <sys/types.h>
34 #include <sys/stropts.h>
35 #include <sys/socket.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip6.h>
41 #include <netinet/ip_icmp.h>
42 #include <netinet/icmp6.h>
43 #include <netinet/if_ether.h>
46 #include <arpa/inet.h>
53 * IPv6 extension header masks. These are used by the print_ipv6_extensions()
54 * function to return information to the caller about which extension headers
55 * were processed. This can be useful if the caller wants to know if the
56 * packet is an IPv6 fragment, for example.
58 #define SNOOP_HOPOPTS 0x01U
59 #define SNOOP_ROUTING 0x02U
60 #define SNOOP_DSTOPTS 0x04U
61 #define SNOOP_FRAGMENT 0x08U
62 #define SNOOP_AH 0x10U
63 #define SNOOP_ESP 0x20U
64 #define SNOOP_IPV6 0x40U
66 static void prt_routing_hdr(int, const struct ip6_rthdr
*);
67 static void prt_fragment_hdr(int, const struct ip6_frag
*);
68 static void prt_hbh_options(int, const struct ip6_hbh
*);
69 static void prt_dest_options(int, const struct ip6_dest
*);
70 static void print_route(const uchar_t
*);
71 static void print_ipoptions(const uchar_t
*, int);
73 /* Keep track of how many nested IP headers we have. */
74 unsigned int encap_levels
;
75 unsigned int total_encap_levels
= 1;
78 interpret_ip(int flags
, const struct ip
*ip
, int fraglen
)
82 boolean_t isfrag
= B_FALSE
;
86 uint16_t iplen
, uitmp
;
88 if (ip
->ip_v
== IPV6_VERSION
) {
89 iplen
= interpret_ipv6(flags
, (ip6_t
*)ip
, fraglen
);
93 if (encap_levels
== 0)
94 total_encap_levels
= 0;
98 hdrlen
= ip
->ip_hl
* 4;
99 data
= ((uchar_t
*)ip
) + hdrlen
;
100 iplen
= ntohs(ip
->ip_len
) - hdrlen
;
105 (void) snprintf(get_sum_line(), MAXLINE
,
106 "IP truncated: header missing %d bytes", -fraglen
);
108 return (fraglen
+ iplen
);
111 * We flag this as a fragment if the more fragments bit is set, or
112 * if the fragment offset is non-zero.
114 morefrag
= (ntohs(ip
->ip_off
) & IP_MF
) == 0 ? B_FALSE
: B_TRUE
;
115 fragoffset
= (ntohs(ip
->ip_off
) & 0x1FFF) * 8;
116 if (morefrag
|| fragoffset
!= 0)
119 src_name
= addrtoname(AF_INET
, &ip
->ip_src
);
120 dst_name
= addrtoname(AF_INET
, &ip
->ip_dst
);
124 (void) snprintf(get_sum_line(), MAXLINE
,
125 "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x "
134 (void) strlcpy(buff
, inet_ntoa(ip
->ip_dst
),
136 uitmp
= ntohs(ip
->ip_len
);
137 (void) snprintf(get_sum_line(), MAXLINE
,
138 "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d",
140 inet_ntoa(ip
->ip_src
),
142 iplen
> fraglen
? "?" : "",
149 if (flags
& F_DTAIL
) {
150 show_header("IP: ", "IP Header", iplen
);
152 (void) snprintf(get_line(0, 0), get_line_remain(),
153 "Version = %d", ip
->ip_v
);
154 (void) snprintf(get_line(0, 0), get_line_remain(),
155 "Header length = %d bytes", hdrlen
);
156 (void) snprintf(get_line(0, 0), get_line_remain(),
157 "Type of service = 0x%02x", ip
->ip_tos
);
158 (void) snprintf(get_line(0, 0), get_line_remain(),
159 " xxx. .... = %d (precedence)",
161 (void) snprintf(get_line(0, 0), get_line_remain(),
162 " %s", getflag(ip
->ip_tos
, IPTOS_LOWDELAY
,
163 "low delay", "normal delay"));
164 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
165 getflag(ip
->ip_tos
, IPTOS_THROUGHPUT
,
166 "high throughput", "normal throughput"));
167 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
168 getflag(ip
->ip_tos
, IPTOS_RELIABILITY
,
169 "high reliability", "normal reliability"));
170 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
171 getflag(ip
->ip_tos
, IPTOS_ECT
,
172 "ECN capable transport", "not ECN capable transport"));
173 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
174 getflag(ip
->ip_tos
, IPTOS_CE
,
175 "ECN congestion experienced",
176 "no ECN congestion experienced"));
177 /* warning: ip_len is signed in netinet/ip.h */
178 uitmp
= ntohs(ip
->ip_len
);
179 (void) snprintf(get_line(0, 0), get_line_remain(),
180 "Total length = %u bytes%s", uitmp
,
181 iplen
> fraglen
? " -- truncated" : "");
182 (void) snprintf(get_line(0, 0), get_line_remain(),
183 "Identification = %d", ntohs(ip
->ip_id
));
184 /* warning: ip_off is signed in netinet/ip.h */
185 uitmp
= ntohs(ip
->ip_off
);
186 (void) snprintf(get_line(0, 0), get_line_remain(),
187 "Flags = 0x%x", uitmp
>> 12);
188 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
189 getflag(uitmp
>> 8, IP_DF
>> 8,
190 "do not fragment", "may fragment"));
191 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
192 getflag(uitmp
>> 8, IP_MF
>> 8,
193 "more fragments", "last fragment"));
194 (void) snprintf(get_line(0, 0), get_line_remain(),
195 "Fragment offset = %u bytes",
197 (void) snprintf(get_line(0, 0), get_line_remain(),
198 "Time to live = %d seconds/hops",
200 (void) snprintf(get_line(0, 0), get_line_remain(),
201 "Protocol = %d (%s)", ip
->ip_p
,
204 * XXX need to compute checksum and print whether it's correct
206 (void) snprintf(get_line(0, 0), get_line_remain(),
207 "Header checksum = %04x",
209 (void) snprintf(get_line(0, 0), get_line_remain(),
210 "Source address = %s, %s",
211 inet_ntoa(ip
->ip_src
), addrtoname(AF_INET
, &ip
->ip_src
));
212 (void) snprintf(get_line(0, 0), get_line_remain(),
213 "Destination address = %s, %s",
214 inet_ntoa(ip
->ip_dst
), addrtoname(AF_INET
, &ip
->ip_dst
));
216 /* Print IP options - if any */
218 print_ipoptions((const uchar_t
*)(ip
+ 1),
219 hdrlen
- sizeof (struct ip
));
224 * If we are in detail mode, and this is not the first fragment of
225 * a fragmented packet, print out a little line stating this.
226 * Otherwise, go to the next protocol layer only if this is not a
227 * fragment, or we are in detail mode and this is the first fragment
228 * of a fragmented packet.
230 if (flags
& F_DTAIL
&& fragoffset
!= 0) {
231 (void) snprintf(get_detail_line(0, 0), MAXLINE
,
232 "%s: [%d byte(s) of data, continuation of IP ident=%d]",
236 } else if (!isfrag
|| (flags
& F_DTAIL
) && isfrag
&& fragoffset
== 0) {
237 /* go to the next protocol layer */
244 (void) interpret_ip(flags
,
245 /* LINTED: alignment */
246 (const struct ip
*)data
, fraglen
);
249 (void) interpret_icmp(flags
,
250 /* LINTED: alignment */
251 (struct icmp
*)data
, iplen
, fraglen
);
254 interpret_igmp(flags
, data
, iplen
, fraglen
);
259 (void) interpret_tcp(flags
,
260 (struct tcphdr
*)data
, iplen
, fraglen
);
264 (void) interpret_esp(flags
, data
, iplen
,
268 (void) interpret_ah(flags
, data
, iplen
,
273 interpret_ospf(flags
, data
, iplen
, fraglen
);
280 (void) interpret_udp(flags
,
281 (struct udphdr
*)data
, iplen
, fraglen
);
289 case IPPROTO_IPV6
: /* IPV6 encap */
290 /* LINTED: alignment */
291 (void) interpret_ipv6(flags
, (ip6_t
*)data
,
295 (void) interpret_sctp(flags
,
296 (struct sctp_hdr
*)data
, iplen
, fraglen
);
307 interpret_ipv6(int flags
, const ip6_t
*ip6h
, int fraglen
)
311 int version
, flow
, class;
313 boolean_t isfrag
= B_FALSE
;
316 * The print_srcname and print_dstname strings are the hostname
317 * parts of the verbose IPv6 header output, including the comma
318 * and the space after the litteral address strings.
320 char print_srcname
[MAXHOSTNAMELEN
+ 2];
321 char print_dstname
[MAXHOSTNAMELEN
+ 2];
322 char src_addrstr
[INET6_ADDRSTRLEN
];
323 char dst_addrstr
[INET6_ADDRSTRLEN
];
325 iplen
= ntohs(ip6h
->ip6_plen
);
326 hdrlen
= IPV6_HDR_LEN
;
329 return (fraglen
+ hdrlen
);
330 data
= ((uint8_t *)ip6h
) + hdrlen
;
332 proto
= ip6h
->ip6_nxt
;
334 src_name
= addrtoname(AF_INET6
, &ip6h
->ip6_src
);
335 dst_name
= addrtoname(AF_INET6
, &ip6h
->ip6_dst
);
338 * Use endian-aware masks to extract traffic class and
339 * flowinfo. Also, flowinfo is now 20 bits and class 8
340 * rather than 24 and 4.
342 class = ntohl((ip6h
->ip6_vcf
& IPV6_FLOWINFO_TCLASS
) >> 20);
343 flow
= ntohl(ip6h
->ip6_vcf
& IPV6_FLOWINFO_FLOWLABEL
);
346 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive,
347 * so the code within the first part of the following if statement
348 * will not affect the detailed printing of the packet.
351 (void) snprintf(get_sum_line(), MAXLINE
,
352 "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x",
353 src_name
, dst_name
, iplen
, ip6h
->ip6_hops
, class, flow
);
354 } else if (flags
& F_DTAIL
) {
356 (void) inet_ntop(AF_INET6
, &ip6h
->ip6_src
, src_addrstr
,
358 (void) inet_ntop(AF_INET6
, &ip6h
->ip6_dst
, dst_addrstr
,
361 version
= ntohl(ip6h
->ip6_vcf
) >> 28;
363 if (strcmp(src_name
, src_addrstr
) == 0) {
364 print_srcname
[0] = '\0';
366 snprintf(print_srcname
, sizeof (print_srcname
),
370 if (strcmp(dst_name
, dst_addrstr
) == 0) {
371 print_dstname
[0] = '\0';
373 snprintf(print_dstname
, sizeof (print_dstname
),
377 show_header("IPv6: ", "IPv6 Header", iplen
);
380 (void) snprintf(get_line(0, 0), get_line_remain(),
381 "Version = %d", version
);
382 (void) snprintf(get_line(0, 0), get_line_remain(),
383 "Traffic Class = %d", class);
384 (void) snprintf(get_line(0, 0), get_line_remain(),
385 "Flow label = 0x%x", flow
);
386 (void) snprintf(get_line(0, 0), get_line_remain(),
387 "Payload length = %d", iplen
);
388 (void) snprintf(get_line(0, 0), get_line_remain(),
389 "Next Header = %d (%s)", proto
,
391 (void) snprintf(get_line(0, 0), get_line_remain(),
392 "Hop Limit = %d", ip6h
->ip6_hops
);
393 (void) snprintf(get_line(0, 0), get_line_remain(),
394 "Source address = %s%s", src_addrstr
, print_srcname
);
395 (void) snprintf(get_line(0, 0), get_line_remain(),
396 "Destination address = %s%s", dst_addrstr
, print_dstname
);
402 * Print IPv6 Extension Headers, or skip them in the summary case.
403 * Set isfrag to true if one of the extension headers encounterred
404 * was a fragment header.
406 if (proto
== IPPROTO_HOPOPTS
|| proto
== IPPROTO_DSTOPTS
||
407 proto
== IPPROTO_ROUTING
|| proto
== IPPROTO_FRAGMENT
) {
408 extmask
= print_ipv6_extensions(flags
, &data
, &proto
, &iplen
,
410 if ((extmask
& SNOOP_FRAGMENT
) != 0) {
416 * We only want to print upper layer information if this is not
417 * a fragment, or if we're printing in detail. Note that the
418 * proto variable will be set to IPPROTO_NONE if this is a fragment
419 * with a non-zero fragment offset.
421 if (!isfrag
|| flags
& F_DTAIL
) {
422 /* go to the next protocol layer */
428 /* LINTED: alignment */
429 (void) interpret_ip(flags
, (const struct ip
*)data
,
433 /* LINTED: alignment */
434 (void) interpret_icmpv6(flags
, (icmp6_t
*)data
, iplen
,
438 interpret_igmp(flags
, data
, iplen
, fraglen
);
443 (void) interpret_tcp(flags
, (struct tcphdr
*)data
,
447 (void) interpret_esp(flags
, data
, iplen
, fraglen
);
450 (void) interpret_ah(flags
, data
, iplen
, fraglen
);
456 (void) interpret_udp(flags
, (struct udphdr
*)data
,
465 /* LINTED: alignment */
466 (void) interpret_ipv6(flags
, (const ip6_t
*)data
,
470 (void) interpret_sctp(flags
, (struct sctp_hdr
*)data
,
474 interpret_ospf6(flags
, data
, iplen
, fraglen
);
483 * ip_ext: data including the extension header.
484 * iplen: length of the data remaining in the packet.
485 * Returns a mask of IPv6 extension headers it processed.
488 print_ipv6_extensions(int flags
, uint8_t **hdr
, uint8_t *next
, int *iplen
,
492 uchar_t proto
= *next
;
493 boolean_t is_extension_header
;
494 struct ip6_hbh
*ipv6ext_hbh
;
495 struct ip6_dest
*ipv6ext_dest
;
496 struct ip6_rthdr
*ipv6ext_rthdr
;
497 struct ip6_frag
*ipv6ext_frag
;
501 if ((hdr
== NULL
) || (*hdr
== NULL
) || (next
== NULL
) || (iplen
== 0))
505 is_extension_header
= B_TRUE
;
506 while (is_extension_header
) {
509 * There must be at least enough data left to read the
510 * next header and header length fields from the next
518 case IPPROTO_HOPOPTS
:
519 ipv6ext_hbh
= (struct ip6_hbh
*)data_ptr
;
520 exthdrlen
= 8 + ipv6ext_hbh
->ip6h_len
* 8;
521 if (*fraglen
<= exthdrlen
) {
524 prt_hbh_options(flags
, ipv6ext_hbh
);
525 extmask
|= SNOOP_HOPOPTS
;
526 proto
= ipv6ext_hbh
->ip6h_nxt
;
528 case IPPROTO_DSTOPTS
:
529 ipv6ext_dest
= (struct ip6_dest
*)data_ptr
;
530 exthdrlen
= 8 + ipv6ext_dest
->ip6d_len
* 8;
531 if (*fraglen
<= exthdrlen
) {
534 prt_dest_options(flags
, ipv6ext_dest
);
535 extmask
|= SNOOP_DSTOPTS
;
536 proto
= ipv6ext_dest
->ip6d_nxt
;
538 case IPPROTO_ROUTING
:
539 ipv6ext_rthdr
= (struct ip6_rthdr
*)data_ptr
;
540 exthdrlen
= 8 + ipv6ext_rthdr
->ip6r_len
* 8;
541 if (*fraglen
<= exthdrlen
) {
544 prt_routing_hdr(flags
, ipv6ext_rthdr
);
545 extmask
|= SNOOP_ROUTING
;
546 proto
= ipv6ext_rthdr
->ip6r_nxt
;
548 case IPPROTO_FRAGMENT
:
549 /* LINTED: alignment */
550 ipv6ext_frag
= (struct ip6_frag
*)data_ptr
;
551 exthdrlen
= sizeof (struct ip6_frag
);
552 if (*fraglen
<= exthdrlen
) {
555 prt_fragment_hdr(flags
, ipv6ext_frag
);
556 extmask
|= SNOOP_FRAGMENT
;
558 * If this is not the first fragment, forget about
559 * the rest of the packet, snoop decoding is
562 if ((ipv6ext_frag
->ip6f_offlg
& IP6F_OFF_MASK
) != 0)
563 proto
= IPPROTO_NONE
;
565 proto
= ipv6ext_frag
->ip6f_nxt
;
568 is_extension_header
= B_FALSE
;
572 if (is_extension_header
) {
574 *fraglen
-= exthdrlen
;
575 data_ptr
+= exthdrlen
;
585 print_ipoptions(const uchar_t
*opt
, int optlen
)
590 const char *truncstr
;
593 (void) snprintf(get_line(0, 0), get_line_remain(),
598 (void) snprintf(get_line(0, 0), get_line_remain(),
599 "Options: (%d bytes)", optlen
);
602 line
= get_line(0, 0);
603 remain
= get_line_remain();
605 truncstr
= len
> optlen
? "?" : "";
608 (void) strlcpy(line
, " - End of option list", remain
);
611 (void) strlcpy(line
, " - No op", remain
);
615 (void) snprintf(line
, remain
,
616 " - Record route (%d bytes%s)", len
, truncstr
);
620 (void) snprintf(line
, remain
,
621 " - Time stamp (%d bytes%s)", len
, truncstr
);
624 (void) snprintf(line
, remain
, " - RIPSO (%d bytes%s)",
628 (void) snprintf(line
, remain
,
629 " - Loose source route (%d bytes%s)", len
,
634 (void) snprintf(line
, remain
,
635 " - SATNET Stream id (%d bytes%s)",
639 (void) snprintf(line
, remain
,
640 " - Strict source route, (%d bytes%s)", len
,
645 (void) snprintf(line
, remain
,
646 " - Option %d (unknown - %d bytes%s) %s",
647 opt
[0], len
, truncstr
,
648 tohex((char *)&opt
[2], len
- 2));
652 (void) snprintf(line
, remain
,
653 " - Incomplete option len %d", len
);
662 print_route(const uchar_t
*opt
)
664 int len
, pointer
, remain
;
671 (void) snprintf(get_line(0, 0), get_line_remain(),
672 " Pointer = %d", pointer
);
674 pointer
-= IPOPT_MINOFF
;
675 opt
+= (IPOPT_OFFSET
+ 1);
676 len
-= (IPOPT_OFFSET
+ 1);
679 line
= get_line(0, 0);
680 remain
= get_line_remain();
681 memcpy((char *)&addr
, opt
, sizeof (addr
));
682 if (addr
.s_addr
== INADDR_ANY
)
683 (void) strlcpy(line
, " -", remain
);
685 (void) snprintf(line
, remain
, " %s",
686 addrtoname(AF_INET
, &addr
));
688 (void) strlcat(line
, " <-- (current)", remain
);
690 opt
+= sizeof (addr
);
691 len
-= sizeof (addr
);
692 pointer
-= sizeof (addr
);
700 case IPPROTO_HOPOPTS
: return ("IPv6-HopOpts");
701 case IPPROTO_IPV6
: return ("IPv6");
702 case IPPROTO_ROUTING
: return ("IPv6-Route");
703 case IPPROTO_FRAGMENT
: return ("IPv6-Frag");
704 case IPPROTO_RSVP
: return ("RSVP");
705 case IPPROTO_ENCAP
: return ("IP-in-IP");
706 case IPPROTO_AH
: return ("AH");
707 case IPPROTO_ESP
: return ("ESP");
708 case IPPROTO_ICMP
: return ("ICMP");
709 case IPPROTO_ICMPV6
: return ("ICMPv6");
710 case IPPROTO_DSTOPTS
: return ("IPv6-DstOpts");
711 case IPPROTO_IGMP
: return ("IGMP");
712 case IPPROTO_GGP
: return ("GGP");
713 case IPPROTO_TCP
: return ("TCP");
714 case IPPROTO_EGP
: return ("EGP");
715 case IPPROTO_PUP
: return ("PUP");
716 case IPPROTO_UDP
: return ("UDP");
717 case IPPROTO_IDP
: return ("IDP");
718 case IPPROTO_HELLO
: return ("HELLO");
719 case IPPROTO_ND
: return ("ND");
720 case IPPROTO_EON
: return ("EON");
721 case IPPROTO_RAW
: return ("RAW");
722 case IPPROTO_OSPF
: return ("OSPF");
723 default: return ("");
728 prt_routing_hdr(int flags
, const struct ip6_rthdr
*ipv6ext_rthdr
)
736 struct ip6_rthdr0
*ipv6ext_rthdr0
;
737 struct in6_addr
*addrs
;
738 char addr
[INET6_ADDRSTRLEN
];
740 /* in summary mode, we don't do anything. */
745 nxt_hdr
= ipv6ext_rthdr
->ip6r_nxt
;
746 type
= ipv6ext_rthdr
->ip6r_type
;
747 len
= 8 * (ipv6ext_rthdr
->ip6r_len
+ 1);
748 segleft
= ipv6ext_rthdr
->ip6r_segleft
;
750 show_header("IPv6-Route: ", "IPv6 Routing Header", 0);
753 (void) snprintf(get_line(0, 0), get_line_remain(),
754 "Next header = %d (%s)", nxt_hdr
, getproto(nxt_hdr
));
755 (void) snprintf(get_line(0, 0), get_line_remain(),
756 "Header length = %d", len
);
757 (void) snprintf(get_line(0, 0), get_line_remain(),
758 "Routing type = %d", type
);
759 (void) snprintf(get_line(0, 0), get_line_remain(),
760 "Segments left = %d", segleft
);
762 if (type
== IPV6_RTHDR_TYPE_0
) {
764 * XXX This loop will print all addresses in the routing header,
765 * XXX not just the segments left.
766 * XXX (The header length field is twice the number of
768 * XXX At some future time, we may want to change this
769 * XXX to differentiate between the hops yet to do
770 * XXX and the hops already taken.
772 /* LINTED: alignment */
773 ipv6ext_rthdr0
= (struct ip6_rthdr0
*)ipv6ext_rthdr
;
774 numaddrs
= ipv6ext_rthdr0
->ip6r0_len
/ 2;
775 addrs
= (struct in6_addr
*)(ipv6ext_rthdr0
+ 1);
776 for (i
= 0; i
< numaddrs
; i
++) {
777 (void) inet_ntop(AF_INET6
, &addrs
[i
], addr
,
779 (void) snprintf(get_line(0, 0), get_line_remain(),
780 "address[%d]=%s", i
, addr
);
788 prt_fragment_hdr(int flags
, const struct ip6_frag
*ipv6ext_frag
)
795 /* extract the various fields from the fragment header */
796 nxt_hdr
= ipv6ext_frag
->ip6f_nxt
;
797 morefrag
= (ipv6ext_frag
->ip6f_offlg
& IP6F_MORE_FRAG
) == 0
799 fragoffset
= ntohs(ipv6ext_frag
->ip6f_offlg
& IP6F_OFF_MASK
);
800 fragident
= ntohl(ipv6ext_frag
->ip6f_ident
);
803 (void) snprintf(get_sum_line(), MAXLINE
,
804 "IPv6 fragment ID=%u Offset=%-4d MF=%d",
808 } else { /* F_DTAIL */
809 show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0);
812 (void) snprintf(get_line(0, 0), get_line_remain(),
813 "Next Header = %d (%s)", nxt_hdr
, getproto(nxt_hdr
));
814 (void) snprintf(get_line(0, 0), get_line_remain(),
815 "Fragment Offset = %d", fragoffset
);
816 (void) snprintf(get_line(0, 0), get_line_remain(),
817 "More Fragments Flag = %s", morefrag
? "true" : "false");
818 (void) snprintf(get_line(0, 0), get_line_remain(),
819 "Identification = %u", fragident
);
826 prt_hbh_options(int flags
, const struct ip6_hbh
*ipv6ext_hbh
)
828 const uint8_t *data
, *ndata
;
834 /* in summary mode, we don't do anything. */
839 show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0);
843 * Store the lengh of this ext hdr in bytes. The caller has
844 * ensured that there is at least len bytes of data left.
846 len
= ipv6ext_hbh
->ip6h_len
* 8 + 8;
848 ndata
= (const uint8_t *)ipv6ext_hbh
+ 2;
851 nxt_hdr
= ipv6ext_hbh
->ip6h_nxt
;
852 (void) snprintf(get_line(0, 0), get_line_remain(),
853 "Next Header = %u (%s)", nxt_hdr
, getproto(nxt_hdr
));
857 GETINT8(op_type
, data
);
858 /* This is the only one-octet IPv6 option */
859 if (op_type
== IP6OPT_PAD1
) {
860 (void) snprintf(get_line(0, 0), get_line_remain(),
866 GETINT8(op_len
, data
);
867 if (len
< 2 || op_len
+ 2 > len
) {
868 (void) snprintf(get_line(0, 0), get_line_remain(),
869 "Error: option %u truncated (%u + 2 > %u)",
870 op_type
, op_len
, len
);
873 * Continue processing the malformed option so that we
874 * can display as much as possible.
878 /* advance pointers to the next option */
880 ndata
= data
+ op_len
;
882 /* process this option */
885 (void) snprintf(get_line(0, 0), get_line_remain(),
886 "padN option len = %u", op_len
);
889 uint32_t payload_len
;
891 (void) snprintf(get_line(0, 0), get_line_remain(),
892 "Jumbo Payload Option len = %u bytes%s", op_len
,
893 op_len
== sizeof (uint32_t) ? "" : "?");
894 if (op_len
== sizeof (uint32_t)) {
895 GETINT32(payload_len
, data
);
896 (void) snprintf(get_line(0, 0),
898 "Jumbo Payload Length = %u bytes",
903 case IP6OPT_ROUTER_ALERT
: {
905 const char *label
[] = {"MLD", "RSVP", "AN"};
907 (void) snprintf(get_line(0, 0), get_line_remain(),
908 "Router Alert Option len = %u bytes%s", op_len
,
909 op_len
== sizeof (uint16_t) ? "" : "?");
910 if (op_len
== sizeof (uint16_t)) {
911 GETINT16(value
, data
);
912 (void) snprintf(get_line(0, 0),
914 "Alert Type = %d (%s)", value
,
915 value
< sizeof (label
) / sizeof (label
[0]) ?
916 label
[value
] : "???");
921 (void) snprintf(get_line(0, 0), get_line_remain(),
922 "Option type = %u, len = %u", op_type
, op_len
);
931 prt_dest_options(int flags
, const struct ip6_dest
*ipv6ext_dest
)
933 const uint8_t *data
, *ndata
;
940 /* in summary mode, we don't do anything. */
945 show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0);
949 * Store the length of this ext hdr in bytes. The caller has
950 * ensured that there is at least len bytes of data left.
952 len
= ipv6ext_dest
->ip6d_len
* 8 + 8;
954 ndata
= (const uint8_t *)ipv6ext_dest
+ 2; /* skip hdr/len */
957 nxt_hdr
= ipv6ext_dest
->ip6d_nxt
;
958 (void) snprintf(get_line(0, 0), get_line_remain(),
959 "Next Header = %u (%s)", nxt_hdr
, getproto(nxt_hdr
));
963 GETINT8(op_type
, data
);
964 if (op_type
== IP6OPT_PAD1
) {
965 (void) snprintf(get_line(0, 0), get_line_remain(),
971 GETINT8(op_len
, data
);
972 if (len
< 2 || op_len
+ 2 > len
) {
973 (void) snprintf(get_line(0, 0), get_line_remain(),
974 "Error: option %u truncated (%u + 2 > %u)",
975 op_type
, op_len
, len
);
978 * Continue processing the malformed option so that we
979 * can display as much as possible.
983 /* advance pointers to the next option */
985 ndata
= data
+ op_len
;
987 /* process this option */
990 (void) snprintf(get_line(0, 0), get_line_remain(),
991 "padN option len = %u", op_len
);
993 case IP6OPT_TUNNEL_LIMIT
:
994 GETINT8(value
, data
);
995 (void) snprintf(get_line(0, 0), get_line_remain(),
996 "tunnel encapsulation limit len = %d, value = %d",
1000 (void) snprintf(get_line(0, 0), get_line_remain(),
1001 "Option type = %u, len = %u", op_type
, op_len
);