/**************************************************************************** 
** File: ethernet.c
**
** Author: Mike Borella
**
** Comments: Dump ethernet packets
**
** $Log: ethernet.c,v $
** Revision 1.2  1998/06/12 21:01:01  mborella
** Added log tag
**
*****************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <pcap.h>
#include <netinet/in.h>
#include "ethernet.h"
#include "config.h"

u_char *packet_ptr;
u_char *packet_end;

extern struct arg_t *my_args;

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

void dump_ethernet(u_char *user, const struct pcap_pkthdr *h, u_char *p)
{
  int length; 
  int caplen;
  int ether_type;
  EtherHdr *ep;
  void dump_ip(u_char *, int);
  void dump_ipx(u_char *, int);
  void dump_arp(u_char *, int, int);
  char *etheraddr_string(u_char *);
  char *etherproto_string(u_short);


  /*
   * Get total packet length and length of the captured section
   */

  length = h->len;
  caplen = h->caplen;

  /*
   * Dump header announcement
   */

  printf("=================================================================\n");
  printf("                        Ethernet Header(%u.%06u)\n",
	 (u_int32_t) h->ts.tv_sec, (u_int32_t) h->ts.tv_usec);
  printf("-----------------------------------------------------------------\n");

  /*
   * Check for truncated header 
   */

  if (caplen < sizeof(EtherHdr)) 
    {
      printf("Ethernet header too short! (%d bytes)\n", length);
      return;
    }


  /*
   * Dump header fields
   */

  ep = (EtherHdr *) p;  
  ether_type = ntohs(ep->ether_type);

  if (!my_args->l)
    {
      printf("Hardware source:        %s\n", 
	     etheraddr_string(ep->ether_src));
      printf("Hardware destination:   %s\n", 
	     etheraddr_string(ep->ether_dst));
      printf("Protocol type:          %xH (%s)\n", ether_type, 
	     etherproto_string(ep->ether_type));
      printf("Length:                 %d\n", length+4); /* add FCS */
    }

 
  /*
   * Some printers want to get back at the link level addresses,
   * and/or check that they're not walking off the end of the packet.
   * Rather than pass them all the way down, we set these globals.
   */
   
  packet_ptr = p;
  packet_end = p + caplen;


  /*
   * Check for IEEE 802 (LLC) encapsulation.  If not, assume regular ethernet
   */

  p += sizeof(EtherHdr);

  if (ether_type <= ETHERMTU) 
    {
      /* XXX do something intelligent with LLC */
    }
  else 
    {
      switch (ether_type)
	{
        case ETHERTYPE_IP:
	  dump_ip(p, length);
	  return;

	case ETHERTYPE_ARP:
        case ETHERTYPE_REVARP:
	  dump_arp(p, length, caplen);
	  return;

	case ETHERTYPE_IPX:
	  dump_ipx(p, length-sizeof(EtherHdr));
	  return;

        default:
	  return;
	  
	}

    } /* else */

}

