/**************************************************************************** 
** File: arp.c
**
** Author: Mike Borella
**
** Comments: Dump ARP / RARP header information
**
** $Id: arp.c,v 1.20 2001/10/19 15:24:56 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 "arp.h"
#include "ethertypes.h"

#define ARP_PADDING_SIZE 18 /* bytes to pad ARP to the min eth frame len */

/*
 * ARP opcode map
 */

strmap_t arp_opcode_map[] =
{
  { ARP_OPCODE_REQUEST,  "request" },
  { ARP_OPCODE_REPLY,    "reply" },
  { RARP_OPCODE_REQUEST, "RARP request" },
  { ARP_OPCODE_REPLY,    "RARP reply" },
  { 0, "" }
};

/*
 * ARP hardware map
 */

strmap_t arp_hardware_map[] =
{
  { ARP_HWTYPE_ETHERNET,    "Ethernet" },
  { ARP_HWTYPE_IEEE802,     "IEEE 802" },
  { ARP_HWTYPE_IEEE1394,    "IEEE 1394" },
  { 0, "" }
};

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

/*----------------------------------------------------------------------------
**
** dump_etherarp()
**
** Parse Ethernet-specifc parts of ARP messages
**
**----------------------------------------------------------------------------
*/

void dump_etherarp(packet_t *pkt)
{
  ether_arp_t etharp;

  /*
   * Get the Ethernet section
   */

  if (get_packet_bytes((u_int8_t *) &etharp, pkt, 20) == 0)
    return;

  /*
   * Do minimal or not-so-minimal mode
   */

  if (my_args->m)
    {
      display_minimal_ipv4((u_int8_t *) &etharp.target_protoaddr);
    }
  else
    {
      display("Sender Ether address", (u_int8_t *) &etharp.sender_hwaddr, 6, 
	      DISP_HEXCOLONS);
      display_ipv4("Sender IP address",
		   (u_int8_t *) &etharp.sender_protoaddr); 
      display("Target Ether address", (u_int8_t *) &etharp.target_hwaddr, 6, 
	      DISP_HEXCOLONS);
      display_ipv4("Target IP address",
		   (u_int8_t *) &etharp.target_protoaddr); 
    }
  
  /*
   * Some ARPs include Ethernet frame padding.  Check for that.  Note that we
   * must allow ARP frames to be 1500 bytes.  Some NICs seems to generate 
   * them as such.  Strange but true.  In any case, we set the apparent end
   * of the packet to be at the place where we stop processing legit ARP 
   * bytes, and if padding is turned on, you'll see the rest of the bytes.
   */
  
  if (!my_args->m)
    {
      int bytes;
      
      bytes = get_packet_apparentbytesleft(pkt); 
      if (bytes > 0)
	set_packet_apparentend(pkt, 0);
    }
  
}

/*----------------------------------------------------------------------------
**
** dump_arp()
**
** Parse ARP header and dump fields
**
**----------------------------------------------------------------------------
*/

void dump_arp(packet_t *pkt)
{
  arp_header_t arp;

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

  /*
   * Stats accounting
   */

  stats_update(STATS_ARP);

  /*
   * Get the ARP fixed header
   */

  if (get_packet_bytes((u_int8_t *) &arp, pkt, 8) == 0)
    return;

  /*
   * Conversions
   */

  arp.hwaddr_format = ntohs(arp.hwaddr_format);
  arp.protoaddr_format = ntohs(arp.protoaddr_format);
  arp.opcode = ntohs(arp.opcode);

  /* 
   * Check for minimal mode first
   */

  if (my_args->m)
    {
      display_minimal_string("| ARP ");
      switch(arp.opcode)
	{
	case ARP_OPCODE_REQUEST:
	case ARP_OPCODE_REPLY:
	  display_minimal_string(map2str(arp_opcode_map, arp.opcode));
	  display_minimal_string(" ");
	  break;
	default:
	  break;
	}
    }
  else
    {
      /* 
       * Banner announcement 
       */
      
      display_header_banner("ARP Header");
      
      /*
       * Dump hardware type
       */
      
      display_strmap_hex("Hardware type", arp.hwaddr_format, 
			 arp_hardware_map);
      
      /*
       * Dump protocol type
       */
      
      display_strmap_hex("Protocol type", arp.protoaddr_format, 
			 ethertype_map);
      
      /* 
       * Dump hardware and protocol lengths
       */
      
      display("Hardware length", (u_int8_t *) &arp.hwaddr_length, 1, 
	      DISP_DEC);
      display("Protocol length", (u_int8_t *) &arp.protoaddr_length, 1, 
	      DISP_DEC);
      
      /*
       * Now do the opcode
       */
      
      display_strmap("Opcode", arp.opcode, arp_opcode_map);
    }
  
  /*
   * Check hardware type and layer 3 address format
   */
  
  switch(arp.hwaddr_format)
    {
    case ARP_HWTYPE_ETHERNET: 
      
      switch(arp.protoaddr_format)
	{
	case ETHERTYPE_IP:
	  dump_etherarp(pkt);
	  break;
	  
	default:
	  break;
	} /* inner switch */

    default:
      break;
    } /* outer switch */


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

}





syntax highlighted by Code2HTML, v. 0.9.1