Ethereal-dev: [Ethereal-dev] Ethereal support for Juniper ATM{1, 2} PIC DLT_ 135, 137

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Hannes Gredler <hannes@xxxxxxxxxxx>
Date: Wed, 19 Jan 2005 18:45:44 +0100
hi ethereal developers, et al,

attached a patch/dissector that adds support for
Juniper DLT_ type 135,137 that is used on our Routers
for taking captures on ATM PIC cards.

the dissector is mainly a heuristic engine that tries
to guess the encapsulation format based on well-known
bit-patterns.

i have expanded to the existing network layer osinl which
passes the first byte of the payload to the actual decoder
(like OSI protos need it typically) another osinl.excl
network layer where protocols that do not need the first
byte (ipv4,ipv6,ppp) can register.


for testing purposes (and for guy's archive ;-)) i have
added a few packet traces taken on such cards.


tx,

/hannes

Attachment: juniper-atm-pcap-traces.tgz
Description: application/tar-gz

/* packet-juniper.c
 * Routines for Juniper Networks, Inc. packet disassembly
 * Copyright 2005 Hannes Gredler <hannes@xxxxxxxxxxx>
 *
 * $Id: packet-juniper.c 12115 2004-09-27 22:55:15Z guy $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <glib.h>
#include <epan/packet.h>
#include "etypes.h"
#include <epan/prefs.h>
#include <epan/addr_resolv.h>
#include "ppptypes.h"
#include "packet-ppp.h"
#include "packet-ip.h"

#define JUNIPER_FLAG_PKT_OUT        0x00     /* Outgoing packet */
#define JUNIPER_FLAG_PKT_IN         0x01     /* Incoming packet */
#define JUNIPER_FLAG_NO_L2          0x02     /* L2 header stripped */
#define JUNIPER_ATM2_PKT_TYPE_MASK  0x70
#define JUNIPER_ATM2_GAP_COUNT_MASK 0x3F
#define JUNIPER_PCAP_MAGIC          0x4d4743

#define JUNIPER_ATM1   1
#define JUNIPER_ATM2   2

#define JUNIPER_HDR_SNAP   0xaaaa03
#define JUNIPER_HDR_NLPID  0xfefe03
#define JUNIPER_HDR_CNLPID 0x03

static const value_string juniper_direction_vals[] = {
    {JUNIPER_FLAG_PKT_OUT, "Out"},
    {JUNIPER_FLAG_PKT_IN,  "In"},
    {0,                    NULL}
};

static const value_string juniper_l2hdr_presence_vals[] = {
    { 0, "Present"},
    { 2, "none"},
    {0,                    NULL}
};

static int proto_juniper = -1;

static int hf_juniper_magic = -1;
static int hf_juniper_direction = -1;
static int hf_juniper_l2hdr_presence = -1;
static int hf_juniper_atm1_cookie = -1;
static int hf_juniper_atm2_cookie = -1;

static gint ett_juniper = -1;

static dissector_handle_t ipv4_handle;
static dissector_handle_t ipv6_handle;
static dissector_handle_t llc_handle;
static dissector_handle_t eth_handle;
static dissector_handle_t ppp_handle;
static dissector_handle_t data_handle;

static dissector_table_t osinl_subdissector_table;
static dissector_table_t osinl_excl_subdissector_table;

static void dissect_juniper_atm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 atm_pictype);
u_int ppp_heuristic_guess(guint16);
u_int ip_heuristic_guess(guint8);

/* wrapper for passing the PIC type to the generic ATM dissector */
static void
dissect_juniper_atm1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{ 
    dissect_juniper_atm(tvb,pinfo,tree, JUNIPER_ATM1);
}

/* wrapper for passing the PIC type to the generic ATM dissector */
static void
dissect_juniper_atm2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{ 
    dissect_juniper_atm(tvb,pinfo,tree, JUNIPER_ATM2);
}

