Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-arp.c
index e33874d68e6c6abd3c307249b40ab254d59806f4..20139cb9f20e7899b066217dcbac5cd5a2452404 100644 (file)
@@ -1,12 +1,11 @@
 /* packet-arp.c
  * Routines for ARP packet disassembly
  *
- * $Id: packet-arp.c,v 1.31 2000/08/07 03:20:21 guy Exp $
+ * $Id: packet-arp.c,v 1.52 2002/08/02 23:35:47 jmayer Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * 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
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
+#include <string.h>
 #include <glib.h>
-#include "packet.h"
+#include <epan/packet.h>
+#include <epan/strutil.h>
+#include <epan/resolv.h>
 #include "packet-arp.h"
 #include "etypes.h"
 
@@ -40,18 +38,26 @@ static int proto_arp = -1;
 static int hf_arp_hard_type = -1;
 static int hf_arp_proto_type = -1;
 static int hf_arp_hard_size = -1;
-static int hf_atmarp_shtl = -1;
+static int hf_atmarp_sht = -1;
+static int hf_atmarp_shl = -1;
+static int hf_atmarp_sst = -1;
 static int hf_atmarp_ssl = -1;
 static int hf_arp_proto_size = -1;
 static int hf_arp_opcode = -1;
 static int hf_atmarp_spln = -1;
-static int hf_atmarp_thtl = -1;
+static int hf_atmarp_tht = -1;
+static int hf_atmarp_thl = -1;
+static int hf_atmarp_tst = -1;
 static int hf_atmarp_tsl = -1;
 static int hf_atmarp_tpln = -1;
-static int hf_arp_src_ether = -1;
+static int hf_arp_src_hw = -1;
+static int hf_arp_src_hw_mac = -1;
 static int hf_arp_src_proto = -1;
-static int hf_arp_dst_ether = -1;
+static int hf_arp_src_proto_ipv4 = -1;
+static int hf_arp_dst_hw = -1;
+static int hf_arp_dst_hw_mac = -1;
 static int hf_arp_dst_proto = -1;
+static int hf_arp_dst_proto_ipv4 = -1;
 static int hf_atmarp_src_atm_num_e164 = -1;
 static int hf_atmarp_src_atm_num_nsap = -1;
 static int hf_atmarp_src_atm_subaddr = -1;
@@ -61,6 +67,9 @@ static int hf_atmarp_dst_atm_subaddr = -1;
 
 static gint ett_arp = -1;
 static gint ett_atmarp_nsap = -1;
+static gint ett_atmarp_tl = -1;
+
+static dissector_handle_t atmarp_handle;
 
 /* Definitions taken from Linux "linux/if_arp.h" header file, and from
 
@@ -139,29 +148,45 @@ static const value_string atmop_vals[] = {
   {ATMARPOP_NAK,   "nak"  },
   {0,              NULL          } };
 
-#define        ATMARP_IS_E164  0x40    /* bit in shtl/thtl for E.164 format */
-#define        ATMARP_LEN_MASK 0x3F    /* length of address in shtl/thtl */
+#define        ATMARP_IS_E164  0x40    /* bit in type/length for E.164 format */
+#define        ATMARP_LEN_MASK 0x3F    /* length of {sub}address in type/length */
+
+/*
+ * Given the hardware address type and length, check whether an address
+ * is an Ethernet address - the address must be of type "Ethernet" or
+ * "IEEE 802.x", and the length must be 6 bytes.
+ */
+#define ARP_HW_IS_ETHER(ar_hrd, ar_hln) \
+       (((ar_hrd) == ARPHRD_ETHER || (ar_hrd) == ARPHRD_IEEE802) \
+                               && (ar_hln) == 6)
+
+/*
+ * Given the protocol address type and length, check whether an address
+ * is an IPv4 address - the address must be of type "IP", and the length
+ * must be 4 bytes.
+ */
+#define ARP_PRO_IS_IPv4(ar_pro, ar_pln) \
+       ((ar_pro) == ETHERTYPE_IP && (ar_pln) == 4)
 
 gchar *
-arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type)
+arphrdaddr_to_str(const guint8 *ad, int ad_len, guint16 type)
 {
   if (ad_len == 0)
     return "<No address>";
-  if ((type == ARPHRD_ETHER || type == ARPHRD_EETHER || type == ARPHRD_IEEE802)
-                               && ad_len == 6) {
-    /* Ethernet address (or Experimental 3Mb Ethernet, or IEEE 802.x
-       address, which are the same type of address). */
+  if (ARP_HW_IS_ETHER(type, ad_len)) {
+    /* Ethernet address (or IEEE 802.x address, which is the same type of
+       address). */
     return ether_to_str(ad);
   }
   return bytes_to_str(ad, ad_len);
 }
 
 static gchar *
-arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type)
+arpproaddr_to_str(const guint8 *ad, int ad_len, guint16 type)
 {
   if (ad_len == 0)
     return "<No address>";
-  if (type == ETHERTYPE_IP && ad_len == 4) {
+  if (ARP_PRO_IS_IPv4(type, ad_len)) {
     /* IPv4 address.  */
     return ip_to_str(ad);
   }
@@ -170,8 +195,9 @@ arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type)
 
 #define        N_ATMARPNUM_TO_STR_STRINGS      2
 #define        MAX_E164_STR_LEN                20
+
 static gchar *
-atmarpnum_to_str(guint8 *ad, int ad_tl)
+atmarpnum_to_str(const guint8 *ad, int ad_tl)
 {
   int           ad_len = ad_tl & ATMARP_LEN_MASK;
   static gchar  str[N_ATMARPNUM_TO_STR_STRINGS][MAX_E164_STR_LEN+3+1];
@@ -209,12 +235,20 @@ atmarpnum_to_str(guint8 *ad, int ad_tl)
 }
 
 static gchar *
-atmarpsubaddr_to_str(guint8 *ad, int ad_len)
+atmarpsubaddr_to_str(const guint8 *ad, int ad_tl)
 {
+  int           ad_len = ad_tl & ATMARP_LEN_MASK;
+
   if (ad_len == 0)
     return "<No address>";
 
   /*
+   * E.164 isn't considered legal in subaddresses (RFC 2225 says that
+   * a null or unknown ATM address is indicated by setting the length
+   * to 0, in which case the type must be ignored; we've seen some
+   * captures in which the length of a subaddress is 0 and the type
+   * is E.164).
+   *
    * XXX - break down into subcomponents?
    */
   return bytes_to_str(ad, ad_len);
@@ -268,16 +302,16 @@ arphrdtype_to_str(guint16 hwtype, const char *fmt) {
 #define        ATM_AR_HRD      0
 #define        ATM_AR_PRO      2
 #define        ATM_AR_SHTL     4
-#define        ATM_AR_SS     5
+#define        ATM_AR_SSTL     5
 #define        ATM_AR_OP       6
 #define        ATM_AR_SPLN     8
 #define        ATM_AR_THTL     9
-#define        ATM_AR_TS     10
+#define        ATM_AR_TSTL     10
 #define        ATM_AR_TPLN     11
 #define MIN_ATMARP_HEADER_SIZE 12
 
 static void
-dissect_atm_number(const u_char *pd, int offset, int tl, int hf_e164,
+dissect_atm_number(tvbuff_t *tvb, int offset, int tl, int hf_e164,
     int hf_nsap, proto_tree *tree)
 {
        int len = tl & ATMARP_LEN_MASK;
@@ -285,76 +319,78 @@ dissect_atm_number(const u_char *pd, int offset, int tl, int hf_e164,
        proto_tree *nsap_tree;
 
        if (tl & ATMARP_IS_E164)
-               proto_tree_add_string(tree, hf_e164, NullTVB, offset, len, &pd[offset]);
+               proto_tree_add_item(tree, hf_e164, tvb, offset, len, FALSE);
        else {
-               ti = proto_tree_add_bytes(tree, hf_nsap, NullTVB, offset, len,
-                   &pd[offset]);
+               ti = proto_tree_add_item(tree, hf_nsap, tvb, offset, len, FALSE);
                if (len >= 20) {
                        nsap_tree = proto_item_add_subtree(ti, ett_atmarp_nsap);
-                       dissect_atm_nsap(pd, offset, len, nsap_tree);
+                       dissect_atm_nsap(tvb, offset, len, nsap_tree);
                }
        }
 }
 
 void
-dissect_atm_nsap(const u_char *pd, int offset, int len, proto_tree *tree)
+dissect_atm_nsap(tvbuff_t *tvb, int offset, int len, proto_tree *tree)
 {
-       switch (pd[offset]) {
+       guint8 afi;
+
+       afi = tvb_get_guint8(tvb, offset);
+       switch (afi) {
 
        case 0x39:      /* DCC ATM format */
        case 0xBD:      /* DCC ATM group format */
-               proto_tree_add_text(tree, NullTVB, offset + 0, 3,
+               proto_tree_add_text(tree, tvb, offset + 0, 3,
                    "Data Country Code%s: 0x%04X",
-                   (pd[offset] == 0xBD) ? " (group)" : "",
-                   pntohs(&pd[offset + 1]));
-               proto_tree_add_text(tree, NullTVB, offset + 3, 10,
+                   (afi == 0xBD) ? " (group)" : "",
+                   tvb_get_ntohs(tvb, offset + 1));
+               proto_tree_add_text(tree, tvb, offset + 3, 10,
                    "High Order DSP: %s",
-                   bytes_to_str(&pd[offset + 3], 10));
-               proto_tree_add_text(tree, NullTVB, offset + 13, 6,
+                   tvb_bytes_to_str(tvb, offset + 3, 10));
+               proto_tree_add_text(tree, tvb, offset + 13, 6,
                    "End System Identifier: %s",
-                   bytes_to_str(&pd[offset + 13], 6));
-               proto_tree_add_text(tree, NullTVB, offset + 19, 1,
-                   "Selector: 0x%02X", pd[offset + 19]);
+                   tvb_bytes_to_str(tvb, offset + 13, 6));
+               proto_tree_add_text(tree, tvb, offset + 19, 1,
+                   "Selector: 0x%02X", tvb_get_guint8(tvb, offset + 19));
                break;
 
        case 0x47:      /* ICD ATM format */
        case 0xC5:      /* ICD ATM group format */
-               proto_tree_add_text(tree, NullTVB, offset + 0, 3,
+               proto_tree_add_text(tree, tvb, offset + 0, 3,
                    "International Code Designator%s: 0x%04X",
-                   (pd[offset] == 0xC5) ? " (group)" : "",
-                   pntohs(&pd[offset + 1]));
-               proto_tree_add_text(tree, NullTVB, offset + 3, 10,
+                   (afi == 0xC5) ? " (group)" : "",
+                   tvb_get_ntohs(tvb, offset + 1));
+               proto_tree_add_text(tree, tvb, offset + 3, 10,
                    "High Order DSP: %s",
-                   bytes_to_str(&pd[offset + 3], 10));
-               proto_tree_add_text(tree, NullTVB, offset + 13, 6,
+                   tvb_bytes_to_str(tvb, offset + 3, 10));
+               proto_tree_add_text(tree, tvb, offset + 13, 6,
                    "End System Identifier: %s",
-                   bytes_to_str(&pd[offset + 13], 6));
-               proto_tree_add_text(tree, NullTVB, offset + 19, 1,
-                   "Selector: 0x%02X", pd[offset + 19]);
+                   tvb_bytes_to_str(tvb, offset + 13, 6));
+               proto_tree_add_text(tree, tvb, offset + 19, 1,
+                   "Selector: 0x%02X", tvb_get_guint8(tvb, offset + 19));
                break;
 
        case 0x45:      /* E.164 ATM format */
        case 0xC3:      /* E.164 ATM group format */
-               proto_tree_add_text(tree, NullTVB, offset + 0, 9,
+               proto_tree_add_text(tree, tvb, offset + 0, 9,
                    "E.164 ISDN%s: %s",
-                   (pd[offset] == 0xC3) ? " (group)" : "",
-                   bytes_to_str(&pd[offset + 1], 8));
-               proto_tree_add_text(tree, NullTVB, offset + 9, 4,
+                   (afi == 0xC3) ? " (group)" : "",
+                   tvb_bytes_to_str(tvb, offset + 1, 8));
+               proto_tree_add_text(tree, tvb, offset + 9, 4,
                    "High Order DSP: %s",
-                   bytes_to_str(&pd[offset + 3], 10));
-               proto_tree_add_text(tree, NullTVB, offset + 13, 6,
+                   tvb_bytes_to_str(tvb, offset + 3, 10));
+               proto_tree_add_text(tree, tvb, offset + 13, 6,
                    "End System Identifier: %s",
-                   bytes_to_str(&pd[offset + 13], 6));
-               proto_tree_add_text(tree, NullTVB, offset + 19, 1,
-                   "Selector: 0x%02X", pd[offset + 19]);
+                   tvb_bytes_to_str(tvb, offset + 13, 6));
+               proto_tree_add_text(tree, tvb, offset + 19, 1,
+                   "Selector: 0x%02X", tvb_get_guint8(tvb, offset + 19));
                break;
 
        default:
-               proto_tree_add_text(tree, NullTVB, offset, 1,
-                   "Unknown AFI: 0x%02X", pd[offset]);
-               proto_tree_add_text(tree, NullTVB, offset + 1, len - 1,
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Unknown AFI: 0x%02X", afi);
+               proto_tree_add_text(tree, tvb, offset + 1, len - 1,
                    "Rest of address: %s",
-                   bytes_to_str(&pd[offset + 1], len - 1));
+                   tvb_bytes_to_str(tvb, offset + 1, len - 1));
                break;
        }
 }
@@ -363,19 +399,19 @@ dissect_atm_nsap(const u_char *pd, int offset, int len, proto_tree *tree)
  * RFC 2225 ATMARP - it's just like ARP, except where it isn't.
  */
 static void
-dissect_atmarp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+dissect_atmarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   guint16     ar_hrd;
   guint16     ar_pro;
   guint8      ar_shtl;
-  guint8      ar_sht;
   guint8      ar_shl;
+  guint8      ar_sstl;
   guint8      ar_ssl;
   guint16     ar_op;
   guint8      ar_spln;
   guint8      ar_thtl;
-  guint8      ar_tht;
   guint8      ar_thl;
+  guint8      ar_tstl;
   guint8      ar_tsl;
   guint8      ar_tpln;
   int         tot_len;
@@ -384,95 +420,119 @@ dissect_atmarp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
   gchar       *op_str;
   int         sha_offset, ssa_offset, spa_offset;
   int         tha_offset, tsa_offset, tpa_offset;
+  const guint8      *sha_val, *ssa_val, *spa_val;
+  const guint8      *tha_val, *tsa_val, *tpa_val;
   gchar       *sha_str, *ssa_str, *spa_str;
   gchar       *tha_str, *tsa_str, *tpa_str;
+  proto_tree  *tl_tree;
+  proto_item  *tl;
 
-  if (!BYTES_ARE_IN_FRAME(offset, MIN_ATMARP_HEADER_SIZE)) {
-    old_dissect_data(pd, offset, fd, tree);
-    return;
-  }
+  /* Override the setting to "ARP/RARP". */
+  pinfo->current_proto = "ATMARP";
 
-  ar_hrd = pntohs(&pd[offset + ATM_AR_HRD]);
-  ar_pro = pntohs(&pd[offset + ATM_AR_PRO]);
-  ar_shtl = (guint8) pd[offset + ATM_AR_SHTL];
-  ar_sht = ar_shtl & ATMARP_IS_E164;
+  ar_hrd = tvb_get_ntohs(tvb, ATM_AR_HRD);
+  ar_pro = tvb_get_ntohs(tvb, ATM_AR_PRO);
+  ar_shtl = tvb_get_guint8(tvb, ATM_AR_SHTL);
   ar_shl = ar_shtl & ATMARP_LEN_MASK;
-  ar_ssl = (guint8) pd[offset + ATM_AR_SSL];
-  ar_op  = pntohs(&pd[offset + AR_OP]);
-  ar_spln = (guint8) pd[offset + ATM_AR_SPLN];
-  ar_thtl = (guint8) pd[offset + ATM_AR_THTL];
-  ar_tht = ar_thtl & ATMARP_IS_E164;
+  ar_sstl = tvb_get_guint8(tvb, ATM_AR_SSTL);
+  ar_ssl = ar_sstl & ATMARP_LEN_MASK;
+  ar_op  = tvb_get_ntohs(tvb, AR_OP);
+  ar_spln = tvb_get_guint8(tvb, ATM_AR_SPLN);
+  ar_thtl = tvb_get_guint8(tvb, ATM_AR_THTL);
   ar_thl = ar_thtl & ATMARP_LEN_MASK;
-  ar_tsl = (guint8) pd[offset + ATM_AR_TSL];
-  ar_tpln = (guint8) pd[offset + ATM_AR_TPLN];
+  ar_tstl = tvb_get_guint8(tvb, ATM_AR_TSTL);
+  ar_tsl = ar_tstl & ATMARP_LEN_MASK;
+  ar_tpln = tvb_get_guint8(tvb, ATM_AR_TPLN);
 
-  tot_len = MIN_ATMARP_HEADER_SIZE + ar_shtl + ar_ssl + ar_spln +
-                               ar_thtl + ar_tsl + ar_tpln;
-  if (!BYTES_ARE_IN_FRAME(offset, tot_len)) {
-    old_dissect_data(pd, offset, fd, tree);
-    return;
-  }
+  tot_len = MIN_ATMARP_HEADER_SIZE + ar_shl + ar_ssl + ar_spln +
+                               ar_thl + ar_tsl + ar_tpln;
+  
+  /* Adjust the length of this tvbuff to include only the ARP datagram.
+     Our caller may use that to determine how much of its packet
+     was padding. */
+  tvb_set_reported_length(tvb, tot_len);
 
   /* Extract the addresses.  */
-  sha_offset = offset + MIN_ATMARP_HEADER_SIZE;
-  if (ar_shl != 0)
-    sha_str = atmarpnum_to_str((guint8 *) &pd[sha_offset], ar_shtl);
-  else
+  sha_offset = MIN_ATMARP_HEADER_SIZE;
+  if (ar_shl != 0) {
+    sha_val = tvb_get_ptr(tvb, sha_offset, ar_shl);
+    sha_str = atmarpnum_to_str(sha_val, ar_shtl);
+  } else {
+    sha_val = NULL;
     sha_str = "<No address>";
+  }
+
   ssa_offset = sha_offset + ar_shl;
-  if (ar_ssl != 0)
-    ssa_str = atmarpsubaddr_to_str((guint8 *) &pd[ssa_offset], ar_ssl);
-  else
+  if (ar_ssl != 0) {
+    ssa_val = tvb_get_ptr(tvb, ssa_offset, ar_ssl);
+    ssa_str = atmarpsubaddr_to_str(ssa_val, ar_sstl);
+  } else {
+    ssa_val = NULL;
     ssa_str = NULL;
+  }
+
   spa_offset = ssa_offset + ar_ssl;
-  spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_spln, ar_pro);
+  spa_val = tvb_get_ptr(tvb, spa_offset, ar_spln);
+  spa_str = arpproaddr_to_str(spa_val, ar_spln, ar_pro);
+
   tha_offset = spa_offset + ar_spln;
-  if (ar_thl != 0)
-    tha_str = atmarpnum_to_str((guint8 *) &pd[tha_offset], ar_thtl);
-  else
+  if (ar_thl != 0) {
+    tha_val = tvb_get_ptr(tvb, tha_offset, ar_thl);
+    tha_str = atmarpnum_to_str(tha_val, ar_thtl);
+  } else {
+    tha_val = NULL;
     tha_str = "<No address>";
+  }
+
   tsa_offset = tha_offset + ar_thl;
-  if (ar_tsl != 0)
-    tsa_str = atmarpsubaddr_to_str((guint8 *) &pd[tsa_offset], ar_tsl);
-  else
+  if (ar_tsl != 0) {
+    tsa_val = tvb_get_ptr(tvb, tsa_offset, ar_tsl);
+    tsa_str = atmarpsubaddr_to_str(tsa_val, ar_tstl);
+  } else {
+    tsa_val = NULL;
     tsa_str = NULL;
+  }
+
   tpa_offset = tsa_offset + ar_tsl;
-  tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_tpln, ar_pro);
-  
-  if (check_col(fd, COL_PROTOCOL)) {
+  tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_tpln);
+  tpa_str = arpproaddr_to_str(tpa_val, ar_tpln, ar_pro);
+
+  if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
     switch (ar_op) {
 
     case ARPOP_REQUEST:
     case ARPOP_REPLY:
     case ATMARPOP_NAK:
     default:
-      col_add_str(fd, COL_PROTOCOL, "ATMARP");
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATMARP");
       break;
 
     case ARPOP_RREQUEST:
     case ARPOP_RREPLY:
-      col_add_str(fd, COL_PROTOCOL, "ATMRARP");
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATMRARP");
       break;
 
     case ARPOP_IREQUEST:
     case ARPOP_IREPLY:
-      col_add_str(fd, COL_PROTOCOL, "Inverse ATMARP");
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "Inverse ATMARP");
       break;
     }
   }
 
-  if (check_col(fd, COL_INFO)) {
+  if (check_col(pinfo->cinfo, COL_INFO)) {
     switch (ar_op) {
       case ARPOP_REQUEST:
-        col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s", tpa_str, spa_str);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s?  Tell %s",
+               tpa_str, spa_str);
         break;
       case ARPOP_REPLY:
-        col_add_fstr(fd, COL_INFO, "%s is at %s%s%s", spa_str, sha_str,
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s%s%s", spa_str, sha_str,
                ((ssa_str != NULL) ? "," : ""),
                ((ssa_str != NULL) ? ssa_str : ""));
         break;
       case ARPOP_IREQUEST:
-        col_add_fstr(fd, COL_INFO, "Who is %s%s%s?  Tell %s%s%s", tha_str,
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Who is %s%s%s?  Tell %s%s%s",
+               tha_str,
                ((tsa_str != NULL) ? "," : ""),
                ((tsa_str != NULL) ? tsa_str : ""),
                sha_str,
@@ -480,76 +540,121 @@ dissect_atmarp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                ((ssa_str != NULL) ? ssa_str : ""));
         break;
       case ARPOP_IREPLY:
-        col_add_fstr(fd, COL_INFO, "%s%s%s is at %s", sha_str,
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s%s is at %s",
+               sha_str,
                ((ssa_str != NULL) ? "," : ""),
                ((ssa_str != NULL) ? ssa_str : ""),
                spa_str);
         break;
       case ATMARPOP_NAK:
-        col_add_fstr(fd, COL_INFO, "I don't know where %s is", spa_str);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "I don't know where %s is", spa_str);
         break;
       default:
-        col_add_fstr(fd, COL_INFO, "Unknown ATMARP opcode 0x%04x", ar_op);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ATMARP opcode 0x%04x", ar_op);
         break;
     }
   }
 
   if (tree) {
     if ((op_str = match_strval(ar_op, atmop_vals)))
-      ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
+      ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len,
                                        "ATM Address Resolution Protocol (%s)", 
                                        op_str);
     else
-      ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
+      ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len,
                                      "ATM Address Resolution Protocol (opcode 0x%04x)", ar_op);
     arp_tree = proto_item_add_subtree(ti, ett_arp);
