I removed the bit-fields that depended upon gcc's ability to use any 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.11 1999/01/28 21:29:34 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 gchar *
121 arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
122   if ((type == ARPHRD_ETHER || type == ARPHRD_EETHER || type == ARPHRD_IEEE802)
123                                 && ad_len == 6) {
124     /* Ethernet address (or Experimental 3Mb Ethernet, or IEEE 802.x
125        address, which are the same type of address). */
126     return ether_to_str(ad);
127   }
128   return arpaddr_to_str(ad, ad_len);
129 }
130
131 static gchar *
132 arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
133   if (type == ETHERTYPE_IP && ad_len == 4) {
134     /* IP address.  */
135     return ip_to_str(ad);
136   }
137   return arpaddr_to_str(ad, ad_len);
138 }
139
140 gchar *
141 arphrdtype_to_str(guint16 hwtype, const char *fmt) {
142   static const value_string hrd_vals[] = {
143     {ARPHRD_NETROM,   "NET/ROM pseudo"       },
144     {ARPHRD_ETHER,    "Ethernet"             },
145     {ARPHRD_EETHER,   "Experimental Ethernet"},
146     {ARPHRD_AX25,     "AX.25"                },
147     {ARPHRD_PRONET,   "ProNET"               },
148     {ARPHRD_CHAOS,    "Chaos"                },
149     {ARPHRD_IEEE802,  "IEEE 802"             },
150     {ARPHRD_ARCNET,   "ARCNET"               },
151     {ARPHRD_HYPERCH,  "Hyperchannel"         },
152     {ARPHRD_LANSTAR,  "Lanstar"              },
153     {ARPHRD_AUTONET,  "Autonet Short Address"},
154     {ARPHRD_LOCALTLK, "Localtalk"            },
155     {ARPHRD_LOCALNET, "LocalNet"             },
156     {ARPHRD_ULTRALNK, "Ultra link"           },
157     {ARPHRD_SMDS,     "SMDS"                 },
158     {ARPHRD_DLCI,     "Frame Relay DLCI"     },
159     {ARPHRD_ATM,      "ATM"                  },
160     {ARPHRD_HDLC,     "HDLC"                 },
161     {ARPHRD_FIBREC,   "Fibre Channel"        },
162     {ARPHRD_ATM2225,  "ATM (RFC 2225)"       },
163     {ARPHRD_SERIAL,   "Serial Line"          },
164     {ARPHRD_ATM2,     "ATM"                  },
165     {ARPHRD_MS188220, "MIL-STD-188-220"      },
166     {ARPHRD_METRICOM, "Metricom STRIP"       },
167     {ARPHRD_IEEE1394, "IEEE 1394.1995"       },
168     {ARPHRD_MAPOS,    "MAPOS"                },
169     {ARPHRD_TWINAX,   "Twinaxial"            },
170     {ARPHRD_EUI_64,   "EUI-64"               },
171     {0,                NULL                  } };
172
173     return val_to_str(hwtype, hrd_vals, fmt);
174 }
175
176 /* Offsets of fields within an ARP packet. */
177 #define AR_HRD          0
178 #define AR_PRO          2
179 #define AR_HLN          4
180 #define AR_PLN          5
181 #define AR_OP           6
182
183 void
184 dissect_arp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
185   guint16     ar_hrd;
186   guint16     ar_pro;
187   guint8      ar_hln;
188   guint8      ar_pln;
189   guint16     ar_op;
190   GtkWidget   *arp_tree, *ti;
191   gchar       *op_str;
192   int         sha_offset, spa_offset, tha_offset, tpa_offset;
193   gchar       *sha_str, *spa_str, *tha_str, *tpa_str;
194   static const value_string op_vals[] = {
195     {ARPOP_REQUEST,  "ARP request" },
196     {ARPOP_REPLY,    "ARP reply"   },
197     {ARPOP_RREQUEST, "RARP request"},
198     {ARPOP_RREPLY,   "RARP reply"  },
199     {0,              NULL          } };
200
201   /* To do: Check for {cap len,pkt len} < struct len */
202   ar_hrd = pntohs(&pd[offset + AR_HRD]);
203   ar_pro = pntohs(&pd[offset + AR_PRO]);
204   ar_hln = (guint8) pd[offset + AR_HLN];
205   ar_pln = (guint8) pd[offset + AR_PLN];
206   ar_op  = pntohs(&pd[offset + AR_OP]);
207
208   /* Extract the addresses.  */
209   sha_offset = offset + 8;
210   sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd);
211   spa_offset = sha_offset + ar_hln;
212   spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_pln, ar_pro);
213   tha_offset = spa_offset + ar_pln;
214   tha_str = arphrdaddr_to_str((guint8 *) &pd[tha_offset], ar_hln, ar_hrd);
215   tpa_offset = tha_offset + ar_hln;
216   tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_pln, ar_pro);
217   
218   if (check_col(fd, COL_PROTOCOL)) {
219     if ((op_str = match_strval(ar_op, op_vals)))
220       col_add_str(fd, COL_PROTOCOL, op_str);
221     else
222       col_add_str(fd, COL_PROTOCOL, "ARP");
223   }
224
225   if (check_col(fd, COL_INFO)) {
226     switch (ar_op) {
227       case ARPOP_REQUEST:
228         col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s",
229           tpa_str, spa_str);
230         break;
231       case ARPOP_REPLY:
232         col_add_fstr(fd, COL_INFO, "%s is at %s", spa_str, sha_str);
233         break;
234       case ARPOP_RREQUEST:
235         col_add_fstr(fd, COL_INFO, "Who is %s?  Tell %s",
236           tha_str, sha_str);
237         break;
238       case ARPOP_RREPLY:
239         col_add_fstr(fd, COL_INFO, "%s is at %s", sha_str, spa_str);
240         break;
241       default:
242         col_add_fstr(fd, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op);
243         break;
244     }
245   }
246
247   if (tree) {
248     if ((op_str = match_strval(ar_op, op_vals)))
249       ti = add_item_to_tree(GTK_WIDGET(tree), offset, 8 + 2*ar_hln + 2*ar_pln,
250         op_str);
251     else
252       ti = add_item_to_tree(GTK_WIDGET(tree), offset, 8 + 2*ar_hln + 2*ar_pln,
253         "Unknown ARP (opcode 0x%04x)", ar_op);
254     arp_tree = gtk_tree_new();
255     add_subtree(ti, arp_tree, ETT_ARP);
256     add_item_to_tree(arp_tree, offset + AR_HRD, 2,
257       "Hardware type: %s", arphrdtype_to_str(ar_hrd, "Unknown (0x%04x)"));
258     add_item_to_tree(arp_tree, offset + AR_PRO, 2,
259       "Protocol type: %s", ethertype_to_str(ar_pro, "Unknown (0x%04x)"));
260     add_item_to_tree(arp_tree, offset + AR_HLN, 1,
261       "Hardware size: %d", ar_hln);
262     add_item_to_tree(arp_tree, offset + AR_PLN, 1,
263       "Protocol size: %d", ar_pln);
264     add_item_to_tree(arp_tree, offset + AR_OP,  2,
265       "Opcode: 0x%04x (%s)", ar_op, op_str ? op_str : "Unknown");
266     add_item_to_tree(arp_tree, sha_offset, ar_hln,
267       "Sender hardware address: %s", sha_str);
268     add_item_to_tree(arp_tree, spa_offset, ar_pln,
269       "Sender protocol address: %s", spa_str);
270     add_item_to_tree(arp_tree, tha_offset, ar_hln,
271       "Target hardware address: %s", tha_str);
272     add_item_to_tree(arp_tree, tpa_offset, ar_pln,
273       "Target protocol address: %s", tpa_str);
274   }
275 }