/* generic ATM dissector */
static void
dissect_juniper_atm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 atm_pictype)
{
  proto_item *ti,*tisub;
  proto_tree *subtree = NULL;
  guint8     direction,l2hdr_presence,flags,ipvers,atm1_header_len,atm2_header_len;
  guint32    magic_number, cookie1, proto;
  guint64    cookie2;
  guint      offset;

  tvbuff_t   *next_tvb;

  switch (atm_pictype) {
  case JUNIPER_ATM1:
      if (check_col(pinfo->cinfo, COL_PROTOCOL))
          col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper ATM1");
      break;
  case JUNIPER_ATM2:
      if (check_col(pinfo->cinfo, COL_PROTOCOL))
          col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper ATM2");
      break;
  default: /* should not happen */
      if (check_col(pinfo->cinfo, COL_PROTOCOL))
          col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper ATM unknown");
      return;

  }

  if (check_col(pinfo->cinfo, COL_INFO))
      col_clear(pinfo->cinfo, COL_INFO);

  offset = 0;
  magic_number = tvb_get_ntoh24(tvb, 0);
  flags = tvb_get_guint8(tvb, 3);
  direction = flags & JUNIPER_FLAG_PKT_IN;
  l2hdr_presence = flags & JUNIPER_FLAG_NO_L2;

  if ((flags & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) {
      atm1_header_len = 8;
      atm2_header_len = 8;
  }
  else {
      atm1_header_len = 8;
      atm2_header_len = 12;
  }

  switch (atm_pictype) {
  case JUNIPER_ATM1:
      ti = proto_tree_add_text (tree, tvb, 0, atm1_header_len, "Juniper ATM1 PIC");
      break;
  case JUNIPER_ATM2:
      ti = proto_tree_add_text (tree, tvb, 0, atm2_header_len, "Juniper ATM2 PIC");
      break;
  default: /* should not happen */
      ti = proto_tree_add_text (tree, tvb, 0, 0 , "Juniper unknown ATM PIC");
      return;
  }

  subtree = proto_item_add_subtree(ti, ett_juniper);  
        
  tisub = proto_tree_add_text (subtree, tvb, 0, 3,
                            "Magic-Number: 0x%06x (%scorrect)", 
                            magic_number,
                            (magic_number == JUNIPER_PCAP_MAGIC) ?  "" : "in" );
    
  if (magic_number != JUNIPER_PCAP_MAGIC)
     return;
  
  tisub = proto_tree_add_uint_format (subtree, hf_juniper_direction, tvb, 3, 1,
                            direction, "Direction: %s",
                            val_to_str(direction,juniper_direction_vals,"Unknown"));
  
  tisub = proto_tree_add_uint_format (subtree, hf_juniper_l2hdr_presence, tvb, 3, 1,
                            l2hdr_presence, "L2-header: %s",
                            val_to_str(l2hdr_presence,juniper_l2hdr_presence_vals,"Unknown"));


  switch (atm_pictype) {
  case JUNIPER_ATM1:
      offset += atm1_header_len;
      break;
  case JUNIPER_ATM2:
      offset += atm2_header_len;
      break;
  default: /* should not happen */
      return;  
  }

  if ((flags & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) { /* no link header present ? */
      next_tvb = tvb_new_subset(tvb, offset, -1, -1);
      ipvers = ip_heuristic_guess(tvb_get_guint8(tvb, offset)); /* try IP */
      if ( ipvers != 0) {
          ti = proto_tree_add_text (tree, tvb, offset, 1,
                                    "Payload Type: Null encapsulation IPv%u",
                                    ipvers);
          subtree = proto_item_add_subtree(ti, ett_juniper);
          switch (ipvers) {
          case 6:
              call_dissector(ipv6_handle, next_tvb, pinfo, subtree);
              break;
          case 4:
              call_dissector(ipv4_handle, next_tvb, pinfo, subtree);  
              break;
          }
      }
      return;
  }

  cookie1 = tvb_get_ntohl(tvb,4);
  cookie2 = tvb_get_ntoh64(tvb,4);

  switch (atm_pictype) {
  case JUNIPER_ATM1:
      tisub = proto_tree_add_uint(subtree, hf_juniper_atm1_cookie, tvb, 4, 4, cookie1);
      break;
  case JUNIPER_ATM2:
      tisub = proto_tree_add_uint64(subtree, hf_juniper_atm2_cookie, tvb, 4, 8, cookie2);
      break;
  default: /* should not happen */
      return;  
  }

  next_tvb = tvb_new_subset(tvb, offset, -1, -1);  

  /* FIXME OAM cells */
    
  proto = tvb_get_ntoh24(tvb, offset); /* first try: 24-Bit guess */

  if (proto == JUNIPER_HDR_NLPID) { /* NLPID encaps ? */
      ti = proto_tree_add_text (tree, tvb, offset, 3, "Payload Type: LLC/NLPID ");
      subtree = proto_item_add_subtree(ti, ett_juniper);
      call_dissector(llc_handle, next_tvb, pinfo, subtree);
      return;
  }

  if (proto == JUNIPER_HDR_SNAP) { /* SNAP encaps ? */
      ti = proto_tree_add_text (tree, tvb, offset, 3, "Payload Type: LLC/SNAP ");
      subtree = proto_item_add_subtree(ti, ett_juniper);
      call_dissector(llc_handle, next_tvb, pinfo, subtree);
      return;
  }

  if (direction != JUNIPER_FLAG_PKT_IN && /* ether-over-1483 encaps ? */
      (cookie1 & JUNIPER_ATM2_GAP_COUNT_MASK) &&
      atm_pictype != JUNIPER_ATM1) {
      ti = proto_tree_add_text (tree, tvb, 4, 1, "Payload Type: Ethernet");
      subtree = proto_item_add_subtree(ti, ett_juniper);
      call_dissector(eth_handle, next_tvb, pinfo, subtree);
      return;
  }

  proto = tvb_get_ntohs(tvb, offset); /* second try: 16-Bit guess */

  if ( ppp_heuristic_guess(proto) != 0 && 
       atm_pictype != JUNIPER_ATM1) { /* VC-MUX PPPoA encaps ? - not supported on ATM1 PICs */
      ti = proto_tree_add_text (tree, tvb, offset, 2, "Payload Type: VC-MUX PPP");
      subtree = proto_item_add_subtree(ti, ett_juniper);
      call_dissector(ppp_handle, next_tvb, pinfo, subtree);  
      return;
  }

  proto = tvb_get_guint8(tvb, offset); /* third try: 8-Bit guess */

  if ( proto == JUNIPER_HDR_CNLPID ) { /* Cisco style NLPID encaps ? */
      ti = proto_tree_add_text (tree, tvb, offset, 1, "Payload Type: Cisco NLPID");
      subtree = proto_item_add_subtree(ti, ett_juniper);
      proto = tvb_get_guint8(tvb, offset+1);
      if(dissector_try_port(osinl_subdissector_table, proto, next_tvb, pinfo, subtree))
          return;
      next_tvb = tvb_new_subset(tvb, offset+2, -1, -1);
      if(dissector_try_port(osinl_excl_subdissector_table, proto, next_tvb, pinfo, subtree))
          return;
  }

  ipvers = ip_heuristic_guess(proto);
  if ( ipvers != 0) { /* last resort: VC-MUX encaps ? */
      ti = proto_tree_add_text (tree, tvb, offset, 1,
                                "Payload Type: VC-MUX IPv%u",
                                ipvers);
      subtree = proto_item_add_subtree(ti, ett_juniper);
      switch (ipvers) {
      case 6:
          call_dissector(ipv6_handle, next_tvb, pinfo, subtree);
          break;
      case 4:
          call_dissector(ipv4_handle, next_tvb, pinfo, subtree);  
          break;
      }
      return;
  }

  /* could not figure what it is */
  ti = proto_tree_add_text (tree, tvb, offset, -1, "Payload Type: unknown");

}

/* list of Juniper supported PPP proto IDs */
u_int
ppp_heuristic_guess(const u_int16_t proto) {

    switch(proto) {
    case PPP_IP :
    case PPP_OSI :
    case PPP_MPLS_UNI :
    case PPP_MPLS_MULTI :
    case PPP_IPCP :
    case PPP_OSICP :
    case PPP_MPLSCP :
    case PPP_LCP :
    case PPP_PAP :
    case PPP_CHAP :
    case PPP_MP :
    case PPP_IPV6 :
    case PPP_IPV6CP :
        return 1;
        break;

    default:
        return 0; /* did not find a ppp header */
        break;
    }
}

/*
 * return the IP version number based on the first byte of the IP header
 * returns 0 if it does not match a valid first IPv4/IPv6 header byte
 */
u_int
ip_heuristic_guess(const u_int8_t ip_header_byte) {

    switch(ip_header_byte) {
    case 0x45:
    case 0x46:
    case 0x47:
    case 0x48:
    case 0x49:
    case 0x4a:
    case 0x4b:
    case 0x4c:
    case 0x4d:
    case 0x4e:
    case 0x4f:
        return 4;
        break;
    case 0x60:
    case 0x61:
    case 0x62:
    case 0x63:
    case 0x64:
    case 0x65:
    case 0x66:
    case 0x67:
    case 0x68:
    case 0x69:
    case 0x6a:
    case 0x6b:
    case 0x6c:
    case 0x6d:
    case 0x6e:
    case 0x6f:
        return 6;
        break;
    default:
        return 0; /* did not find a ip header */
    }
}

void
proto_register_juniper(void)
{
  static hf_register_info hf[] = {
    { &hf_juniper_magic,
      { "Magic Number", "juniper.magic-number", FT_UINT24, BASE_HEX,
        NULL, 0x0, "", HFILL }},
    { &hf_juniper_direction,
      { "Direction", "juniper.direction", FT_UINT8, BASE_HEX,
        VALS(juniper_direction_vals), 0x0, "", HFILL }},
    { &hf_juniper_l2hdr_presence,
      { "L2 header presence", "juniper.l2hdr", FT_UINT8, BASE_HEX,
        VALS(juniper_l2hdr_presence_vals), 0x0, "", HFILL }},
    { &hf_juniper_atm2_cookie,
      { "Cookie", "juniper.atm2.cookie", FT_UINT64, BASE_HEX,
        NULL, 0x0, "", HFILL }},
    { &hf_juniper_atm1_cookie,
      { "Cookie", "juniper.atm1.cookie", FT_UINT32, BASE_HEX,
        NULL, 0x0, "", HFILL }},
  };

  static gint *ett[] = {
    &ett_juniper,
  };

  proto_juniper = proto_register_protocol("Juniper", "Juniper", "juniper");
  proto_register_field_array(proto_juniper, hf, array_length(hf));
  proto_register_subtree_array(ett, array_length(ett));

}

void
proto_reg_handoff_juniper(void)
{
  dissector_handle_t juniper_atm1_handle;
  dissector_handle_t juniper_atm2_handle;

  osinl_subdissector_table = find_dissector_table("osinl");
  osinl_excl_subdissector_table = find_dissector_table("osinl.excl");
  eth_handle = find_dissector("eth_withoutfcs");
  ppp_handle = find_dissector("ppp");
  llc_handle = find_dissector("llc");
  ipv4_handle = find_dissector("ip");
  ipv6_handle = find_dissector("ipv6");
  data_handle = find_dissector("data");

  juniper_atm2_handle = create_dissector_handle(dissect_juniper_atm2, proto_juniper);
  juniper_atm1_handle = create_dissector_handle(dissect_juniper_atm1, proto_juniper);
  dissector_add("wtap_encap", WTAP_ENCAP_JUNIPER_ATM2, juniper_atm2_handle);
  dissector_add("wtap_encap", WTAP_ENCAP_JUNIPER_ATM1, juniper_atm1_handle);
}

Index: epan/dissectors/packet-osi.c
===================================================================
--- epan/dissectors/packet-osi.c	(revision 13118)
+++ epan/dissectors/packet-osi.c	(working copy)
@@ -224,6 +224,7 @@
 };
 
 static dissector_table_t osinl_subdissector_table;
+static dissector_table_t osinl_excl_subdissector_table;
 static dissector_handle_t data_handle, ppp_handle;
 
 static void dissect_osi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
@@ -235,10 +236,15 @@
 
   nlpid = tvb_get_guint8(tvb, 0);
 
-  /* do lookup with the subdissector table */
+  /* try lookup with the subdissector tables that includes the nlpid */
   if (dissector_try_port(osinl_subdissector_table, nlpid, tvb, pinfo, tree))
       return;
 
+  /* try lookup with the subdissector tables that excludes the nlpid */
+  new_tvb = tvb_new_subset(tvb, 1, -1, -1);
+  if (dissector_try_port(osinl_excl_subdissector_table, nlpid, new_tvb, pinfo, tree))
+      return;
+
   switch (nlpid) {
 
     /* ESIS (X.25) is not currently decoded */
@@ -255,14 +261,6 @@
       }
       call_dissector(data_handle,tvb, pinfo, tree);
       break;
-    case NLPID_PPP:
-      /* XXX - we should put the NLPID into the protocol tree.
-         We should also probably have a subdissector table for
-         those protocols whose PDUs *aren't* defined to begin
-         with an NLPID. */
-      new_tvb = tvb_new_subset(tvb, 1, -1, -1);
-      call_dissector(ppp_handle, new_tvb, pinfo, tree);
-      break;
     default:
       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
 	col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISO");
@@ -280,9 +278,17 @@
 {
 	/* There's no "OSI" protocol *per se*, but we do register a
 	   dissector table so various protocols running at the
-	   network layer can register themselves. */
+	   network layer can register themselves.
+           all protocols that require inclusion of the NLPID
+           should register here */
 	osinl_subdissector_table = register_dissector_table("osinl",
-	    "OSI NLPID", FT_UINT8, BASE_HEX);
+	    "OSI incl NLPID", FT_UINT8, BASE_HEX);
+
+        /* This dissector table is for those protocols whose PDUs
+         * aren't* defined to begin with an NLPID.
+         * (typically non OSI protocols like IP,IPv6,PPP */
+	osinl_excl_subdissector_table = register_dissector_table("osinl.excl",
+	    "OSI excl NLPID", FT_UINT8, BASE_HEX);
 }
 
 void
