xref: /netbsd-src/external/bsd/tcpdump/dist/print-icmp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  */
210f74e101Schristos 
2211b3aaa1Schristos #include <sys/cdefs.h>
230f74e101Schristos #ifndef lint
24*26ba0b50Schristos __RCSID("$NetBSD: print-icmp.c,v 1.14 2024/09/02 16:15:31 christos Exp $");
250f74e101Schristos #endif
260f74e101Schristos 
27dc860a36Sspz /* \summary: Internet Control Message Protocol (ICMP) printer */
28dc860a36Sspz 
29c74ad251Schristos #include <config.h>
300f74e101Schristos 
31c74ad251Schristos #include "netdissect-stdinc.h"
320f74e101Schristos 
330f74e101Schristos #include <stdio.h>
340f74e101Schristos #include <string.h>
350f74e101Schristos 
36fdccd7e4Schristos #include "netdissect.h"
370f74e101Schristos #include "addrtoname.h"
38fdccd7e4Schristos #include "extract.h"
390f74e101Schristos 
400f74e101Schristos #include "ip.h"
410f74e101Schristos #include "udp.h"
420f74e101Schristos #include "ipproto.h"
430f74e101Schristos #include "mpls.h"
440f74e101Schristos 
450f74e101Schristos /*
460f74e101Schristos  * Interface Control Message Protocol Definitions.
470f74e101Schristos  * Per RFC 792, September 1981.
480f74e101Schristos  */
490f74e101Schristos 
500f74e101Schristos /*
510f74e101Schristos  * Structure of an icmp header.
520f74e101Schristos  */
530f74e101Schristos struct icmp {
54c74ad251Schristos 	nd_uint8_t  icmp_type;		/* type of message, see below */
55c74ad251Schristos 	nd_uint8_t  icmp_code;		/* type sub code */
56c74ad251Schristos 	nd_uint16_t icmp_cksum;		/* ones complement cksum of struct */
570f74e101Schristos 	union {
58c74ad251Schristos 		nd_uint8_t ih_pptr;	/* ICMP_PARAMPROB */
59c74ad251Schristos 		nd_ipv4 ih_gwaddr;	/* ICMP_REDIRECT */
600f74e101Schristos 		struct ih_idseq {
61c74ad251Schristos 			nd_uint16_t icd_id;
62c74ad251Schristos 			nd_uint16_t icd_seq;
630f74e101Schristos 		} ih_idseq;
64c74ad251Schristos 		nd_uint32_t ih_void;
650f74e101Schristos 	} icmp_hun;
660f74e101Schristos #define	icmp_pptr	icmp_hun.ih_pptr
670f74e101Schristos #define	icmp_gwaddr	icmp_hun.ih_gwaddr
680f74e101Schristos #define	icmp_id		icmp_hun.ih_idseq.icd_id
690f74e101Schristos #define	icmp_seq	icmp_hun.ih_idseq.icd_seq
700f74e101Schristos #define	icmp_void	icmp_hun.ih_void
710f74e101Schristos 	union {
720f74e101Schristos 		struct id_ts {
73c74ad251Schristos 			nd_uint32_t its_otime;
74c74ad251Schristos 			nd_uint32_t its_rtime;
75c74ad251Schristos 			nd_uint32_t its_ttime;
760f74e101Schristos 		} id_ts;
770f74e101Schristos 		struct id_ip  {
780f74e101Schristos 			struct ip idi_ip;
790f74e101Schristos 			/* options and then 64 bits of data */
800f74e101Schristos 		} id_ip;
81c74ad251Schristos 		nd_uint32_t id_mask;
82c74ad251Schristos 		nd_byte id_data[1];
830f74e101Schristos 	} icmp_dun;
840f74e101Schristos #define	icmp_otime	icmp_dun.id_ts.its_otime
850f74e101Schristos #define	icmp_rtime	icmp_dun.id_ts.its_rtime
860f74e101Schristos #define	icmp_ttime	icmp_dun.id_ts.its_ttime
870f74e101Schristos #define	icmp_ip		icmp_dun.id_ip.idi_ip
880f74e101Schristos #define	icmp_mask	icmp_dun.id_mask
890f74e101Schristos #define	icmp_data	icmp_dun.id_data
90daed3b99Sthorpej } UNALIGNED;
910f74e101Schristos 
920f74e101Schristos /*
930f74e101Schristos  * Lower bounds on packet lengths for various types.
940f74e101Schristos  * For the error advice packets must first insure that the
95c74ad251Schristos  * packet is large enough to contain the returned ip header.
960f74e101Schristos  * Only then can we do the check to see if 64 bits of packet
970f74e101Schristos  * data have been returned, since we need to check the returned
980f74e101Schristos  * ip header length.
990f74e101Schristos  */
1000f74e101Schristos #define	ICMP_MINLEN	8				/* abs minimum */
1010f74e101Schristos #define ICMP_EXTD_MINLEN (156 - sizeof (struct ip))     /* draft-bonica-internet-icmp-08 */
102b3a00663Schristos #define	ICMP_TSLEN	(8 + 3 * sizeof (uint32_t))	/* timestamp */
1030f74e101Schristos #define	ICMP_MASKLEN	12				/* address mask */
1040f74e101Schristos #define	ICMP_ADVLENMIN	(8 + sizeof (struct ip) + 8)	/* min */
1050f74e101Schristos #define	ICMP_ADVLEN(p)	(8 + (IP_HL(&(p)->icmp_ip) << 2) + 8)
1060f74e101Schristos 	/* N.B.: must separately check that ip_hl >= 5 */
1070f74e101Schristos 
1080f74e101Schristos /*
1090f74e101Schristos  * Definition of type and code field values.
1100f74e101Schristos  */
1110f74e101Schristos #define	ICMP_ECHOREPLY		0		/* echo reply */
1120f74e101Schristos #define	ICMP_UNREACH		3		/* dest unreachable, codes: */
1130f74e101Schristos #define		ICMP_UNREACH_NET	0		/* bad net */
1140f74e101Schristos #define		ICMP_UNREACH_HOST	1		/* bad host */
1150f74e101Schristos #define		ICMP_UNREACH_PROTOCOL	2		/* bad protocol */
1160f74e101Schristos #define		ICMP_UNREACH_PORT	3		/* bad port */
1170f74e101Schristos #define		ICMP_UNREACH_NEEDFRAG	4		/* IP_DF caused drop */
1180f74e101Schristos #define		ICMP_UNREACH_SRCFAIL	5		/* src route failed */
1190f74e101Schristos #define		ICMP_UNREACH_NET_UNKNOWN 6		/* unknown net */
1200f74e101Schristos #define		ICMP_UNREACH_HOST_UNKNOWN 7		/* unknown host */
1210f74e101Schristos #define		ICMP_UNREACH_ISOLATED	8		/* src host isolated */
1220f74e101Schristos #define		ICMP_UNREACH_NET_PROHIB	9		/* prohibited access */
1230f74e101Schristos #define		ICMP_UNREACH_HOST_PROHIB 10		/* ditto */
1240f74e101Schristos #define		ICMP_UNREACH_TOSNET	11		/* bad tos for net */
1250f74e101Schristos #define		ICMP_UNREACH_TOSHOST	12		/* bad tos for host */
1260f74e101Schristos #define	ICMP_SOURCEQUENCH	4		/* packet lost, slow down */
1270f74e101Schristos #define	ICMP_REDIRECT		5		/* shorter route, codes: */
1280f74e101Schristos #define		ICMP_REDIRECT_NET	0		/* for network */
1290f74e101Schristos #define		ICMP_REDIRECT_HOST	1		/* for host */
1300f74e101Schristos #define		ICMP_REDIRECT_TOSNET	2		/* for tos and net */
1310f74e101Schristos #define		ICMP_REDIRECT_TOSHOST	3		/* for tos and host */
1320f74e101Schristos #define	ICMP_ECHO		8		/* echo service */
1330f74e101Schristos #define	ICMP_ROUTERADVERT	9		/* router advertisement */
1340f74e101Schristos #define	ICMP_ROUTERSOLICIT	10		/* router solicitation */
1350f74e101Schristos #define	ICMP_TIMXCEED		11		/* time exceeded, code: */
1360f74e101Schristos #define		ICMP_TIMXCEED_INTRANS	0		/* ttl==0 in transit */
1370f74e101Schristos #define		ICMP_TIMXCEED_REASS	1		/* ttl==0 in reass */
1380f74e101Schristos #define	ICMP_PARAMPROB		12		/* ip header bad */
1390f74e101Schristos #define		ICMP_PARAMPROB_OPTABSENT 1		/* req. opt. absent */
1400f74e101Schristos #define	ICMP_TSTAMP		13		/* timestamp request */
1410f74e101Schristos #define	ICMP_TSTAMPREPLY	14		/* timestamp reply */
1420f74e101Schristos #define	ICMP_IREQ		15		/* information request */
1430f74e101Schristos #define	ICMP_IREQREPLY		16		/* information reply */
1440f74e101Schristos #define	ICMP_MASKREQ		17		/* address mask request */
1450f74e101Schristos #define	ICMP_MASKREPLY		18		/* address mask reply */
1460f74e101Schristos 
1470f74e101Schristos #define	ICMP_MAXTYPE		18
1480f74e101Schristos 
149ba2ff121Schristos #define ICMP_ERRTYPE(type) \
150ba2ff121Schristos 	((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \
151ba2ff121Schristos 	(type) == ICMP_REDIRECT || (type) == ICMP_TIMXCEED || \
152ba2ff121Schristos 	(type) == ICMP_PARAMPROB)
153c74ad251Schristos #define	ICMP_MULTIPART_EXT_TYPE(type) \
1540f74e101Schristos 	((type) == ICMP_UNREACH || \
1550f74e101Schristos          (type) == ICMP_TIMXCEED || \
1560f74e101Schristos          (type) == ICMP_PARAMPROB)
1570f74e101Schristos /* rfc1700 */
1580f74e101Schristos #ifndef ICMP_UNREACH_NET_UNKNOWN
1590f74e101Schristos #define ICMP_UNREACH_NET_UNKNOWN	6	/* destination net unknown */
1600f74e101Schristos #endif
1610f74e101Schristos #ifndef ICMP_UNREACH_HOST_UNKNOWN
1620f74e101Schristos #define ICMP_UNREACH_HOST_UNKNOWN	7	/* destination host unknown */
1630f74e101Schristos #endif
1640f74e101Schristos #ifndef ICMP_UNREACH_ISOLATED
1650f74e101Schristos #define ICMP_UNREACH_ISOLATED		8	/* source host isolated */
1660f74e101Schristos #endif
1670f74e101Schristos #ifndef ICMP_UNREACH_NET_PROHIB
1680f74e101Schristos #define ICMP_UNREACH_NET_PROHIB		9	/* admin prohibited net */
1690f74e101Schristos #endif
1700f74e101Schristos #ifndef ICMP_UNREACH_HOST_PROHIB
1710f74e101Schristos #define ICMP_UNREACH_HOST_PROHIB	10	/* admin prohibited host */
1720f74e101Schristos #endif
1730f74e101Schristos #ifndef ICMP_UNREACH_TOSNET
1740f74e101Schristos #define ICMP_UNREACH_TOSNET		11	/* tos prohibited net */
1750f74e101Schristos #endif
1760f74e101Schristos #ifndef ICMP_UNREACH_TOSHOST
1770f74e101Schristos #define ICMP_UNREACH_TOSHOST		12	/* tos prohibited host */
1780f74e101Schristos #endif
1790f74e101Schristos 
1800f74e101Schristos /* rfc1716 */
1810f74e101Schristos #ifndef ICMP_UNREACH_FILTER_PROHIB
1820f74e101Schristos #define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
1830f74e101Schristos #endif
1840f74e101Schristos #ifndef ICMP_UNREACH_HOST_PRECEDENCE
1850f74e101Schristos #define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
1860f74e101Schristos #endif
1870f74e101Schristos #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
1880f74e101Schristos #define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
1890f74e101Schristos #endif
1900f74e101Schristos 
1910f74e101Schristos /* Most of the icmp types */
192870189d2Schristos static const struct tok icmp2str[] = {
1930f74e101Schristos 	{ ICMP_ECHOREPLY,		"echo reply" },
1940f74e101Schristos 	{ ICMP_SOURCEQUENCH,		"source quench" },
1950f74e101Schristos 	{ ICMP_ECHO,			"echo request" },
1960f74e101Schristos 	{ ICMP_ROUTERSOLICIT,		"router solicitation" },
1970f74e101Schristos 	{ ICMP_TSTAMP,			"time stamp request" },
1980f74e101Schristos 	{ ICMP_TSTAMPREPLY,		"time stamp reply" },
1990f74e101Schristos 	{ ICMP_IREQ,			"information request" },
2000f74e101Schristos 	{ ICMP_IREQREPLY,		"information reply" },
2010f74e101Schristos 	{ ICMP_MASKREQ,			"address mask request" },
2020f74e101Schristos 	{ 0,				NULL }
2030f74e101Schristos };
2040f74e101Schristos 
2050f74e101Schristos /* rfc1191 */
2060f74e101Schristos struct mtu_discovery {
207c74ad251Schristos 	nd_uint16_t unused;
208c74ad251Schristos 	nd_uint16_t nexthopmtu;
2090f74e101Schristos };
2100f74e101Schristos 
2110f74e101Schristos /* rfc1256 */
2120f74e101Schristos struct ih_rdiscovery {
213c74ad251Schristos 	nd_uint8_t ird_addrnum;
214c74ad251Schristos 	nd_uint8_t ird_addrsiz;
215c74ad251Schristos 	nd_uint16_t ird_lifetime;
2160f74e101Schristos };
2170f74e101Schristos 
2180f74e101Schristos struct id_rdiscovery {
219c74ad251Schristos 	nd_uint32_t ird_addr;
220c74ad251Schristos 	nd_uint32_t ird_pref;
2210f74e101Schristos };
2220f74e101Schristos 
2230f74e101Schristos /*
224c74ad251Schristos  * RFC 4884 - Extended ICMP to Support Multi-Part Messages
225c74ad251Schristos  *
226c74ad251Schristos  * This is a general extension mechanism, based on the mechanism
227c74ad251Schristos  * in draft-bonica-icmp-mpls-02 ICMP Extensions for MultiProtocol
228c74ad251Schristos  * Label Switching.
2290f74e101Schristos  *
2300f74e101Schristos  * The Destination Unreachable, Time Exceeded
231c74ad251Schristos  * and Parameter Problem messages are slightly changed as per
232c74ad251Schristos  * the above RFC. A new Length field gets added to give
233c74ad251Schristos  * the caller an idea about the length of the piggybacked
234c74ad251Schristos  * IP packet before the extension header starts.
2350f74e101Schristos  *
2360f74e101Schristos  * The Length field represents length of the padded "original datagram"
2370f74e101Schristos  * field  measured in 32-bit words.
2380f74e101Schristos  *
2390f74e101Schristos  * 0                   1                   2                   3
2400f74e101Schristos  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2410f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2420f74e101Schristos  * |     Type      |     Code      |          Checksum             |
2430f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2440f74e101Schristos  * |     unused    |    Length     |          unused               |
2450f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2460f74e101Schristos  * |      Internet Header + leading octets of original datagram    |
2470f74e101Schristos  * |                                                               |
2480f74e101Schristos  * |                           //                                  |
2490f74e101Schristos  * |                                                               |
2500f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2510f74e101Schristos  */
2520f74e101Schristos 
2530f74e101Schristos struct icmp_ext_t {
254c74ad251Schristos     nd_uint8_t  icmp_type;
255c74ad251Schristos     nd_uint8_t  icmp_code;
256c74ad251Schristos     nd_uint16_t icmp_checksum;
257c74ad251Schristos     nd_byte     icmp_reserved;
258c74ad251Schristos     nd_uint8_t  icmp_length;
259c74ad251Schristos     nd_byte     icmp_reserved2[2];
260c74ad251Schristos     nd_byte     icmp_ext_legacy_header[128]; /* extension header starts 128 bytes after ICMP header */
261c74ad251Schristos     nd_byte     icmp_ext_version_res[2];
262c74ad251Schristos     nd_uint16_t icmp_ext_checksum;
263c74ad251Schristos     nd_byte     icmp_ext_data[1];
2640f74e101Schristos };
2650f74e101Schristos 
266c74ad251Schristos /*
267c74ad251Schristos  * Extract version from the first octet of icmp_ext_version_res.
268c74ad251Schristos  */
269c74ad251Schristos #define ICMP_EXT_EXTRACT_VERSION(x) (((x)&0xf0)>>4)
270c74ad251Schristos 
271c74ad251Schristos /*
272c74ad251Schristos  * Current version.
273c74ad251Schristos  */
274c74ad251Schristos #define ICMP_EXT_VERSION 2
275c74ad251Schristos 
276c74ad251Schristos /*
277c74ad251Schristos  * Extension object class numbers.
278c74ad251Schristos  *
279c74ad251Schristos  * Class 1 dates back to draft-bonica-icmp-mpls-02.
280c74ad251Schristos  */
281c74ad251Schristos 
282c74ad251Schristos /* rfc4950  */
283c74ad251Schristos #define MPLS_STACK_ENTRY_OBJECT_CLASS            1
284c74ad251Schristos 
285c74ad251Schristos struct icmp_multipart_ext_object_header_t {
286c74ad251Schristos     nd_uint16_t length;
287c74ad251Schristos     nd_uint8_t  class_num;
288c74ad251Schristos     nd_uint8_t  ctype;
2890f74e101Schristos };
2900f74e101Schristos 
291c74ad251Schristos static const struct tok icmp_multipart_ext_obj_values[] = {
2920f74e101Schristos     { 1, "MPLS Stack Entry" },
293c74ad251Schristos     { 2, "Interface Identification" },
2940f74e101Schristos     { 0, NULL}
2950f74e101Schristos };
2960f74e101Schristos 
2970f74e101Schristos /* prototypes */
2980f74e101Schristos const char *icmp_tstamp_print(u_int);
2990f74e101Schristos 
3000f74e101Schristos /* print the milliseconds since midnight UTC */
3010f74e101Schristos const char *
302ba2ff121Schristos icmp_tstamp_print(u_int tstamp)
303ba2ff121Schristos {
3040f74e101Schristos     u_int msec,sec,min,hrs;
3050f74e101Schristos 
3060f74e101Schristos     static char buf[64];
3070f74e101Schristos 
3080f74e101Schristos     msec = tstamp % 1000;
3090f74e101Schristos     sec = tstamp / 1000;
3100f74e101Schristos     min = sec / 60; sec -= min * 60;
3110f74e101Schristos     hrs = min / 60; min -= hrs * 60;
3120f74e101Schristos     snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u",hrs,min,sec,msec);
3130f74e101Schristos     return buf;
3140f74e101Schristos }
3150f74e101Schristos 
316a8e08e94Skamil UNALIGNED_OK
3170f74e101Schristos void
318b3a00663Schristos icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *bp2,
319b3a00663Schristos            int fragmented)
3200f74e101Schristos {
3210f74e101Schristos 	char *cp;
3220f74e101Schristos 	const struct icmp *dp;
323c74ad251Schristos 	uint8_t icmp_type, icmp_code;
3240f74e101Schristos         const struct icmp_ext_t *ext_dp;
3250f74e101Schristos 	const struct ip *ip;
326c74ad251Schristos 	const char *str;
3270f74e101Schristos 	const struct ip *oip;
328c74ad251Schristos 	uint8_t ip_proto;
3290f74e101Schristos 	const struct udphdr *ouh;
330b3a00663Schristos         const uint8_t *obj_tptr;
331b3a00663Schristos         uint32_t raw_label;
332c74ad251Schristos 	const struct icmp_multipart_ext_object_header_t *icmp_multipart_ext_object_header;
333c74ad251Schristos 	u_int hlen, mtu, obj_tlen, obj_class_num, obj_ctype;
334c74ad251Schristos 	uint16_t dport;
3350f74e101Schristos 	char buf[MAXHOSTNAMELEN + 100];
3360e9868baSchristos 	struct cksum_vec vec[1];
3370f74e101Schristos 
338c74ad251Schristos 	ndo->ndo_protocol = "icmp";
339fdccd7e4Schristos 	dp = (const struct icmp *)bp;
340fdccd7e4Schristos         ext_dp = (const struct icmp_ext_t *)bp;
341fdccd7e4Schristos 	ip = (const struct ip *)bp2;
3420f74e101Schristos 	str = buf;
3430f74e101Schristos 
344c74ad251Schristos 	icmp_type = GET_U_1(dp->icmp_type);
345c74ad251Schristos 	icmp_code = GET_U_1(dp->icmp_code);
346c74ad251Schristos 	switch (icmp_type) {
3470f74e101Schristos 
3480f74e101Schristos 	case ICMP_ECHO:
3490f74e101Schristos 	case ICMP_ECHOREPLY:
3500f74e101Schristos 		(void)snprintf(buf, sizeof(buf), "echo %s, id %u, seq %u",
351c74ad251Schristos                                icmp_type == ICMP_ECHO ?
3520f74e101Schristos                                "request" : "reply",
353c74ad251Schristos                                GET_BE_U_2(dp->icmp_id),
354c74ad251Schristos                                GET_BE_U_2(dp->icmp_seq));
3550f74e101Schristos 		break;
3560f74e101Schristos 
3570f74e101Schristos 	case ICMP_UNREACH:
358c74ad251Schristos 		switch (icmp_code) {
359c74ad251Schristos 
360c74ad251Schristos 		case ICMP_UNREACH_NET:
361c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
362c74ad251Schristos 			    "net %s unreachable",
363c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
364c74ad251Schristos 			break;
365c74ad251Schristos 
366c74ad251Schristos 		case ICMP_UNREACH_HOST:
367c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
368c74ad251Schristos 			    "host %s unreachable",
369c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
370c74ad251Schristos 			break;
3710f74e101Schristos 
3720f74e101Schristos 		case ICMP_UNREACH_PROTOCOL:
3730f74e101Schristos 			(void)snprintf(buf, sizeof(buf),
374c74ad251Schristos 			    "%s protocol %u unreachable",
375c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
376c74ad251Schristos 			    GET_U_1(dp->icmp_ip.ip_p));
3770f74e101Schristos 			break;
3780f74e101Schristos 
3790f74e101Schristos 		case ICMP_UNREACH_PORT:
380c74ad251Schristos 			ND_TCHECK_1(dp->icmp_ip.ip_p);
3810f74e101Schristos 			oip = &dp->icmp_ip;
3820f74e101Schristos 			hlen = IP_HL(oip) * 4;
383fdccd7e4Schristos 			ouh = (const struct udphdr *)(((const u_char *)oip) + hlen);
384c74ad251Schristos 			dport = GET_BE_U_2(ouh->uh_dport);
385c74ad251Schristos 			ip_proto = GET_U_1(oip->ip_p);
386c74ad251Schristos 			switch (ip_proto) {
3870f74e101Schristos 
3880f74e101Schristos 			case IPPROTO_TCP:
3890f74e101Schristos 				(void)snprintf(buf, sizeof(buf),
3900f74e101Schristos 					"%s tcp port %s unreachable",
391c74ad251Schristos 					GET_IPADDR_STRING(oip->ip_dst),
392fdccd7e4Schristos 					tcpport_string(ndo, dport));
3930f74e101Schristos 				break;
3940f74e101Schristos 
3950f74e101Schristos 			case IPPROTO_UDP:
3960f74e101Schristos 				(void)snprintf(buf, sizeof(buf),
3970f74e101Schristos 					"%s udp port %s unreachable",
398c74ad251Schristos 					GET_IPADDR_STRING(oip->ip_dst),
399fdccd7e4Schristos 					udpport_string(ndo, dport));
4000f74e101Schristos 				break;
4010f74e101Schristos 
4020f74e101Schristos 			default:
4030f74e101Schristos 				(void)snprintf(buf, sizeof(buf),
404817e9a7eSchristos 					"%s protocol %u port %u unreachable",
405c74ad251Schristos 					GET_IPADDR_STRING(oip->ip_dst),
406c74ad251Schristos 					ip_proto, dport);
4070f74e101Schristos 				break;
4080f74e101Schristos 			}
4090f74e101Schristos 			break;
4100f74e101Schristos 
4110f74e101Schristos 		case ICMP_UNREACH_NEEDFRAG:
4120f74e101Schristos 		    {
413c74ad251Schristos 			const struct mtu_discovery *mp;
414fdccd7e4Schristos 			mp = (const struct mtu_discovery *)(const u_char *)&dp->icmp_void;
415c74ad251Schristos 			mtu = GET_BE_U_2(mp->nexthopmtu);
4160f74e101Schristos 			if (mtu) {
4170f74e101Schristos 				(void)snprintf(buf, sizeof(buf),
418c74ad251Schristos 				    "%s unreachable - need to frag (mtu %u)",
419c74ad251Schristos 				    GET_IPADDR_STRING(dp->icmp_ip.ip_dst), mtu);
4200f74e101Schristos 			} else {
4210f74e101Schristos 				(void)snprintf(buf, sizeof(buf),
4220f74e101Schristos 				    "%s unreachable - need to frag",
423c74ad251Schristos 				    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
4240f74e101Schristos 			}
4250f74e101Schristos 		    }
4260f74e101Schristos 			break;
4270f74e101Schristos 
428c74ad251Schristos 		case ICMP_UNREACH_SRCFAIL:
429c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
430c74ad251Schristos 			    "%s unreachable - source route failed",
431c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
432c74ad251Schristos 			break;
433c74ad251Schristos 
434c74ad251Schristos 		case ICMP_UNREACH_NET_UNKNOWN:
435c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
436c74ad251Schristos 			    "net %s unreachable - unknown",
437c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
438c74ad251Schristos 			break;
439c74ad251Schristos 
440c74ad251Schristos 		case ICMP_UNREACH_HOST_UNKNOWN:
441c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
442c74ad251Schristos 			    "host %s unreachable - unknown",
443c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
444c74ad251Schristos 			break;
445c74ad251Schristos 
446c74ad251Schristos 		case ICMP_UNREACH_ISOLATED:
447c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
448c74ad251Schristos 			    "%s unreachable - source host isolated",
449c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
450c74ad251Schristos 			break;
451c74ad251Schristos 
452c74ad251Schristos 		case ICMP_UNREACH_NET_PROHIB:
453c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
454c74ad251Schristos 			    "net %s unreachable - admin prohibited",
455c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
456c74ad251Schristos 			break;
457c74ad251Schristos 
458c74ad251Schristos 		case ICMP_UNREACH_HOST_PROHIB:
459c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
460c74ad251Schristos 			    "host %s unreachable - admin prohibited",
461c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
462c74ad251Schristos 			break;
463c74ad251Schristos 
464c74ad251Schristos 		case ICMP_UNREACH_TOSNET:
465c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
466c74ad251Schristos 			    "net %s unreachable - tos prohibited",
467c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
468c74ad251Schristos 			break;
469c74ad251Schristos 
470c74ad251Schristos 		case ICMP_UNREACH_TOSHOST:
471c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
472c74ad251Schristos 			    "host %s unreachable - tos prohibited",
473c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
474c74ad251Schristos 			break;
475c74ad251Schristos 
476c74ad251Schristos 		case ICMP_UNREACH_FILTER_PROHIB:
477c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
478c74ad251Schristos 			    "host %s unreachable - admin prohibited filter",
479c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
480c74ad251Schristos 			break;
481c74ad251Schristos 
482c74ad251Schristos 		case ICMP_UNREACH_HOST_PRECEDENCE:
483c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
484c74ad251Schristos 			    "host %s unreachable - host precedence violation",
485c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
486c74ad251Schristos 			break;
487c74ad251Schristos 
488c74ad251Schristos 		case ICMP_UNREACH_PRECEDENCE_CUTOFF:
489c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
490c74ad251Schristos 			    "host %s unreachable - precedence cutoff",
491c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
492c74ad251Schristos 			break;
493c74ad251Schristos 
4940f74e101Schristos 		default:
495c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
496c74ad251Schristos 			    "%s unreachable - #%u",
497c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
498c74ad251Schristos 			    icmp_code);
4990f74e101Schristos 			break;
5000f74e101Schristos 		}
5010f74e101Schristos 		break;
5020f74e101Schristos 
5030f74e101Schristos 	case ICMP_REDIRECT:
504c74ad251Schristos 		switch (icmp_code) {
505c74ad251Schristos 
506c74ad251Schristos 		case ICMP_REDIRECT_NET:
507c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
508c74ad251Schristos 			    "redirect %s to net %s",
509c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
510c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_gwaddr));
511c74ad251Schristos 			break;
512c74ad251Schristos 
513c74ad251Schristos 		case ICMP_REDIRECT_HOST:
514c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
515c74ad251Schristos 			    "redirect %s to host %s",
516c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
517c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_gwaddr));
518c74ad251Schristos 			break;
519c74ad251Schristos 
520c74ad251Schristos 		case ICMP_REDIRECT_TOSNET:
521c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
522c74ad251Schristos 			    "redirect-tos %s to net %s",
523c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
524c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_gwaddr));
525c74ad251Schristos 			break;
526c74ad251Schristos 
527c74ad251Schristos 		case ICMP_REDIRECT_TOSHOST:
528c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
529c74ad251Schristos 			    "redirect-tos %s to host %s",
530c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
531c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_gwaddr));
532c74ad251Schristos 			break;
533c74ad251Schristos 
534c74ad251Schristos 		default:
535c74ad251Schristos 			(void)snprintf(buf, sizeof(buf),
536c74ad251Schristos 			    "redirect-#%u %s to %s", icmp_code,
537c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
538c74ad251Schristos 			    GET_IPADDR_STRING(dp->icmp_gwaddr));
539c74ad251Schristos 			break;
540c74ad251Schristos 		}
5410f74e101Schristos 		break;
5420f74e101Schristos 
5430f74e101Schristos 	case ICMP_ROUTERADVERT:
5440f74e101Schristos 	    {
545c74ad251Schristos 		const struct ih_rdiscovery *ihp;
546c74ad251Schristos 		const struct id_rdiscovery *idp;
5470f74e101Schristos 		u_int lifetime, num, size;
5480f74e101Schristos 
5490f74e101Schristos 		(void)snprintf(buf, sizeof(buf), "router advertisement");
5500f74e101Schristos 		cp = buf + strlen(buf);
5510f74e101Schristos 
552fdccd7e4Schristos 		ihp = (const struct ih_rdiscovery *)&dp->icmp_void;
553c74ad251Schristos 		ND_TCHECK_SIZE(ihp);
5540f74e101Schristos 		(void)strncpy(cp, " lifetime ", sizeof(buf) - (cp - buf));
5550f74e101Schristos 		cp = buf + strlen(buf);
556c74ad251Schristos 		lifetime = GET_BE_U_2(ihp->ird_lifetime);
5570f74e101Schristos 		if (lifetime < 60) {
5580f74e101Schristos 			(void)snprintf(cp, sizeof(buf) - (cp - buf), "%u",
5590f74e101Schristos 			    lifetime);
5600f74e101Schristos 		} else if (lifetime < 60 * 60) {
5610f74e101Schristos 			(void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u",
5620f74e101Schristos 			    lifetime / 60, lifetime % 60);
5630f74e101Schristos 		} else {
5640f74e101Schristos 			(void)snprintf(cp, sizeof(buf) - (cp - buf),
5650f74e101Schristos 			    "%u:%02u:%02u",
5660f74e101Schristos 			    lifetime / 3600,
5670f74e101Schristos 			    (lifetime % 3600) / 60,
5680f74e101Schristos 			    lifetime % 60);
5690f74e101Schristos 		}
5700f74e101Schristos 		cp = buf + strlen(buf);
5710f74e101Schristos 
572c74ad251Schristos 		num = GET_U_1(ihp->ird_addrnum);
573c74ad251Schristos 		(void)snprintf(cp, sizeof(buf) - (cp - buf), " %u:", num);
5740f74e101Schristos 		cp = buf + strlen(buf);
5750f74e101Schristos 
576c74ad251Schristos 		size = GET_U_1(ihp->ird_addrsiz);
5770f74e101Schristos 		if (size != 2) {
5780f74e101Schristos 			(void)snprintf(cp, sizeof(buf) - (cp - buf),
579c74ad251Schristos 			    " [size %u]", size);
5800f74e101Schristos 			break;
5810f74e101Schristos 		}
582fdccd7e4Schristos 		idp = (const struct id_rdiscovery *)&dp->icmp_data;
583c74ad251Schristos 		while (num > 0) {
584c74ad251Schristos 			ND_TCHECK_SIZE(idp);
5850f74e101Schristos 			(void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}",
586c74ad251Schristos 			    GET_IPADDR_STRING(idp->ird_addr),
587c74ad251Schristos 			    GET_BE_U_4(idp->ird_pref));
5880f74e101Schristos 			cp = buf + strlen(buf);
5890f74e101Schristos 			++idp;
590c74ad251Schristos 		num--;
5910f74e101Schristos 		}
5920f74e101Schristos 	    }
5930f74e101Schristos 		break;
5940f74e101Schristos 
5950f74e101Schristos 	case ICMP_TIMXCEED:
596c74ad251Schristos 		ND_TCHECK_4(dp->icmp_ip.ip_dst);
597c74ad251Schristos 		switch (icmp_code) {
5980f74e101Schristos 
5990f74e101Schristos 		case ICMP_TIMXCEED_INTRANS:
6000f74e101Schristos 			str = "time exceeded in-transit";
6010f74e101Schristos 			break;
6020f74e101Schristos 
6030f74e101Schristos 		case ICMP_TIMXCEED_REASS:
6040f74e101Schristos 			str = "ip reassembly time exceeded";
6050f74e101Schristos 			break;
6060f74e101Schristos 
6070f74e101Schristos 		default:
608817e9a7eSchristos 			(void)snprintf(buf, sizeof(buf), "time exceeded-#%u",
609c74ad251Schristos 			    icmp_code);
6100f74e101Schristos 			break;
6110f74e101Schristos 		}
6120f74e101Schristos 		break;
6130f74e101Schristos 
6140f74e101Schristos 	case ICMP_PARAMPROB:
615c74ad251Schristos 		if (icmp_code)
6160f74e101Schristos 			(void)snprintf(buf, sizeof(buf),
617c74ad251Schristos 			    "parameter problem - code %u", icmp_code);
6180f74e101Schristos 		else {
6190f74e101Schristos 			(void)snprintf(buf, sizeof(buf),
620c74ad251Schristos 			    "parameter problem - octet %u",
621c74ad251Schristos 			    GET_U_1(dp->icmp_pptr));
6220f74e101Schristos 		}
6230f74e101Schristos 		break;
6240f74e101Schristos 
6250f74e101Schristos 	case ICMP_MASKREPLY:
6260f74e101Schristos 		(void)snprintf(buf, sizeof(buf), "address mask is 0x%08x",
627c74ad251Schristos 		    GET_BE_U_4(dp->icmp_mask));
6280f74e101Schristos 		break;
6290f74e101Schristos 
6300f74e101Schristos 	case ICMP_TSTAMP:
6310f74e101Schristos 		(void)snprintf(buf, sizeof(buf),
6320f74e101Schristos 		    "time stamp query id %u seq %u",
633c74ad251Schristos 		    GET_BE_U_2(dp->icmp_id),
634c74ad251Schristos 		    GET_BE_U_2(dp->icmp_seq));
6350f74e101Schristos 		break;
6360f74e101Schristos 
6370f74e101Schristos 	case ICMP_TSTAMPREPLY:
638c74ad251Schristos 		ND_TCHECK_4(dp->icmp_ttime);
6390f74e101Schristos 		(void)snprintf(buf, sizeof(buf),
6400f74e101Schristos 		    "time stamp reply id %u seq %u: org %s",
641c74ad251Schristos                                GET_BE_U_2(dp->icmp_id),
642c74ad251Schristos                                GET_BE_U_2(dp->icmp_seq),
643c74ad251Schristos                                icmp_tstamp_print(GET_BE_U_4(dp->icmp_otime)));
6440f74e101Schristos 
6450f74e101Schristos                 (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", recv %s",
646c74ad251Schristos                          icmp_tstamp_print(GET_BE_U_4(dp->icmp_rtime)));
6470f74e101Schristos                 (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", xmit %s",
648c74ad251Schristos                          icmp_tstamp_print(GET_BE_U_4(dp->icmp_ttime)));
6490f74e101Schristos                 break;
6500f74e101Schristos 
6510f74e101Schristos 	default:
652c74ad251Schristos 		str = tok2str(icmp2str, "type-#%u", icmp_type);
6530f74e101Schristos 		break;
6540f74e101Schristos 	}
655c74ad251Schristos 	ND_PRINT("ICMP %s, length %u", str, plen);
656b3a00663Schristos 	if (ndo->ndo_vflag && !fragmented) { /* don't attempt checksumming if this is a frag */
657c74ad251Schristos 		if (ND_TTEST_LEN(bp, plen)) {
658817e9a7eSchristos 			uint16_t sum;
659817e9a7eSchristos 
660fdccd7e4Schristos 			vec[0].ptr = (const uint8_t *)(const void *)dp;
6610e9868baSchristos 			vec[0].len = plen;
6620e9868baSchristos 			sum = in_cksum(vec, 1);
6630f74e101Schristos 			if (sum != 0) {
664c74ad251Schristos 				uint16_t icmp_sum = GET_BE_U_2(dp->icmp_cksum);
665c74ad251Schristos 				ND_PRINT(" (wrong icmp cksum %x (->%x)!)",
6660f74e101Schristos 					     icmp_sum,
667c74ad251Schristos 					     in_cksum_shouldbe(icmp_sum, sum));
6680f74e101Schristos 			}
6690f74e101Schristos 		}
6700f74e101Schristos 	}
6710f74e101Schristos 
6720f74e101Schristos         /*
6730f74e101Schristos          * print the remnants of the IP packet.
674c74ad251Schristos          * save the snaplength as this may get overridden in the IP printer.
6750f74e101Schristos          */
676c74ad251Schristos 	if (ndo->ndo_vflag >= 1 && ICMP_ERRTYPE(icmp_type)) {
677c74ad251Schristos 		const u_char *snapend_save;
678c74ad251Schristos 
6790f74e101Schristos 		bp += 8;
680c74ad251Schristos 		ND_PRINT("\n\t");
681fdccd7e4Schristos 		ip = (const struct ip *)bp;
682b3a00663Schristos 		snapend_save = ndo->ndo_snapend;
683c74ad251Schristos 		/*
684c74ad251Schristos 		 * Update the snapend because extensions (MPLS, ...) may be
685c74ad251Schristos 		 * present after the IP packet. In this case the current
686c74ad251Schristos 		 * (outer) packet's snapend is not what ip_print() needs to
687c74ad251Schristos 		 * decode an IP packet nested in the middle of an ICMP payload.
688c74ad251Schristos 		 *
689c74ad251Schristos 		 * This prevents that, in ip_print(), for the nested IP packet,
690c74ad251Schristos 		 * the remaining length < remaining caplen.
691c74ad251Schristos 		 */
692c74ad251Schristos 		ndo->ndo_snapend = ND_MIN(bp + GET_BE_U_2(ip->ip_len),
693c74ad251Schristos 					  ndo->ndo_snapend);
694c74ad251Schristos 		ip_print(ndo, bp, GET_BE_U_2(ip->ip_len));
695b3a00663Schristos 		ndo->ndo_snapend = snapend_save;
6960f74e101Schristos 	}
6970f74e101Schristos 
698c74ad251Schristos 	/* ndo_protocol reassignment after ip_print() call */
699c74ad251Schristos 	ndo->ndo_protocol = "icmp";
700c74ad251Schristos 
7010f74e101Schristos         /*
702c74ad251Schristos          * Attempt to decode multi-part message extensions (rfc4884) only for some ICMP types.
7030f74e101Schristos          */
704c74ad251Schristos         if (ndo->ndo_vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MULTIPART_EXT_TYPE(icmp_type)) {
7050f74e101Schristos 
706c74ad251Schristos             ND_TCHECK_SIZE(ext_dp);
7070f74e101Schristos 
7080f74e101Schristos             /*
709c74ad251Schristos              * Check first if the multi-part extension header shows a non-zero length.
7100f74e101Schristos              * If the length field is not set then silently verify the checksum
7110f74e101Schristos              * to check if an extension header is present. This is expedient,
7120f74e101Schristos              * however not all implementations set the length field proper.
7130f74e101Schristos              */
714c74ad251Schristos             if (GET_U_1(ext_dp->icmp_length) == 0 &&
715c74ad251Schristos                 ND_TTEST_LEN(ext_dp->icmp_ext_version_res, plen - ICMP_EXTD_MINLEN)) {
716fdccd7e4Schristos                 vec[0].ptr = (const uint8_t *)(const void *)&ext_dp->icmp_ext_version_res;
7170e9868baSchristos                 vec[0].len = plen - ICMP_EXTD_MINLEN;
7180e9868baSchristos                 if (in_cksum(vec, 1)) {
7190f74e101Schristos                     return;
7200f74e101Schristos                 }
7210e9868baSchristos             }
7220f74e101Schristos 
723c74ad251Schristos             ND_PRINT("\n\tICMP Multi-Part extension v%u",
724c74ad251Schristos                    ICMP_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)));
7250f74e101Schristos 
7260f74e101Schristos             /*
7270f74e101Schristos              * Sanity checking of the header.
7280f74e101Schristos              */
729c74ad251Schristos             if (ICMP_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)) !=
730c74ad251Schristos                 ICMP_EXT_VERSION) {
731c74ad251Schristos                 ND_PRINT(" packet not supported");
7320f74e101Schristos                 return;
7330f74e101Schristos             }
7340f74e101Schristos 
7350f74e101Schristos             hlen = plen - ICMP_EXTD_MINLEN;
736c74ad251Schristos             if (ND_TTEST_LEN(ext_dp->icmp_ext_version_res, hlen)) {
737fdccd7e4Schristos                 vec[0].ptr = (const uint8_t *)(const void *)&ext_dp->icmp_ext_version_res;
7380e9868baSchristos                 vec[0].len = hlen;
739c74ad251Schristos                 ND_PRINT(", checksum 0x%04x (%scorrect), length %u",
740c74ad251Schristos                        GET_BE_U_2(ext_dp->icmp_ext_checksum),
7410e9868baSchristos                        in_cksum(vec, 1) ? "in" : "",
742c74ad251Schristos                        hlen);
74372c96ff3Schristos             }
7440f74e101Schristos 
7450f74e101Schristos             hlen -= 4; /* subtract common header size */
746fdccd7e4Schristos             obj_tptr = (const uint8_t *)ext_dp->icmp_ext_data;
7470f74e101Schristos 
748c74ad251Schristos             while (hlen > sizeof(struct icmp_multipart_ext_object_header_t)) {
7490f74e101Schristos 
750c74ad251Schristos                 icmp_multipart_ext_object_header = (const struct icmp_multipart_ext_object_header_t *)obj_tptr;
751c74ad251Schristos                 ND_TCHECK_SIZE(icmp_multipart_ext_object_header);
752c74ad251Schristos                 obj_tlen = GET_BE_U_2(icmp_multipart_ext_object_header->length);
753c74ad251Schristos                 obj_class_num = GET_U_1(icmp_multipart_ext_object_header->class_num);
754c74ad251Schristos                 obj_ctype = GET_U_1(icmp_multipart_ext_object_header->ctype);
755c74ad251Schristos                 obj_tptr += sizeof(struct icmp_multipart_ext_object_header_t);
7560f74e101Schristos 
757c74ad251Schristos                 ND_PRINT("\n\t  %s Object (%u), Class-Type: %u, length %u",
758c74ad251Schristos                        tok2str(icmp_multipart_ext_obj_values,"unknown",obj_class_num),
7590f74e101Schristos                        obj_class_num,
7600f74e101Schristos                        obj_ctype,
761c74ad251Schristos                        obj_tlen);
7620f74e101Schristos 
763c74ad251Schristos                 hlen-=sizeof(struct icmp_multipart_ext_object_header_t); /* length field includes tlv header */
7640f74e101Schristos 
7650f74e101Schristos                 /* infinite loop protection */
7660f74e101Schristos                 if ((obj_class_num == 0) ||
767c74ad251Schristos                     (obj_tlen < sizeof(struct icmp_multipart_ext_object_header_t))) {
7680f74e101Schristos                     return;
7690f74e101Schristos                 }
770c74ad251Schristos                 obj_tlen-=sizeof(struct icmp_multipart_ext_object_header_t);
7710f74e101Schristos 
7720f74e101Schristos                 switch (obj_class_num) {
773c74ad251Schristos                 case MPLS_STACK_ENTRY_OBJECT_CLASS:
7740f74e101Schristos                     switch(obj_ctype) {
7750f74e101Schristos                     case 1:
776c74ad251Schristos                         raw_label = GET_BE_U_4(obj_tptr);
777c74ad251Schristos                         ND_PRINT("\n\t    label %u, tc %u", MPLS_LABEL(raw_label), MPLS_TC(raw_label));
7780f74e101Schristos                         if (MPLS_STACK(raw_label))
779c74ad251Schristos                             ND_PRINT(", [S]");
780c74ad251Schristos                         ND_PRINT(", ttl %u", MPLS_TTL(raw_label));
7810f74e101Schristos                         break;
7820f74e101Schristos                     default:
783b3a00663Schristos                         print_unknown_data(ndo, obj_tptr, "\n\t    ", obj_tlen);
7840f74e101Schristos                     }
7850f74e101Schristos                     break;
7860f74e101Schristos 
7870f74e101Schristos                 default:
788b3a00663Schristos                     print_unknown_data(ndo, obj_tptr, "\n\t    ", obj_tlen);
7890f74e101Schristos                     break;
7900f74e101Schristos                 }
7910f74e101Schristos                 if (hlen < obj_tlen)
7920f74e101Schristos                     break;
7930f74e101Schristos                 hlen -= obj_tlen;
7940f74e101Schristos                 obj_tptr += obj_tlen;
7950f74e101Schristos             }
7960f74e101Schristos         }
7970f74e101Schristos 
7980f74e101Schristos 	return;
7990f74e101Schristos trunc:
800c74ad251Schristos 	nd_print_trunc(ndo);
8010f74e101Schristos }
802