-    proto_tree_add_uint(arp_tree, hf_arp_hard_type, NullTVB, offset + ATM_AR_HRD, 2,
-                              ar_hrd);
-    proto_tree_add_uint(arp_tree, hf_arp_proto_type, NullTVB, offset + ATM_AR_PRO, 2,
-                              ar_pro);
-    proto_tree_add_uint(arp_tree, hf_atmarp_shtl, NullTVB, offset + ATM_AR_SHTL, 1,
-                              ar_shtl);
-    proto_tree_add_uint(arp_tree, hf_atmarp_ssl, NullTVB, offset + ATM_AR_SSL, 1,
+
+    proto_tree_add_uint(arp_tree, hf_arp_hard_type, tvb, ATM_AR_HRD, 2, ar_hrd);
+
+    proto_tree_add_uint(arp_tree, hf_arp_proto_type, tvb, ATM_AR_PRO, 2,ar_pro);
+
+    tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_SHTL, 1,
+                              "Sender ATM number type/length: %s/%u",
+                              (ar_shtl & ATMARP_IS_E164 ?
+                                 "E.164" :
+                                 "ATM Forum NSAPA"),
+                              ar_shl);
+    tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl);
+    proto_tree_add_boolean(tl_tree, hf_atmarp_sht, tvb, ATM_AR_SHTL, 1, ar_shtl);
+    proto_tree_add_uint(tl_tree, hf_atmarp_shl, tvb, ATM_AR_SHTL, 1, ar_shtl);
+
+    tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_SSTL, 1,
+                              "Sender ATM subaddress type/length: %s/%u",
+                              (ar_sstl & ATMARP_IS_E164 ?
+                                 "E.164" :
+                                 "ATM Forum NSAPA"),
                               ar_ssl);
