/**************************************************************************** 
** File: ipv6.c
**
** Author: Mike Borella
**
** Comments: Dump IP header information
**
** $Id: ipv6.c,v 1.15 2007/06/25 11:46:16 farooq-i-azam Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Library General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/

#include "ipv6.h"
#include "ip_protocols.h"

#define HOLDER_SIZE 64

/* Structure of IPv6 header */
typedef struct ipv6_header
{
#if defined(WORDS_BIGENDIAN)
  u_int8_t       version:4, 
                 traffic_class_high:4;
  u_int8_t       traffic_class_low:4,
                 flow_label_high:4;
#else
  u_int8_t       traffic_class_high:4,
                 version:4;
  u_int8_t       flow_label_high:4,
                 traffic_class_low:4;
#endif
  u_int16_t      flow_label_low;
  u_int16_t      payload_length;
  u_int8_t       next_header;
  u_int8_t       hop_limit;
  u_int8_t       src_addr[16];
  u_int8_t       dst_addr[16];
} ipv6_header_t;

extern struct arg_t *my_args;
extern void (*ip_proto_func[])(packet_t *);
extern strmap_t ipproto_map[];

/*----------------------------------------------------------------------------
**
** dump_ipv6()
**
** Parse IPv6 header and dump fields
**
**----------------------------------------------------------------------------
*/

void dump_ipv6(packet_t *pkt)
{
  ipv6_header_t ipv6;
  char          holder[HOLDER_SIZE];
  u_int8_t      ver;
  u_int8_t      class; 
  u_int32_t     flow;

  /* Set the layer */
  set_layer(LAYER_NETWORK);

  /*
   * Stats accounting
   */

  stats_update(STATS_IPV6);

  /*
   * Stats accounting
   */

  stats_update(STATS_IP);

  /*
   * Get the IPv6 header
   */

  if (get_packet_bytes((u_int8_t *) &ipv6, pkt, 40) == 0)
    return;

  /*
   * Conversions
   */

  ver = ipv6.version;
  class = ipv6.traffic_class_high * 0x10 + ipv6.traffic_class_low;
  flow = ipv6.flow_label_high * 0x10000 + ntohs(ipv6.flow_label_low);
  ipv6.payload_length = ntohs(ipv6.payload_length);

  /*
   * Dump header
   */

  if (my_args->m)
    {
      display_minimal_string("| IPv6 ");
      display_minimal_ipv6((u_int8_t *) &ipv6.src_addr); 
      display_minimal_string("->");
      display_minimal_ipv6((u_int8_t *) &ipv6.dst_addr); 
      display_minimal_string(" ");
    }
  else
    {
      /* announcement */
      display_header_banner("IPv6 Header");
      
      /* print fields */
      display("Version", (u_int8_t *) &ver, 1, DISP_DEC);
      display("Traffic class", (u_int8_t *) &class, 1, DISP_HEX);
      display("Flow label", (u_int8_t *) &flow, 4, DISP_HEX);
      display("Payload length", (u_int8_t *) &ipv6.payload_length, 2, 
	      DISP_DEC);
      snprintf(holder, HOLDER_SIZE, "%d (%s)", ipv6.next_header, 
	      map2str(ipproto_map, ipv6.next_header));
      display("Next header", holder, strlen(holder), DISP_STRING);
      display("Hop limit", (u_int8_t *) &ipv6.hop_limit, 1, DISP_DEC);
      display_ipv6("Source address",(u_int8_t *) &ipv6.src_addr); 
      display_ipv6("Destination address",(u_int8_t *) &ipv6.dst_addr); 
    }

  /* dump the hex buffer */
  hexbuffer_flush();

  /*
   * Hand it to the next higher level protocol.
   */
  
  if (ip_proto_func[ipv6.next_header]) 
    ip_proto_func[ipv6.next_header](pkt);
}

