The protocol tree field created for a protocol itself is of type
[obnox/wireshark/wip.git] / packet-arp.c
1 /* packet-arp.c
2  * Routines for ARP packet disassembly
3  *
4  * $Id: packet-arp.c,v 1.16 1999/07/30 05:42:25 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <glib.h>
35 #include "packet.h"
36 #include "etypes.h"
37
38 static int proto_arp = -1;
39
40 /* Definitions taken from Linux "linux/if_arp.h" header file, and from
41
42         http://www.isi.edu/in-notes/iana/assignments/arp-parameters
43
44  */
45
46 /* ARP protocol HARDWARE identifiers. */
47 #define ARPHRD_NETROM   0               /* from KA9Q: NET/ROM pseudo    */
48 #define ARPHRD_ETHER    1               /* Ethernet 10Mbps              */
49 #define ARPHRD_EETHER   2               /* Experimental Ethernet        */
50 #define ARPHRD_AX25     3               /* AX.25 Level 2                */
51 #define ARPHRD_PRONET   4               /* PROnet token ring            */
52 #define ARPHRD_CHAOS    5               /* Chaosnet                     */
53 #define ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB    */
54 #define ARPHRD_ARCNET   7               /* ARCnet                       */
55 #define ARPHRD_HYPERCH  8               /* Hyperchannel                 */
56 #define ARPHRD_LANSTAR  9               /* Lanstar                      */
57 #define ARPHRD_AUTONET  10              /* Autonet Short Address        */
58 #define ARPHRD_LOCALTLK 11              /* Localtalk                    */
59 #define ARPHRD_LOCALNET 12              /* LocalNet (IBM PCNet/Sytek LocalNET) */
60 #define ARPHRD_ULTRALNK 13              /* Ultra link                   */
61 #define ARPHRD_SMDS     14              /* SMDS                         */
62 #define ARPHRD_DLCI     15              /* Frame Relay DLCI             */
63 #define ARPHRD_ATM      16              /* ATM                          */
64 #define ARPHRD_HDLC     17              /* HDLC                         */
65 #define ARPHRD_FIBREC   18              /* Fibre Channel                */
66 #define ARPHRD_ATM2225  19              /* ATM (RFC 2225)               */
67 #define ARPHRD_SERIAL   20              /* Serial Line                  */
68 #define ARPHRD_ATM2     21              /* ATM                          */
69 #define ARPHRD_MS188220 22              /* MIL-STD-188-220              */
70 #define ARPHRD_METRICOM 23              /* Metricom STRIP               */
71 #define ARPHRD_IEEE1394 24              /* IEEE 1394.1995               */
72 #define ARPHRD_MAPOS    25              /* MAPOS                        */
73 #define ARPHRD_TWINAX   26              /* Twinaxial                    */
74 #define ARPHRD_EUI_64   27              /* EUI-64                       */
75
76 /* ARP / RARP structs and definitions */
77 #ifndef ARPOP_REQUEST
78 #define ARPOP_REQUEST  1       /* ARP request.  */
79 #endif
80 #ifndef ARPOP_REPLY
81 #define ARPOP_REPLY    2       /* ARP reply.  */
82 #endif
83 /* Some OSes have different names, or don't define these at all */
84 #ifndef ARPOP_RREQUEST
85 #define ARPOP_RREQUEST 3       /* RARP request.  */
86 #endif
87 #ifndef ARPOP_RREPLY
88 #define ARPOP_RREPLY   4       /* RARP reply.  */
89 #endif
90
91 gchar *
92 arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
93   if ((type == ARPHRD_ETHER || type == ARPHRD_EETHER || type == ARPHRD_IEEE802)
94                                 && ad_len == 6) {
95     /* Ethernet address (or Experimental 3Mb Ethernet, or IEEE 802.x
96        address, which are the same type of address). */
97     return ether_to_str(ad);
98   }
99   return bytes_to_str(ad, ad_len);
100 }
101
102 static gchar *
103 arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
104   if (type == ETHERTYPE_IP && ad_len == 4) {
105     /* IP address.  */
106     return ip_to_str(ad);
107   }
108   return bytes_to_str(ad, ad_len);
109 }
110
111 gchar *
112 arphrdtype_to_str(guint16 hwtype, const char *fmt) {
113   static const value_string hrd_vals[] = {
114     {ARPHRD_NETROM,   "NET/ROM pseudo"       },
115     {ARPHRD_ETHER,    "Ethernet"             },
116     {ARPHRD_EETHER,   "Experimental Ethernet"},
117     {ARPHRD_AX25,     "AX.25"                },
118     {ARPHRD_PRONET,   "ProNET"               },
119     {ARPHRD_CHAOS,    "Chaos"                },
120     {ARPHRD_IEEE802,  "IEEE 802"             },
121     {ARPHRD_ARCNET,   "ARCNET"               },
122     {ARPHRD_HYPERCH,  "Hyperchannel"         },
123     {ARPHRD_LANSTAR,  "Lanstar"              },
124     {ARPHRD_AUTONET,  "Autonet Short Address"},
125     {ARPHRD_LOCALTLK, "Localtalk"            },
126     {ARPHRD_LOCALNET, "LocalNet"             },
127     {ARPHRD_ULTRALNK, "Ultra link"           },
128     {ARPHRD_SMDS,     "SMDS"                 },
129     {ARPHRD_DLCI,     "Frame Relay DLCI"     },
130     {ARPHRD_ATM,      "ATM"                  },
131     {ARPHRD_HDLC,     "HDLC"                 },
132     {ARPHRD_FIBREC,   "Fibre Channel"        },
133     {ARPHRD_ATM2225,  "ATM (RFC 2225)"       },
134     {ARPHRD_SERIAL,   "Serial Line"          },
135     {ARPHRD_ATM2,     "ATM"                  },
136     {ARPHRD_MS188220, "MIL-STD-188-220"      },
137     {ARPHRD_METRICOM, "Metricom STRIP"       },
138     {ARPHRD_IEEE1394, "IEEE 1394.1995"       },
139     {ARPHRD_MAPOS,    "MAPOS"                },
140     {ARPHRD_TWINAX,   "Twinaxial"            },
141     {ARPHRD_EUI_64,   "EUI-64"               },
142     {0,                NULL                  } };
143
144     return val_to_str(hwtype, hrd_vals, fmt);
145 }
146
147 /* Offsets of fields within an ARP packet. */
148 #define AR_HRD          0
149 #define AR_PRO          2
150 #define AR_HLN          4
151 #define AR_PLN          5
152 #define AR_OP           6
153
154 void
155 dissect_arp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
156   guint16     ar_hrd;
157   guint16     ar_pro;
158   guint8      ar_hln;
159   guint8      ar_pln;
160   guint16     ar_op;
161   proto_tree  *arp_tree;
162   proto_item  *ti;
163   gchar       *op_str;
164   int         sha_offset, spa_offset, tha_offset, tpa_offset;
165   gchar       *sha_str, *spa_str, *tha_str, *tpa_str;
166   static const value_string op_vals[] = {
167     {ARPOP_REQUEST,  "ARP request" },
168     {ARPOP_REPLY,    "ARP reply"   },
169     {ARPOP_RREQUEST, "RARP request"},
170     {ARPOP_RREPLY,   "RARP reply"  },
171     {0,              NULL          } };
172
173   /* To do: Check for {cap len,pkt len} < struct len */
174   ar_hrd = pntohs(&pd[offset + AR_HRD]);
175   ar_pro = pntohs(&pd[offset + AR_PRO]);
176   ar_hln = (guint8) pd[offset + AR_HLN];
177   ar_pln = (guint8) pd[offset + AR_PLN];
178   ar_op  = pntohs(&pd[offset + AR_OP]);
179
180   /* Extract the addresses.  */
181   sha_offset = offset + 8;
182   sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd);
183   spa_offset = sha_offset + ar_hln;
184   spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_pln, ar_pro);
185   tha_offset = spa_offset + ar_pln;
186   tha_str = arphrdaddr_to_str((guint8 *) &pd[tha_offset], ar_hln, ar_hrd);
187   tpa_offset = tha_offset + ar_hln;
188   tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_pln, ar_pro);
189   
190   if (check_col(fd, COL_PROTOCOL)) {
191     if ((op_str = match_strval(ar_op, op_vals)))
192       col_add_str(fd, COL_PROTOCOL, op_str);
193     else
194       col_add_str(fd, COL_PROTOCOL, "ARP");
195   }
196
197   if (check_col(fd, COL_INFO)) {
198     switch (ar_op) {
199       case ARPOP_REQUEST:
200         col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s",
201           tpa_str, spa_str);
202         break;
203       case ARPOP_REPLY:
204         col_add_fstr(fd, COL_INFO, "%s is at %s", spa_str, sha_str);
205         break;
206       case ARPOP_RREQUEST:
207         col_add_fstr(fd, COL_INFO, "Who is %s?  Tell %s",
208           tha_str, sha_str);
209         break;
210       case ARPOP_RREPLY:
211         col_add_fstr(fd, COL_INFO, "%s is at %s", sha_str, spa_str);
212         break;
213       default:
214         col_add_fstr(fd, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op);
215         break;
216     }
217   }
218
219   if (tree) {
220     if ((op_str = match_strval(ar_op, op_vals)))
221       ti = proto_tree_add_item_format(tree, proto_arp, offset,
222         8 + 2*ar_hln + 2*ar_pln, NULL, op_str);
223     else
224       ti = proto_tree_add_item_format(tree, proto_arp, offset,
225         8 + 2*ar_hln + 2*ar_pln, NULL, "Unknown ARP (opcode 0x%04x)", ar_op);
226     arp_tree = proto_item_add_subtree(ti, ETT_ARP);
227     proto_tree_add_text(arp_tree, offset + AR_HRD, 2,
228       "Hardware type: %s", arphrdtype_to_str(ar_hrd, "Unknown (0x%04x)"));
229     proto_tree_add_text(arp_tree, offset + AR_PRO, 2,
230       "Protocol type: %s", val_to_str(ar_pro, etype_vals, "Unknown (0x%04x)"));
231     proto_tree_add_text(arp_tree, offset + AR_HLN, 1,
232       "Hardware size: %d", ar_hln);
233     proto_tree_add_text(arp_tree, offset + AR_PLN, 1,
234       "Protocol size: %d", ar_pln);
235     proto_tree_add_text(arp_tree, offset + AR_OP,  2,
236       "Opcode: 0x%04x (%s)", ar_op, op_str ? op_str : "Unknown");
237     proto_tree_add_text(arp_tree, sha_offset, ar_hln,
238       "Sender hardware address: %s", sha_str);
239     proto_tree_add_text(arp_tree, spa_offset, ar_pln,
240       "Sender protocol address: %s", spa_str);
241     proto_tree_add_text(arp_tree, tha_offset, ar_hln,
242       "Target hardware address: %s", tha_str);
243     proto_tree_add_text(arp_tree, tpa_offset, ar_pln,
244       "Target protocol address: %s", tpa_str);
245   }
246 }
247
248 void
249 proto_register_arp(void)
250 {
251 /*        static hf_register_info hf[] = {
252                 { &variable,
253                 { "Name",           "arp.abbreviation", TYPE, VALS_POINTER }},
254         };*/
255
256         proto_arp = proto_register_protocol("Address Resolution Protocol", "arp");
257  /*       proto_register_field_array(proto_arp, hf, array_length(hf));*/
258 }