-    proto_tree_add_uint(arp_tree, hf_arp_opcode, NullTVB, offset + AR_OP,  2,
-                              ar_op);
-    proto_tree_add_uint(arp_tree, hf_atmarp_spln, NullTVB, offset + ATM_AR_SPLN, 1,
-                              ar_spln);
-    proto_tree_add_uint(arp_tree, hf_atmarp_thtl, NullTVB, offset + ATM_AR_THTL, 1,
-                              ar_thtl);
-    proto_tree_add_uint(arp_tree, hf_atmarp_tsl, NullTVB, offset + ATM_AR_TSL, 1,
+    tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl);
+    proto_tree_add_boolean(tl_tree, hf_atmarp_sst, tvb, ATM_AR_SSTL, 1, ar_sstl);
+    proto_tree_add_uint(tl_tree, hf_atmarp_ssl, tvb, ATM_AR_SSTL, 1, ar_sstl);
+
+    proto_tree_add_uint(arp_tree, hf_arp_opcode, tvb, AR_OP,  2, ar_op);
+
+    proto_tree_add_uint(arp_tree, hf_atmarp_spln, tvb, ATM_AR_SPLN, 1, ar_spln);
+
+    tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_THTL, 1,
+                              "Target ATM number type/length: %s/%u",
+                              (ar_thtl & ATMARP_IS_E164 ?
+                                 "E.164" :
+                                 "ATM Forum NSAPA"),
+                              ar_thl);
+    tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl);
+    proto_tree_add_boolean(tl_tree, hf_atmarp_tht, tvb, ATM_AR_THTL, 1, ar_thtl);
+    proto_tree_add_uint(tl_tree, hf_atmarp_thl, tvb, ATM_AR_THTL, 1, ar_thtl);
+
+    tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_TSTL, 1,
+                              "Target ATM subaddress type/length: %s/%u",
+                              (ar_tstl & ATMARP_IS_E164 ?
+                                 "E.164" :
+                                 "ATM Forum NSAPA"),
                               ar_tsl);
