/*
 * TCPVIEW
 *
 * Author:	Martin Hunt
 *		Networks and Distributed Computing
 *		Computing & Communications
 *		University of Washington
 *		Administration Building, AG-44
 *		Seattle, WA  98195
 *		Internet: martinh@cac.washington.edu
 *
 *
 * Copyright 1992 by the University of Washington
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appears in all copies and that both the
 * above copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the University of Washington not be
 * used in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  This software is made
 * available "as is", and
 * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
 * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
 * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */
#ifndef lint
static char rcsid[] =
    "@(#) $Header: /usr/staff/martinh/tcpview/RCS/bgp.c,v 1.2 1993/04/22 20:11:19 martinh Exp $ (UW)";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "os.h"
#include "md.h"

int PrintFrames = 0;

#ifdef __STDC__
int getbyte(void);
u_short getword(void);
u_long getlword(void);
#else
int getbyte();
u_short getword();
u_long getlword();
#endif

char *msg_type[]= { "null","OPEN","UPDATE","NOTIFICATION","KEEPALIVE" };
char *origin_str[] = { "IGP","EGP","INCOMPLETE" };

void bgp_open(), bgp_update(), bgp_note(), bgp_keepalive();
void mess_err(), update_err(), open_err();
int getattributes();

void (*type_func[])() = { NULL, bgp_open, bgp_update, bgp_note, bgp_keepalive };

main(argc, argv)
int argc;
char *argv[];
{
  int c, i=0;
  int type;
  int length;

  if( argc > 1 )
    if( *argv[1]=='-' && argv[1][1]=='f' )
      PrintFrames=1;

sync:  
  /* look for 16 0xFF octets */
  while( (c = getbyte()) != EOF) {
    if( c == 0xFF ) {
      i++;
      if( i == 16 )
	break;
    } else
      i = 0;
  }

  while(1) {
    length = getword();
    if( length < 19 || length > 4096 )
      goto sync;

    type = getbyte();
    if( type < 1 || type > 4 )
      goto sync;

    (type_func[type])(length);

    /* eat Marker */
    for(i=0;i<16;i++)
      if(getbyte()==EOF)
	exit(0);
  }
}

void bgp_open(length)
     int length;
{
  int i, min_length;
  u_short asn, htime, version, auth;
  long id;

  version = getbyte();
  if(version > 2)
    min_length = 29;
  else
    min_length = 25;

  if( length < min_length)
    printf("OPEN: ERROR has a length of %d. Must be >= %d\n",length,min_length);

  asn = getword();
  htime = getword();

  if(version > 2) 
    id = getlword();

  auth = getbyte();

  if(version > 2)
    printf("OPEN: version: %d,  asn=%d,  htime=%d,  id=%d  auth=%d\n",
	   version,asn,htime,id,auth);
  else
    printf("OPEN version: %d,  asn=%d,  htime=%d,  auth=%d\n",
	   version,asn,htime,auth);

  if( length > min_length ) {
    printf("WARNING: authentication data present\n");
    /*fread(&auth_data,length-min_length,1,stdin); */
  }

  /* eat any excess */
  for(i=min_length;i<length;i++)
    if(getbyte()==EOF)
      exit(0);
}

void bgp_update(length)
     int length;
{
  int j, tpal, nets;
  long ip;

  printf("UPDATE ");
  tpal = getword(); /* Total Path Attributes Length */
  nets = (length-21-tpal)/4;
  if (nets<0 || length != nets*4+21+tpal) {
    printf("INVALID FORMAT - ");
    printf("length=%d  TPAL=%d\n",length,tpal);
    return; 
  }

  if(getattributes(tpal))
    printf("\nERROR: TPAL was incorrect length");

  putchar('\n');

  /* now print out networks */
  j = 0;
  while(nets--) {
    ip = getlword();
    printf("\t%s ",inet_ntoa(htonl(ip)));
    if ( j++ == 4 ) {
      j = 0;
      putchar('\n');
    }
  }
  putchar('\n');
}

char *e_msg[] = { "","Message Header Error","OPEN Message Error",
			  "UPDATE Message Error","Hold Timer Expired",
			  "Finite State Machine Error","Cease" };
    
void bgp_note(length)
     int length;
{
  int i, len=0;
  int code, sub, data_len;

  printf("NOTIFICATION: ");
  code = getbyte();
  sub = getbyte();
  if(sub==-1 || code==-1)
    exit(0);

  data_len = length - 21;
  if( code>0 && code <7 ) {
    printf("%s: ",e_msg[code]);
    switch (code) {
    case 1: 
      mess_err(sub, data_len);
      break;
    case 2:
      open_err(sub, data_len);
      break;
    case 3:
      update_err(sub, data_len);
      break;
    default:
      for(i=21;i<length;i++)
	if(getbyte()==EOF)
	  exit(0);
    }      
  } else
    printf("Unknown Error Code (%d.%d)\n",code,sub);
}

