2 * Routines for packet disassembly
4 * $Id: packet.c,v 1.69 2000/03/27 17:53:20 gram 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>
51 #ifdef NEED_SNPRINTF_H
52 # include "snprintf.h"
55 #ifdef HAVE_NETINET_IN_H
56 # include <netinet/in.h>
59 #ifdef HAVE_ARPA_INET_H
60 #include <arpa/inet.h>
63 #ifdef NEED_INET_V6DEFS_H
64 # include "inet_v6defs.h"
69 #include "timestamp.h"
72 #include "packet-ascend.h"
73 #include "packet-atalk.h"
74 #include "packet-atm.h"
75 #include "packet-clip.h"
76 #include "packet-eth.h"
77 #include "packet-fddi.h"
78 #include "packet-ipv6.h"
79 #include "packet-lapb.h"
80 #include "packet-lapd.h"
81 #include "packet-null.h"
82 #include "packet-ppp.h"
83 #include "packet-raw.h"
84 #include "packet-sna.h"
85 #include "packet-tr.h"
86 #include "packet-v120.h"
87 #include "packet-vines.h"
93 extern capture_file cf;
95 static int proto_frame = -1;
96 static int hf_frame_arrival_time = -1;
97 static int hf_frame_time_delta = -1;
98 static int hf_frame_number = -1;
99 static int hf_frame_packet_len = -1;
100 static int hf_frame_capture_len = -1;
102 static gint ett_frame = -1;
104 /* Wrapper for the most common case of asking
105 * for a string using a colon as the hex-digit separator.
108 ether_to_str(const guint8 *ad)
110 return ether_to_str_punct(ad, ':');
113 /* Places char punct in the string as the hex-digit separator.
114 * If punct is '\0', no punctuation is applied (and thus
115 * the resulting string is 5 bytes shorter)
118 ether_to_str_punct(const guint8 *ad, char punct) {
119 static gchar str[3][18];
124 static const gchar hex_digits[16] = "0123456789abcdef";
126 if (cur == &str[0][0]) {
128 } else if (cur == &str[1][0]) {
138 *--p = hex_digits[octet&0xF];
140 *--p = hex_digits[octet&0xF];
151 ip_to_str(const guint8 *ad) {
152 static gchar str[3][16];
159 if (cur == &str[0][0]) {
161 } else if (cur == &str[1][0]) {
171 *--p = (octet%10) + '0';
175 if (digit != 0 || octet != 0)
188 ip6_to_str(struct e_in6_addr *ad) {
189 #ifndef INET6_ADDRSTRLEN
190 #define INET6_ADDRSTRLEN 46
192 static gchar buf[INET6_ADDRSTRLEN];
194 inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf));
199 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
200 #define COMMA(do_it) ((do_it) ? ", " : "")
203 time_secs_to_str(guint32 time)
205 static gchar str[3][8+1+4+2+2+5+2+2+7+2+2+7+1];
206 static gchar *cur, *p;
207 int hours, mins, secs;
210 if (cur == &str[0][0]) {
212 } else if (cur == &str[1][0]) {
219 sprintf(cur, "0 time");
232 sprintf(p, "%u day%s", time, PLURALIZE(time));
238 sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
244 sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
250 sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
254 /* Max string length for displaying byte string. */
255 #define MAX_BYTE_STR_LEN 32
257 /* Turn an array of bytes into a string showing the bytes in hex. */
258 #define N_BYTES_TO_STR_STRINGS 6
260 bytes_to_str(const guint8 *bd, int bd_len) {
261 static gchar str[N_BYTES_TO_STR_STRINGS][MAX_BYTE_STR_LEN+3+1];
266 static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
267 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
270 if (cur_idx >= N_BYTES_TO_STR_STRINGS)
272 cur = &str[cur_idx][0];
274 len = MAX_BYTE_STR_LEN;
275 while (bd_len > 0 && len > 0) {
276 *p++ = hex[(*bd) >> 4];
277 *p++ = hex[(*bd) & 0xF];
283 /* Note that we're not showing the full string. */
292 static const char *mon_names[12] = {
308 abs_time_to_str(struct timeval *abs_time)
312 static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+4+1 + 5 /* extra */];
314 if (cur == &str[0][0]) {
316 } else if (cur == &str[1][0]) {
322 tmp = localtime(&abs_time->tv_sec);
323 sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%04ld",
324 mon_names[tmp->tm_mon],
330 (long)abs_time->tv_usec/100);
336 rel_time_to_str(struct timeval *rel_time)
339 static char str[3][10+1+6+1];
341 if (cur == &str[0][0]) {
343 } else if (cur == &str[1][0]) {
349 sprintf(cur, "%ld.%06ld", (long)rel_time->tv_sec,
350 (long)rel_time->tv_usec);
356 * Given a pointer into a data buffer, and to the end of the buffer,
357 * find the end of the (putative) line at that position in the data
359 * Return a pointer to the EOL character(s) in "*eol".
362 find_line_end(const u_char *data, const u_char *dataend, const u_char **eol)
364 const u_char *lineend;
366 lineend = memchr(data, '\n', dataend - data);
367 if (lineend == NULL) {
369 * No LF - line is probably continued in next TCP segment.
375 * Is the LF at the beginning of the line?
377 if (lineend > data) {
379 * No - is it preceded by a carriage return?
380 * (Perhaps it's supposed to be, but that's not guaranteed....)
382 if (*(lineend - 1) == '\r') {
384 * Yes. The EOL starts with the CR.
389 * No. The EOL starts with the LF.
394 * I seem to remember that we once saw lines ending with LF-CR
395 * in an HTTP request or response, so check if it's *followed*
396 * by a carriage return.
398 if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
400 * It's <non-LF><LF><CR>; say it ends with the CR.
408 * Point to the character after the last character.
415 #define MAX_COLUMNS_LINE_DETAIL 62
418 * Get the length of the next token in a line, and the beginning of the
419 * next token after that (if any).
420 * Return 0 if there is no next token.
423 get_token_len(const u_char *linep, const u_char *lineend,
424 const u_char **next_token)
426 const u_char *tokenp;
432 * Search for a blank, a CR or an LF, or the end of the buffer.
434 while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
436 token_len = linep - tokenp;
439 * Skip trailing blanks.
441 while (linep < lineend && *linep == ' ')
450 * Given a string, generate a string from it that shows non-printable
451 * characters as C-style escapes, and return a pointer to it.
454 format_text(const u_char *string, int len)
456 static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
459 const u_char *stringend = string + len;
464 fmtbufp = &fmtbuf[0];
465 while (string < stringend) {
466 if (column >= MAX_COLUMNS_LINE_DETAIL) {
468 * Put "..." and quit.
470 strcpy(fmtbufp, " ...");
525 *fmtbufp++ = i + '0';
528 *fmtbufp++ = i + '0';
531 *fmtbufp++ = i + '0';
542 /* Tries to match val against each element in the value_string array vs.
543 Returns the associated string ptr on a match.
544 Formats val with fmt, and returns the resulting string, on failure. */
546 val_to_str(guint32 val, const value_string *vs, const char *fmt) {
548 static gchar str[3][64];
551 ret = match_strval(val, vs);
554 if (cur == &str[0][0]) {
556 } else if (cur == &str[1][0]) {
561 snprintf(cur, 64, fmt, val);
565 /* Tries to match val against each element in the value_string array vs.
566 Returns the associated string ptr on a match, or NULL on failure. */
568 match_strval(guint32 val, const value_string *vs) {
571 while (vs[i].strptr) {
572 if (vs[i].value == val)
573 return(vs[i].strptr);
580 /* Generate, into "buf", a string showing the bits of a bitfield.
581 Return a pointer to the character after that string. */
583 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
591 bit = 1 << (width - 1);
594 /* This bit is part of the field. Show its value. */
600 /* This bit is not part of the field. */
615 /* Generate a string describing a Boolean bitfield (a one-bit field that
616 says something is either true of false). */
618 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
619 const char *truedesc, const char *falsedesc)
621 static char buf[1025];
624 p = decode_bitfield_value(buf, val, mask, width);
628 strcpy(p, falsedesc);
632 /* Generate a string describing an enumerated bitfield (an N-bit field
633 with various specific values having particular names). */
635 decode_enumerated_bitfield(guint32 val, guint32 mask, int width,
636 const value_string *tab, const char *fmt)
638 static char buf[1025];
641 p = decode_bitfield_value(buf, val, mask, width);
642 sprintf(p, fmt, val_to_str(val & mask, tab, "Unknown"));
646 /* Generate a string describing a numeric bitfield (an N-bit field whose
647 value is just a number). */
649 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
652 static char buf[1025];
656 /* Compute the number of bits we have to shift the bitfield right
657 to extract its value. */
658 while ((mask & (1<<shift)) == 0)
661 p = decode_bitfield_value(buf, val, mask, width);
662 sprintf(p, fmt, (val & mask) >> shift);
666 /* Checks to see if a particular packet information element is needed for
669 check_col(frame_data *fd, gint el) {
673 for (i = 0; i < fd->cinfo->num_cols; i++) {
674 if (fd->cinfo->fmt_matx[i][el])
681 /* Adds a vararg list to a packet info string. */
683 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
688 va_start(ap, format);
689 for (i = 0; i < fd->cinfo->num_cols; i++) {
690 if (fd->cinfo->fmt_matx[i][el]) {
692 max_len = COL_MAX_INFO_LEN;
694 max_len = COL_MAX_LEN;
695 vsnprintf(fd->cinfo->col_data[i], max_len, format, ap);
701 col_add_str(frame_data *fd, gint el, const gchar* str) {
705 for (i = 0; i < fd->cinfo->num_cols; i++) {
706 if (fd->cinfo->fmt_matx[i][el]) {
708 max_len = COL_MAX_INFO_LEN;
710 max_len = COL_MAX_LEN;
711 strncpy(fd->cinfo->col_data[i], str, max_len);
712 fd->cinfo->col_data[i][max_len - 1] = 0;
717 /* Appends a vararg list to a packet info string. */
719 col_append_fstr(frame_data *fd, gint el, gchar *format, ...) {
724 va_start(ap, format);
725 for (i = 0; i < fd->cinfo->num_cols; i++) {
726 if (fd->cinfo->fmt_matx[i][el]) {
727 len = strlen(fd->cinfo->col_data[i]);
729 max_len = COL_MAX_INFO_LEN;
731 max_len = COL_MAX_LEN;
732 vsnprintf(&fd->cinfo->col_data[i][len], max_len - len, format, ap);
738 col_append_str(frame_data *fd, gint el, gchar* str) {
742 for (i = 0; i < fd->cinfo->num_cols; i++) {
743 if (fd->cinfo->fmt_matx[i][el]) {
744 len = strlen(fd->cinfo->col_data[i]);
746 max_len = COL_MAX_LEN;
748 max_len = COL_MAX_INFO_LEN;
749 strncat(fd->cinfo->col_data[i], str, max_len - len);
750 fd->cinfo->col_data[i][max_len - 1] = 0;
755 /* To do: Add check_col checks to the col_add* routines */
758 col_set_abs_time(frame_data *fd, int col)
764 tmp = localtime(&then);
765 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
769 (long)fd->abs_usecs/100);
773 col_set_rel_time(frame_data *fd, int col)
775 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
780 col_set_delta_time(frame_data *fd, int col)
782 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
786 /* Add "command-line-specified" time.
787 XXX - this is called from "file.c" when the user changes the time
788 format they want for "command-line-specified" time; it's a bit ugly
789 that we have to export it, but if we go to a CList-like widget that
790 invokes callbacks to get the text for the columns rather than
791 requiring us to stuff the text into the widget from outside, we
792 might be able to clean this up. */
794 col_set_cls_time(frame_data *fd, int col)
796 switch (timestamp_type) {
798 col_set_abs_time(fd, col);
802 col_set_rel_time(fd, col);
806 col_set_delta_time(fd, col);
812 col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
815 struct e_in6_addr ipv6_addr;
816 struct atalk_ddp_addr ddp_addr;
817 struct sna_fid_type_4_addr sna_fid_type_4_addr;
819 switch (addr->type) {
823 strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
825 strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
829 memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
831 strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
833 strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
837 memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
839 strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
841 strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
845 strncpy(fd->cinfo->col_data[col],
846 ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
853 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]);
857 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X",
858 pntohs(&addr->data[0]));
861 case SNA_FID_TYPE_4_ADDR_LEN:
862 memcpy(&sna_fid_type_4_addr, addr->data, SNA_FID_TYPE_4_ADDR_LEN);
863 strncpy(fd->cinfo->col_data[col],
864 sna_fid_type_4_addr_to_str(&sna_fid_type_4_addr), COL_MAX_LEN);
870 memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
871 strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr),
876 strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]),
883 fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
887 col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
894 strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN);
896 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
901 strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN);
903 snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
909 fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
913 fill_in_columns(frame_data *fd)
917 for (i = 0; i < fd->cinfo->num_cols; i++) {
918 switch (fd->cinfo->col_fmt[i]) {
921 snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
925 col_set_cls_time(fd, i);
929 col_set_abs_time(fd, i);
933 col_set_rel_time(fd, i);
937 col_set_delta_time(fd, i);
941 case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */
942 col_set_addr(fd, i, &pi.src, TRUE);
946 col_set_addr(fd, i, &pi.src, FALSE);
951 col_set_addr(fd, i, &pi.dl_src, TRUE);
954 case COL_UNRES_DL_SRC:
955 col_set_addr(fd, i, &pi.dl_src, FALSE);
958 case COL_DEF_NET_SRC:
959 case COL_RES_NET_SRC:
960 col_set_addr(fd, i, &pi.net_src, TRUE);
963 case COL_UNRES_NET_SRC:
964 col_set_addr(fd, i, &pi.net_src, FALSE);
968 case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */
969 col_set_addr(fd, i, &pi.dst, TRUE);
973 col_set_addr(fd, i, &pi.dst, FALSE);
978 col_set_addr(fd, i, &pi.dl_dst, TRUE);
981 case COL_UNRES_DL_DST:
982 col_set_addr(fd, i, &pi.dl_dst, FALSE);
985 case COL_DEF_NET_DST:
986 case COL_RES_NET_DST:
987 col_set_addr(fd, i, &pi.net_dst, TRUE);
990 case COL_UNRES_NET_DST:
991 col_set_addr(fd, i, &pi.net_dst, FALSE);
994 case COL_DEF_SRC_PORT:
995 case COL_RES_SRC_PORT: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
996 col_set_port(fd, i, pi.ptype, pi.srcport, TRUE);
999 case COL_UNRES_SRC_PORT:
1000 col_set_port(fd, i, pi.ptype, pi.srcport, FALSE);
1003 case COL_DEF_DST_PORT:
1004 case COL_RES_DST_PORT: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
1005 col_set_port(fd, i, pi.ptype, pi.destport, TRUE);
1008 case COL_UNRES_DST_PORT:
1009 col_set_port(fd, i, pi.ptype, pi.destport, FALSE);
1012 case COL_PROTOCOL: /* currently done by dissectors */
1013 case COL_INFO: /* currently done by dissectors */
1016 case COL_PACKET_LENGTH:
1017 snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
1020 case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
1026 void blank_packetinfo(void)
1028 pi.dl_src.type = AT_NONE;
1029 pi.dl_dst.type = AT_NONE;
1030 pi.net_src.type = AT_NONE;
1031 pi.net_dst.type = AT_NONE;
1032 pi.src.type = AT_NONE;
1033 pi.dst.type = AT_NONE;
1040 /* Allow protocols to register "init" routines, which are called before
1041 we make a pass through a capture file and dissect all its packets
1042 (e.g., when we read in a new capture file, or run a "filter packets"
1043 or "colorize packets" pass over the current capture file). */
1044 static GSList *init_routines;
1047 register_init_routine(void (*func)(void))
1049 init_routines = g_slist_append(init_routines, func);
1052 /* Call all the registered "init" routines. */
1054 call_init_routine(gpointer routine, gpointer dummy)
1056 void (*func)(void) = routine;
1062 init_all_protocols(void)
1064 g_slist_foreach(init_routines, &call_init_routine, NULL);
1067 /* this routine checks the frame type from the cf structure */
1069 dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
1071 proto_tree *fh_tree;
1075 /* Put in frame header information. */
1077 ti = proto_tree_add_protocol_format(tree, proto_frame, 0, fd->cap_len,
1078 "Frame %u (%u on wire, %u captured)", fd->num,
1079 fd->pkt_len, fd->cap_len);
1081 fh_tree = proto_item_add_subtree(ti, ett_frame);
1083 tv.tv_sec = fd->abs_secs;
1084 tv.tv_usec = fd->abs_usecs;
1086 proto_tree_add_item(fh_tree, hf_frame_arrival_time,
1089 tv.tv_sec = fd->del_secs;
1090 tv.tv_usec = fd->del_usecs;
1092 proto_tree_add_item(fh_tree, hf_frame_time_delta,
1095 proto_tree_add_item(fh_tree, hf_frame_number,
1098 proto_tree_add_uint_format(fh_tree, hf_frame_packet_len,
1099 0, 0, fd->pkt_len, "Packet Length: %d byte%s", fd->pkt_len,
1100 plurality(fd->pkt_len, "", "s"));
1102 proto_tree_add_uint_format(fh_tree, hf_frame_capture_len,
1103 0, 0, fd->cap_len, "Capture Length: %d byte%s", fd->cap_len,
1104 plurality(fd->cap_len, "", "s"));
1109 /* Set the initial payload to the packet length, and the initial
1110 captured payload to the capture length (other protocols may
1111 reduce them if their headers say they're less). */
1112 pi.len = fd->pkt_len;
1113 pi.captured_len = fd->cap_len;
1115 switch (fd->lnk_t) {
1116 case WTAP_ENCAP_ETHERNET :
1117 dissect_eth(pd, 0, fd, tree);
1119 case WTAP_ENCAP_FDDI :
1120 dissect_fddi(pd, fd, tree, FALSE);
1122 case WTAP_ENCAP_FDDI_BITSWAPPED :
1123 dissect_fddi(pd, fd, tree, TRUE);
1125 case WTAP_ENCAP_TR :
1126 dissect_tr(pd, 0, fd, tree);
1128 case WTAP_ENCAP_NULL :
1129 dissect_null(pd, fd, tree);
1131 case WTAP_ENCAP_PPP :
1132 dissect_ppp(pd, 0, fd, tree);
1134 case WTAP_ENCAP_LAPB :
1135 dissect_lapb(pd, fd, tree);
1137 case WTAP_ENCAP_RAW_IP :
1138 dissect_raw(pd, fd, tree);
1140 case WTAP_ENCAP_LINUX_ATM_CLIP :
1141 dissect_clip(pd, fd, tree);
1143 case WTAP_ENCAP_ATM_SNIFFER :
1144 dissect_atm(pd, fd, tree);
1146 case WTAP_ENCAP_ASCEND :
1147 dissect_ascend(pd, fd, tree);
1149 case WTAP_ENCAP_LAPD :
1150 dissect_lapd(pd, fd, tree);
1152 case WTAP_ENCAP_V120 :
1153 dissect_v120(pd, fd, tree);
1158 gint p_compare(gconstpointer a, gconstpointer b)
1161 if (((frame_proto_data *)a) -> proto > ((frame_proto_data *)b) -> proto)
1163 else if (((frame_proto_data *)a) -> proto == ((frame_proto_data *)b) -> proto)
1171 p_add_proto_data(frame_data *fd, int proto, void *proto_data)
1173 frame_proto_data *p1 = malloc(sizeof(frame_proto_data)); /* FIXME */
1175 g_assert(p1 != NULL);
1177 p1 -> proto = proto;
1178 p1 -> proto_data = proto_data;
1180 /* Allocate a frame_proto_data struct and then add it to the GSLIST */
1183 fd -> pfd = g_slist_insert_sorted(fd -> pfd,
1190 p_get_proto_data(frame_data *fd, int proto)
1192 frame_proto_data temp;
1196 temp.proto_data = NULL;
1198 item = g_slist_find_custom(fd->pfd, (gpointer *)&temp, p_compare);
1200 if (item) return (void *)item->data;
1207 p_rem_proto_data(frame_data *fd, int proto)
1214 proto_register_frame(void)
1216 static hf_register_info hf[] = {
1217 { &hf_frame_arrival_time,
1218 { "Arrival Time", "frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1221 { &hf_frame_time_delta,
1222 { "Time delta from previous packet", "frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL,
1227 { "Frame Number", "frame.number", FT_UINT32, BASE_DEC, NULL, 0x0,
1230 { &hf_frame_packet_len,
1231 { "Total Frame Length", "frame.pkt_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1234 { &hf_frame_capture_len,
1235 { "Capture Frame Length", "frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1238 static gint *ett[] = {
1242 proto_frame = proto_register_protocol("Frame", "frame");
1243 proto_register_field_array(proto_frame, hf, array_length(hf));
1244 proto_register_subtree_array(ett, array_length(ett));