-    proto_tree_add_uint(arp_tree, hf_atmarp_tpln, NullTVB, offset + ATM_AR_TPLN, 1,
-                              ar_tpln);
+    tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl);
+    proto_tree_add_boolean(tl_tree, hf_atmarp_tst, tvb, ATM_AR_TSTL, 1, ar_tstl);
+    proto_tree_add_uint(tl_tree, hf_atmarp_tsl, tvb, ATM_AR_TSTL, 1, ar_tstl);
+
+    proto_tree_add_uint(arp_tree, hf_atmarp_tpln, tvb, ATM_AR_TPLN, 1, ar_tpln);
+
     if (ar_shl != 0)
-      dissect_atm_number(pd, sha_offset, ar_shtl, hf_atmarp_src_atm_num_e164,
+      dissect_atm_number(tvb, sha_offset, ar_shtl, hf_atmarp_src_atm_num_e164,
                               hf_atmarp_src_atm_num_nsap, arp_tree);
+
     if (ar_ssl != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_atmarp_src_atm_subaddr, NullTVB, ssa_offset,
+      proto_tree_add_bytes_format(arp_tree, hf_atmarp_src_atm_subaddr, tvb, ssa_offset,
                               ar_ssl,
-                              &pd[ssa_offset],
+                              ssa_val,
                               "Sender ATM subaddress: %s", ssa_str);
-    if (ar_spln != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_arp_src_proto, NullTVB, spa_offset, ar_spln,
-                              &pd[spa_offset],
-                              "Sender protocol address: %s", spa_str);
+
+    if (ar_spln != 0) {
+      proto_tree_add_item(arp_tree,
+       ARP_PRO_IS_IPv4(ar_pro, ar_spln) ? hf_arp_src_proto_ipv4
+                                       : hf_arp_src_proto,
+       tvb, spa_offset, ar_spln, FALSE);
+    }
+
     if (ar_thl != 0)
-      dissect_atm_number(pd, tha_offset, ar_thtl, hf_atmarp_dst_atm_num_e164,
+      dissect_atm_number(tvb, tha_offset, ar_thtl, hf_atmarp_dst_atm_num_e164,
                               hf_atmarp_dst_atm_num_nsap, arp_tree);
+
     if (ar_tsl != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_atmarp_dst_atm_subaddr, NullTVB, tsa_offset,
+      proto_tree_add_bytes_format(arp_tree, hf_atmarp_dst_atm_subaddr, tvb, tsa_offset,
                               ar_tsl,
-                              &pd[tsa_offset],
+                              tsa_val,
                               "Target ATM subaddress: %s", tsa_str);
-    if (ar_tpln != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_arp_dst_proto, NullTVB, tpa_offset, ar_tpln,
-                              &pd[tpa_offset],
-                              "Target protocol address: %s", tpa_str);
+
+    if (ar_tpln != 0) {
+      proto_tree_add_item(arp_tree,
+       ARP_PRO_IS_IPv4(ar_pro, ar_tpln) ? hf_arp_dst_proto_ipv4
+                                       : hf_arp_dst_proto,
+       tvb, tpa_offset, ar_tpln, FALSE);
+    }
   }
 }
 
+static const guint8 mac_broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
 static void
-dissect_arp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+dissect_arp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   guint16     ar_hrd;
   guint16     ar_pro;
@@ -561,241 +666,332 @@ dissect_arp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
   proto_item  *ti;
   gchar       *op_str;
   int         sha_offset, spa_offset, tha_offset, tpa_offset;
+  const guint8      *sha_val, *spa_val, *tha_val, *tpa_val;
   gchar       *sha_str, *spa_str, *tha_str, *tpa_str;
 
-  if (!BYTES_ARE_IN_FRAME(offset, MIN_ARP_HEADER_SIZE)) {
-    old_dissect_data(pd, offset, fd, tree);
-    return;
-  }
+  /* Call it ARP, for now, so that if we throw an exception before
+     we decide whether it's ARP or RARP or IARP or ATMARP, it shows
+     up in the packet list as ARP.
 
-  ar_hrd = pntohs(&pd[offset + AR_HRD]);
+     Clear the Info column so that, if we throw an exception, it
+     shows up as a short or malformed ARP frame. */
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+      col_clear(pinfo->cinfo, COL_INFO);
+
+  ar_hrd = tvb_get_ntohs(tvb, AR_HRD);
   if (ar_hrd == ARPHRD_ATM2225) {
-    dissect_atmarp(pd, offset, fd, tree);
+    call_dissector(atmarp_handle, tvb, pinfo, tree);
     return;
   }
-  ar_pro = pntohs(&pd[offset + AR_PRO]);
-  ar_hln = (guint8) pd[offset + AR_HLN];
-  ar_pln = (guint8) pd[offset + AR_PLN];
-  ar_op  = pntohs(&pd[offset + AR_OP]);
+  ar_pro = tvb_get_ntohs(tvb, AR_PRO);
+  ar_hln = tvb_get_guint8(tvb, AR_HLN);
+  ar_pln = tvb_get_guint8(tvb, AR_PLN);
+  ar_op  = tvb_get_ntohs(tvb, AR_OP);
 
   tot_len = MIN_ARP_HEADER_SIZE + ar_hln*2 + ar_pln*2;
-  if (!BYTES_ARE_IN_FRAME(offset, tot_len)) {
-    old_dissect_data(pd, offset, fd, tree);
-    return;
-  }
+  
+  /* Adjust the length of this tvbuff to include only the ARP datagram.
+     Our caller may use that to determine how much of its packet
+     was padding. */
+  tvb_set_reported_length(tvb, tot_len);
 
-  /* Extract the addresses.  */
-  sha_offset = offset + MIN_ARP_HEADER_SIZE;
-  sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd);
+  /* Get the offsets of the addresses. */
+  sha_offset = MIN_ARP_HEADER_SIZE;
   spa_offset = sha_offset + ar_hln;
-  spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_pln, ar_pro);
   tha_offset = spa_offset + ar_pln;
