/**************************************************************************** 
** File: ospf.c
**
** Author: Mike Borella
**
** Comments: Dump OSPF information
**
** $Id: ospf.c,v 1.14 2002/01/03 00:04:01 mborella 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 "global.h"
#include "ospf.h"

#define HOLDER_SIZE 64

/*
 * OSPF type map
 */

strmap_t ospf_type_map [] =
{
  { OSPF_TYPE_HELLO,        "hello" },
  { OSPF_TYPE_DATABASEDESC, "database description" },
  { OSPF_TYPE_LSREQUEST,    "link state request" },
  { OSPF_TYPE_LSUPDATE,     "link state update" },
  { OSPF_TYPE_LSACK,        "link state acknowledgement" },
  { 0, "" }
};

/*
 * OSPF auth type map
 */

strmap_t ospf_auth_map [] =
{
  { OSPF_AUTH_NONE,         "none" },
  { OSPF_AUTH_SIMPLE,       "simple" },
  { OSPF_AUTH_CRYPTO,       "cryptographic" },
  { 0, "" }
};

extern struct arg_t * my_args;

/*----------------------------------------------------------------------------
**
** dump_ospf_hello()
**
** Parse OSPF hello header and dump fields
**
**----------------------------------------------------------------------------
*/

void dump_ospf_hello(packet_t *pkt, u_int16_t length)
{
  ospf_hello_header_t ospf_hello;
  u_int8_t neighbor[4];

  /*
   * Get the header
   */
  
  if (get_packet_bytes((u_int8_t *) &ospf_hello, pkt, 
		       sizeof(ospf_hello_header_t)) == 0)
    return;
  
  /*
   * Conversions 
   */

  ospf_hello.interval = ntohs(ospf_hello.interval);
  ospf_hello.dead_interval = ntohl(ospf_hello.dead_interval);
  
  /*
   * Dump the fields 
   */
  
  if (my_args->m)
    {
      display_minimal_ipv4((u_int8_t *) &ospf_hello.designated_router);
      display_minimal_string(" ");
    }
  else
    { 
      display_ipv4("Netmask", (u_int8_t *) &ospf_hello.netmask);
      display("Interval", (u_int8_t *) &ospf_hello.interval, 2, 
	      DISP_DEC);
      display("Options", (u_int8_t *) &ospf_hello.options, 1, DISP_HEX);
      display("Router priority", (u_int8_t *) &ospf_hello.router_priority, 
	      1, DISP_DEC);
      display("Dead interval", (u_int8_t *) &ospf_hello.dead_interval, 4, 
	      DISP_DEC);
      display_ipv4("Designated router", 
		   (u_int8_t *) &ospf_hello.designated_router);
      display_ipv4("Backup router", (u_int8_t *) &ospf_hello.backup_router);
    }

  /*
   * Dump the neighbors, which should just be a bunch of IP addresses
   * lasting the rest of the packet.
   */

  while (get_packet_apparentbytesleft(pkt))
    {
      if (get_packet_bytes((u_int8_t *) &neighbor, pkt, 4) == 0)
	return;

      if (my_args->m)
	{
	  display_minimal_ipv4((u_int8_t *) &neighbor);
	  display_minimal_string(" ");
	}
      else
	display_ipv4("Neighbor", (u_int8_t *) &neighbor);
    }
}

/*----------------------------------------------------------------------------
**
** dump_ospf()
**
** Parse OSPF common header and dump fields
**
**----------------------------------------------------------------------------
*/

void dump_ospf(packet_t *pkt)
{
  ospf_common_header_t ospf;
  char holder[HOLDER_SIZE];
  
  /* Set the layer */
  set_layer(LAYER_APPLICATION);

  /*
   * Stats accounting
   */

  stats_update(STATS_OSPF);

  /*
   * Get the header
   */
  
  if (get_packet_bytes((u_int8_t *) &ospf, pkt, 
		       sizeof(ospf_common_header_t)) == 0)
    return;
  
  /*
   * Conversions 
   */
  
  ospf.length = ntohs(ospf.length);
  ospf.checksum = ntohs(ospf.checksum);
  ospf.auth_type = ntohs(ospf.auth_type);

  /*
   * Dump the fields 
   */
  
  if (my_args->m)
    {
      /* In minimal mode lets just dump the type and the router ID */
      display_minimal_string("| OSPF ");
      display_minimal_string(map2str(ospf_type_map, ospf.type));
      display_minimal_string(" ");      
      display_minimal_ipv4((u_int8_t *) &ospf.router_id);
      display_minimal_string(" ");      
    }
  else
    { 
      /* announcement */
      display_header_banner("OSPF Header");
      
      display("Version", (u_int8_t *) &ospf.version, 1, DISP_DEC);
      snprintf(holder, HOLDER_SIZE, "%d (%s)", ospf.type, 
	       map2str(ospf_type_map, ospf.type));
      display_string("Type", holder);
      display("Length", (u_int8_t *) &ospf.length, 2, DISP_DEC);
      display_ipv4("Router ID", (u_int8_t *) &ospf.router_id);
      display_ipv4("Area ID", (u_int8_t *) &ospf.area_id);
      display("Checksum", (u_int8_t *) &ospf.checksum, 2, DISP_DEC);
      snprintf(holder, HOLDER_SIZE, "%d (%s)", ospf.auth_type, 
	       map2str(ospf_auth_map, ospf.auth_type));
      display_string("Authentication", holder);
      display("Authentication data", (u_int8_t *) &ospf.auth_data, 8, 
	      DISP_HEX);
    }

  /*
   * Dump the more specific header type XXX NOT COMPLETE!
   */
  
  switch(ospf.type)
    {
    case OSPF_TYPE_HELLO:
      dump_ospf_hello(pkt, ospf.length);
      break;
    default:
      break;
    }

  /* Dump the hex buffer */
  hexbuffer_flush();
}

