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