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