/**************************************************************************** 
** File: l2tp.c
**
** Author: Mike Borella
**
** Comments: Dump L2TP header information
**
** $Log$
*****************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include "config.h"
#include "l2tp.h"

extern u_char *packet_end;

/*----------------------------------------------------------------------------
**
** dump_l2tp()
**
** Parse L2TP packet and dump fields
**
**----------------------------------------------------------------------------
*/

void dump_l2tp(u_char *bp, int length)
{
  u_char *ep = bp + length;
  u_char *p;
  u_char type;
  int len;
  int AVP_len;
  L2TPCtrlHdr *ch;
  int parse_AVP(u_char *, u_char *);

  /*
   * Make sure we don't run off the end of the packet
   */

  if (ep > packet_end) 
    ep = packet_end;
  p = bp;

  /*
   * Determine type: either control or data
   */

  type = *p && 0x7f;
  if (type == 0)
    {
      /*
       * Parse and print data packet headers
       */

      printf("----------------------------------------------------------\n");
      printf("                        L2TP Data Header\n");
      printf("----------------------------------------------------------\n");

    }

  else

    {
      /*
       * Parse and print control packet headers
       */
      
      ch = (L2TPCtrlHdr *) p;

      printf("----------------------------------------------------------\n");
      printf("                        L2TP Control Header\n");
      printf("----------------------------------------------------------\n");
      
      /*
       * Check for valid bits
       */
      
      if (ch->bits != 0xc8)
	{
	  printf("Invalid TLF bits\n");
	  return;
	}

      printf("Version:                %d\n", ch->version);
      len = ntohs(ch->length);
      printf("Length:                 %d\n", len);
      printf("Tunnel ID:              %d\n", ntohs(ch->tunnelID));
      printf("Call ID:                %d\n", ntohs(ch->callID)); 
      printf("Next Sent:              %d\n", ntohs(ch->ns));
      printf("Next Received:          %d\n", ntohs(ch->nr));
      
      p += sizeof(L2TPCtrlHdr);
      AVP_len = parse_AVP(p, ep);
    }
}

/*----------------------------------------------------------------------------
**
** parse_AVP()
**
** Parse L2TP AVP subheader
**
**----------------------------------------------------------------------------
*/

int parse_AVP(u_char *p, u_char *ep)
{
  L2TP_AVP *avp;
  u_char *p2;
  u_int16_t val;
  void dump_AVP(L2TP_AVP *, char *);
  
  avp = (L2TP_AVP *) p;
  
  switch(avp->attribute)
    {
    case 0:
      dump_AVP(avp, "Message Type");
      p2 = p+sizeof(L2TP_AVP);
      val = EXTRACT_16BITS(p2);
      printf("Value:                  %d (%s)\n", val, CtrlMsgType[val]);
      break;

    case 1:
      dump_AVP(avp, "Result Code");
      break;

    case 2:
      dump_AVP(avp, "Protocol Version");
      break;
      
    case 3: 
      dump_AVP(avp, "Framing Capabilities");
      break;
      
    case 4:
      dump_AVP(avp, "Bearer Capabilities");
      break;

    case 5:
      dump_AVP(avp, "Tiebreaker");
      break;

    case 6:
      dump_AVP(avp, "Firmware Revision");
      break;

    case 7: 
      dump_AVP(avp, "Host Name");
      break;

    case 8:
      dump_AVP(avp, "Vendor Name");
      break;

    case 9:
      dump_AVP(avp, "Assigned Tunnel ID");
      break;

    case 10:
      dump_AVP(avp, "Receive Window Size");
      break;

    case 14:
      dump_AVP(avp, "Assigned Call ID");
      break;


    default: 
      return -1;
      
    }

  return avp->length;
}


/*----------------------------------------------------------------------------
**
** dump_AVP()
**
** Print L2TP AVP subheader
**
**----------------------------------------------------------------------------
*/

void dump_AVP(L2TP_AVP *avp, char *name)
{
  printf("%s AVP\n", name);
  printf("  M bit:                %d\n", avp->m);
  printf("  H bit:                %d\n", avp->h);
  printf("  Zeros:                %d\n", avp->zeros);
  printf("  Length:               %d\n", avp->length);
  printf("  Vendor ID:            %d\n", avp->vendorID);
  printf("  Attribute:            %d\n", avp->attribute);
}