Index: epan/dissectors/packet-ppp.c
===================================================================
--- epan/dissectors/packet-ppp.c	(revision 13118)
+++ epan/dissectors/packet-ppp.c	(working copy)
@@ -3690,6 +3690,7 @@
   ppp_hdlc_handle = find_dissector("ppp_hdlc");
   dissector_add("wtap_encap", WTAP_ENCAP_PPP, ppp_hdlc_handle);
   dissector_add("wtap_encap", WTAP_ENCAP_PPP_WITH_PHDR, ppp_hdlc_handle);
+  dissector_add("osinl.excl", NLPID_PPP, ppp_handle);
   dissector_add("gre.proto", ETHERTYPE_PPP, ppp_hdlc_handle);
 }
 
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 13118)
+++ epan/dissectors/Makefile.common	(working copy)
@@ -317,6 +317,7 @@
 	packet-isup.c	\
 	packet-iua.c	\
 	packet-jabber.c	\
+	packet-juniper.c \
 	packet-jxta.c	\
 	packet-kadm5.c	\
 	packet-kerberos.c	\
Index: epan/dissectors/packet-ip.c
===================================================================
--- epan/dissectors/packet-ip.c	(revision 13118)
+++ epan/dissectors/packet-ip.c	(working copy)
@@ -1762,6 +1762,7 @@
 	dissector_add("ip.proto", IP_PROTO_IPIP, ip_handle);
 	dissector_add("null.type", BSD_AF_INET, ip_handle);
 	dissector_add("chdlctype", ETHERTYPE_IP, ip_handle);
