+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_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_tsl = -1;
+static int hf_atmarp_tpln = -1;
+static int hf_arp_src_ether = -1;
+static int hf_arp_src_proto = -1;
+static int hf_arp_dst_ether = -1;
+static int hf_arp_dst_proto = -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;
+static int hf_atmarp_dst_atm_num_e164 = -1;
+static int hf_atmarp_dst_atm_num_nsap = -1;
+static int hf_atmarp_dst_atm_subaddr = -1;
+
+static gint ett_arp = -1;
+static gint ett_atmarp_nsap = -1;
+
+/* Definitions taken from Linux "linux/if_arp.h" header file, and from
+
+ http://www.isi.edu/in-notes/iana/assignments/arp-parameters
+
+ */
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */
+#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
+#define ARPHRD_EETHER 2 /* Experimental Ethernet */
+#define ARPHRD_AX25 3 /* AX.25 Level 2 */
+#define ARPHRD_PRONET 4 /* PROnet token ring */
+#define ARPHRD_CHAOS 5 /* Chaosnet */
+#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
+#define ARPHRD_ARCNET 7 /* ARCnet */
+#define ARPHRD_HYPERCH 8 /* Hyperchannel */
+#define ARPHRD_LANSTAR 9 /* Lanstar */
+#define ARPHRD_AUTONET 10 /* Autonet Short Address */
+#define ARPHRD_LOCALTLK 11 /* Localtalk */
+#define ARPHRD_LOCALNET 12 /* LocalNet (IBM PCNet/Sytek LocalNET) */
+#define ARPHRD_ULTRALNK 13 /* Ultra link */
+#define ARPHRD_SMDS 14 /* SMDS */
+#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
+#define ARPHRD_ATM 16 /* ATM */
+#define ARPHRD_HDLC 17 /* HDLC */
+#define ARPHRD_FIBREC 18 /* Fibre Channel */
+#define ARPHRD_ATM2225 19 /* ATM (RFC 2225) */
+#define ARPHRD_SERIAL 20 /* Serial Line */
+#define ARPHRD_ATM2 21 /* ATM */
+#define ARPHRD_MS188220 22 /* MIL-STD-188-220 */
+#define ARPHRD_METRICOM 23 /* Metricom STRIP */
+#define ARPHRD_IEEE1394 24 /* IEEE 1394.1995 */
+#define ARPHRD_MAPOS 25 /* MAPOS */
+#define ARPHRD_TWINAX 26 /* Twinaxial */
+#define ARPHRD_EUI_64 27 /* EUI-64 */
+
+/* ARP / RARP structs and definitions */
+#ifndef ARPOP_REQUEST
+#define ARPOP_REQUEST 1 /* ARP request. */
+#endif
+#ifndef ARPOP_REPLY
+#define ARPOP_REPLY 2 /* ARP reply. */
+#endif
+/* Some OSes have different names, or don't define these at all */
+#ifndef ARPOP_RREQUEST
+#define ARPOP_RREQUEST 3 /* RARP request. */
+#endif
+#ifndef ARPOP_RREPLY
+#define ARPOP_RREPLY 4 /* RARP reply. */
+#endif
+#ifndef ARPOP_IREQUEST
+#define ARPOP_IREQUEST 8 /* Inverse ARP (RFC 1293) request. */
+#endif
+#ifndef ARPOP_IREPLY
+#define ARPOP_IREPLY 9 /* Inverse ARP reply. */
+#endif
+#ifndef ATMARPOP_NAK
+#define ATMARPOP_NAK 10 /* ATMARP NAK. */
+#endif
+
+static const value_string op_vals[] = {
+ {ARPOP_REQUEST, "request" },
+ {ARPOP_REPLY, "reply" },
+ {ARPOP_RREQUEST, "reverse request"},
+ {ARPOP_RREPLY, "reverse reply" },
+ {ARPOP_IREQUEST, "inverse request"},
+ {ARPOP_IREPLY, "inverse reply" },
+ {0, NULL } };
+
+static const value_string atmop_vals[] = {
+ {ARPOP_REQUEST, "request" },
+ {ARPOP_REPLY, "reply" },
+ {ARPOP_IREQUEST, "inverse request"},
+ {ARPOP_IREPLY, "inverse reply" },
+ {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 */
+
+gchar *
+arphrdaddr_to_str(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). */
+ return ether_to_str(ad);
+ }
+ return bytes_to_str(ad, ad_len);
+}
+
+static gchar *
+arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type)
+{
+ if (ad_len == 0)
+ return "<No address>";
+ if (type == ETHERTYPE_IP && ad_len == 4) {
+ /* IPv4 address. */
+ return ip_to_str(ad);
+ }
+ return bytes_to_str(ad, ad_len);
+}
+
+#define N_ATMARPNUM_TO_STR_STRINGS 2
+#define MAX_E164_STR_LEN 20
+static gchar *
+atmarpnum_to_str(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];
+ static int cur_idx;
+ gchar *cur;
+
+ if (ad_len == 0)
+ return "<No address>";
+
+ if (ad_tl & ATMARP_IS_E164) {
+ /*
+ * I'm assuming this means it's an ASCII (IA5) string.
+ */
+ cur_idx++;
+ if (cur_idx >= N_ATMARPNUM_TO_STR_STRINGS)
+ cur_idx = 0;
+ cur = &str[cur_idx][0];
+ if (ad_len > MAX_E164_STR_LEN) {
+ /* Can't show it all. */
+ memcpy(cur, ad, MAX_E164_STR_LEN);
+ strcpy(&cur[MAX_E164_STR_LEN], "...");
+ } else {
+ memcpy(cur, ad, ad_len);
+ cur[ad_len + 1] = '\0';
+ }
+ return cur;
+ } else {
+ /*
+ * NSAP.
+ *
+ * XXX - break down into subcomponents.
+ */
+ return bytes_to_str(ad, ad_len);
+ }
+}
+
+static gchar *
+atmarpsubaddr_to_str(guint8 *ad, int ad_len)
+{
+ if (ad_len == 0)
+ return "<No address>";
+
+ /*
+ * XXX - break down into subcomponents?
+ */
+ return bytes_to_str(ad, ad_len);
+}
+
+static const value_string hrd_vals[] = {
+ {ARPHRD_NETROM, "NET/ROM pseudo" },
+ {ARPHRD_ETHER, "Ethernet" },
+ {ARPHRD_EETHER, "Experimental Ethernet"},
+ {ARPHRD_AX25, "AX.25" },
+ {ARPHRD_PRONET, "ProNET" },
+ {ARPHRD_CHAOS, "Chaos" },
+ {ARPHRD_IEEE802, "IEEE 802" },
+ {ARPHRD_ARCNET, "ARCNET" },
+ {ARPHRD_HYPERCH, "Hyperchannel" },
+ {ARPHRD_LANSTAR, "Lanstar" },
+ {ARPHRD_AUTONET, "Autonet Short Address"},
+ {ARPHRD_LOCALTLK, "Localtalk" },
+ {ARPHRD_LOCALNET, "LocalNet" },
+ {ARPHRD_ULTRALNK, "Ultra link" },
+ {ARPHRD_SMDS, "SMDS" },
+ {ARPHRD_DLCI, "Frame Relay DLCI" },
+ {ARPHRD_ATM, "ATM" },
+ {ARPHRD_HDLC, "HDLC" },
+ {ARPHRD_FIBREC, "Fibre Channel" },
+ {ARPHRD_ATM2225, "ATM (RFC 2225)" },
+ {ARPHRD_SERIAL, "Serial Line" },
+ {ARPHRD_ATM2, "ATM" },
+ {ARPHRD_MS188220, "MIL-STD-188-220" },
+ {ARPHRD_METRICOM, "Metricom STRIP" },
+ {ARPHRD_IEEE1394, "IEEE 1394.1995" },
+ {ARPHRD_MAPOS, "MAPOS" },
+ {ARPHRD_TWINAX, "Twinaxial" },
+ {ARPHRD_EUI_64, "EUI-64" },
+ {0, NULL } };
+
+gchar *
+arphrdtype_to_str(guint16 hwtype, const char *fmt) {
+ return val_to_str(hwtype, hrd_vals, fmt);
+}
+
+/* Offsets of fields within an ARP packet. */
+#define AR_HRD 0
+#define AR_PRO 2
+#define AR_HLN 4
+#define AR_PLN 5
+#define AR_OP 6
+#define MIN_ARP_HEADER_SIZE 8
+
+/* Offsets of fields within an ATMARP packet. */
+#define ATM_AR_HRD 0
+#define ATM_AR_PRO 2
+#define ATM_AR_SHTL 4
+#define ATM_AR_SSL 5
+#define ATM_AR_OP 6
+#define ATM_AR_SPLN 8
+#define ATM_AR_THTL 9
+#define ATM_AR_TSL 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,
+ int hf_nsap, proto_tree *tree)
+{
+ int len = tl & ATMARP_LEN_MASK;
+ proto_item *ti;
+ proto_tree *nsap_tree;
+
+ if (tl & ATMARP_IS_E164)
+ proto_tree_add_string(tree, hf_e164, NullTVB, offset, len, &pd[offset]);
+ else {
+ ti = proto_tree_add_bytes(tree, hf_nsap, NullTVB, offset, len,
+ &pd[offset]);
+ if (len >= 20) {
+ nsap_tree = proto_item_add_subtree(ti, ett_atmarp_nsap);
+ dissect_atm_nsap(pd, offset, len, nsap_tree);
+ }
+ }
+}
+