-  tha_str = arphrdaddr_to_str((guint8 *) &pd[tha_offset], ar_hln, ar_hrd);
   tpa_offset = tha_offset + ar_hln;
-  tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_pln, ar_pro);
   
-  if (check_col(fd, COL_PROTOCOL)) {
+  if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
     switch (ar_op) {
 
     case ARPOP_REQUEST:
     case ARPOP_REPLY:
     default:
-      col_add_str(fd, COL_PROTOCOL, "ARP");
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP");
       break;
 
     case ARPOP_RREQUEST:
     case ARPOP_RREPLY:
-      col_add_str(fd, COL_PROTOCOL, "RARP");
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "RARP");
       break;
 
     case ARPOP_IREQUEST:
     case ARPOP_IREPLY:
-      col_add_str(fd, COL_PROTOCOL, "Inverse ARP");
+      col_set_str(pinfo->cinfo, COL_PROTOCOL, "Inverse ARP");
       break;
     }
   }
 
-  if (check_col(fd, COL_INFO)) {
+  if (check_col(pinfo->cinfo, COL_INFO)) {
+    sha_val = tvb_get_ptr(tvb, sha_offset, ar_hln);
+    sha_str = arphrdaddr_to_str(sha_val, ar_hln, ar_hrd);
+
+    spa_val = tvb_get_ptr(tvb, spa_offset, ar_pln);
+    spa_str = arpproaddr_to_str(spa_val, ar_pln, ar_pro);
+
+    tha_val = tvb_get_ptr(tvb, tha_offset, ar_hln);
+    tha_str = arphrdaddr_to_str(tha_val, ar_hln, ar_hrd);
+
+    tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_pln);
+    tpa_str = arpproaddr_to_str(tpa_val, ar_pln, ar_pro);
     switch (ar_op) {
       case ARPOP_REQUEST:
-        col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s", tpa_str, spa_str);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s?  Tell %s", tpa_str, spa_str);
         break;
       case ARPOP_REPLY:
-        col_add_fstr(fd, COL_INFO, "%s is at %s", spa_str, sha_str);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", spa_str, sha_str);
         break;
       case ARPOP_RREQUEST:
       case ARPOP_IREQUEST:
-        col_add_fstr(fd, COL_INFO, "Who is %s?  Tell %s", tha_str, sha_str);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Who is %s?  Tell %s", tha_str, sha_str);
         break;
       case ARPOP_RREPLY:
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", tha_str, tpa_str);
+        break;
       case ARPOP_IREPLY:
-        col_add_fstr(fd, COL_INFO, "%s is at %s", sha_str, spa_str);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", sha_str, spa_str);
         break;
       default:
-        col_add_fstr(fd, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op);
         break;
     }
   }
 
