+#define IP_RES 0x8000
+
+static struct tok ip_frag_values[] = {
+ { IP_MF, "+" },
+ { IP_DF, "DF" },
+ { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */
+ { 0, NULL }
+};
+
+struct ip_print_demux_state {
+ const struct ip *ip;
+ const u_char *cp;
+ u_int len, off;
+ u_char nh;
+ int advance;
+};
+
+static void
+ip_print_demux(netdissect_options *ndo,
+ struct ip_print_demux_state *ipds)
+{
+ struct protoent *proto;
+
+again:
+ switch (ipds->nh) {
+
+ case IPPROTO_AH:
+ ipds->nh = *ipds->cp;
+ ipds->advance = ah_print(ipds->cp);
+ if (ipds->advance <= 0)
+ break;
+ ipds->cp += ipds->advance;
+ ipds->len -= ipds->advance;
+ goto again;
+
+ case IPPROTO_ESP:
+ {
+ int enh, padlen;
+ ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
+ (const u_char *)ipds->ip,
+ &enh, &padlen);
+ if (ipds->advance <= 0)
+ break;
+ ipds->cp += ipds->advance;
+ ipds->len -= ipds->advance + padlen;
+ ipds->nh = enh & 0xff;
+ goto again;
+ }
+
+ case IPPROTO_IPCOMP:
+ {
+ int enh;
+ ipds->advance = ipcomp_print(ipds->cp, &enh);
+ if (ipds->advance <= 0)
+ break;
+ ipds->cp += ipds->advance;
+ ipds->len -= ipds->advance;
+ ipds->nh = enh & 0xff;
+ goto again;
+ }
+
+ case IPPROTO_SCTP:
+ sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
+ break;
+
+ case IPPROTO_DCCP:
+ dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
+ break;
+
+ case IPPROTO_TCP:
+ /* pass on the MF bit plus the offset to detect fragments */
+ tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
+ ipds->off & (IP_MF|IP_OFFMASK));
+ break;
+
+ case IPPROTO_UDP:
+ /* pass on the MF bit plus the offset to detect fragments */
+ udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
+ ipds->off & (IP_MF|IP_OFFMASK));
+ break;
+
+ case IPPROTO_ICMP:
+ /* pass on the MF bit plus the offset to detect fragments */
+ icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
+ ipds->off & (IP_MF|IP_OFFMASK));
+ break;
+
+ case IPPROTO_PIGP:
+ /*
+ * XXX - the current IANA protocol number assignments
+ * page lists 9 as "any private interior gateway
+ * (used by Cisco for their IGRP)" and 88 as
+ * "EIGRP" from Cisco.
+ *
+ * Recent BSD <netinet/in.h> headers define
+ * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
+ * We define IP_PROTO_PIGP as 9 and
+ * IP_PROTO_EIGRP as 88; those names better
+ * match was the current protocol number
+ * assignments say.
+ */
+ igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
+ break;
+
+ case IPPROTO_EIGRP:
+ eigrp_print(ipds->cp, ipds->len);
+ break;
+
+ case IPPROTO_ND:
+ ND_PRINT((ndo, " nd %d", ipds->len));
+ break;
+
+ case IPPROTO_EGP:
+ egp_print(ipds->cp, ipds->len);
+ break;
+
+ case IPPROTO_OSPF:
+ ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
+ break;
+
+ case IPPROTO_IGMP:
+ igmp_print(ipds->cp, ipds->len);
+ break;
+
+ case IPPROTO_IPV4:
+ /* DVMRP multicast tunnel (ip-in-ip encapsulation) */
+ ip_print(gndo, ipds->cp, ipds->len);
+ if (! vflag) {
+ ND_PRINT((ndo, " (ipip-proto-4)"));
+ return;
+ }
+ break;
+
+#ifdef INET6
+ case IPPROTO_IPV6:
+ /* ip6-in-ip encapsulation */
+ ip6_print(ipds->cp, ipds->len);
+ break;
+#endif /*INET6*/
+
+ case IPPROTO_RSVP:
+ rsvp_print(ipds->cp, ipds->len);
+ break;
+
+ case IPPROTO_GRE:
+ /* do it */
+ gre_print(ipds->cp, ipds->len);
+ break;
+
+ case IPPROTO_MOBILE:
+ mobile_print(ipds->cp, ipds->len);
+ break;
+
+ case IPPROTO_PIM:
+ pim_print(ipds->cp, ipds->len,
+ in_cksum((const u_short*)ipds->cp, ipds->len, 0));
+ break;
+
+ case IPPROTO_VRRP:
+ vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
+ break;
+
+ case IPPROTO_PGM:
+ pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
+ break;
+
+ default:
+ if ((proto = getprotobynumber(ipds->nh)) != NULL)
+ ND_PRINT((ndo, " %s", proto->p_name));
+ else
+ ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
+ ND_PRINT((ndo, " %d", ipds->len));
+ break;
+ }
+}
+
+void
+ip_print_inner(netdissect_options *ndo,
+ const u_char *bp,
+ u_int length, u_int nh,
+ const u_char *bp2)
+{
+ struct ip_print_demux_state ipd;
+
+ ipd.ip = (const struct ip *)bp2;
+ ipd.cp = bp;
+ ipd.len = length;
+ ipd.off = 0;
+ ipd.nh = nh;
+ ipd.advance = 0;
+
+ ip_print_demux(ndo, &ipd);
+}
+
+