/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
*      The Regents of the University of California.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

/* \summary: IPv4/IPv6 payload printer */

#include <config.h>

#include "netdissect-stdinc.h"

#include "netdissect.h"
#include "addrtoname.h"
#include "extract.h"

#include "ip.h"
#include "ipproto.h"

void
ip_demux_print(netdissect_options *ndo,
              const u_char *bp,
              u_int length, u_int ver, int fragmented, u_int ttl_hl,
              uint8_t nh, const u_char *iph)
{
       int advance;
       const char *p_name;

       advance = 0;

again:
       switch (nh) {

       case IPPROTO_AH:
               if (!ND_TTEST_1(bp)) {
                       ndo->ndo_protocol = "ah";
                       nd_print_trunc(ndo);
                       break;
               }
               nh = GET_U_1(bp);
               advance = ah_print(ndo, bp);
               if (advance <= 0)
                       break;
               bp += advance;
               length -= advance;
               goto again;

       case IPPROTO_ESP:
       {
               esp_print(ndo, bp, length, iph, ver, fragmented, ttl_hl);
               /*
                * Either this has decrypted the payload and
                * printed it, in which case there's nothing more
                * to do, or it hasn't, in which case there's
                * nothing more to do.
                */
               break;
       }

       case IPPROTO_IPCOMP:
       {
               ipcomp_print(ndo, bp);
               /*
                * Either this has decompressed the payload and
                * printed it, in which case there's nothing more
                * to do, or it hasn't, in which case there's
                * nothing more to do.
                */
               break;
       }

       case IPPROTO_SCTP:
               sctp_print(ndo, bp, iph, length);
               break;

       case IPPROTO_DCCP:
               dccp_print(ndo, bp, iph, length);
               break;

       case IPPROTO_TCP:
               tcp_print(ndo, bp, length, iph, fragmented);
               break;

       case IPPROTO_UDP:
               udp_print(ndo, bp, length, iph, fragmented, ttl_hl);
               break;

       case IPPROTO_ICMP:
               if (ver == 4)
                       icmp_print(ndo, bp, length, iph, fragmented);
               else {
                       ND_PRINT("[%s requires IPv4]",
                                tok2str(ipproto_values,"unknown",nh));
                       nd_print_invalid(ndo);
               }
               break;

       case IPPROTO_ICMPV6:
               if (ver == 6)
                       icmp6_print(ndo, bp, length, iph, fragmented);
               else {
                       ND_PRINT("[%s requires IPv6]",
                                tok2str(ipproto_values,"unknown",nh));
                       nd_print_invalid(ndo);
               }
               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(ndo, bp, length);
               break;

       case IPPROTO_EIGRP:
               eigrp_print(ndo, bp, length);
               break;

       case IPPROTO_ND:
               ND_PRINT(" nd %u", length);
               break;

       case IPPROTO_EGP:
               egp_print(ndo, bp, length);
               break;

       case IPPROTO_OSPF:
               if (ver == 6)
                       ospf6_print(ndo, bp, length);
               else
                       ospf_print(ndo, bp, length, iph);
               break;

       case IPPROTO_IGMP:
               if (ver == 4)
                       igmp_print(ndo, bp, length);
               else {
                       ND_PRINT("[%s requires IPv4]",
                                tok2str(ipproto_values,"unknown",nh));
                       nd_print_invalid(ndo);
               }
               break;

       case IPPROTO_IPV4:
               /* ipv4-in-ip encapsulation */
               ip_print(ndo, bp, length);
               break;

       case IPPROTO_IPV6:
               /* ip6-in-ip encapsulation */
               ip6_print(ndo, bp, length);
               break;

       case IPPROTO_RSVP:
               rsvp_print(ndo, bp, length);
               break;

       case IPPROTO_GRE:
               gre_print(ndo, bp, length);
               break;

       case IPPROTO_MOBILE:
               mobile_print(ndo, bp, length);
               break;

       case IPPROTO_PIM:
               pim_print(ndo, bp, length, iph);
               break;

       case IPPROTO_VRRP:
               if (ndo->ndo_packettype == PT_CARP) {
                       carp_print(ndo, bp, length, ttl_hl);
               } else {
                       vrrp_print(ndo, bp, length, iph, ttl_hl, ver);
               }
               break;

       case IPPROTO_PGM:
               pgm_print(ndo, bp, length, iph);
               break;

       case IPPROTO_ETHERNET:
               if (ver == 6)
                       ether_print(ndo, bp, length, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
               else {
                       ND_PRINT("[%s requires IPv6]",
                                tok2str(ipproto_values,"unknown",nh));
                       nd_print_invalid(ndo);
               }
               break;

       case IPPROTO_NONE:
               ND_PRINT("no next header");
               break;

       default:
               if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(nh)) != NULL)
                       ND_PRINT(" %s", p_name);
               else
                       ND_PRINT(" ip-proto-%u", nh);
               ND_PRINT(" %u", length);
               break;
       }
}