+  if ((ar_op == ARPOP_REPLY || ar_op == ARPOP_REQUEST) &&
+      ARP_HW_IS_ETHER(ar_hrd, ar_hln) &&
+      ARP_PRO_IS_IPv4(ar_pro, ar_pln)) {
+
+    /* inform resolv.c module of the new discovered addresses */
+
+    guint ip;
+    const guint8 *mac;
+
+    /* add sender address in all cases */
+
+    tvb_memcpy(tvb, (guint8 *)&ip, spa_offset, sizeof(ip));
+    add_ether_byip(ip, tvb_get_ptr(tvb, sha_offset, 6));
+    
+    if (ar_op == ARPOP_REQUEST) {
+      /* Add target address *if* the target MAC address isn't a
+         broadcast address. */
+      tvb_memcpy(tvb, (guint8 *)&ip, tpa_offset, sizeof(ip));
+      mac = tvb_get_ptr(tvb, tha_offset, 6);
+      if (memcmp(mac, mac_broadcast, 6) != 0)
+        add_ether_byip(ip, mac);
+    }
+  }
+
   if (tree) {
     if ((op_str = match_strval(ar_op, op_vals)))
-      ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
+      ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len,
                                        "Address Resolution Protocol (%s)", op_str);
     else
-      ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
+      ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len,
                                      "Address Resolution Protocol (opcode 0x%04x)", ar_op);
     arp_tree = proto_item_add_subtree(ti, ett_arp);