void bgp_keepalive(length)
     int length;
{
  int i;
  printf("KEEPALIVE\n");
  if(length != 19)
    printf("WARNING: KEEPALIVE message has length of %d (should be 19)\n",length);
  for(i=19;i<length;i++)
    if(getbyte()==EOF)
      exit(0);
}

void mess_err(subtype, length)
     int length, subtype;
{
  int i, len=0;
  
  switch(subtype) {
  case 1:
    printf("Connection Not Synchronized.\n");
    break;
  case 2:
    printf("Bad Message Length: ");
    if(length==2) {
      printf("%d\n",getword());
      len += 2;
    } else if (length==1) {
      printf("%d\n",getbyte());
      len++;
    } else printf("???\n");
    break;
  case 3:
    printf("Bad Message Type: ");
    if(length==2) {
      printf("%d\n",getword());
      len += 2;
    } else if (length==1) {
      printf("%d\n",getbyte());
      len++;
    } else printf("???\n");
    break;
  default:
    printf("ERROR: unknown subtype\n");
  }
  for(i=len;i<length;i++)
    if(getbyte()==EOF)
      exit(0);
}

void open_err(subtype, length)
     int length, subtype;
{
  int i, len=0;

  switch(subtype) {
  case 1:
    printf("Unsupported Version Number: ");
    if(length==2) {
      printf("largest supported = %d\n",getword());
      len += 2;
    } else if (length==1) {
      printf("largest supported = %d\n",getbyte());
      len++;
    } else printf("???\n");
    break;
  case 2:
    printf("Bad Peer AS\n");
    break;
  case 3:
    printf("Bad BGP Identifier\n");
    break;
  case 4:
    printf("Unsupported Authentication Code\n");
    break;
  case 5:
    printf("Authentication Failure\n");
    break;
  default:
    printf("ERROR: unknown subtype\n");
  }
  for(i=len;i<length;i++)
    if(getbyte()==EOF)
      exit(0);
}

char *update_error[] = { "", "Malformed Attribute List",
				 "Unrecognized Well-known Attribute: ",
				 "Missing Well-known Attribute: ",
				 "Attribute Flags Error: ",
				 "Attribute Length Error: ",
				 "Invalid ORIGIN Attribute: ",
				 "AS Routing Loop: ",
				 "Invalid NEXT_HOP Attribute: ",
				 "Optional Attribute Error: ",
				 "Invalid Network Field" };

void update_err(subtype, length)
     int length, subtype;
{
  int i;

  if(subtype>0 && subtype <11) {
    printf("%s",update_error[subtype]);
    if(getattributes(length)) 
      printf("\nERROR parsing subcode data");
    putchar('\n');
  } else {
    printf("bad subtype (%d)\n",subtype);
    for(i=0;i<length;i++)
      if(getbyte()==EOF)
	exit(0);
  }
}


int getattributes(len)
int len;
{
  int attr_flag, attr_type, extended;
  int i, adl, origin, asn;
  long ip;

  while(len) {
    attr_flag = getbyte();
    attr_type = getbyte();
    len -= 2;
    putchar('(');
    if(attr_flag & 128) putchar('O');
    if(attr_flag & 64) putchar('T');
    if(attr_flag & 32) putchar('P');
    extended = attr_flag & 16;
    if(extended) putchar('E');
    putchar(')'); putchar(' ');

    if( (attr_flag & 15) != 0 )
      printf("\nWARNING: lower 4 bits of Attribute Flags Octet not zero\n");

    if( extended ) {
      adl = getword();
      len -= 2;
    } else {
      adl = getbyte();
      len -= 1;
    }

    switch(attr_type) {
    case 1:
      origin = getbyte();
      len -= 1;
      if(origin<0 || origin>2)
	printf("ORIGIN: unknown  ");
      else
	printf("ORIGIN: %s  ",origin_str[origin]);
      break;
    case 2:
      printf("ASN_PATH: ");
      for(i=0;i<adl;i+=2) {
	asn = getword();
	printf("%d ",asn);
	len -= 2;
      }
      break;
    case 3:
      ip = getlword();
      len -= 4;
      printf("NEXT_HOP: %s  ",inet_ntoa(htonl(ip)));
      break;
    case 4:
      printf("UNREACHABLE  ");
      break;
    case 5:
      printf("INTER-AS METRIC %d  ",getword());
      len -= 2;
      break;
    default:
      printf("UNKNOWN TYPE CODE %d  ",attr_type);
    }
  }
  return(len);
}

/* some basic I/O functions */

int getbyte()
{
  u_char b;
  if(hexread(&b,1))
    return( (int)b );
  else 
    return( EOF );
}

u_short getword()
{
  unsigned short buf;
  if( hexread(&buf,2) )
    return( ntohs(buf) );
  else
    return( EOF );
}

u_long getlword()
{
  unsigned int buf;
  if( hexread(&buf,4) )
    return( ntohl(buf) );
  else
    return( EOF );
}





syntax highlighted by Code2HTML, v. 0.9.1