/**************************************************************************** 
** File: ethernet.c
**
** Author: Mike Borella
**
** Comments: Dump ethernet packets
**
** $Id: ethernet.c,v 1.18 2001/05/28 19:24:04 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 "ethernet.h"
#include "ethertypes.h"
#include "ipx.h"
#include "llc.h"
#include "arp.h"
#include "ip_protocols.h"

extern struct arg_t * my_args;
extern strmap_t       ethertype_map[];

/*----------------------------------------------------------------------------
**
** dump_ethernet()
**
** Process packets from the DLT_EN10MB interface type
**
**----------------------------------------------------------------------------
*/

void dump_ethernet(packet_t *pkt)
{
  ether_header_t eth;
  ethertype_func_t et;

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

  /*
   * Read the header
   */

  if (get_packet_bytes((u_int8_t *) &eth, pkt, 14) == 0)
    return;

  /*
   * Conversions
   */

  eth.type = ntohs(eth.type);

  /*
   * Dump header
   */
  if (my_args->m)
    {
      if (my_args->T)
	display_minimal_string("ETH ");
      else
	display_minimal_string("| ETH ");
      display_minimal((u_int8_t *) &eth.src, 6, DISP_HEXCOLONS);
      display_minimal_string("->");
      display_minimal((u_int8_t *) &eth.dst, 6, DISP_HEXCOLONS);
      display_minimal_string(" ");
    }
  else
    {
      /* announcement */
      display_header_banner_ts("Ethernet", pkt->timestamp);
      
      /* fields */
      display("Hardware source", (u_int8_t *) &eth.src, 6, DISP_HEXCOLONS);
      display("Hardware destination", (u_int8_t *) &eth.dst, 6, 
	      DISP_HEXCOLONS);
      display_strmap_hex("Type / Length", eth.type, ethertype_map);
      display("Media length", (u_int8_t *) &pkt->media_length, 2, DISP_DEC);  
    }
  
  /* dump the hex buffer */
  hexbuffer_flush();
  
  /*
   * Check for IEEE 802 (LLC) encapsulation.  If not, assume regular ethernet
   */

  if (eth.type <= ETHERMTU) 
    {
      /* Do something intelligent with LLC */
      if (my_args->m)
	{
	  display_minimal_string("(");
	  display_minimal((u_int8_t *) &eth.type, 2, DISP_HEX);
	  display_minimal_string(") ");
	}
      dump_llc(pkt);
    }
  else 
    {
      /*
       * Display the rest of the packet
       */

      et = ethertype2func(eth.type);
      if (et)
	{
	  et(pkt);
	}
      else
	{
	  /* 
	   * If we can't map the type, and we're in minimal mode, 
	   * dump the protocol type 
	   */
	  
	  if (my_args->m)
	    {
	      display_minimal_string("(");
	      display_minimal((u_int8_t *) &eth.type, 2, DISP_HEX);
	      display_minimal_string(") ");
	    }
	}
    } /* else */

}

