Give the IPX dissector dissector hash tables for the IPX type and socket
[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.29 2000/05/11 08:14:51 gram 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 "packet-arp.h"
37 #include "etypes.h"
38
39 static int proto_arp = -1;
40 static int hf_arp_hard_type = -1;
41 static int hf_arp_proto_type = -1;
42 static int hf_arp_hard_size = -1;
43 static int hf_atmarp_shtl = -1;
44 static int hf_atmarp_ssl = -1;
45 static int hf_arp_proto_size = -1;
46 static int hf_arp_opcode = -1;
47 static int hf_atmarp_spln = -1;
48 static int hf_atmarp_thtl = -1;
49 static int hf_atmarp_tsl = -1;
50 static int hf_atmarp_tpln = -1;
51 static int hf_arp_src_ether = -1;
52 static int hf_arp_src_proto = -1;
53 static int hf_arp_dst_ether = -1;
54 static int hf_arp_dst_proto = -1;
55 static int hf_atmarp_src_atm_num_e164 = -1;
56 static int hf_atmarp_src_atm_num_nsap = -1;
57 static int hf_atmarp_src_atm_subaddr = -1;
58 static int hf_atmarp_dst_atm_num_e164 = -1;
59 static int hf_atmarp_dst_atm_num_nsap = -1;
60 static int hf_atmarp_dst_atm_subaddr = -1;
61
62 static gint ett_arp = -1;
63 static gint ett_atmarp_nsap = -1;
64
65 /* Definitions taken from Linux "linux/if_arp.h" header file, and from
66
67         http://www.isi.edu/in-notes/iana/assignments/arp-parameters
68
69  */
70
71 /* ARP protocol HARDWARE identifiers. */
72 #define ARPHRD_NETROM   0               /* from KA9Q: NET/ROM pseudo    */
73 #define ARPHRD_ETHER    1               /* Ethernet 10Mbps              */
74 #define ARPHRD_EETHER   2               /* Experimental Ethernet        */
75 #define ARPHRD_AX25     3               /* AX.25 Level 2                */
76 #define ARPHRD_PRONET   4               /* PROnet token ring            */
77 #define ARPHRD_CHAOS    5               /* Chaosnet                     */
78 #define ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB    */
79 #define ARPHRD_ARCNET   7               /* ARCnet                       */
80 #define ARPHRD_HYPERCH  8               /* Hyperchannel                 */
81 #define ARPHRD_LANSTAR  9               /* Lanstar                      */
82 #define ARPHRD_AUTONET  10              /* Autonet Short Address        */
83 #define ARPHRD_LOCALTLK 11              /* Localtalk                    */
84 #define ARPHRD_LOCALNET 12              /* LocalNet (IBM PCNet/Sytek LocalNET) */
85 #define ARPHRD_ULTRALNK 13              /* Ultra link                   */
86 #define ARPHRD_SMDS     14              /* SMDS                         */
87 #define ARPHRD_DLCI     15              /* Frame Relay DLCI             */
88 #define ARPHRD_ATM      16              /* ATM                          */
89 #define ARPHRD_HDLC     17              /* HDLC                         */
90 #define ARPHRD_FIBREC   18              /* Fibre Channel                */
91 #define ARPHRD_ATM2225  19              /* ATM (RFC 2225)               */
92 #define ARPHRD_SERIAL   20              /* Serial Line                  */
93 #define ARPHRD_ATM2     21              /* ATM                          */
94 #define ARPHRD_MS188220 22              /* MIL-STD-188-220              */
95 #define ARPHRD_METRICOM 23              /* Metricom STRIP               */
96 #define ARPHRD_IEEE1394 24              /* IEEE 1394.1995               */
97 #define ARPHRD_MAPOS    25              /* MAPOS                        */
98 #define ARPHRD_TWINAX   26              /* Twinaxial                    */
99 #define ARPHRD_EUI_64   27              /* EUI-64                       */
100
101 /* ARP / RARP structs and definitions */
102 #ifndef ARPOP_REQUEST
103 #define ARPOP_REQUEST  1       /* ARP request.  */
104 #endif
105 #ifndef ARPOP_REPLY
106 #define ARPOP_REPLY    2       /* ARP reply.  */
107 #endif
108 /* Some OSes have different names, or don't define these at all */
109 #ifndef ARPOP_RREQUEST
110 #define ARPOP_RREQUEST 3       /* RARP request.  */
111 #endif
112 #ifndef ARPOP_RREPLY
113 #define ARPOP_RREPLY   4       /* RARP reply.  */
114 #endif
115 #ifndef ARPOP_IREQUEST
116 #define ARPOP_IREQUEST 8       /* Inverse ARP (RFC 1293) request.  */
117 #endif
118 #ifndef ARPOP_IREPLY
119 #define ARPOP_IREPLY   9       /* Inverse ARP reply.  */
120 #endif
121 #ifndef ATMARPOP_NAK
122 #define ATMARPOP_NAK   10      /* ATMARP NAK.  */
123 #endif
124
125 static const value_string op_vals[] = {
126   {ARPOP_REQUEST,  "request" },
127   {ARPOP_REPLY,    "reply"   },
128   {ARPOP_RREQUEST, "reverse request"},
129   {ARPOP_RREPLY,   "reverse reply"  },
130   {ARPOP_IREQUEST, "inverse request"},
131   {ARPOP_IREPLY,   "inverse reply"  },
132   {0,              NULL          } };
133
134 static const value_string atmop_vals[] = {
135   {ARPOP_REQUEST,  "request" },
136   {ARPOP_REPLY,    "reply"   },
137   {ARPOP_IREQUEST, "inverse request"},
138   {ARPOP_IREPLY,   "inverse reply"  },
139   {ATMARPOP_NAK,   "nak"  },
140   {0,              NULL          } };
141
142 #define ATMARP_IS_E164  0x40    /* bit in shtl/thtl for E.164 format */
143 #define ATMARP_LEN_MASK 0x3F    /* length of address in shtl/thtl */
144
145 gchar *
146 arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type)
147 {
148   if (ad_len == 0)
149     return "<No address>";
150   if ((type == ARPHRD_ETHER || type == ARPHRD_EETHER || type == ARPHRD_IEEE802)
151                                 && ad_len == 6) {
152     /* Ethernet address (or Experimental 3Mb Ethernet, or IEEE 802.x
153        address, which are the same type of address). */
154     return ether_to_str(ad);
155   }
156   return bytes_to_str(ad, ad_len);
157 }
158
159 static gchar *
160 arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type)
161 {
162   if (ad_len == 0)
163     return "<No address>";
164   if (type == ETHERTYPE_IP && ad_len == 4) {
165     /* IPv4 address.  */
166     return ip_to_str(ad);
167   }
168   return bytes_to_str(ad, ad_len);
169 }
170
171 #define N_ATMARPNUM_TO_STR_STRINGS      2
172 #define MAX_E164_STR_LEN                20
173 static gchar *
174 atmarpnum_to_str(guint8 *ad, int ad_tl)
175 {
176   int           ad_len = ad_tl & ATMARP_LEN_MASK;
177   static gchar  str[N_ATMARPNUM_TO_STR_STRINGS][MAX_E164_STR_LEN+3+1];
178   static int    cur_idx;
179   gchar        *cur;
180
181   if (ad_len == 0)
182     return "<No address>";
183
184   if (ad_tl & ATMARP_IS_E164) {
185     /*
186      * I'm assuming this means it's an ASCII (IA5) string.
187      */
188     cur_idx++;
189     if (cur_idx >= N_ATMARPNUM_TO_STR_STRINGS)
190       cur_idx = 0;
191     cur = &str[cur_idx][0];
192     if (ad_len > MAX_E164_STR_LEN) {
193       /* Can't show it all. */
194       memcpy(cur, ad, MAX_E164_STR_LEN);
195       strcpy(&cur[MAX_E164_STR_LEN], "...");
196     } else {
197       memcpy(cur, ad, ad_len);
198       cur[ad_len + 1] = '\0';
199     }
200     return cur;
201   } else {
202     /*
203      * NSAP.
204      *
205      * XXX - break down into subcomponents.
206      */
207     return bytes_to_str(ad, ad_len);
208   }
209 }
210
211 static gchar *
212 atmarpsubaddr_to_str(guint8 *ad, int ad_len)
213 {
214   if (ad_len == 0)
215     return "<No address>";
216
217   /*
218    * XXX - break down into subcomponents?
219    */
220   return bytes_to_str(ad, ad_len);
221 }
222
223 static const value_string hrd_vals[] = {
224   {ARPHRD_NETROM,   "NET/ROM pseudo"       },
225   {ARPHRD_ETHER,    "Ethernet"             },
226   {ARPHRD_EETHER,   "Experimental Ethernet"},
227   {ARPHRD_AX25,     "AX.25"                },
228   {ARPHRD_PRONET,   "ProNET"               },
229   {ARPHRD_CHAOS,    "Chaos"                },
230   {ARPHRD_IEEE802,  "IEEE 802"             },
231   {ARPHRD_ARCNET,   "ARCNET"               },
232   {ARPHRD_HYPERCH,  "Hyperchannel"         },
233   {ARPHRD_LANSTAR,  "Lanstar"              },
234   {ARPHRD_AUTONET,  "Autonet Short Address"},
235   {ARPHRD_LOCALTLK, "Localtalk"            },
236   {ARPHRD_LOCALNET, "LocalNet"             },
237   {ARPHRD_ULTRALNK, "Ultra link"           },
238   {ARPHRD_SMDS,     "SMDS"                 },
239   {ARPHRD_DLCI,     "Frame Relay DLCI"     },
240   {ARPHRD_ATM,      "ATM"                  },
241   {ARPHRD_HDLC,     "HDLC"                 },
242   {ARPHRD_FIBREC,   "Fibre Channel"        },
243   {ARPHRD_ATM2225,  "ATM (RFC 2225)"       },
244   {ARPHRD_SERIAL,   "Serial Line"          },
245   {ARPHRD_ATM2,     "ATM"                  },
246   {ARPHRD_MS188220, "MIL-STD-188-220"      },
247   {ARPHRD_METRICOM, "Metricom STRIP"       },
248   {ARPHRD_IEEE1394, "IEEE 1394.1995"       },
249   {ARPHRD_MAPOS,    "MAPOS"                },
250   {ARPHRD_TWINAX,   "Twinaxial"            },
251   {ARPHRD_EUI_64,   "EUI-64"               },
252   {0,                NULL                  } };
253
254 gchar *
255 arphrdtype_to_str(guint16 hwtype, const char *fmt) {
256     return val_to_str(hwtype, hrd_vals, fmt);
257 }
258
259 /* Offsets of fields within an ARP packet. */
260 #define AR_HRD          0
261 #define AR_PRO          2
262 #define AR_HLN          4
263 #define AR_PLN          5
264 #define AR_OP           6
265 #define MIN_ARP_HEADER_SIZE     8
266
267 /* Offsets of fields within an ATMARP packet. */
268 #define ATM_AR_HRD      0
269 #define ATM_AR_PRO      2
270 #define ATM_AR_SHTL     4
271 #define ATM_AR_SSL      5
272 #define ATM_AR_OP       6
273 #define ATM_AR_SPLN     8
274 #define ATM_AR_THTL     9
275 #define ATM_AR_TSL      10
276 #define ATM_AR_TPLN     11
277 #define MIN_ATMARP_HEADER_SIZE  12
278
279 static void
280 dissect_atm_number(const u_char *pd, int offset, int tl, int hf_e164,
281     int hf_nsap, proto_tree *tree)
282 {
283         int len = tl & ATMARP_LEN_MASK;
284         proto_item *ti;
285         proto_tree *nsap_tree;
286
287         if (tl & ATMARP_IS_E164)
288                 proto_tree_add_item(tree, hf_e164, NullTVB, offset, len, &pd[offset]);
289         else {
290                 ti = proto_tree_add_item(tree, hf_nsap, NullTVB, offset, len,
291                     &pd[offset]);
292                 if (len >= 20) {
293                         nsap_tree = proto_item_add_subtree(ti, ett_atmarp_nsap);
294                         dissect_atm_nsap(pd, offset, len, nsap_tree);
295                 }
296         }
297 }
298
299 void
300 dissect_atm_nsap(const u_char *pd, int offset, int len, proto_tree *tree)
301 {
302         switch (pd[offset]) {
303
304         case 0x39:      /* DCC ATM format */
305         case 0xBD:      /* DCC ATM group format */
306                 proto_tree_add_text(tree, NullTVB, offset + 0, 3,
307                     "Data Country Code%s: 0x%04X",
308                     (pd[offset] == 0xBD) ? " (group)" : "",
309                     pntohs(&pd[offset + 1]));
310                 proto_tree_add_text(tree, NullTVB, offset + 3, 10,
311                     "High Order DSP: %s",
312                     bytes_to_str(&pd[offset + 3], 10));
313                 proto_tree_add_text(tree, NullTVB, offset + 13, 6,
314                     "End System Identifier: %s",
315                     bytes_to_str(&pd[offset + 13], 6));
316                 proto_tree_add_text(tree, NullTVB, offset + 19, 1,
317                     "Selector: 0x%02X", pd[offset + 19]);
318                 break;
319
320         case 0x47:      /* ICD ATM format */
321         case 0xC5:      /* ICD ATM group format */
322                 proto_tree_add_text(tree, NullTVB, offset + 0, 3,
323                     "International Code Designator%s: 0x%04X",
324                     (pd[offset] == 0xC5) ? " (group)" : "",
325                     pntohs(&pd[offset + 1]));
326                 proto_tree_add_text(tree, NullTVB, offset + 3, 10,
327                     "High Order DSP: %s",
328                     bytes_to_str(&pd[offset + 3], 10));
329                 proto_tree_add_text(tree, NullTVB, offset + 13, 6,
330                     "End System Identifier: %s",
331                     bytes_to_str(&pd[offset + 13], 6));
332                 proto_tree_add_text(tree, NullTVB, offset + 19, 1,
333                     "Selector: 0x%02X", pd[offset + 19]);
334                 break;
335
336         case 0x45:      /* E.164 ATM format */
337         case 0xC3:      /* E.164 ATM group format */
338                 proto_tree_add_text(tree, NullTVB, offset + 0, 9,
339                     "E.164 ISDN%s: %s",
340                     (pd[offset] == 0xC3) ? " (group)" : "",
341                     bytes_to_str(&pd[offset + 1], 8));
342                 proto_tree_add_text(tree, NullTVB, offset + 9, 4,
343                     "High Order DSP: %s",
344                     bytes_to_str(&pd[offset + 3], 10));
345                 proto_tree_add_text(tree, NullTVB, offset + 13, 6,
346                     "End System Identifier: %s",
347                     bytes_to_str(&pd[offset + 13], 6));
348                 proto_tree_add_text(tree, NullTVB, offset + 19, 1,
349                     "Selector: 0x%02X", pd[offset + 19]);
350                 break;
351
352         default:
353                 proto_tree_add_text(tree, NullTVB, offset, 1,
354                     "Unknown AFI: 0x%02X", pd[offset]);
355                 proto_tree_add_text(tree, NullTVB, offset + 1, len - 1,
356                     "Rest of address: %s",
357                     bytes_to_str(&pd[offset + 1], len - 1));
358                 break;
359         }
360 }
361
362 /*
363  * RFC 2225 ATMARP - it's just like ARP, except where it isn't.
364  */
365 static void
366 dissect_atmarp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
367 {
368   guint16     ar_hrd;
369   guint16     ar_pro;
370   guint8      ar_shtl;
371   guint8      ar_sht;
372   guint8      ar_shl;
373   guint8      ar_ssl;
374   guint16     ar_op;
375   guint8      ar_spln;
376   guint8      ar_thtl;
377   guint8      ar_tht;
378   guint8      ar_thl;
379   guint8      ar_tsl;
380   guint8      ar_tpln;
381   int         tot_len;
382   proto_tree  *arp_tree;
383   proto_item  *ti;
384   gchar       *op_str;
385   int         sha_offset, ssa_offset, spa_offset;
386   int         tha_offset, tsa_offset, tpa_offset;
387   gchar       *sha_str, *ssa_str, *spa_str;
388   gchar       *tha_str, *tsa_str, *tpa_str;
389
390   if (!BYTES_ARE_IN_FRAME(offset, MIN_ATMARP_HEADER_SIZE)) {
391     dissect_data(pd, offset, fd, tree);
392     return;
393   }
394
395   ar_hrd = pntohs(&pd[offset + ATM_AR_HRD]);
396   ar_pro = pntohs(&pd[offset + ATM_AR_PRO]);
397   ar_shtl = (guint8) pd[offset + ATM_AR_SHTL];
398   ar_sht = ar_shtl & ATMARP_IS_E164;
399   ar_shl = ar_shtl & ATMARP_LEN_MASK;
400   ar_ssl = (guint8) pd[offset + ATM_AR_SSL];
401   ar_op  = pntohs(&pd[offset + AR_OP]);
402   ar_spln = (guint8) pd[offset + ATM_AR_SPLN];
403   ar_thtl = (guint8) pd[offset + ATM_AR_THTL];
404   ar_tht = ar_thtl & ATMARP_IS_E164;
405   ar_thl = ar_thtl & ATMARP_LEN_MASK;
406   ar_tsl = (guint8) pd[offset + ATM_AR_TSL];
407   ar_tpln = (guint8) pd[offset + ATM_AR_TPLN];
408
409   tot_len = MIN_ATMARP_HEADER_SIZE + ar_shtl + ar_ssl + ar_spln +
410                                 ar_thtl + ar_tsl + ar_tpln;
411   if (!BYTES_ARE_IN_FRAME(offset, tot_len)) {
412     dissect_data(pd, offset, fd, tree);
413     return;
414   }
415
416   /* Extract the addresses.  */
417   sha_offset = offset + MIN_ATMARP_HEADER_SIZE;
418   if (ar_shl != 0)
419     sha_str = atmarpnum_to_str((guint8 *) &pd[sha_offset], ar_shtl);
420   else
421     sha_str = "<No address>";
422   ssa_offset = sha_offset + ar_shl;
423   if (ar_ssl != 0)
424     ssa_str = atmarpsubaddr_to_str((guint8 *) &pd[ssa_offset], ar_ssl);
425   else
426     ssa_str = NULL;
427   spa_offset = ssa_offset + ar_ssl;
428   spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_spln, ar_pro);
429   tha_offset = spa_offset + ar_spln;
430   if (ar_thl != 0)
431     tha_str = atmarpnum_to_str((guint8 *) &pd[tha_offset], ar_thtl);
432   else
433     tha_str = "<No address>";
434   tsa_offset = tha_offset + ar_thl;
435   if (ar_tsl != 0)
436     tsa_str = atmarpsubaddr_to_str((guint8 *) &pd[tsa_offset], ar_tsl);
437   else
438     tsa_str = NULL;
439   tpa_offset = tsa_offset + ar_tsl;
440   tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_tpln, ar_pro);
441   
442   if (check_col(fd, COL_PROTOCOL)) {
443     switch (ar_op) {
444
445     case ARPOP_REQUEST:
446     case ARPOP_REPLY:
447     case ATMARPOP_NAK:
448     default:
449       col_add_str(fd, COL_PROTOCOL, "ATMARP");
450       break;
451
452     case ARPOP_RREQUEST:
453     case ARPOP_RREPLY:
454       col_add_str(fd, COL_PROTOCOL, "ATMRARP");
455       break;
456
457     case ARPOP_IREQUEST:
458     case ARPOP_IREPLY:
459       col_add_str(fd, COL_PROTOCOL, "Inverse ATMARP");
460       break;
461     }
462   }
463
464   if (check_col(fd, COL_INFO)) {
465     switch (ar_op) {
466       case ARPOP_REQUEST:
467         col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s", tpa_str, spa_str);
468         break;
469       case ARPOP_REPLY:
470         col_add_fstr(fd, COL_INFO, "%s is at %s%s%s", spa_str, sha_str,
471                 ((ssa_str != NULL) ? "," : ""),
472                 ((ssa_str != NULL) ? ssa_str : ""));
473         break;
474       case ARPOP_IREQUEST:
475         col_add_fstr(fd, COL_INFO, "Who is %s%s%s?  Tell %s%s%s", tha_str,
476                 ((tsa_str != NULL) ? "," : ""),
477                 ((tsa_str != NULL) ? tsa_str : ""),
478                 sha_str,
479                 ((ssa_str != NULL) ? "," : ""),
480                 ((ssa_str != NULL) ? ssa_str : ""));
481         break;
482       case ARPOP_IREPLY:
483         col_add_fstr(fd, COL_INFO, "%s%s%s is at %s", sha_str,
484                 ((ssa_str != NULL) ? "," : ""),
485                 ((ssa_str != NULL) ? ssa_str : ""),
486                 spa_str);
487         break;
488       case ATMARPOP_NAK:
489         col_add_fstr(fd, COL_INFO, "I don't know where %s is", spa_str);
490         break;
491       default:
492         col_add_fstr(fd, COL_INFO, "Unknown ATMARP opcode 0x%04x", ar_op);
493         break;
494     }
495   }
496
497   if (tree) {
498     if ((op_str = match_strval(ar_op, atmop_vals)))
499       ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
500                                         "ATM Address Resolution Protocol (%s)", 
501                                         op_str);
502     else
503       ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
504                                       "ATM Address Resolution Protocol (opcode 0x%04x)", ar_op);
505     arp_tree = proto_item_add_subtree(ti, ett_arp);
506     proto_tree_add_item(arp_tree, hf_arp_hard_type, NullTVB, offset + ATM_AR_HRD, 2,
507                                ar_hrd);
508     proto_tree_add_item(arp_tree, hf_arp_proto_type, NullTVB, offset + ATM_AR_PRO, 2,
509                                ar_pro);
510     proto_tree_add_item(arp_tree, hf_atmarp_shtl, NullTVB, offset + ATM_AR_SHTL, 1,
511                                ar_shtl);
512     proto_tree_add_item(arp_tree, hf_atmarp_ssl, NullTVB, offset + ATM_AR_SSL, 1,
513                                ar_ssl);
514     proto_tree_add_item(arp_tree, hf_arp_opcode, NullTVB, offset + AR_OP,  2,
515                                ar_op);
516     proto_tree_add_item(arp_tree, hf_atmarp_spln, NullTVB, offset + ATM_AR_SPLN, 1,
517                                ar_spln);
518     proto_tree_add_item(arp_tree, hf_atmarp_thtl, NullTVB, offset + ATM_AR_THTL, 1,
519                                ar_thtl);
520     proto_tree_add_item(arp_tree, hf_atmarp_tsl, NullTVB, offset + ATM_AR_TSL, 1,
521                                ar_tsl);
522     proto_tree_add_item(arp_tree, hf_atmarp_tpln, NullTVB, offset + ATM_AR_TPLN, 1,
523                                ar_tpln);
524     if (ar_shl != 0)
525       dissect_atm_number(pd, sha_offset, ar_shtl, hf_atmarp_src_atm_num_e164,
526                                hf_atmarp_src_atm_num_nsap, arp_tree);
527     if (ar_ssl != 0)
528       proto_tree_add_bytes_format(arp_tree, hf_atmarp_src_atm_subaddr, NullTVB, ssa_offset,
529                                ar_ssl,
530                                &pd[ssa_offset],
531                                "Sender ATM subaddress: %s", ssa_str);
532     if (ar_spln != 0)
533       proto_tree_add_bytes_format(arp_tree, hf_arp_src_proto, NullTVB, spa_offset, ar_spln,
534                                &pd[spa_offset],
535                                "Sender protocol address: %s", spa_str);
536     if (ar_thl != 0)
537       dissect_atm_number(pd, tha_offset, ar_thtl, hf_atmarp_dst_atm_num_e164,
538                                hf_atmarp_dst_atm_num_nsap, arp_tree);
539     if (ar_tsl != 0)
540       proto_tree_add_bytes_format(arp_tree, hf_atmarp_dst_atm_subaddr, NullTVB, tsa_offset,
541                                ar_tsl,
542                                &pd[tsa_offset],
543                                "Target ATM subaddress: %s", tsa_str);
544     if (ar_tpln != 0)
545       proto_tree_add_bytes_format(arp_tree, hf_arp_dst_proto, NullTVB, tpa_offset, ar_tpln,
546                                &pd[tpa_offset],
547                                "Target protocol address: %s", tpa_str);
548   }
549 }
550
551 static void
552 dissect_arp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
553 {
554   guint16     ar_hrd;
555   guint16     ar_pro;
556   guint8      ar_hln;
557   guint8      ar_pln;
558   guint16     ar_op;
559   int         tot_len;
560   proto_tree  *arp_tree;
561   proto_item  *ti;
562   gchar       *op_str;
563   int         sha_offset, spa_offset, tha_offset, tpa_offset;
564   gchar       *sha_str, *spa_str, *tha_str, *tpa_str;
565
566   if (!BYTES_ARE_IN_FRAME(offset, MIN_ARP_HEADER_SIZE)) {
567     dissect_data(pd, offset, fd, tree);
568     return;
569   }
570
571   ar_hrd = pntohs(&pd[offset + AR_HRD]);
572   if (ar_hrd == ARPHRD_ATM2225) {
573     dissect_atmarp(pd, offset, fd, tree);
574     return;
575   }
576   ar_pro = pntohs(&pd[offset + AR_PRO]);
577   ar_hln = (guint8) pd[offset + AR_HLN];
578   ar_pln = (guint8) pd[offset + AR_PLN];
579   ar_op  = pntohs(&pd[offset + AR_OP]);
580
581   tot_len = MIN_ARP_HEADER_SIZE + ar_hln*2 + ar_pln*2;
582   if (!BYTES_ARE_IN_FRAME(offset, tot_len)) {
583     dissect_data(pd, offset, fd, tree);
584     return;
585   }
586
587   /* Extract the addresses.  */
588   sha_offset = offset + MIN_ARP_HEADER_SIZE;
589   sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd);
590   spa_offset = sha_offset + ar_hln;
591   spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_pln, ar_pro);
592   tha_offset = spa_offset + ar_pln;
593   tha_str = arphrdaddr_to_str((guint8 *) &pd[tha_offset], ar_hln, ar_hrd);
594   tpa_offset = tha_offset + ar_hln;
595   tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_pln, ar_pro);
596   
597   if (check_col(fd, COL_PROTOCOL)) {
598     switch (ar_op) {
599
600     case ARPOP_REQUEST:
601     case ARPOP_REPLY:
602     default:
603       col_add_str(fd, COL_PROTOCOL, "ARP");
604       break;
605
606     case ARPOP_RREQUEST:
607     case ARPOP_RREPLY:
608       col_add_str(fd, COL_PROTOCOL, "RARP");
609       break;
610
611     case ARPOP_IREQUEST:
612     case ARPOP_IREPLY:
613       col_add_str(fd, COL_PROTOCOL, "Inverse ARP");
614       break;
615     }
616   }
617
618   if (check_col(fd, COL_INFO)) {
619     switch (ar_op) {
620       case ARPOP_REQUEST:
621         col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s", tpa_str, spa_str);
622         break;
623       case ARPOP_REPLY:
624         col_add_fstr(fd, COL_INFO, "%s is at %s", spa_str, sha_str);
625         break;
626       case ARPOP_RREQUEST:
627       case ARPOP_IREQUEST:
628         col_add_fstr(fd, COL_INFO, "Who is %s?  Tell %s", tha_str, sha_str);
629         break;
630       case ARPOP_RREPLY:
631       case ARPOP_IREPLY:
632         col_add_fstr(fd, COL_INFO, "%s is at %s", sha_str, spa_str);
633         break;
634       default:
635         col_add_fstr(fd, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op);
636         break;
637     }
638   }
639
640   if (tree) {
641     if ((op_str = match_strval(ar_op, op_vals)))
642       ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
643                                         "Address Resolution Protocol (%s)", op_str);
644     else
645       ti = proto_tree_add_protocol_format(tree, proto_arp, NullTVB, offset, tot_len,
646                                       "Address Resolution Protocol (opcode 0x%04x)", ar_op);
647     arp_tree = proto_item_add_subtree(ti, ett_arp);
648     proto_tree_add_item(arp_tree, hf_arp_hard_type, NullTVB, offset + AR_HRD, 2,
649                                ar_hrd);
650     proto_tree_add_item(arp_tree, hf_arp_proto_type, NullTVB, offset + AR_PRO, 2,
651                                ar_pro);
652     proto_tree_add_item(arp_tree, hf_arp_hard_size, NullTVB, offset + AR_HLN, 1,
653                                ar_hln);
654     proto_tree_add_item(arp_tree, hf_arp_proto_size, NullTVB, offset + AR_PLN, 1,
655                                ar_pln);
656     proto_tree_add_item(arp_tree, hf_arp_opcode, NullTVB, offset + AR_OP,  2,
657                                ar_op);
658     if (ar_hln != 0)
659       proto_tree_add_bytes_format(arp_tree, hf_arp_src_ether, NullTVB, sha_offset, ar_hln,
660                                &pd[sha_offset],
661                                "Sender hardware address: %s", sha_str);
662     if (ar_pln != 0)
663       proto_tree_add_bytes_format(arp_tree, hf_arp_src_proto, NullTVB, spa_offset, ar_pln,
664                                &pd[spa_offset],
665                                "Sender protocol address: %s", spa_str);
666     if (ar_hln != 0)
667       proto_tree_add_bytes_format(arp_tree, hf_arp_dst_ether, NullTVB, tha_offset, ar_hln,
668                                &pd[tha_offset],
669                                "Target hardware address: %s", tha_str);
670     if (ar_pln != 0)
671       proto_tree_add_bytes_format(arp_tree, hf_arp_dst_proto, NullTVB, tpa_offset, ar_pln,
672                                &pd[tpa_offset],
673                                "Target protocol address: %s", tpa_str);
674   }
675 }
676
677 void
678 proto_register_arp(void)
679 {
680   static hf_register_info hf[] = {
681     { &hf_arp_hard_type,
682       { "Hardware type",                "arp.hw.type",   
683         FT_UINT16,      BASE_HEX,       VALS(hrd_vals), 0x0,
684         "" }},
685
686     { &hf_arp_proto_type,
687       { "Protocol type",                "arp.proto.type",
688         FT_UINT16,      BASE_HEX,       VALS(etype_vals),       0x0,
689         "" }},
690
691     { &hf_arp_hard_size,
692       { "Hardware size",                "arp.hw.size",
693         FT_UINT8,       BASE_DEC,       NULL,   0x0,
694         "" }},
695
696     { &hf_atmarp_shtl,
697       { "Sender ATM number type and length",    "arp.src.htl",  
698         FT_UINT8,       BASE_DEC,       NULL,   0x0,
699         "" }},
700
701     { &hf_atmarp_ssl,
702       { "Sender ATM subaddress length", "arp.src.slen",
703         FT_UINT8,       BASE_DEC,       NULL,   0x0,
704         "" }},
705
706     { &hf_arp_proto_size,
707       { "Protocol size",                "arp.proto.size",
708         FT_UINT8,       BASE_DEC,       NULL,   0x0,
709         "" }},
710
711     { &hf_arp_opcode,
712       { "Opcode",                       "arp.opcode",
713         FT_UINT16,      BASE_HEX,       VALS(op_vals),  0x0,
714         "" }},
715
716     { &hf_atmarp_spln,
717       { "Sender protocol size",         "arp.src.pln",
718         FT_UINT8,       BASE_DEC,       NULL,   0x0,
719         "" }},
720
721     { &hf_atmarp_thtl,
722       { "Target ATM number type and length",    "arp.dst.htl",
723         FT_UINT8,       BASE_DEC,       NULL,   0x0,
724         "" }},
725
726     { &hf_atmarp_tsl,
727       { "Target ATM subaddress length", "arp.dst.slen",
728         FT_UINT8,       BASE_DEC,       NULL,   0x0,
729         "" }},
730
731     { &hf_atmarp_tpln,
732       { "Target protocol size",         "arp.dst.pln",
733         FT_UINT8,       BASE_DEC,       NULL,   0x0,
734         "" }},
735
736     { &hf_arp_src_ether,
737       { "Sender hardware address",      "arp.src.hw",
738         FT_BYTES,       BASE_NONE,      NULL,   0x0,
739         "" }},
740
741     { &hf_atmarp_src_atm_num_e164,
742       { "Sender ATM number (E.164)",    "arp.src.atm_num_e164",
743         FT_STRING,      BASE_NONE,      NULL,   0x0,
744         "" }},
745
746     { &hf_atmarp_src_atm_num_nsap,
747       { "Sender ATM number (NSAP)",     "arp.src.atm_num_nsap",
748         FT_BYTES,       BASE_NONE,      NULL,   0x0,
749         "" }},
750
751     { &hf_atmarp_src_atm_subaddr,
752       { "Sender ATM subaddress",        "arp.src.atm_subaddr",
753         FT_BYTES,       BASE_NONE,      NULL,   0x0,
754         "" }},
755
756     { &hf_arp_src_proto,
757       { "Sender protocol address",      "arp.src.proto", 
758         FT_BYTES,       BASE_NONE,      NULL,   0x0,
759         "" }},
760
761     { &hf_arp_dst_ether,
762       { "Target hardware address",      "arp.dst.hw",
763         FT_BYTES,       BASE_NONE,      NULL,   0x0,
764         "" }},
765
766     { &hf_atmarp_dst_atm_num_e164,
767       { "Target ATM number (E.164)",    "arp.dst.atm_num_e164",
768         FT_STRING,      BASE_NONE,      NULL,   0x0,
769         "" }},
770
771     { &hf_atmarp_dst_atm_num_nsap,
772       { "Target ATM number (NSAP)",     "arp.dst.atm_num_nsap",
773         FT_BYTES,       BASE_NONE,      NULL,   0x0,
774         "" }},
775
776     { &hf_atmarp_dst_atm_subaddr,
777       { "Target ATM subaddress",        "arp.dst.atm_subaddr",
778         FT_BYTES,       BASE_NONE,      NULL,   0x0,
779         "" }},
780
781     { &hf_arp_dst_proto,
782       { "Target protocol address",      "arp.dst.proto", 
783         FT_BYTES,       BASE_NONE,      NULL,   0x0,
784       "" }}
785   };
786   static gint *ett[] = {
787     &ett_arp,
788     &ett_atmarp_nsap,
789   };
790
791   proto_arp = proto_register_protocol("Address Resolution Protocol", "arp");
792   proto_register_field_array(proto_arp, hf, array_length(hf));
793   proto_register_subtree_array(ett, array_length(ett));
794 }
795
796 void
797 proto_reg_handoff_arp(void)
798 {
799         dissector_add("ethertype", ETHERTYPE_ARP, dissect_arp);
800         dissector_add("ethertype", ETHERTYPE_REVARP, dissect_arp);
801 }