/*************************************************************************
  (c) Copyright.  Digital Equipment Corporation, 1995.  All Rights
  Reserved.

  Permission is hereby granted to use, copy, modify, or enhance this 
  software freely, as long as the foregoing copyright of Digital Equipment
  Corporation and this notice are retained on the software.  This 
  software may not be distributed or sublicensed for a fee.  Digital      
  makes this software available "AS IS" and without warranties of any
  kind.  
 *************************************************************************/
/*
 * Marko Kiiskila carnil@cs.tut.fi 
 * 
 * Tampere University of Technology - Telecommunications Laboratory
 *
 * Permission to use, copy, modify and distribute this
 * software and its documentation is hereby granted,
 * provided that both the copyright notice and this
 * permission notice appear in all copies of the software,
 * derivative works or modified versions, and any portions
 * thereof, that both notices appear in supporting
 * documentation, and that the use of this software is
 * acknowledged in any publications resulting from using
 * the software.
 * 
 * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS
 * SOFTWARE.
 * 
 */

/* le_disp.c
 *
 * LE Frame Parser and Displayer
 *
 */
#include <stdio.h>
#include "codes.h"
#include "g_types.h"
#include "atm.h"
#include "system.h"
#include "g_endian.h"
#include "af_lane.h"
#include "le_disp.h"

const char *disp_status_text (UINT16 status)
   {
   switch (status)
      {
      case 0 :  return "Success";
      case 1 :  return "Version_Not_Supported";
      case 2 :  return "Invalid_Parameters";
      case 4 :  return "Duplicate_LAN_Destination";
      case 5 :  return "Duplicate_ATM_Address";
      case 6 :  return "Insufficient_Resources";
      case 7 :  return "Access_Denied";
      case 8 :  return "Invalid_Request_ID";
      case 9 :  return "Invalid_LAN_Destination";
      case 10 : return "Invalid_ATM_Address";
      case 20 : return "No_Configuration";
      case 21 : return "LE_Configuration_Error";
      case 22 : return "Insufficient_Information";
      default : return "<Unknown Error Code>";
      }
   }

static const char *opcode_text (UINT16 opcode)
   {
   switch (opcode)
      {
      case 0x0001 : return "LE_CONFIG_REQUEST";
      case 0x0101 : return "LE_CONFIG_RESPONSE";
      case 0x0002 : return "LE_JOIN_REQUEST";
      case 0x0102 : return "LE_JOIN_RESPONSE";
      case 0x0003 : return "READY_QUERY";
      case 0x0103 : return "READY_INDICATION";
      case 0x0004 : return "LE_REGISTER_REQUEST";
      case 0x0104 : return "LE_REGISTER_RESPONSE";
      case 0x0005 : return "LE_UNREGISTER_REQUEST";
      case 0x0105 : return "LE_UNREGISTER_RESPONSE";
      case 0x0006 : return "LE_ARP_REQUEST";
      case 0x0106 : return "LE_ARP_RESPONSE";
      case 0x0007 : return "LE_FLUSH_REQUEST";
      case 0x0107 : return "LE_FLUSH_RESPONSE";
      case 0x0008 : return "LE_NARP_REQUEST";
      case 0x0009 : return "LE_TOPOLOGY_REQUEST";
      default :     return "<Unknown Opcode>";
      }
   }

char *disp_atm_text (ADDR_ATM atm)
   {
   static char buffer[100];
   int         i;

   for (i = 0; i < 100; i++)  buffer[i] = (char) 0;

   sprintf(buffer, "pre:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
                   " esi:%02x-%02x-%02x-%02x-%02x-%02x sel:%02x",
           atm.prefix[0],
           atm.prefix[1],
           atm.prefix[2],
           atm.prefix[3],
           atm.prefix[4],
           atm.prefix[5],
           atm.prefix[6],
           atm.prefix[7],
           atm.prefix[8],
           atm.prefix[9],
           atm.prefix[10],
           atm.prefix[11],
           atm.prefix[12],
           atm.esi[0],
           atm.esi[1],
           atm.esi[2],
           atm.esi[3],
           atm.esi[4],
           atm.esi[5],
           atm.sel);

   return buffer;
   }

char *disp_esi_text (ESI esi)
   {
   static char buffer[100];
   int         i;

   for (i = 0; i < 100; i++)  buffer[i] = (char) 0;

   sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x",
           esi[0],
           esi[1],
           esi[2],
           esi[3],
           esi[4],
           esi[5]);

   return buffer;
   }

static void disp_lan_dst (LE_LAN_DST *p_dst)
   {
   switch (ntoh16 (p_dst->tag))
      {
      case TAG_NOT_PRESENT :

         printf ("<Not Present>\n");
         break;
      case TAG_MAC_ADDR :

         printf ("MAC : %s\n", disp_esi_text (p_dst->mac_addr));
         break;
      case TAG_ROUTE_DESC :

         printf ("Route Desc: \n");
         break;

      default:
         printf ("<Unknown Tag>  Tag=%d\n", ntoh16 (p_dst->tag));
      }
   }

