The Sniffer-reading code in wiretap now decodes the time field for each
[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.9 1998/11/12 00:06:23 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 #include <gtk/gtk.h>
31
32 #include <stdio.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include "ethereal.h"
43 #include "packet.h"
44 #include "etypes.h"
45
46 /* Definitions taken from Linux "linux/if_arp.h" header file, and from
47
48         http://www.isi.edu/in-notes/iana/assignments/arp-parameters
49
50  */
51
52 /* ARP protocol HARDWARE identifiers. */
53 #define ARPHRD_NETROM   0               /* from KA9Q: NET/ROM pseudo    */
54 #define ARPHRD_ETHER    1               /* Ethernet 10Mbps              */
55 #define ARPHRD_EETHER   2               /* Experimental Ethernet        */
56 #define ARPHRD_AX25     3               /* AX.25 Level 2                */
57 #define ARPHRD_PRONET   4               /* PROnet token ring            */
58 #define ARPHRD_CHAOS    5               /* Chaosnet                     */
59 #define ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB    */
60 #define ARPHRD_ARCNET   7               /* ARCnet                       */
61 #define ARPHRD_HYPERCH  8               /* Hyperchannel                 */
62 #define ARPHRD_LANSTAR  9               /* Lanstar                      */
63 #define ARPHRD_AUTONET  10              /* Autonet Short Address        */
64 #define ARPHRD_LOCALTLK 11              /* Localtalk                    */
65 #define ARPHRD_LOCALNET 12              /* LocalNet (IBM PCNet/Sytek LocalNET) */
66 #define ARPHRD_ULTRALNK 13              /* Ultra link                   */
67 #define ARPHRD_SMDS     14              /* SMDS                         */
68 #define ARPHRD_DLCI     15              /* Frame Relay DLCI             */
69 #define ARPHRD_ATM      16              /* ATM                          */
70 #define ARPHRD_HDLC     17              /* HDLC                         */
71 #define ARPHRD_FIBREC   18              /* Fibre Channel                */
72 #define ARPHRD_ATM2225  19              /* ATM (RFC 2225)               */
73 #define ARPHRD_SERIAL   20              /* Serial Line                  */
74 #define ARPHRD_ATM2     21              /* ATM                          */
75 #define ARPHRD_MS188220 22              /* MIL-STD-188-220              */
76 #define ARPHRD_METRICOM 23              /* Metricom STRIP               */
77 #define ARPHRD_IEEE1394 24              /* IEEE 1394.1995               */
78 #define ARPHRD_MAPOS    25              /* MAPOS                        */
79 #define ARPHRD_TWINAX   26              /* Twinaxial                    */
80 #define ARPHRD_EUI_64   27              /* EUI-64                       */
81
82 /* Max string length for displaying unknown type of ARP address.  */
83 #define MAX_ADDR_STR_LEN        16
84
85 static gchar *
86 arpaddr_to_str(guint8 *ad, int ad_len) {
87   static gchar  str[3][MAX_ADDR_STR_LEN+3+1];
88   static gchar *cur;
89   gchar        *p;
90   int           len;
91   static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
92                                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
93
94   if (cur == &str[0][0]) {
95     cur = &str[1][0];
96   } else if (cur == &str[1][0]) {  
97     cur = &str[2][0];
98   } else {  
99     cur = &str[0][0];
100   }
101   p = cur;
102   len = MAX_ADDR_STR_LEN;
103   while (ad_len > 0 && len > 0) {
104     *p++ = hex[(*ad) >> 4];
105     *p++ = hex[(*ad) & 0xF];
106     len -= 2;
107     ad++;
108     ad_len--;
109   }
110   if (ad_len != 0) {
111     /* Note that we're not showing the full address.  */
112     *p++ = '.';
113     *p++ = '.';
114     *p++ = '.';
115   }
116   *p = '\0';
117   return cur;
118 }
119
120 static gchar *
121 arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
122   if (type == ARPHRD_ETHER && ad_len == 6) {
123     /* Ethernet address.  */
124     return ether_to_str(ad);
125   }
126   return arpaddr_to_str(ad, ad_len);
127 }
128
129 static gchar *
130 arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
131   if (type == ETHERTYPE_IP && ad_len == 4) {
132     /* IP address.  */
133     return ip_to_str(ad);
134   }
135   return arpaddr_to_str(ad, ad_len);
136 }
137
138 /* Offsets of fields within an ARP packet. */
139 #define AR_HRD          0
140 #define AR_PRO          2
141 #define AR_HLN          4
142 #define AR_PLN          5
143 #define AR_OP           6
144
145 void
146 dissect_arp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
147   guint16     ar_hrd;
148   guint16     ar_pro;
149   guint8      ar_hln;
150   guint8      ar_pln;
151   guint16     ar_op;
152   GtkWidget   *arp_tree, *ti;
153   gchar       *op_str;
154   int         sha_offset, spa_offset, tha_offset, tpa_offset;
155   gchar       *sha_str, *spa_str, *tha_str, *tpa_str;
156   static const value_string op_vals[] = {
157     {ARPOP_REQUEST,  "ARP request" },
158     {ARPOP_REPLY,    "ARP reply"   },
159     {ARPOP_RREQUEST, "RARP request"},
160     {ARPOP_RREPLY,   "RARP reply"  },
161     {0,              NULL          } };
162   static const value_string hrd_vals[] = {
163     {ARPHRD_NETROM,   "NET/ROM pseudo"       },
164     {ARPHRD_ETHER,    "Ethernet"             },
165     {ARPHRD_EETHER,   "Experimental Ethernet"},
166     {ARPHRD_AX25,     "AX.25"                },
167     {ARPHRD_PRONET,   "ProNET"               },
168     {ARPHRD_CHAOS,    "Chaos"                },
169     {ARPHRD_IEEE802,  "IEEE 802"             },
170     {ARPHRD_ARCNET,   "ARCNET"               },
171     {ARPHRD_HYPERCH,  "Hyperchannel"         },
172     {ARPHRD_LANSTAR,  "Lanstar"              },
173     {ARPHRD_AUTONET,  "Autonet Short Address"},
174     {ARPHRD_LOCALTLK, "Localtalk"            },
175     {ARPHRD_LOCALNET, "LocalNet"             },
176     {ARPHRD_ULTRALNK, "Ultra link"           },
177     {ARPHRD_SMDS,     "SMDS"                 },
178     {ARPHRD_DLCI,     "Frame Relay DLCI"     },
179     {ARPHRD_ATM,      "ATM"                  },
180     {ARPHRD_HDLC,     "HDLC"                 },
181     {ARPHRD_FIBREC,   "Fibre Channel"        },
182     {ARPHRD_ATM2225,  "ATM (RFC 2225)"       },
183     {ARPHRD_SERIAL,   "Serial Line"          },
184     {ARPHRD_ATM2,     "ATM"                  },
185     {ARPHRD_MS188220, "MIL-STD-188-220"      },
186     {ARPHRD_METRICOM, "Metricom STRIP"       },
187     {ARPHRD_IEEE1394, "IEEE 1394.1995"       },
188     {ARPHRD_MAPOS,    "MAPOS"                },
189     {ARPHRD_TWINAX,   "Twinaxial"            },
190     {ARPHRD_EUI_64,   "EUI-64"               },
191     {0,                NULL                  } };
192
193   /* To do: Check for {cap len,pkt len} < struct len */
194   ar_hrd = pntohs(&pd[offset + AR_HRD]);
195   ar_pro = pntohs(&pd[offset + AR_PRO]);
196   ar_hln = (guint8) pd[offset + AR_HLN];
197   ar_pln = (guint8) pd[offset + AR_PLN];
198   ar_op  = pntohs(&pd[offset + AR_OP]);
199
200   /* Extract the addresses.  */
201   sha_offset = offset + 8;
202   sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd);
203   spa_offset = sha_offset + ar_hln;
204   spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_pln, ar_pro);
205   tha_offset = spa_offset + ar_pln;
206   tha_str = arphrdaddr_to_str((guint8 *) &pd[tha_offset], ar_hln, ar_hrd);
207   tpa_offset = tha_offset + ar_hln;
208   tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_pln, ar_pro);
209   
210   if (fd->win_info[COL_NUM]) {
211     switch (ar_op) {
212       case ARPOP_REQUEST:
213         strcpy(fd->win_info[COL_PROTOCOL], "ARP");
214         sprintf(fd->win_info[COL_INFO], "Who has %s?  Tell %s",
215           tpa_str, spa_str);
216         break;
217       case ARPOP_REPLY:
218         strcpy(fd->win_info[COL_PROTOCOL], "ARP");
219         sprintf(fd->win_info[COL_INFO], "%s is at %s",
220           spa_str, sha_str);
221         break;
222       case ARPOP_RREQUEST:
223         strcpy(fd->win_info[COL_PROTOCOL], "RARP");
224         sprintf(fd->win_info[COL_INFO], "Who is %s?  Tell %s",
225           tha_str, sha_str);
226         break;
227       case ARPOP_RREPLY:
228         strcpy(fd->win_info[COL_PROTOCOL], "RARP");
229         sprintf(fd->win_info[COL_INFO], "%s is at %s",
230           sha_str, spa_str);
231         break;
232       default:
233         strcpy(fd->win_info[COL_PROTOCOL], "ARP");
234         sprintf(fd->win_info[COL_INFO], "Unknown ARP opcode 0x%04x", ar_op);
235         break;
236     }
237   }
238
239   if (tree) {
240     if ((op_str = match_strval(ar_op, op_vals)))
241       ti = add_item_to_tree(GTK_WIDGET(tree), offset, 8 + 2*ar_hln + 2*ar_pln,
242         op_str);
243     else
244       ti = add_item_to_tree(GTK_WIDGET(tree), offset, 8 + 2*ar_hln + 2*ar_pln,
245         "Unknown ARP (opcode 0x%04x)", ar_op);
246     arp_tree = gtk_tree_new();
247     add_subtree(ti, arp_tree, ETT_ARP);
248     add_item_to_tree(arp_tree, offset + AR_HRD, 2,
249       "Hardware type: %s", val_to_str(ar_hrd, hrd_vals, "Unknown (0x%04x)"));
250     add_item_to_tree(arp_tree, offset + AR_PRO, 2,
251       "Protocol type: %s", ethertype_to_str(ar_pro, "Unknown (0x%04x)"));
252     add_item_to_tree(arp_tree, offset + AR_HLN, 1,
253       "Hardware size: %d", ar_hln);
254     add_item_to_tree(arp_tree, offset + AR_PLN, 1,
255       "Protocol size: %d", ar_pln);
256     add_item_to_tree(arp_tree, offset + AR_OP,  2,
257       "Opcode: 0x%04x (%s)", ar_op, op_str ? op_str : "Unknown");
258     add_item_to_tree(arp_tree, sha_offset, ar_hln,
259       "Sender hardware address: %s", sha_str);
260     add_item_to_tree(arp_tree, spa_offset, ar_pln,
261       "Sender protocol address: %s", spa_str);
262     add_item_to_tree(arp_tree, tha_offset, ar_hln,
263       "Target hardware address: %s", tha_str);
264     add_item_to_tree(arp_tree, tpa_offset, ar_pln,
265       "Target protocol address: %s", tpa_str);
266   }
267 }