Add summary-vs-detail radio buttons to the print dialog box; detail
[obnox/wireshark/wip.git] / packet.c
1 /* packet.c
2  * Routines for packet disassembly
3  *
4  * $Id: packet.c,v 1.42 1999/09/12 06:11:36 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 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37
38 #ifdef HAVE_WINSOCK_H
39 #include <winsock.h>
40 #endif
41
42 #include <glib.h>
43
44 #include <stdio.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <time.h>
49
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
52 #endif
53
54 #ifdef HAVE_NETINET_IN_H
55 # include <netinet/in.h>
56 #endif
57
58 #include "packet.h"
59 #include "file.h"
60
61 extern capture_file  cf;
62
63 int proto_frame = -1;
64 int hf_frame_arrival_time = -1;
65 int hf_frame_time_delta = -1;
66 int hf_frame_number = -1;
67 int hf_frame_packet_len = -1;
68 int hf_frame_capture_len = -1;
69
70 gchar *
71 ether_to_str(const guint8 *ad) {
72   static gchar  str[3][18];
73   static gchar *cur;
74   gchar        *p;
75   int          i;
76   guint32      octet;
77   static const gchar hex_digits[16] = "0123456789abcdef";
78
79   if (cur == &str[0][0]) {
80     cur = &str[1][0];
81   } else if (cur == &str[1][0]) {  
82     cur = &str[2][0];
83   } else {  
84     cur = &str[0][0];
85   }
86   p = &cur[18];
87   *--p = '\0';
88   i = 5;
89   for (;;) {
90     octet = ad[i];
91     *--p = hex_digits[octet&0xF];
92     octet >>= 4;
93     *--p = hex_digits[octet&0xF];
94     if (i == 0)
95       break;
96     *--p = ':';
97     i--;
98   }
99   return p;
100 }
101
102 gchar *
103 ip_to_str(const guint8 *ad) {
104   static gchar  str[3][16];
105   static gchar *cur;
106   gchar        *p;
107   int           i;
108   guint32       octet;
109   guint32       digit;
110
111   if (cur == &str[0][0]) {
112     cur = &str[1][0];
113   } else if (cur == &str[1][0]) {  
114     cur = &str[2][0];
115   } else {  
116     cur = &str[0][0];
117   }
118   p = &cur[16];
119   *--p = '\0';
120   i = 3;
121   for (;;) {
122     octet = ad[i];
123     *--p = (octet%10) + '0';
124     octet /= 10;
125     digit = octet%10;
126     octet /= 10;
127     if (digit != 0 || octet != 0)
128       *--p = digit + '0';
129     if (octet != 0)
130       *--p = octet + '0';
131     if (i == 0)
132       break;
133     *--p = '.';
134     i--;
135   }
136   return p;
137 }
138
139 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
140 #define COMMA(do_it)    ((do_it) ? ", " : "")
141
142 gchar *
143 time_secs_to_str(guint32 time)
144 {
145   static gchar  str[3][8+1+4+2+2+5+2+2+7+2+2+7+1];
146   static gchar *cur, *p;
147   int hours, mins, secs;
148   int do_comma;
149
150   if (cur == &str[0][0]) {
151     cur = &str[1][0];
152   } else if (cur == &str[1][0]) {  
153     cur = &str[2][0];
154   } else {  
155     cur = &str[0][0];
156   }
157
158   secs = time % 60;
159   time /= 60;
160   mins = time % 60;
161   time /= 60;
162   hours = time % 24;
163   time /= 24;
164
165   p = cur;
166   if (time != 0) {
167     sprintf(p, "%u day%s", time, PLURALIZE(time));
168     p += strlen(p);
169     do_comma = 1;
170   } else
171     do_comma = 0;
172   if (hours != 0) {
173     sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
174     p += strlen(p);
175     do_comma = 1;
176   } else
177     do_comma = 0;
178   if (mins != 0) {
179     sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
180     p += strlen(p);
181     do_comma = 1;
182   } else
183     do_comma = 0;
184   if (secs != 0)
185     sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
186   return cur;
187 }
188
189 /* Max string length for displaying byte string.  */
190 #define MAX_BYTE_STR_LEN        16
191
192 /* Turn an array of bytes into a string showing the bytes in hex. */
193 gchar *
194 bytes_to_str(const guint8 *bd, int bd_len) {
195   static gchar  str[3][MAX_BYTE_STR_LEN+3+1];
196   static gchar *cur;
197   gchar        *p;
198   int           len;
199   static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
200                                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
201
202   if (cur == &str[0][0]) {
203     cur = &str[1][0];
204   } else if (cur == &str[1][0]) {  
205     cur = &str[2][0];
206   } else {  
207     cur = &str[0][0];
208   }
209   p = cur;
210   len = MAX_BYTE_STR_LEN;
211   while (bd_len > 0 && len > 0) {
212     *p++ = hex[(*bd) >> 4];
213     *p++ = hex[(*bd) & 0xF];
214     len -= 2;
215     bd++;
216     bd_len--;
217   }
218   if (bd_len != 0) {
219     /* Note that we're not showing the full string.  */
220     *p++ = '.';
221     *p++ = '.';
222     *p++ = '.';
223   }
224   *p = '\0';
225   return cur;
226 }
227
228 static const char *mon_names[12] = {
229         "Jan",
230         "Feb",
231         "Mar",
232         "Apr",
233         "May",
234         "Jun",
235         "Jul",
236         "Aug",
237         "Sep",
238         "Oct",
239         "Nov",
240         "Dec"
241 };
242
243 gchar *
244 abs_time_to_str(struct timeval *abs_time)
245 {
246         struct tm *tmp;
247         static gchar *cur;
248         static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+4+1 + 5 /* extra */];
249
250         if (cur == &str[0][0]) {
251                 cur = &str[1][0];
252         } else if (cur == &str[1][0]) {
253                 cur = &str[2][0];
254         } else {
255                 cur = &str[0][0];
256         }
257
258         tmp = localtime(&abs_time->tv_sec);
259         sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%04ld",
260             mon_names[tmp->tm_mon],
261             tmp->tm_mday,
262             tmp->tm_year + 1900,
263             tmp->tm_hour,
264             tmp->tm_min,
265             tmp->tm_sec,
266             (long)abs_time->tv_usec/100);
267
268         return cur;
269 }
270
271 gchar *
272 rel_time_to_str(struct timeval *rel_time)
273 {
274         static gchar *cur;
275         static char str[3][10+1+6+1];
276
277         if (cur == &str[0][0]) {
278                 cur = &str[1][0];
279         } else if (cur == &str[1][0]) {
280                 cur = &str[2][0];
281         } else {
282                 cur = &str[0][0];
283         }
284
285         sprintf(cur, "%ld.%06ld", (long)rel_time->tv_sec,
286                 (long)rel_time->tv_usec);
287
288         return cur;
289 }
290
291 /*
292  * Given a pointer into a data buffer, and to the end of the buffer,
293  * find the end of the (putative) line at that position in the data
294  * buffer.
295  * Return a pointer to the EOL character(s) in "*eol".
296  */
297 const u_char *
298 find_line_end(const u_char *data, const u_char *dataend, const u_char **eol)
299 {
300   const u_char *lineend;
301
302   lineend = memchr(data, '\n', dataend - data);
303   if (lineend == NULL) {
304     /*
305      * No LF - line is probably continued in next TCP segment.
306      */
307     lineend = dataend;
308     *eol = dataend;
309   } else {
310     /*
311      * Is the LF at the beginning of the line?
312      */
313     if (lineend > data) {
314       /*
315        * No - is it preceded by a carriage return?
316        * (Perhaps it's supposed to be, but that's not guaranteed....)
317        */
318       if (*(lineend - 1) == '\r') {
319         /*
320          * Yes.  The EOL starts with the CR.
321          */
322         *eol = lineend - 1;
323       } else {
324         /*
325          * No.  The EOL starts with the LF.
326          */
327         *eol = lineend;
328
329         /*
330          * I seem to remember that we once saw lines ending with LF-CR
331          * in an HTTP request or response, so check if it's *followed*
332          * by a carriage return.
333          */
334         if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
335           /*
336            * It's <non-LF><LF><CR>; say it ends with the CR.
337            */
338           lineend++;
339         }
340       }
341     }
342
343     /*
344      * Point to the character after the last character.
345      */
346     lineend++;
347   }
348   return lineend;
349 }
350
351 #define MAX_COLUMNS_LINE_DETAIL 62
352
353 /*
354  * Get the length of the next token in a line, and the beginning of the
355  * next token after that (if any).
356  * Return 0 if there is no next token.
357  */
358 int
359 get_token_len(const u_char *linep, const u_char *lineend,
360               const u_char **next_token)
361 {
362   const u_char *tokenp;
363   int token_len;
364
365   tokenp = linep;
366   
367   /*
368    * Search for a blank, a CR or an LF, or the end of the buffer.
369    */
370   while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
371       linep++;
372   token_len = linep - tokenp;
373
374   /*
375    * Skip trailing blanks.
376    */
377   while (linep < lineend && *linep == ' ')
378     linep++;
379
380   *next_token = linep;
381
382   return token_len;
383 }
384
385 /*
386  * Given a string, generate a string from it that shows non-printable
387  * characters as C-style escapes, and return a pointer to it.
388  */
389 gchar *
390 format_text(const u_char *string, int len)
391 {
392   static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
393   gchar *fmtbufp;
394   int column;
395   const u_char *stringend = string + len;
396   u_char c;
397   int i;
398
399   column = 0;
400   fmtbufp = &fmtbuf[0];
401   while (string < stringend) {
402     if (column >= MAX_COLUMNS_LINE_DETAIL) {
403       /*
404        * Put "..." and quit.
405        */
406       strcpy(fmtbufp, " ...");
407       break;
408     }
409     c = *string++;
410     if (isprint(c)) {
411       *fmtbufp++ = c;
412       column++;
413     } else {
414       *fmtbufp++ =  '\\';
415       column++;
416       switch (c) {
417
418       case '\\':
419         *fmtbufp++ = '\\';
420         column++;
421         break;
422
423       case '\a':
424         *fmtbufp++ = 'a';
425         column++;
426         break;
427
428       case '\b':
429         *fmtbufp++ = 'b';
430         column++;
431         break;
432
433       case '\f':
434         *fmtbufp++ = 'f';
435         column++;
436         break;
437
438       case '\n':
439         *fmtbufp++ = 'n';
440         column++;
441         break;
442
443       case '\r':
444         *fmtbufp++ = 'r';
445         column++;
446         break;
447
448       case '\t':
449         *fmtbufp++ = 't';
450         column++;
451         break;
452
453       case '\v':
454         *fmtbufp++ = 'v';
455         column++;
456         break;
457
458       default:
459         i = (c>>6)&03;
460         *fmtbufp++ = i + '0';
461         column++;
462         i = (c>>3)&07;
463         *fmtbufp++ = i + '0';
464         column++;
465         i = (c>>0)&07;
466         *fmtbufp++ = i + '0';
467         column++;
468         break;
469       }
470     }
471   }
472   *fmtbufp = '\0';
473   return fmtbuf;
474 }
475
476
477 /* Tries to match val against each element in the value_string array vs.
478    Returns the associated string ptr on a match.
479    Formats val with fmt, and returns the resulting string, on failure. */
480 gchar*
481 val_to_str(guint32 val, const value_string *vs, const char *fmt) {
482   gchar *ret;
483   static gchar  str[3][64];
484   static gchar *cur;
485
486   ret = match_strval(val, vs);
487   if (ret != NULL)
488     return ret;
489   if (cur == &str[0][0]) {
490     cur = &str[1][0];
491   } else if (cur == &str[1][0]) {  
492     cur = &str[2][0];
493   } else {  
494     cur = &str[0][0];
495   }
496   snprintf(cur, 64, fmt, val);
497   return cur;
498 }
499
500 /* Tries to match val against each element in the value_string array vs.
501    Returns the associated string ptr on a match, or NULL on failure. */
502 gchar*
503 match_strval(guint32 val, const value_string *vs) {
504   gint i = 0;
505   
506   while (vs[i].strptr) {
507     if (vs[i].value == val)
508       return(vs[i].strptr);
509     i++;
510   }
511
512   return(NULL);
513 }
514
515 /* Generate, into "buf", a string showing the bits of a bitfield.
516    Return a pointer to the character after that string. */
517 static char *
518 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
519 {
520   int i;
521   guint32 bit;
522   char *p;
523
524   i = 0;
525   p = buf;
526   bit = 1 << (width - 1);
527   for (;;) {
528     if (mask & bit) {
529       /* This bit is part of the field.  Show its value. */
530       if (val & bit)
531         *p++ = '1';
532       else
533         *p++ = '0';
534     } else {
535       /* This bit is not part of the field. */
536       *p++ = '.';
537     }
538     bit >>= 1;
539     i++;
540     if (i >= width)
541       break;
542     if (i % 4 == 0)
543       *p++ = ' ';
544   }
545   strcpy(p, " = ");
546   p += 3;
547   return p;
548 }
549
550 /* Generate a string describing a Boolean bitfield (a one-bit field that
551    says something is either true of false). */
552 const char *
553 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
554     const char *truedesc, const char *falsedesc)
555 {
556   static char buf[1025];
557   char *p;
558
559   p = decode_bitfield_value(buf, val, mask, width);
560   if (val & mask)
561     strcpy(p, truedesc);
562   else
563     strcpy(p, falsedesc);
564   return buf;
565 }
566
567 /* Generate a string describing an enumerated bitfield (an N-bit field
568    with various specific values having particular names). */
569 const char *
570 decode_enumerated_bitfield(guint32 val, guint32 mask, int width,
571     const value_string *tab, const char *fmt)
572 {
573   static char buf[1025];
574   char *p;
575
576   p = decode_bitfield_value(buf, val, mask, width);
577   sprintf(p, fmt, val_to_str(val & mask, tab, "Unknown"));
578   return buf;
579 }
580
581 /* Generate a string describing a numeric bitfield (an N-bit field whose
582    value is just a number). */
583 const char *
584 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
585     const char *fmt)
586 {
587   static char buf[1025];
588   char *p;
589   int shift = 0;
590
591   /* Compute the number of bits we have to shift the bitfield right
592      to extract its value. */
593   while ((mask & (1<<shift)) == 0)
594     shift++;
595
596   p = decode_bitfield_value(buf, val, mask, width);
597   sprintf(p, fmt, (val & mask) >> shift);
598   return buf;
599 }
600
601 /* Checks to see if a particular packet information element is needed for
602    the packet list */
603 gint
604 check_col(frame_data *fd, gint el) {
605   int i;
606
607   if (fd->cinfo) {
608     for (i = 0; i < fd->cinfo->num_cols; i++) {
609       if (fd->cinfo->fmt_matx[i][el])
610         return TRUE;
611     }
612   }
613   return FALSE;
614 }
615
616 /* Adds a vararg list to a packet info string. */
617 void
618 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
619   va_list    ap;
620   int        i;
621   
622   va_start(ap, format);
623   for (i = 0; i < fd->cinfo->num_cols; i++) {
624     if (fd->cinfo->fmt_matx[i][el])
625       vsnprintf(fd->cinfo->col_data[i], COL_MAX_LEN, format, ap);
626   }
627 }
628
629 void
630 col_add_str(frame_data *fd, gint el, const gchar* str) {
631   int i;
632   
633   for (i = 0; i < fd->cinfo->num_cols; i++) {
634     if (fd->cinfo->fmt_matx[i][el]) {
635       strncpy(fd->cinfo->col_data[i], str, COL_MAX_LEN);
636       fd->cinfo->col_data[i][COL_MAX_LEN - 1] = 0;
637     }
638   }
639 }
640
641 /* this routine checks the frame type from the cf structure */
642 void
643 dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
644 {
645         proto_tree *fh_tree;
646         proto_item *ti;
647         struct timeval tv;
648
649         /* Put in frame header information. */
650         if (tree) {
651           ti = proto_tree_add_item_format(tree, proto_frame, 0, fd->cap_len,
652             NULL, "Frame (%d on wire, %d captured)", fd->pkt_len, fd->cap_len);
653
654           fh_tree = proto_item_add_subtree(ti, ETT_FRAME);
655
656           tv.tv_sec = fd->abs_secs;
657           tv.tv_usec = fd->abs_usecs;
658
659           proto_tree_add_item(fh_tree, hf_frame_arrival_time,
660                 0, 0, &tv);
661
662           tv.tv_sec = fd->del_secs;
663           tv.tv_usec = fd->del_usecs;
664
665           proto_tree_add_item(fh_tree, hf_frame_time_delta,
666                 0, 0, &tv);
667
668           proto_tree_add_item(fh_tree, hf_frame_number,
669                 0, 0, fd->num);
670
671           proto_tree_add_item_format(fh_tree, hf_frame_packet_len,
672                 0, 0, fd->pkt_len, "Packet Length: %d byte%s", fd->pkt_len,
673                 plurality(fd->pkt_len, "", "s"));
674                 
675           proto_tree_add_item_format(fh_tree, hf_frame_capture_len,
676                 0, 0, fd->cap_len, "Capture Length: %d byte%s", fd->cap_len,
677                 plurality(fd->cap_len, "", "s"));
678         }
679
680         /* Set the initial payload to the packet length, and the initial
681            captured payload to the capture length (other protocols may
682            reduce them if their headers say they're less). */
683         pi.len = fd->pkt_len;
684         pi.captured_len = fd->cap_len;
685
686         switch (fd->lnk_t) {
687                 case WTAP_ENCAP_ETHERNET :
688                         dissect_eth(pd, 0, fd, tree);
689                         break;
690                 case WTAP_ENCAP_FDDI :
691                         dissect_fddi(pd, fd, tree, FALSE);
692                         break;
693                 case WTAP_ENCAP_FDDI_BITSWAPPED :
694                         dissect_fddi(pd, fd, tree, TRUE);
695                         break;
696                 case WTAP_ENCAP_TR :
697                         dissect_tr(pd, 0, fd, tree);
698                         break;
699                 case WTAP_ENCAP_NULL :
700                         dissect_null(pd, fd, tree);
701                         break;
702                 case WTAP_ENCAP_PPP :
703                         dissect_ppp(pd, fd, tree);
704                         break;
705                 case WTAP_ENCAP_LAPB :
706                         dissect_lapb(pd, fd, tree);
707                         break;
708                 case WTAP_ENCAP_RAW_IP :
709                         dissect_raw(pd, fd, tree);
710                         break;
711                 case WTAP_ENCAP_LINUX_ATM_CLIP :
712                         dissect_clip(pd, fd, tree);
713                         break;
714                 case WTAP_ENCAP_ATM_SNIFFER :
715                         dissect_atm(pd, fd, tree);
716                         break;
717                 case WTAP_ENCAP_ASCEND :
718                         dissect_ascend(pd, fd, tree);
719                         break;
720         }
721 }
722
723 void
724 proto_register_frame(void)
725 {
726         static hf_register_info hf[] = {
727                 { &hf_frame_arrival_time,
728                 { "Arrival Time",               "frame.time", FT_ABSOLUTE_TIME, NULL }},
729
730                 { &hf_frame_time_delta,
731                 { "Time delta from previous packet",    "frame.time_delta", FT_RELATIVE_TIME, NULL }},
732
733                 { &hf_frame_number,
734                 { "Frame Number",               "frame.number", FT_UINT32, NULL }},
735
736                 { &hf_frame_packet_len,
737                 { "Total Frame Length",         "frame.pkt_len", FT_UINT32, NULL }},
738
739                 { &hf_frame_capture_len,
740                 { "Capture Frame Length",       "frame.cap_len", FT_UINT32, NULL }}
741         };
742
743         proto_frame = proto_register_protocol("Frame", "frame");
744         proto_register_field_array(proto_frame, hf, array_length(hf));
745 }