2 * Routines for packet disassembly
4 * $Id: packet.c,v 1.67 2000/03/26 06:57:40 sharpe Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
54 #ifdef HAVE_NETINET_IN_H
55 # include <netinet/in.h>
58 #ifdef HAVE_ARPA_INET_H
59 #include <arpa/inet.h>
62 #ifdef NEED_INET_V6DEFS_H
63 # include "inet_v6defs.h"
68 #include "timestamp.h"
71 #include "packet-ascend.h"
72 #include "packet-atalk.h"
73 #include "packet-atm.h"
74 #include "packet-clip.h"
75 #include "packet-eth.h"
76 #include "packet-fddi.h"
77 #include "packet-ipv6.h"
78 #include "packet-lapb.h"
79 #include "packet-lapd.h"
80 #include "packet-null.h"
81 #include "packet-ppp.h"
82 #include "packet-raw.h"
83 #include "packet-sna.h"
84 #include "packet-tr.h"
85 #include "packet-v120.h"
86 #include "packet-vines.h"
92 extern capture_file cf;
94 static int proto_frame = -1;
95 static int hf_frame_arrival_time = -1;
96 static int hf_frame_time_delta = -1;
97 static int hf_frame_number = -1;
98 static int hf_frame_packet_len = -1;
99 static int hf_frame_capture_len = -1;
101 static gint ett_frame = -1;
103 /* Wrapper for the most common case of asking
104 * for a string using a colon as the hex-digit separator.
107 ether_to_str(const guint8 *ad)
109 return ether_to_str_punct(ad, ':');
112 /* Places char punct in the string as the hex-digit separator.
113 * If punct is '\0', no punctuation is applied (and thus
114 * the resulting string is 5 bytes shorter)
117 ether_to_str_punct(const guint8 *ad, char punct) {
118 static gchar str[3][18];
123 static const gchar hex_digits[16] = "0123456789abcdef";
125 if (cur == &str[0][0]) {
127 } else if (cur == &str[1][0]) {
137 *--p = hex_digits[octet&0xF];
139 *--p = hex_digits[octet&0xF];
150 ip_to_str(const guint8 *ad) {
151 static gchar str[3][16];
158 if (cur == &str[0][0]) {
160 } else if (cur == &str[1][0]) {
170 *--p = (octet%10) + '0';
174 if (digit != 0 || octet != 0)
187 ip6_to_str(struct e_in6_addr *ad) {
188 #ifndef INET6_ADDRSTRLEN
189 #define INET6_ADDRSTRLEN 46
191 static gchar buf[INET6_ADDRSTRLEN];
193 inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf));
198 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
199 #define COMMA(do_it) ((do_it) ? ", " : "")
202 time_secs_to_str(guint32 time)
204 static gchar str[3][8+1+4+2+2+5+2+2+7+2+2+7+1];
205 static gchar *cur, *p;
206 int hours, mins, secs;
209 if (cur == &str[0][0]) {
211 } else if (cur == &str[1][0]) {
218 sprintf(cur, "0 time");
231 sprintf(p, "%u day%s", time, PLURALIZE(time));
237 sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
243 sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
249 sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
253 /* Max string length for displaying byte string. */
254 #define MAX_BYTE_STR_LEN 32
256 /* Turn an array of bytes into a string showing the bytes in hex. */
257 #define N_BYTES_TO_STR_STRINGS 6
259 bytes_to_str(const guint8 *bd, int bd_len) {
260 static gchar str[N_BYTES_TO_STR_STRINGS][MAX_BYTE_STR_LEN+3+1];
265 static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
266 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
269 if (cur_idx >= N_BYTES_TO_STR_STRINGS)
271 cur = &str[cur_idx][0];
273 len = MAX_BYTE_STR_LEN;
274 while (bd_len > 0 && len > 0) {
275 *p++ = hex[(*bd) >> 4];
276 *p++ = hex[(*bd) & 0xF];
282 /* Note that we're not showing the full string. */
291 static const char *mon_names[12] = {
307 abs_time_to_str(struct timeval *abs_time)
311 static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+4+1 + 5 /* extra */];
313 if (cur == &str[0][0]) {
315 } else if (cur == &str[1][0]) {
321 tmp = localtime(&abs_time->tv_sec);
322 sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%04ld",
323 mon_names[tmp->tm_mon],
329 (long)abs_time->tv_usec/100);
335 rel_time_to_str(struct timeval *rel_time)
338 static char str[3][10+1+6+1];
340 if (cur == &str[0][0]) {
342 } else if (cur == &str[1][0]) {
348 sprintf(cur, "%ld.%06ld", (long)rel_time->tv_sec,
349 (long)rel_time->tv_usec);
355 * Given a pointer into a data buffer, and to the end of the buffer,
356 * find the end of the (putative) line at that position in the data
358 * Return a pointer to the EOL character(s) in "*eol".
361 find_line_end(const u_char *data, const u_char *dataend, const u_char **eol)
363 const u_char *lineend;
365 lineend = memchr(data, '\n', dataend - data);
366 if (lineend == NULL) {
368 * No LF - line is probably continued in next TCP segment.
374 * Is the LF at the beginning of the line?
376 if (lineend > data) {
378 * No - is it preceded by a carriage return?
379 * (Perhaps it's supposed to be, but that's not guaranteed....)
381 if (*(lineend - 1) == '\r') {
383 * Yes. The EOL starts with the CR.
388 * No. The EOL starts with the LF.
393 * I seem to remember that we once saw lines ending with LF-CR
394 * in an HTTP request or response, so check if it's *followed*
395 * by a carriage return.
397 if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
399 * It's <non-LF><LF><CR>; say it ends with the CR.
407 * Point to the character after the last character.
414 #define MAX_COLUMNS_LINE_DETAIL 62
417 * Get the length of the next token in a line, and the beginning of the
418 * next token after that (if any).
419 * Return 0 if there is no next token.
422 get_token_len(const u_char *linep, const u_char *lineend,
423 const u_char **next_token)
425 const u_char *tokenp;
431 * Search for a blank, a CR or an LF, or the end of the buffer.
433 while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
435 token_len = linep - tokenp;
438 * Skip trailing blanks.
440 while (linep < lineend && *linep == ' ')
449 * Given a string, generate a string from it that shows non-printable
450 * characters as C-style escapes, and return a pointer to it.
453 format_text(const u_char *string, int len)
455 static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
458 const u_char *stringend = string + len;
463 fmtbufp = &fmtbuf[0];
464 while (string < stringend) {
465 if (column >= MAX_COLUMNS_LINE_DETAIL) {
467 * Put "..." and quit.
469 strcpy(fmtbufp, " ...");
524 *fmtbufp++ = i + '0';
527 *fmtbufp++ = i + '0';
530 *fmtbufp++ = i + '0';
541 /* Tries to match val against each element in the value_string array vs.
542 Returns the associated string ptr on a match.
543 Formats val with fmt, and returns the resulting string, on failure. */
545 val_to_str(guint32 val, const value_string *vs, const char *fmt) {
547 static gchar str[3][64];
550 ret = match_strval(val, vs);
553 if (cur == &str[0][0]) {
555 } else if (cur == &str[1][0]) {
560 snprintf(cur, 64, fmt, val);
564 /* Tries to match val against each element in the value_string array vs.
565 Returns the associated string ptr on a match, or NULL on failure. */
567 match_strval(guint32 val, const value_string *vs) {
570 while (vs[i].strptr) {
571 if (vs[i].value == val)
572 return(vs[i].strptr);
579 /* Generate, into "buf", a string showing the bits of a bitfield.
580 Return a pointer to the character after that string. */
582 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
590 bit = 1 << (width - 1);
593 /* This bit is part of the field. Show its value. */
599 /* This bit is not part of the field. */
614 /* Generate a string describing a Boolean bitfield (a one-bit field that
615 says something is either true of false). */
617 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
618 const char *truedesc, const char *falsedesc)
620 static char buf[1025];
623 p = decode_bitfield_value(buf, val, mask, width);
627 strcpy(p, falsedesc);
631 /* Generate a string describing an enumerated bitfield (an N-bit field
632 with various specific values having particular names). */
634 decode_enumerated_bitfield(guint32 val, guint32 mask, int width,
635 const value_string *tab, const char *fmt)
637 static char buf[1025];
640 p = decode_bitfield_value(buf, val, mask, width);
641 sprintf(p, fmt, val_to_str(val & mask, tab, "Unknown"));
645 /* Generate a string describing a numeric bitfield (an N-bit field whose
646 value is just a number). */
648 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
651 static char buf[1025];
655 /* Compute the number of bits we have to shift the bitfield right
656 to extract its value. */
657 while ((mask & (1<<shift)) == 0)
660 p = decode_bitfield_value(buf, val, mask, width);
661 sprintf(p, fmt, (val & mask) >> shift);
665 /* Checks to see if a particular packet information element is needed for
668 check_col(frame_data *fd, gint el) {
672 for (i = 0; i < fd->cinfo->num_cols; i++) {
673 if (fd->cinfo->fmt_matx[i][el])
680 /* Adds a vararg list to a packet info string. */
682 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
687 va_start(ap, format);
688 for (i = 0; i < fd->cinfo->num_cols; i++) {
689 if (fd->cinfo->fmt_matx[i][el]) {
691 max_len = COL_MAX_INFO_LEN;
693 max_len = COL_MAX_LEN;
694 vsnprintf(fd->cinfo->col_data[i], max_len, format, ap);
700 col_add_str(frame_data *fd, gint el, const gchar* str) {
704 for (i = 0; i < fd->cinfo->num_cols; i++) {
705 if (fd->cinfo->fmt_matx[i][el]) {
707 max_len = COL_MAX_INFO_LEN;
709 max_len = COL_MAX_LEN;
710 strncpy(fd->cinfo->col_data[i], str, max_len);
711 fd->cinfo->col_data[i][max_len - 1] = 0;
716 /* Appends a vararg list to a packet info string. */
718 col_append_fstr(frame_data *fd, gint el, gchar *format, ...) {
723 va_start(ap, format);
724 for (i = 0; i < fd->cinfo->num_cols; i++) {
725 if (fd->cinfo->fmt_matx[i][el]) {
726 len = strlen(fd->cinfo->col_data[i]);
728 max_len = COL_MAX_INFO_LEN;
730 max_len = COL_MAX_LEN;
731 vsnprintf(&fd->cinfo->col_data[i][len], max_len - len, format, ap);
737 col_append_str(frame_data *fd, gint el, gchar* str) {
741 for (i = 0; i < fd->cinfo->num_cols; i++) {
742 if (fd->cinfo->fmt_matx[i][el]) {
743 len = strlen(fd->cinfo->col_data[i]);
745 max_len = COL_MAX_LEN;
747 max_len = COL_MAX_INFO_LEN;
748 strncat(fd->cinfo->col_data[i], str, max_len - len);
749 fd->cinfo->col_data[i][max_len - 1] = 0;
754 /* To do: Add check_col checks to the col_add* routines */
757 col_set_abs_time(frame_data *fd, int col)
763 tmp = localtime(&then);
764 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
768 (long)fd->abs_usecs/100);
772 col_set_rel_time(frame_data *fd, int col)
774 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
779 col_set_delta_time(frame_data *fd, int col)
781 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
785 /* Add "command-line-specified" time.
786 XXX - this is called from "file.c" when the user changes the time
787 format they want for "command-line-specified" time; it's a bit ugly
788 that we have to export it, but if we go to a CList-like widget that
789 invokes callbacks to get the text for the columns rather than
790 requiring us to stuff the text into the widget from outside, we
791 might be able to clean this up. */
793 col_set_cls_time(frame_data *fd, int col)
795 switch (timestamp_type) {
797 col_set_abs_time(fd, col);
801 col_set_rel_time(fd, col);
805 col_set_delta_time(fd, col);
811 col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
814 struct e_in6_addr ipv6_addr;
815 struct atalk_ddp_addr ddp_addr;
816 struct sna_fid_type_4_addr sna_fid_type_4_addr;
818 switch (addr->type) {
822 strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
824 strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
828 memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
830 strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
832 strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
836 memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
838 strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
840 strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
844 strncpy(fd->cinfo->col_data[col],
845 ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
852 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]);
856 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X",
857 pntohs(&addr->data[0]));
860 case SNA_FID_TYPE_4_ADDR_LEN:
861 memcpy(&sna_fid_type_4_addr, addr->data, SNA_FID_TYPE_4_ADDR_LEN);
862 strncpy(fd->cinfo->col_data[col],
863 sna_fid_type_4_addr_to_str(&sna_fid_type_4_addr), COL_MAX_LEN);
869 memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
870 strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr),
875 strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]),
882 fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
886 col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
893 strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN);
895 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
900 strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN);
902 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
908 fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
912 fill_in_columns(frame_data *fd)
916 for (i = 0; i < fd->cinfo->num_cols; i++) {
917 switch (fd->cinfo->col_fmt[i]) {
920 snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
924 col_set_cls_time(fd, i);
928 col_set_abs_time(fd, i);
932 col_set_rel_time(fd, i);
936 col_set_delta_time(fd, i);
940 case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */
941 col_set_addr(fd, i, &pi.src, TRUE);
945 col_set_addr(fd, i, &pi.src, FALSE);
950 col_set_addr(fd, i, &pi.dl_src, TRUE);
953 case COL_UNRES_DL_SRC:
954 col_set_addr(fd, i, &pi.dl_src, FALSE);
957 case COL_DEF_NET_SRC:
958 case COL_RES_NET_SRC:
959 col_set_addr(fd, i, &pi.net_src, TRUE);
962 case COL_UNRES_NET_SRC:
963 col_set_addr(fd, i, &pi.net_src, FALSE);
967 case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */
968 col_set_addr(fd, i, &pi.dst, TRUE);
972 col_set_addr(fd, i, &pi.dst, FALSE);
977 col_set_addr(fd, i, &pi.dl_dst, TRUE);
980 case COL_UNRES_DL_DST:
981 col_set_addr(fd, i, &pi.dl_dst, FALSE);
984 case COL_DEF_NET_DST:
985 case COL_RES_NET_DST:
986 col_set_addr(fd, i, &pi.net_dst, TRUE);
989 case COL_UNRES_NET_DST:
990 col_set_addr(fd, i, &pi.net_dst, FALSE);
993 case COL_DEF_SRC_PORT:
994 case COL_RES_SRC_PORT: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
995 col_set_port(fd, i, pi.ptype, pi.srcport, TRUE);
998 case COL_UNRES_SRC_PORT:
999 col_set_port(fd, i, pi.ptype, pi.srcport, FALSE);
1002 case COL_DEF_DST_PORT:
1003 case COL_RES_DST_PORT: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
1004 col_set_port(fd, i, pi.ptype, pi.destport, TRUE);
1007 case COL_UNRES_DST_PORT:
1008 col_set_port(fd, i, pi.ptype, pi.destport, FALSE);
1011 case COL_PROTOCOL: /* currently done by dissectors */
1012 case COL_INFO: /* currently done by dissectors */
1015 case COL_PACKET_LENGTH:
1016 snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
1019 case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
1025 void blank_packetinfo(void)
1027 pi.dl_src.type = AT_NONE;
1028 pi.dl_dst.type = AT_NONE;
1029 pi.net_src.type = AT_NONE;
1030 pi.net_dst.type = AT_NONE;
1031 pi.src.type = AT_NONE;
1032 pi.dst.type = AT_NONE;
1039 /* Allow protocols to register "init" routines, which are called before
1040 we make a pass through a capture file and dissect all its packets
1041 (e.g., when we read in a new capture file, or run a "filter packets"
1042 or "colorize packets" pass over the current capture file). */
1043 static GSList *init_routines;
1046 register_init_routine(void (*func)(void))
1048 init_routines = g_slist_append(init_routines, func);
1051 /* Call all the registered "init" routines. */
1053 call_init_routine(gpointer routine, gpointer dummy)
1055 void (*func)(void) = routine;
1061 init_all_protocols(void)
1063 g_slist_foreach(init_routines, &call_init_routine, NULL);
1066 /* this routine checks the frame type from the cf structure */
1068 dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
1070 proto_tree *fh_tree;
1074 /* Put in frame header information. */
1076 ti = proto_tree_add_protocol_format(tree, proto_frame, 0, fd->cap_len,
1077 "Frame %u (%u on wire, %u captured)", fd->num,
1078 fd->pkt_len, fd->cap_len);
1080 fh_tree = proto_item_add_subtree(ti, ett_frame);
1082 tv.tv_sec = fd->abs_secs;
1083 tv.tv_usec = fd->abs_usecs;
1085 proto_tree_add_item(fh_tree, hf_frame_arrival_time,
1088 tv.tv_sec = fd->del_secs;
1089 tv.tv_usec = fd->del_usecs;
1091 proto_tree_add_item(fh_tree, hf_frame_time_delta,
1094 proto_tree_add_item(fh_tree, hf_frame_number,
1097 proto_tree_add_uint_format(fh_tree, hf_frame_packet_len,
1098 0, 0, fd->pkt_len, "Packet Length: %d byte%s", fd->pkt_len,
1099 plurality(fd->pkt_len, "", "s"));
1101 proto_tree_add_uint_format(fh_tree, hf_frame_capture_len,
1102 0, 0, fd->cap_len, "Capture Length: %d byte%s", fd->cap_len,
1103 plurality(fd->cap_len, "", "s"));
1108 /* Set the initial payload to the packet length, and the initial
1109 captured payload to the capture length (other protocols may
1110 reduce them if their headers say they're less). */
1111 pi.len = fd->pkt_len;
1112 pi.captured_len = fd->cap_len;
1114 switch (fd->lnk_t) {
1115 case WTAP_ENCAP_ETHERNET :
1116 dissect_eth(pd, 0, fd, tree);
1118 case WTAP_ENCAP_FDDI :
1119 dissect_fddi(pd, fd, tree, FALSE);
1121 case WTAP_ENCAP_FDDI_BITSWAPPED :
1122 dissect_fddi(pd, fd, tree, TRUE);
1124 case WTAP_ENCAP_TR :
1125 dissect_tr(pd, 0, fd, tree);
1127 case WTAP_ENCAP_NULL :
1128 dissect_null(pd, fd, tree);
1130 case WTAP_ENCAP_PPP :
1131 dissect_ppp(pd, fd, tree);
1133 case WTAP_ENCAP_LAPB :
1134 dissect_lapb(pd, fd, tree);
1136 case WTAP_ENCAP_RAW_IP :
1137 dissect_raw(pd, fd, tree);
1139 case WTAP_ENCAP_LINUX_ATM_CLIP :
1140 dissect_clip(pd, fd, tree);
1142 case WTAP_ENCAP_ATM_SNIFFER :
1143 dissect_atm(pd, fd, tree);
1145 case WTAP_ENCAP_ASCEND :
1146 dissect_ascend(pd, fd, tree);
1148 case WTAP_ENCAP_LAPD :
1149 dissect_lapd(pd, fd, tree);
1151 case WTAP_ENCAP_V120 :
1152 dissect_v120(pd, fd, tree);
1157 gint p_compare(gconstpointer a, gconstpointer b)
1160 if (((frame_proto_data *)a) -> proto > ((frame_proto_data *)b) -> proto)
1162 else if (((frame_proto_data *)a) -> proto == ((frame_proto_data *)b) -> proto)
1170 p_add_proto_data(frame_data *fd, int proto, void *proto_data)
1172 frame_proto_data *p1 = malloc(sizeof(frame_proto_data)); /* FIXME */
1174 g_assert(p1 != NULL);
1176 p1 -> proto = proto;
1177 p1 -> proto_data = proto_data;
1179 /* Allocate a frame_proto_data struct and then add it to the GSLIST */
1182 fd -> pfd = g_slist_insert_sorted(fd -> pfd,
1189 p_get_proto_data(frame_data *fd, int proto)
1197 p_rem_proto_data(frame_data *fd, int proto)
1204 proto_register_frame(void)
1206 static hf_register_info hf[] = {
1207 { &hf_frame_arrival_time,
1208 { "Arrival Time", "frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1211 { &hf_frame_time_delta,
1212 { "Time delta from previous packet", "frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL,
1217 { "Frame Number", "frame.number", FT_UINT32, BASE_DEC, NULL, 0x0,
1220 { &hf_frame_packet_len,
1221 { "Total Frame Length", "frame.pkt_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1224 { &hf_frame_capture_len,
1225 { "Capture Frame Length", "frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1228 static gint *ett[] = {
1232 proto_frame = proto_register_protocol("Frame", "frame");
1233 proto_register_field_array(proto_frame, hf, array_length(hf));
1234 proto_register_subtree_array(ett, array_length(ett));