-    proto_tree_add_uint(arp_tree, hf_arp_hard_type, NullTVB, offset + AR_HRD, 2,
-                              ar_hrd);
-    proto_tree_add_uint(arp_tree, hf_arp_proto_type, NullTVB, offset + AR_PRO, 2,
-                              ar_pro);
-    proto_tree_add_uint(arp_tree, hf_arp_hard_size, NullTVB, offset + AR_HLN, 1,
-                              ar_hln);
-    proto_tree_add_uint(arp_tree, hf_arp_proto_size, NullTVB, offset + AR_PLN, 1,
-                              ar_pln);
-    proto_tree_add_uint(arp_tree, hf_arp_opcode, NullTVB, offset + AR_OP,  2,
-                              ar_op);
-    if (ar_hln != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_arp_src_ether, NullTVB, sha_offset, ar_hln,
-                              &pd[sha_offset],
-                              "Sender hardware address: %s", sha_str);
-    if (ar_pln != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_arp_src_proto, NullTVB, spa_offset, ar_pln,
-                              &pd[spa_offset],
-                              "Sender protocol address: %s", spa_str);
-    if (ar_hln != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_arp_dst_ether, NullTVB, tha_offset, ar_hln,
-                              &pd[tha_offset],
-                              "Target hardware address: %s", tha_str);
-    if (ar_pln != 0)
-      proto_tree_add_bytes_format(arp_tree, hf_arp_dst_proto, NullTVB, tpa_offset, ar_pln,
-                              &pd[tpa_offset],
-                              "Target protocol address: %s", tpa_str);
+    proto_tree_add_uint(arp_tree, hf_arp_hard_type, tvb, AR_HRD, 2, ar_hrd);
+    proto_tree_add_uint(arp_tree, hf_arp_proto_type, tvb, AR_PRO, 2, ar_pro);
+    proto_tree_add_uint(arp_tree, hf_arp_hard_size, tvb, AR_HLN, 1, ar_hln);
+    proto_tree_add_uint(arp_tree, hf_arp_proto_size, tvb, AR_PLN, 1, ar_pln);
+    proto_tree_add_uint(arp_tree, hf_arp_opcode, tvb, AR_OP,  2, ar_op);
+    if (ar_hln != 0) {
+      proto_tree_add_item(arp_tree,
+       ARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_arp_src_hw_mac : hf_arp_src_hw,
+       tvb, sha_offset, ar_hln, FALSE);
+    }
+    if (ar_pln != 0) {
+      proto_tree_add_item(arp_tree,
+       ARP_PRO_IS_IPv4(ar_pro, ar_pln) ? hf_arp_src_proto_ipv4
+                                       : hf_arp_src_proto,
+       tvb, spa_offset, ar_pln, FALSE);
+    }
+    if (ar_hln != 0) {
+      proto_tree_add_item(arp_tree,
+       ARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_arp_dst_hw_mac : hf_arp_dst_hw,
+       tvb, tha_offset, ar_hln, FALSE);
+    }
+    if (ar_pln != 0) {
+      proto_tree_add_item(arp_tree,
+       ARP_PRO_IS_IPv4(ar_pro, ar_pln) ? hf_arp_dst_proto_ipv4
+                                       : hf_arp_dst_proto,
+       tvb, tpa_offset, ar_pln, FALSE);
+    }
   }
 }
 
 void
 proto_register_arp(void)
 {
+  static struct true_false_string type_bit = { "E.164", "ATM Forum NSAPA" };
+
   static hf_register_info hf[] = {
     { &hf_arp_hard_type,
       { "Hardware type",               "arp.hw.type",   
        FT_UINT16,      BASE_HEX,       VALS(hrd_vals), 0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_arp_proto_type,
       { "Protocol type",               "arp.proto.type",
        FT_UINT16,      BASE_HEX,       VALS(etype_vals),       0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_arp_hard_size,
       { "Hardware size",               "arp.hw.size",
        FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
-    { &hf_atmarp_shtl,
-      { "Sender ATM number type and length",   "arp.src.htl",  
-       FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+    { &hf_atmarp_sht,
+      { "Sender ATM number type",      "arp.src.htype",
+       FT_BOOLEAN,     8,              &type_bit,      ATMARP_IS_E164,
+       "", HFILL }},
+
+    { &hf_atmarp_shl,
+      { "Sender ATM number length",    "arp.src.hlen",
+       FT_UINT8,       BASE_DEC,       NULL,           ATMARP_LEN_MASK,
+       "", HFILL }},
+
+    { &hf_atmarp_sst,
+      { "Sender ATM subaddress type",  "arp.src.stype",
+       FT_BOOLEAN,     8,              &type_bit,      ATMARP_IS_E164,
+       "", HFILL }},
 
     { &hf_atmarp_ssl,
       { "Sender ATM subaddress length",        "arp.src.slen",
-       FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+       FT_UINT8,       BASE_DEC,       NULL,           ATMARP_LEN_MASK,
+       "", HFILL }},
 
     { &hf_arp_proto_size,
       { "Protocol size",               "arp.proto.size",
        FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_arp_opcode,
       { "Opcode",                      "arp.opcode",
        FT_UINT16,      BASE_HEX,       VALS(op_vals),  0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_atmarp_spln,
       { "Sender protocol size",                "arp.src.pln",
        FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
-    { &hf_atmarp_thtl,
-      { "Target ATM number type and length",   "arp.dst.htl",
-       FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+    { &hf_atmarp_tht,
+      { "Target ATM number type",      "arp.dst.htype",
+       FT_BOOLEAN,     8,              &type_bit,      ATMARP_IS_E164,
+       "", HFILL }},
+
+    { &hf_atmarp_thl,
+      { "Target ATM number length",    "arp.dst.hlen",
+       FT_UINT8,       BASE_DEC,       NULL,           ATMARP_LEN_MASK,
+       "", HFILL }},
+
+    { &hf_atmarp_tst,
+      { "Target ATM subaddress type",  "arp.dst.stype",
+       FT_BOOLEAN,     8,              &type_bit,      ATMARP_IS_E164,
+       "", HFILL }},
 
     { &hf_atmarp_tsl,
       { "Target ATM subaddress length",        "arp.dst.slen",
-       FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+       FT_UINT8,       BASE_DEC,       NULL,           ATMARP_LEN_MASK,
+       "", HFILL }},
 
     { &hf_atmarp_tpln,
       { "Target protocol size",                "arp.dst.pln",
        FT_UINT8,       BASE_DEC,       NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
-    { &hf_arp_src_ether,
+    { &hf_arp_src_hw,
       { "Sender hardware address",     "arp.src.hw",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
+
+    { &hf_arp_src_hw_mac,
+      { "Sender MAC address",          "arp.src.hw_mac",
+       FT_ETHER,       BASE_NONE,      NULL,   0x0,
+       "", HFILL }},
 
     { &hf_atmarp_src_atm_num_e164,
       { "Sender ATM number (E.164)",   "arp.src.atm_num_e164",
        FT_STRING,      BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_atmarp_src_atm_num_nsap,
       { "Sender ATM number (NSAP)",    "arp.src.atm_num_nsap",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_atmarp_src_atm_subaddr,
       { "Sender ATM subaddress",       "arp.src.atm_subaddr",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_arp_src_proto,
-      { "Sender protocol address",     "arp.src.proto", 
+      { "Sender protocol address",     "arp.src.proto",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
-    { &hf_arp_dst_ether,
+    { &hf_arp_src_proto_ipv4,
+      { "Sender IP address",           "arp.src.proto_ipv4",
+       FT_IPv4,        BASE_NONE,      NULL,   0x0,
+       "", HFILL }},
+
+    { &hf_arp_dst_hw,
       { "Target hardware address",     "arp.dst.hw",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
+
+    { &hf_arp_dst_hw_mac,
+      { "Target MAC address",          "arp.dst.hw_mac",
+       FT_ETHER,       BASE_NONE,      NULL,   0x0,
+       "", HFILL }},
 
     { &hf_atmarp_dst_atm_num_e164,
       { "Target ATM number (E.164)",   "arp.dst.atm_num_e164",
        FT_STRING,      BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_atmarp_dst_atm_num_nsap,
       { "Target ATM number (NSAP)",    "arp.dst.atm_num_nsap",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_atmarp_dst_atm_subaddr,
       { "Target ATM subaddress",       "arp.dst.atm_subaddr",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-       "" }},
+       "", HFILL }},
 
     { &hf_arp_dst_proto,
-      { "Target protocol address",     "arp.dst.proto", 
+      { "Target protocol address",     "arp.dst.proto",
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
-      "" }}
+      "", HFILL }},
+
+    { &hf_arp_dst_proto_ipv4,
+      { "Target IP address",           "arp.dst.proto_ipv4",
+       FT_IPv4,        BASE_NONE,      NULL,   0x0,
+      "", HFILL }}
   };
   static gint *ett[] = {
     &ett_arp,
     &ett_atmarp_nsap,
+    &ett_atmarp_tl,
   };
 
-  proto_arp = proto_register_protocol("Address Resolution Protocol", "arp");
+  proto_arp = proto_register_protocol("Address Resolution Protocol",
+                                     "ARP/RARP", "arp");
   proto_register_field_array(proto_arp, hf, array_length(hf));
   proto_register_subtree_array(ett, array_length(ett));
+
+  atmarp_handle = create_dissector_handle(dissect_atmarp, proto_arp);
 }
 
 void
 proto_reg_handoff_arp(void)
 {
-       old_dissector_add("ethertype", ETHERTYPE_ARP, dissect_arp);
-       old_dissector_add("ethertype", ETHERTYPE_REVARP, dissect_arp);
+  dissector_handle_t arp_handle;
+
+  arp_handle = create_dissector_handle(dissect_arp, proto_arp);
+  dissector_add("ethertype", ETHERTYPE_ARP, arp_handle);
+  dissector_add("ethertype", ETHERTYPE_REVARP, arp_handle);
 }