+	dissector_add("osinl.excl", NLPID_IP, ip_handle);
 	dissector_add("fr.ietf", NLPID_IP, ip_handle);
 	dissector_add("x.25.spi", NLPID_IP, ip_handle);
         dissector_add("arcnet.protocol_id", ARCNET_PROTO_IP_1051, ip_handle);
Index: epan/dissectors/packet-ipv6.c
===================================================================
--- epan/dissectors/packet-ipv6.c	(revision 13118)
+++ epan/dissectors/packet-ipv6.c	(working copy)
@@ -953,6 +953,7 @@
   dissector_add("null.type", BSD_AF_INET6_DARWIN, ipv6_handle);
   dissector_add("chdlctype", ETHERTYPE_IPv6, ipv6_handle);
   dissector_add("fr.ietf", NLPID_IP6, ipv6_handle);
+  dissector_add("osinl.excl", NLPID_IP6, ipv6_handle);
   dissector_add("x.25.spi", NLPID_IP6, ipv6_handle);
   dissector_add("arcnet.protocol_id", ARCNET_PROTO_IPv6, ipv6_handle);
 
Index: wiretap/wtap.c
===================================================================
--- wiretap/wtap.c	(revision 13118)
+++ wiretap/wtap.c	(working copy)
@@ -260,6 +260,12 @@
 
 	/* WTAP_ENCAP_GPRS_LLC */
 	{ "GPRS LLC", "gprs-llc" },
