/* packet-arp.c * Routines for ARP packet disassembly * * $Id: packet-arp.c,v 1.33 2000/08/13 14:07:58 deniel Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * 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 #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "packet.h" #include "resolv.h" #include "packet-arp.h" #include "etypes.h" 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 ""; 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 ""; 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 ""; 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 ""; /* * 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); } } } void dissect_atm_nsap(const u_char *pd, int offset, int len, proto_tree *tree) { switch (pd[offset]) { case 0x39: /* DCC ATM format */ case 0xBD: /* DCC ATM group format */ proto_tree_add_text(tree, NullTVB, 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, "High Order DSP: %s", bytes_to_str(&pd[offset + 3], 10)); proto_tree_add_text(tree, NullTVB, 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]); break; case 0x47: /* ICD ATM format */ case 0xC5: /* ICD ATM group format */ proto_tree_add_text(tree, NullTVB, 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, "High Order DSP: %s", bytes_to_str(&pd[offset + 3], 10)); proto_tree_add_text(tree, NullTVB, 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]); break; case 0x45: /* E.164 ATM format */ case 0xC3: /* E.164 ATM group format */ proto_tree_add_text(tree, NullTVB, 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, "High Order DSP: %s", bytes_to_str(&pd[offset + 3], 10)); proto_tree_add_text(tree, NullTVB, 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]); 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, "Rest of address: %s", bytes_to_str(&pd[offset + 1], len - 1)); break; } } /* * 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) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_shtl; guint8 ar_sht; guint8 ar_shl; guint8 ar_ssl; guint16 ar_op; guint8 ar_spln; guint8 ar_thtl; guint8 ar_tht; guint8 ar_thl; guint8 ar_tsl; guint8 ar_tpln; int tot_len; proto_tree *arp_tree; proto_item *ti; gchar *op_str; int sha_offset, ssa_offset, spa_offset; int tha_offset, tsa_offset, tpa_offset; gchar *sha_str, *ssa_str, *spa_str; gchar *tha_str, *tsa_str, *tpa_str; if (!BYTES_ARE_IN_FRAME(offset, MIN_ATMARP_HEADER_SIZE)) { old_dissect_data(pd, offset, fd, tree); return; } 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_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_thl = ar_thtl & ATMARP_LEN_MASK; ar_tsl = (guint8) pd[offset + ATM_AR_TSL]; ar_tpln = (guint8) pd[offset + 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; } /* 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_str = ""; ssa_offset = sha_offset + ar_shl; if (ar_ssl != 0) ssa_str = atmarpsubaddr_to_str((guint8 *) &pd[ssa_offset], ar_ssl); else ssa_str = NULL; spa_offset = ssa_offset + ar_ssl; spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], 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 tha_str = ""; tsa_offset = tha_offset + ar_thl; if (ar_tsl != 0) tsa_str = atmarpsubaddr_to_str((guint8 *) &pd[tsa_offset], ar_tsl); else 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)) { switch (ar_op) { case ARPOP_REQUEST: case ARPOP_REPLY: case ATMARPOP_NAK: default: col_add_str(fd, COL_PROTOCOL, "ATMARP"); break; case ARPOP_RREQUEST: case ARPOP_RREPLY: col_add_str(fd, COL_PROTOCOL, "ATMRARP"); break; case ARPOP_IREQUEST: case ARPOP_IREPLY: col_add_str(fd, COL_PROTOCOL, "Inverse ATMARP"); break; } } if (check_col(fd, COL_INFO)) { switch (ar_op) { case ARPOP_REQUEST: col_add_fstr(fd, 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, ((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, ((tsa_str != NULL) ? "," : ""), ((tsa_str != NULL) ? tsa_str : ""), sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : "")); break; case ARPOP_IREPLY: col_add_fstr(fd, 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); break; default: col_add_fstr(fd, 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, "ATM Address Resolution Protocol (%s)", op_str); else ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, 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, 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, ar_tsl); proto_tree_add_uint(arp_tree, hf_atmarp_tpln, NullTVB, offset + ATM_AR_TPLN, 1, ar_tpln); if (ar_shl != 0) dissect_atm_number(pd, 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, ar_ssl, &pd[ssa_offset], "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_thl != 0) dissect_atm_number(pd, 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, ar_tsl, &pd[tsa_offset], "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); } } static void dissect_arp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_hln; guint8 ar_pln; guint16 ar_op; int tot_len; proto_tree *arp_tree; proto_item *ti; gchar *op_str; int sha_offset, spa_offset, tha_offset, tpa_offset; gchar *sha_str, *spa_str, *tha_str, *tpa_str; OLD_CHECK_DISPLAY_AS_DATA(proto_arp, pd, offset, fd, tree); if (!BYTES_ARE_IN_FRAME(offset, MIN_ARP_HEADER_SIZE)) { old_dissect_data(pd, offset, fd, tree); return; } ar_hrd = pntohs(&pd[offset + AR_HRD]); if (ar_hrd == ARPHRD_ATM2225) { dissect_atmarp(pd, offset, fd, 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]); 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; } /* Extract the addresses. */ sha_offset = offset + MIN_ARP_HEADER_SIZE; sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd); 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)) { switch (ar_op) { case ARPOP_REQUEST: case ARPOP_REPLY: default: col_add_str(fd, COL_PROTOCOL, "ARP"); break; case ARPOP_RREQUEST: case ARPOP_RREPLY: col_add_str(fd, COL_PROTOCOL, "RARP"); break; case ARPOP_IREQUEST: case ARPOP_IREPLY: col_add_str(fd, COL_PROTOCOL, "Inverse ARP"); break; } } if (check_col(fd, COL_INFO)) { switch (ar_op) { case ARPOP_REQUEST: col_add_fstr(fd, 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); break; case ARPOP_RREQUEST: case ARPOP_IREQUEST: col_add_fstr(fd, COL_INFO, "Who is %s? Tell %s", tha_str, sha_str); break; case ARPOP_RREPLY: case ARPOP_IREPLY: col_add_fstr(fd, 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); break; } } if ((ar_op == ARPOP_REPLY || ar_op == ARPOP_REQUEST) && ar_hln == 6 && ar_pln == 4) { /* inform resolv.c module of the new discovered addresses */ u_int ip; /* add sender address in all cases */ memcpy(&ip, &pd[spa_offset], sizeof(ip)); add_ether_byip(ip, &pd[sha_offset]); if (ar_op == ARPOP_REQUEST) { /* add destination address */ memcpy(&ip, &pd[tpa_offset], sizeof(ip)); add_ether_byip(ip, &pd[tha_offset]); } } if (tree) { if ((op_str = match_strval(ar_op, op_vals))) ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len, "Address Resolution Protocol (%s)", op_str); else ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, 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); } } void proto_register_arp(void) { static hf_register_info hf[] = { { &hf_arp_hard_type, { "Hardware type", "arp.hw.type", FT_UINT16, BASE_HEX, VALS(hrd_vals), 0x0, "" }}, { &hf_arp_proto_type, { "Protocol type", "arp.proto.type", FT_UINT16, BASE_HEX, VALS(etype_vals), 0x0, "" }}, { &hf_arp_hard_size, { "Hardware size", "arp.hw.size", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_atmarp_shtl, { "Sender ATM number type and length", "arp.src.htl", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_atmarp_ssl, { "Sender ATM subaddress length", "arp.src.slen", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_arp_proto_size, { "Protocol size", "arp.proto.size", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_arp_opcode, { "Opcode", "arp.opcode", FT_UINT16, BASE_HEX, VALS(op_vals), 0x0, "" }}, { &hf_atmarp_spln, { "Sender protocol size", "arp.src.pln", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_atmarp_thtl, { "Target ATM number type and length", "arp.dst.htl", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_atmarp_tsl, { "Target ATM subaddress length", "arp.dst.slen", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_atmarp_tpln, { "Target protocol size", "arp.dst.pln", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_arp_src_ether, { "Sender hardware address", "arp.src.hw", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_atmarp_src_atm_num_e164, { "Sender ATM number (E.164)", "arp.src.atm_num_e164", FT_STRING, BASE_NONE, NULL, 0x0, "" }}, { &hf_atmarp_src_atm_num_nsap, { "Sender ATM number (NSAP)", "arp.src.atm_num_nsap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_atmarp_src_atm_subaddr, { "Sender ATM subaddress", "arp.src.atm_subaddr", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_arp_src_proto, { "Sender protocol address", "arp.src.proto", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_arp_dst_ether, { "Target hardware address", "arp.dst.hw", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_atmarp_dst_atm_num_e164, { "Target ATM number (E.164)", "arp.dst.atm_num_e164", FT_STRING, BASE_NONE, NULL, 0x0, "" }}, { &hf_atmarp_dst_atm_num_nsap, { "Target ATM number (NSAP)", "arp.dst.atm_num_nsap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_atmarp_dst_atm_subaddr, { "Target ATM subaddress", "arp.dst.atm_subaddr", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, { &hf_arp_dst_proto, { "Target protocol address", "arp.dst.proto", FT_BYTES, BASE_NONE, NULL, 0x0, "" }} }; static gint *ett[] = { &ett_arp, &ett_atmarp_nsap, }; proto_arp = proto_register_protocol("Address Resolution Protocol", "arp"); proto_register_field_array(proto_arp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } void proto_reg_handoff_arp(void) { old_dissector_add("ethertype", ETHERTYPE_ARP, dissect_arp); old_dissector_add("ethertype", ETHERTYPE_REVARP, dissect_arp); }