static void disp_arp (void *frame, UINT32 length)
   {
   LE_ARP_FRAME   *p_arp;

   p_arp = (LE_ARP_FRAME *) frame;

   printf ("    Source LAN Destination : ");
   disp_lan_dst (&p_arp->src_lan_dst);
   printf ("    Target LAN Destination : ");
   disp_lan_dst (&p_arp->target_lan_dst);

   printf ("    Source ATM : %s\n", disp_atm_text (p_arp->src_atm_addr));
   printf ("    Target ATM : %s\n", disp_atm_text (p_arp->target_atm_addr));
   }

static void disp_join (void *frame, unsigned long length)
{
  LE_JOIN_FRAME *p_frame;
  
  p_frame = (LE_JOIN_FRAME *) frame;

  printf ("    Source LAN Destination : ");
  disp_lan_dst(&p_frame->src_lan_dst);
  printf ("    Source ATM : %s\n", disp_atm_text (p_frame->src_atm_addr));
}

static void
disp_flush(void *frame, unsigned long length)
{
  LE_FLUSH_FRAME *p_frame;

  p_frame = (LE_FLUSH_FRAME *)frame;
  printf ("    Source ATM : %s\n", disp_atm_text (p_frame->src_atm_addr));
  printf ("    Target ATM : %s\n", disp_atm_text (p_frame->target_atm_addr));
  
}

static void 
disp_control (void *frame, UINT32 length)
{
   LE_CTRL_HDR *p_hdr;

   p_hdr = (LE_CTRL_HDR *) frame;

   printf ("          %02x - Protocol\n", p_hdr->protocol);
   printf ("          %02x - Version\n",  p_hdr->version);
   printf ("        %04x - OpCode (%s)\n",
           ntoh16 (p_hdr->op_code),
           opcode_text (ntoh16 (p_hdr->op_code)));
   
   if ((ntoh16 (p_hdr->op_code) & 0x00ff) != READY_QUERY)
      {
      printf ("        %04x - Status (%s)\n",
              ntoh16 (p_hdr->status),
              disp_status_text (ntoh16 (p_hdr->status)));
      printf ("    %08lx - Transaction ID\n", ntoh32 (p_hdr->tran_id));
      printf ("        %04x - Requestor LEC_ID\n", ntoh16 (p_hdr->req_lec_id));
      printf ("        %04x - Flags\n", ntoh16 (p_hdr->flags));
      }

   switch (ntoh16 (p_hdr->op_code))
      {
      case LE_ARP_RSP :
      case LE_ARP_REQ :    disp_arp(frame, length);  break;
      case LE_JOIN_REQ:
      case LE_JOIN_RSP:
	disp_join(frame, length);
	break;
      case LE_FLUSH_REQ:
      case LE_FLUSH_RSP:
	disp_flush(frame, length);
	break;
      }
   }

static void 
disp_data (void *frame, UINT32 length)
   {
   UINT8 *p_data;

   p_data = (UINT8*) frame;

   printf("        %02X-%02X-%02X-%02X-%02X-%02X - Destination Address\n",
          p_data[2],p_data[3],p_data[4],
          p_data[5],p_data[6],p_data[7]);
   printf("        %02X-%02X-%02X-%02X-%02X-%02X - Source Address\n",
          p_data[8], p_data[9], p_data[10],
          p_data[11],p_data[12],p_data[13]);
   }


void le_frame_display (void   *frame,
                       UINT32  length,
                       const char   *text)
   {
   UINT16   *p_hdr;

   p_hdr = (UINT16 *) frame;

   printf ("\nLAN Emulation Frame %s: (%ld bytes)\n\n",
           text,
           length);
   printf ("        %04X - ", ntoh16 (*p_hdr));

   if (ntoh16 (*p_hdr) == LE_CTRL_MARKER)
      {
      printf ("Control Frame Marker\n");
      disp_control (frame, length);
      return;
      }

   if (ntoh16 (*p_hdr) < LE_CTRL_MARKER)
      {
      printf ("Data Frame\n");
      disp_data (frame, length);
      return;
      }

   printf ("Illegal Frame\n");
   }

void disp_sockaddr(struct sockaddr_atmsvc *addr)
{
  int i;
  printf("Sas_family:%d\n\tAddress:",addr->sas_family);
  for(i=0;i<20;i++) {
    printf("%2.2x ",addr->sas_addr.prv[i]);
  }
  if (!addr->sas_addr.blli) {
    printf("No blli information\n");
    fflush(stdout);
  } else {
    printf("\nBlli:\n\t");
    printf("l2_proto:%d\n\t",addr->sas_addr.blli->l2_proto);
    fflush(stdout);
    printf("l3_proto:%d\n\t\t",addr->sas_addr.blli->l3_proto);
    fflush(stdout);
    printf("ipi:%x\tsnap:",addr->sas_addr.blli->l3.tr9577.ipi);
    fflush(stdout);
    for(i=0;i<5;i++) {
      printf("%2.2x ",addr->sas_addr.blli->l3.tr9577.snap[i]);
    }
    printf("\n");
  }
}