+
+	/* WTAP_ENCAP_JUNIPER_ATM1 */
+	{ "Juniper ATM1", "juniper-atm1" },
+
+	/* WTAP_ENCAP_JUNIPER_ATM2 */
+	{ "Juniper ATM2", "juniper-atm2" },
 };
 
 /* Name that should be somewhat descriptive. */
Index: wiretap/wtap.h
===================================================================
--- wiretap/wtap.h	(revision 13118)
+++ wiretap/wtap.h	(working copy)
@@ -156,9 +156,11 @@
 #define WTAP_ENCAP_RAW_ICMP			64
 #define WTAP_ENCAP_RAW_ICMPV6			65
 #define WTAP_ENCAP_GPRS_LLC			67
+#define WTAP_ENCAP_JUNIPER_ATM1			68
+#define WTAP_ENCAP_JUNIPER_ATM2			69
 
 /* last WTAP_ENCAP_ value + 1 */
-#define WTAP_NUM_ENCAP_TYPES			67
+#define WTAP_NUM_ENCAP_TYPES			70
 
 /* File types that can be read by wiretap.
    We support writing some many of these file types, too, so we
Index: wiretap/libpcap.c
===================================================================
--- wiretap/libpcap.c	(revision 13118)
+++ wiretap/libpcap.c	(working copy)
@@ -298,6 +298,9 @@
 	 * hardware.
 	 */
 
+        { 135,          WTAP_ENCAP_JUNIPER_ATM2 }, /* various encapsulations captured on the ATM2 PIC */
+        { 137,          WTAP_ENCAP_JUNIPER_ATM1 }, /* various encapsulations captured on the ATM1 PIC */
+
 	{ 138,		WTAP_ENCAP_APPLE_IP_OVER_IEEE1394 },
 						/* Apple IP-over-IEEE 1394 */