0c4a5c6d75797119cf04aa36e6a377c21b1b97cc
[obnox/wireshark/wip.git] / packet.c
1 /* packet.c
2  * Routines for packet disassembly
3  *
4  * $Id: packet.c,v 1.12 1998/11/18 03:01:38 gerald 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 <gtk/gtk.h>
35
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <time.h>
41
42 #ifdef NEED_SNPRINTF_H
43 # include "snprintf.h"
44 #endif
45
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
49
50 #include "ethereal.h"
51 #include "packet.h"
52 #include "etypes.h"
53 #include "file.h"
54
55 extern GtkWidget    *byte_view;
56 extern GdkFont      *m_r_font, *m_b_font;
57 extern capture_file  cf;
58
59 gchar *
60 ether_to_str(guint8 *ad) {
61   static gchar  str[3][18];
62   static gchar *cur;
63
64   if (cur == &str[0][0]) {
65     cur = &str[1][0];
66   } else if (cur == &str[1][0]) {  
67     cur = &str[2][0];
68   } else {  
69     cur = &str[0][0];
70   }
71   sprintf(cur, "%02x:%02x:%02x:%02x:%02x:%02x", ad[0], ad[1], ad[2],
72     ad[3], ad[4], ad[5]);
73   return cur;
74 }
75
76 gchar *
77 ip_to_str(guint8 *ad) {
78   static gchar  str[3][16];
79   static gchar *cur;
80
81   if (cur == &str[0][0]) {
82     cur = &str[1][0];
83   } else if (cur == &str[1][0]) {  
84     cur = &str[2][0];
85   } else {  
86     cur = &str[0][0];
87   }
88   sprintf(cur, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
89   return cur;
90 }
91
92 void
93 packet_hex_print(GtkText *bv, guchar *pd, gint len, gint bstart, gint blen) {
94   gint     i = 0, j, k, cur;
95   gchar    line[128], hexchars[] = "0123456789abcdef";
96   GdkFont *cur_font, *new_font;
97   
98   while (i < len) {
99     /* Print the line number */
100     sprintf(line, "%04x  ", i);
101     gtk_text_insert(bv, m_r_font, NULL, NULL, line, -1);
102     /* Do we start in bold? */
103     cur_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
104     j   = i;
105     k   = i + BYTE_VIEW_WIDTH;
106     cur = 0;
107     /* Print the hex bit */
108     while (i < k) {
109       if (i < len) {
110         line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
111         line[cur++] = hexchars[pd[i] & 0x0f];
112       } else {
113         line[cur++] = ' '; line[cur++] = ' ';
114       }
115       line[cur++] = ' ';
116       i++;
117       /* Did we cross a bold/plain boundary? */
118       new_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
119       if (cur_font != new_font) {
120         gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
121         cur_font = new_font;
122         cur = 0;
123       }
124     }
125     line[cur++] = ' ';
126     gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
127     cur = 0;
128     i = j;
129     /* Print the ASCII bit */
130     cur_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
131     while (i < k) {
132       if (i < len) {
133         line[cur++] = (isgraph(pd[i])) ? pd[i] : '.';
134       } else {
135         line[cur++] = ' ';
136       }
137       i++;
138       /* Did we cross a bold/plain boundary? */
139       new_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
140       if (cur_font != new_font) {
141         gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
142         cur_font = new_font;
143         cur = 0;
144       }
145     }
146     line[cur++] = '\n';
147     line[cur]   = '\0';
148     gtk_text_insert(bv, cur_font, NULL, NULL, line, -1);
149   }
150 }
151
152 GtkWidget *
153 add_item_to_tree(GtkWidget *tree, gint start, gint len,
154   gchar *format, ...) {
155   GtkWidget *ti;
156   va_list    ap;
157   gchar      label_str[256];
158   
159   va_start(ap, format);
160   vsnprintf(label_str, 256, format, ap);
161   ti = gtk_tree_item_new_with_label(label_str);
162   gtk_object_set_data(GTK_OBJECT(ti), E_TREEINFO_START_KEY, (gpointer) start);
163   gtk_object_set_data(GTK_OBJECT(ti), E_TREEINFO_LEN_KEY, (gpointer) len);
164   gtk_tree_append(GTK_TREE(tree), ti);
165   gtk_widget_show(ti);
166
167   return ti;
168 }
169
170 void
171 add_subtree(GtkWidget *ti, GtkWidget *subtree, gint idx) {
172   static gint tree_type[NUM_TREE_TYPES];
173
174   gtk_tree_item_set_subtree(GTK_TREE_ITEM(ti), subtree);
175   if (tree_type[idx])
176     gtk_tree_item_expand(GTK_TREE_ITEM(ti));
177   gtk_signal_connect(GTK_OBJECT(ti), "expand", (GtkSignalFunc) expand_tree,
178     (gpointer) &tree_type[idx]);
179   gtk_signal_connect(GTK_OBJECT(ti), "collapse", (GtkSignalFunc) collapse_tree,
180     (gpointer) &tree_type[idx]);
181 }
182
183 void
184 expand_tree(GtkWidget *w, gpointer data) {
185   gint *val = (gint *) data;
186   *val = 1;
187 }
188
189 void
190 collapse_tree(GtkWidget *w, gpointer data) {
191   gint *val = (gint *) data;
192   *val = 0;
193 }
194
195 /* Tries to match val against each element in the value_string array vs.
196    Returns the associated string ptr on a match.
197    Formats val with fmt, and returns the resulting string, on failure. */
198 gchar*
199 val_to_str(guint32 val, const value_string *vs, const char *fmt) {
200   gchar *ret;
201   static gchar  str[3][64];
202   static gchar *cur;
203
204   ret = match_strval(val, vs);
205   if (ret != NULL)
206     return ret;
207   if (cur == &str[0][0]) {
208     cur = &str[1][0];
209   } else if (cur == &str[1][0]) {  
210     cur = &str[2][0];
211   } else {  
212     cur = &str[0][0];
213   }
214   snprintf(cur, 64, fmt, val);
215   return cur;
216 }
217
218 /* Tries to match val against each element in the value_string array vs.
219    Returns the associated string ptr on a match, or NULL on failure. */
220 gchar*
221 match_strval(guint32 val, const value_string *vs) {
222   gint i = 0;
223   
224   while (vs[i].strptr) {
225     if (vs[i].value == val)
226       return(vs[i].strptr);
227     i++;
228   }
229   
230   return(NULL);
231 }
232
233 /* Checks to see if a particular packet information element is needed for
234    the packet list */
235 gint
236 check_col(frame_data *fd, gint el) {
237   int i;
238   
239   if (fd->cinfo) {
240     for (i = 0; i < fd->cinfo->num_cols; i++) {
241       if (fd->cinfo->fmt_matx[i][el])
242         return TRUE;
243     }
244   }
245   return FALSE;
246 }
247
248 /* To do: Add check_col checks to the pinfo_add* routines */
249
250 /* Adds a vararg list to a packet info string. */
251 void
252 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
253   va_list    ap;
254   int        i;
255   
256   va_start(ap, format);
257   for (i = 0; i < fd->cinfo->num_cols; i++) {
258     if (fd->cinfo->fmt_matx[i][el])
259       vsnprintf(fd->cinfo->col_data[i], COL_MAX_LEN, format, ap);
260   }
261 }
262
263 void
264 col_add_str(frame_data *fd, gint el, gchar* str) {
265   int i;
266   
267   for (i = 0; i < fd->cinfo->num_cols; i++) {
268     if (fd->cinfo->fmt_matx[i][el]) {
269       strncpy(fd->cinfo->col_data[i], str, COL_MAX_LEN);
270       fd->cinfo->col_data[i][COL_MAX_LEN - 1] = 0;
271     }
272   }
273 }
274
275 static const char *mon_names[12] = {
276         "Jan",
277         "Feb",
278         "Mar",
279         "Apr",
280         "May",
281         "Jun",
282         "Jul",
283         "Aug",
284         "Sep",
285         "Oct",
286         "Nov",
287         "Dec"
288 };
289
290 /* this routine checks the frame type from the cf structure */
291 void
292 dissect_packet(const u_char *pd, guint32 ts_secs, guint32 ts_usecs,
293   frame_data *fd, GtkTree *tree)
294 {
295         GtkWidget *fh_tree, *ti;
296         struct tm *tmp;
297         time_t then;
298
299         /* Put in frame header information. */
300         if (check_col(fd, COL_ABS_TIME)) {
301           if (timestamp_type == ABSOLUTE) {
302             then = fd->secs;
303             tmp = localtime(&then);
304             col_add_fstr(fd, COL_ABS_TIME, "%02d:%02d:%02d.%04ld",
305               tmp->tm_hour,
306               tmp->tm_min,                                                      
307               tmp->tm_sec,
308               (long)fd->usecs/100);
309           }
310         }
311         if (check_col(fd, COL_REL_TIME)) {
312             col_add_fstr(fd, COL_REL_TIME, "%d.%06d", ts_secs, ts_usecs);
313         }
314
315         if (tree) {
316           ti = add_item_to_tree(GTK_WIDGET(tree), 0, fd->cap_len,
317             "Frame (%d on wire, %d captured)",
318             fd->pkt_len, fd->cap_len);
319
320           fh_tree = gtk_tree_new();
321           add_subtree(ti, fh_tree, ETT_FRAME);
322           then = fd->secs;
323           tmp = localtime(&then);
324           add_item_to_tree(fh_tree, 0, 0,
325             "Frame arrived on %s %2d, %d %02d:%02d:%02d.%04ld",
326             mon_names[tmp->tm_mon],
327             tmp->tm_mday,
328             tmp->tm_year + 1900,
329             tmp->tm_hour,
330             tmp->tm_min,                                                      
331             tmp->tm_sec,
332             (long)fd->usecs/100);
333
334           add_item_to_tree(fh_tree, 0, 0, "Total frame length: %d bytes",
335             fd->pkt_len);
336           add_item_to_tree(fh_tree, 0, 0, "Capture frame length: %d bytes",
337             fd->cap_len);
338         }
339
340 #ifdef WITH_WIRETAP
341         switch (cf.lnk_t) {
342                 case WTAP_ENCAP_ETHERNET :
343                         dissect_eth(pd, fd, tree);
344                         break;
345                 case WTAP_ENCAP_FDDI :
346                         dissect_fddi(pd, fd, tree);
347                         break;
348                 case WTAP_ENCAP_TR :
349                         dissect_tr(pd, fd, tree);
350                         break;
351                 case WTAP_ENCAP_NONE :
352                         dissect_null(pd, fd, tree);
353                         break;
354                 case WTAP_ENCAP_PPP :
355                         dissect_ppp(pd, fd, tree);
356                         break;
357                 case WTAP_ENCAP_RAW_IP :
358                         dissect_raw(pd, fd, tree);
359                         break;
360         }
361 #else
362         switch (cf.lnk_t) {
363                 case DLT_EN10MB :
364                         dissect_eth(pd, fd, tree);
365                         break;
366                 case DLT_FDDI :
367                         dissect_fddi(pd, fd, tree);
368                         break;
369                 case DLT_IEEE802 :
370                         dissect_tr(pd, fd, tree);
371                         break;
372                 case DLT_NULL :
373                         dissect_null(pd, fd, tree);
374                         break;
375                 case DLT_PPP :
376                         dissect_ppp(pd, fd, tree);
377                         break;
378                 case DLT_RAW :
379                         dissect_raw(pd, fd, tree);
380                         break;
381         }
382 #endif
383 }