/*  -*- Mode: C;  -*- */

/******************************************************************************
*                                                                             *
*   Copyright 2005 University of Cambridge Computer Laboratory.               *
*                                                                             *
*   This file is part of Nprobe.                                              *
*                                                                             *
*   Nprobe 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.                                       *
*                                                                             *
*   Nprobe 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 General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with Nprobe; if not, write to the Free Software                     *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*                                                                             *
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef __alpha__
#include <sys/mbuf.h>
#endif
#include <sys/time.h>
#include <net/route.h>
#include <net/if.h>
#ifdef __alpha__
#include <net/if_llc.h>
#endif
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/if_fddi.h>

#ifdef __linux__
#include "linux_tweaks.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>

#include <netinet/if_ether.h>

#include <linux/limits.h>


#include "basic_defs.h"
#include <netinet/ip.h>
#include "list.h"
#include "pkt.h"
#include "flows.h"
#include "http.h"
#include "tcp.h"
#include "service.h"
#include "udp.h"
#include "udp_ns.h"
#include "output.h"
#include "report.h"
#include "pool.h"
#include "if_nprobe.h"
#include "writer.h"
#include "counters.h"
#include "timeouts.h"
#include "print_util.h"
#include "sundry_records.h"
#include "ace_clk.h"
#include "sk98_clk.h"
#include "interface.h"
#include "probe_config.h"

/*
 * Advance set offset to IP hdr
 */

int 
strip_constant_offset(prec_t *pp)
{

  pp->len -= ip_hdr_offset;
  pp->buf += ip_hdr_offset;

  return ETHERTYPE_IP;
} 
  
/*
 * Strip raw IP packet
 * 
 */
int 
strip_raw_encaps(prec_t *pp)
{
  /* do nothing */
  return ETHERTYPE_IP;
}


/* 
 * Strip 10 Mb ether encapsulation, adjust ptr. to start of encapsulated 
 * packet and length, return ethertype of packet if successful, otherwise 0 
 */
int 
strip_eth10_encaps(prec_t *pp)
{
  struct ether_header *ep;
  unsigned short etype;

  if (pp->len < sizeof(struct ether_header)) 
    {
#ifdef PRINT_OUT
      printf("[ether truncated hdr]\n");
#endif
      BUMP_DROPS(MACHdr);
      return 0;
    }

  ep = (struct ether_header *)pp->buf;
  etype = ntohs(ep->ether_type);
  if (etype < ETHERMTU)	      /* 802.3 encapsulation - for the moment reject */
    {
#ifdef PRINT_OUT
      printf("[802.3 encaps]\n");
#endif
      BUMP_DROPS(wrong_encaps);
      return 0;
    }

  pp->len -= sizeof(struct ether_header);
  pp->buf += sizeof(struct ether_header);

  return etype;
}


int 
strip_llc_encaps(prec_t *pp)
{
  unsigned short etype;

  if (pp->len < LLC_SNAP_LEN)
    {
#ifdef PRINT_OUT
      printf("[llc/snap truncated hdr]\n");
#endif
      BUMP_DROPS(MACHdr);
      return 0;
    }

  /*
   * How many of these checks are necessary will depend on nature of any 
   * pre-filtering before we get handed the buffer 
   */

  if (((struct llc *)pp->buf)->llc_control != LLC_UI)
    {
#ifdef PRINT_OUT
      printf("not llc_ui\n");
#endif
      BUMP_DROPS(wrong_llc_type);      return 0;
    }

  if (!LLC_IS_SNAPSAP((int *)pp->buf))
    {
#ifdef PRINT_OUT
      printf("not llc_snapsap\n");
#endif
      BUMP_DROPS(wrong_llc_type);
      return 0;
    }

  if (!LLC_IS_ENCAP_ETHER((int *)pp->buf))
    {
#ifdef PRINT_OUT
      printf("not llc_encaps ether\n");
#endif
      BUMP_DROPS(wrong_encaps);
      return 0;
    }

  /**/

  etype = ntohs(((struct llc *)pp->buf)->llc_ether_type);
  pp->len -= sizeof(struct llc);
  pp->buf += sizeof(struct llc);

  return etype;
}

      


int 
strip_fddi_encaps(prec_t *pp)
{

  if (pp->len < sizeof(struct fddi_header)) 
    {
#ifdef PRINT_OUT
      printf("[fddi truncated hdr]\n");
#endif
      BUMP_DROPS(MACHdr);
      return 0;
    }

  pp->len -= FDDI_HDR_LEN;
  pp->buf += FDDI_HDR_LEN;

  /*
   * For the moment assume llc/snap encapsulation - 
   */
  return strip_llc_encaps(pp);
}

#ifdef TCPDUMP_FED

/* Will never come across this in live operation */

int 
strip_nprobe_encaps(prec_t *pp)
{
  nprobe_hdr_t *nh;
  unsigned short etype;

  if (pp->len < sizeof(nprobe_hdr_t)) 
    {
#ifdef PRINT_OUT
      printf("[nprobe truncated hdr]\n");
#endif
      BUMP_DROPS(MACHdr);
      return 0;
    }

  nh = (nprobe_hdr_t *)pp->buf;
#if 0
  if (nh->u.nh.code != HTTP_ERR_NONE && nh->u.nh.code != TCP_TESTPKT)
    {
      
      /* error packet - drop it */
      BUMP_DROPS(Nprobe_errpkts);
      return 0;
    }
#endif

  pp->atmdata = ntohl(nh->u.nh.atmdata);
  etype = ntohs(nh->u.nh.etype);

  pp->len -= sizeof(nprobe_hdr_t);
  pp->buf += sizeof(nprobe_hdr_t);

  return etype;
}

#endif

/*
 * Construct a table to allow look up of function to strip link specific 
 * encapsulation
 */
struct linktype 
{
  int (*strip)();
  int linktype;
};

static struct linktype linktypes[] = 
{
  {strip_eth10_encaps,  LINK_ETH_10MB},
  {strip_fddi_encaps, LINK_FDDI},
#ifdef TCPDUMP_FED
  {strip_nprobe_encaps, LINK_NPROBE},
  {strip_raw_encaps, LINK_RAW_HIGH},
#endif
  {0, 0}
};

/*
 * Fn. to do the lookup 
 */
void get_linkstripper(link_data_t *ld)
{
  struct linktype *ltp;
  char errbuf[5];
  int type = ld->linktype;

  if (ip_hdr_offset != 0)
    return strip_constant_offset;
  
  
  for (ltp = linktypes; ltp->strip; ++ltp)
    if (type == ltp->linktype)
      {
	ld->linkstripper =  ltp->strip;
	return;
      }
  
  sprintf(errbuf, "get_linkstripper: unknown data link type %.2d", type);
  error(errbuf, "");

  /* NOTREACHED */
  return NULL;
}

/*
 * end interface.c 
 */
