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