diff options
author | Gilbert Ramirez <gram@alumni.rice.edu> | 2000-09-27 05:18:06 +0000 |
---|---|---|
committer | Gilbert Ramirez <gram@alumni.rice.edu> | 2000-09-27 05:18:06 +0000 |
commit | cba2930d6bb7e8cf2b0c03d14203624b56460835 (patch) | |
tree | 0f3f194c5a494193939c9fce55e70e0429037f20 /epan | |
parent | 137fa6c00e19aa941413b73462d26da8e5b6eade (diff) | |
download | wireshark-cba2930d6bb7e8cf2b0c03d14203624b56460835.tar.gz wireshark-cba2930d6bb7e8cf2b0c03d14203624b56460835.tar.bz2 wireshark-cba2930d6bb7e8cf2b0c03d14203624b56460835.zip |
Move packet.[ch] to epan
svn path=/trunk/; revision=2460
Diffstat (limited to 'epan')
-rw-r--r-- | epan/Makefile.am | 4 | ||||
-rw-r--r-- | epan/packet.c | 1587 | ||||
-rw-r--r-- | epan/packet.h | 371 |
3 files changed, 1961 insertions, 1 deletions
diff --git a/epan/Makefile.am b/epan/Makefile.am index f7d9c92784..da1e3c9e2a 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -2,7 +2,7 @@ # Automake file for the EPAN library # (Ethereal Protocol ANalyzer Library) # -# $Id: Makefile.am,v 1.2 2000/09/27 05:05:32 gram Exp $ +# $Id: Makefile.am,v 1.3 2000/09/27 05:18:05 gram Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@zing.org> @@ -46,6 +46,8 @@ libepan_a_SOURCES = \ except.c \ except.h \ exception.h \ + packet.c \ + packet.h \ pint.h \ plugins.c \ plugins.h \ diff --git a/epan/packet.c b/epan/packet.c new file mode 100644 index 0000000000..676e0970cf --- /dev/null +++ b/epan/packet.c @@ -0,0 +1,1587 @@ +/* packet.c + * Routines for packet disassembly + * + * $Id: packet.c,v 1.1 2000/09/27 05:18:05 gram Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@zing.org> + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#ifdef HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#include <glib.h> + +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#endif + +#include <string.h> +#include <ctype.h> +#include <time.h> + +#ifdef NEED_SNPRINTF_H +# include "snprintf.h" +#endif + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef NEED_INET_V6DEFS_H +# include "inet_v6defs.h" +#endif + +#include "packet.h" +#include "print.h" +#include "timestamp.h" +#include "file.h" + +#include "packet-ascend.h" +#include "packet-atalk.h" +#include "packet-atm.h" +#include "packet-clip.h" +#include "packet-eth.h" +#include "packet-fddi.h" +#include "packet-ipv6.h" +#include "packet-lapb.h" +#include "packet-lapd.h" +#include "packet-llc.h" +#include "packet-null.h" +#include "packet-ppp.h" +#include "packet-raw.h" +#include "packet-sna.h" +#include "packet-tr.h" +#include "packet-v120.h" +#include "packet-vines.h" + +#include "resolv.h" +#include "tvbuff.h" +#include "plugins.h" + +extern capture_file cfile; + +static int proto_frame = -1; +static int hf_frame_arrival_time = -1; +static int hf_frame_time_delta = -1; +static int hf_frame_number = -1; +static int hf_frame_packet_len = -1; +static int hf_frame_capture_len = -1; +static int hf_frame_p2p_dir = -1; +static int proto_short = -1; +static int proto_malformed = -1; + +static gint ett_frame = -1; + +static void display_signed_time(gchar *, int, gint32, gint32); + + +static const value_string p2p_dirs[] = { + { P2P_DIR_SENT, "Sent" }, + { P2P_DIR_RECV, "Received" }, + { 0, NULL } +}; + + +/* Protocol-specific data attched to a frame_data structure - protocol + index and opaque pointer. */ +typedef struct _frame_proto_data { + int proto; + void *proto_data; +} frame_proto_data; + +GMemChunk *frame_proto_data_area = NULL; + +/* + * Free up any space allocated for frame proto data areas and then + * allocate a new area. + * + * We can free the area, as the structures it contains are pointed to by + * frames, that will be freed as well. + */ +static void +packet_init_protocol(void) +{ + + if (frame_proto_data_area) + g_mem_chunk_destroy(frame_proto_data_area); + + frame_proto_data_area = g_mem_chunk_new("frame_proto_data_area", + sizeof(frame_proto_data), + 20 * sizeof(frame_proto_data), /* FIXME*/ + G_ALLOC_ONLY); + +} + +/* Wrapper for the most common case of asking + * for a string using a colon as the hex-digit separator. + */ +gchar * +ether_to_str(const guint8 *ad) +{ + return ether_to_str_punct(ad, ':'); +} + +/* Places char punct in the string as the hex-digit separator. + * If punct is '\0', no punctuation is applied (and thus + * the resulting string is 5 bytes shorter) + */ +gchar * +ether_to_str_punct(const guint8 *ad, char punct) { + static gchar str[3][18]; + static gchar *cur; + gchar *p; + int i; + guint32 octet; + static const gchar hex_digits[16] = "0123456789abcdef"; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + p = &cur[18]; + *--p = '\0'; + i = 5; + for (;;) { + octet = ad[i]; + *--p = hex_digits[octet&0xF]; + octet >>= 4; + *--p = hex_digits[octet&0xF]; + if (i == 0) + break; + if (punct) + *--p = punct; + i--; + } + return p; +} + +gchar * +ip_to_str(const guint8 *ad) { + static gchar str[3][16]; + static gchar *cur; + gchar *p; + int i; + guint32 octet; + guint32 digit; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + p = &cur[16]; + *--p = '\0'; + i = 3; + for (;;) { + octet = ad[i]; + *--p = (octet%10) + '0'; + octet /= 10; + digit = octet%10; + octet /= 10; + if (digit != 0 || octet != 0) + *--p = digit + '0'; + if (octet != 0) + *--p = octet + '0'; + if (i == 0) + break; + *--p = '.'; + i--; + } + return p; +} + +gchar * +ip6_to_str(struct e_in6_addr *ad) { +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + static gchar buf[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf)); + return buf; +} + + +#define PLURALIZE(n) (((n) > 1) ? "s" : "") +#define COMMA(do_it) ((do_it) ? ", " : "") + +gchar * +time_secs_to_str(guint32 time) +{ + static gchar str[3][8+1+4+2+2+5+2+2+7+2+2+7+1]; + static gchar *cur, *p; + int hours, mins, secs; + int do_comma; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + + if (time == 0) { + sprintf(cur, "0 time"); + return cur; + } + + secs = time % 60; + time /= 60; + mins = time % 60; + time /= 60; + hours = time % 24; + time /= 24; + + p = cur; + if (time != 0) { + sprintf(p, "%u day%s", time, PLURALIZE(time)); + p += strlen(p); + do_comma = 1; + } else + do_comma = 0; + if (hours != 0) { + sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours)); + p += strlen(p); + do_comma = 1; + } else + do_comma = 0; + if (mins != 0) { + sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins)); + p += strlen(p); + do_comma = 1; + } else + do_comma = 0; + if (secs != 0) + sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs)); + return cur; +} + +/* Max string length for displaying byte string. */ +#define MAX_BYTE_STR_LEN 32 + +/* Turn an array of bytes into a string showing the bytes in hex. */ +#define N_BYTES_TO_STR_STRINGS 6 +gchar * +bytes_to_str(const guint8 *bd, int bd_len) { + static gchar str[N_BYTES_TO_STR_STRINGS][MAX_BYTE_STR_LEN+3+1]; + static int cur_idx; + gchar *cur; + gchar *p; + int len; + static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + cur_idx++; + if (cur_idx >= N_BYTES_TO_STR_STRINGS) + cur_idx = 0; + cur = &str[cur_idx][0]; + p = cur; + len = MAX_BYTE_STR_LEN; + while (bd_len > 0 && len > 0) { + *p++ = hex[(*bd) >> 4]; + *p++ = hex[(*bd) & 0xF]; + len -= 2; + bd++; + bd_len--; + } + if (bd_len != 0) { + /* Note that we're not showing the full string. */ + *p++ = '.'; + *p++ = '.'; + *p++ = '.'; + } + *p = '\0'; + return cur; +} + +static const char *mon_names[12] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + +gchar * +abs_time_to_str(struct timeval *abs_time) +{ + struct tm *tmp; + static gchar *cur; + static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+4+1 + 5 /* extra */]; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + + tmp = localtime(&abs_time->tv_sec); + sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%04ld", + mon_names[tmp->tm_mon], + tmp->tm_mday, + tmp->tm_year + 1900, + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (long)abs_time->tv_usec/100); + + return cur; +} + +#define REL_TIME_LEN (1+10+1+6+1) + +gchar * +rel_time_to_str(struct timeval *rel_time) +{ + static gchar *cur; + static char str[3][REL_TIME_LEN]; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + + display_signed_time(cur, REL_TIME_LEN, rel_time->tv_sec, + rel_time->tv_usec); + return cur; +} + +static void +display_signed_time(gchar *buf, int buflen, gint32 sec, gint32 usec) +{ + char *sign; + + /* If the microseconds part of the time stamp is negative, + print its absolute value and, if the seconds part isn't + (the seconds part should be zero in that case), stick + a "-" in front of the entire time stamp. */ + sign = ""; + if (usec < 0) { + usec = -usec; + if (sec >= 0) + sign = "-"; + } + snprintf(buf, buflen, "%s%d.%06d", sign, sec, usec); +} + + +/* Tries to match val against each element in the value_string array vs. + Returns the associated string ptr on a match. + Formats val with fmt, and returns the resulting string, on failure. */ +gchar* +val_to_str(guint32 val, const value_string *vs, const char *fmt) { + gchar *ret; + static gchar str[3][64]; + static gchar *cur; + + ret = match_strval(val, vs); + if (ret != NULL) + return ret; + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + snprintf(cur, 64, fmt, val); + return cur; +} + +/* Tries to match val against each element in the value_string array vs. + Returns the associated string ptr on a match, or NULL on failure. */ +gchar* +match_strval(guint32 val, const value_string *vs) { + gint i = 0; + + while (vs[i].strptr) { + if (vs[i].value == val) + return(vs[i].strptr); + i++; + } + + return(NULL); +} + +/* Generate, into "buf", a string showing the bits of a bitfield. + Return a pointer to the character after that string. */ +char * +decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width) +{ + int i; + guint32 bit; + char *p; + + i = 0; + p = buf; + bit = 1 << (width - 1); + for (;;) { + if (mask & bit) { + /* This bit is part of the field. Show its value. */ + if (val & bit) + *p++ = '1'; + else + *p++ = '0'; + } else { + /* This bit is not part of the field. */ + *p++ = '.'; + } + bit >>= 1; + i++; + if (i >= width) + break; + if (i % 4 == 0) + *p++ = ' '; + } + strcpy(p, " = "); + p += 3; + return p; +} + +/* Generate a string describing a Boolean bitfield (a one-bit field that + says something is either true of false). */ +const char * +decode_boolean_bitfield(guint32 val, guint32 mask, int width, + const char *truedesc, const char *falsedesc) +{ + static char buf[1025]; + char *p; + + p = decode_bitfield_value(buf, val, mask, width); + if (val & mask) + strcpy(p, truedesc); + else + strcpy(p, falsedesc); + return buf; +} + +/* Generate a string describing an enumerated bitfield (an N-bit field + with various specific values having particular names). */ +const char * +decode_enumerated_bitfield(guint32 val, guint32 mask, int width, + const value_string *tab, const char *fmt) +{ + static char buf[1025]; + char *p; + + p = decode_bitfield_value(buf, val, mask, width); + sprintf(p, fmt, val_to_str(val & mask, tab, "Unknown")); + return buf; +} + +/* Generate a string describing a numeric bitfield (an N-bit field whose + value is just a number). */ +const char * +decode_numeric_bitfield(guint32 val, guint32 mask, int width, + const char *fmt) +{ + static char buf[1025]; + char *p; + int shift = 0; + + /* Compute the number of bits we have to shift the bitfield right + to extract its value. */ + while ((mask & (1<<shift)) == 0) + shift++; + + p = decode_bitfield_value(buf, val, mask, width); + sprintf(p, fmt, (val & mask) >> shift); + return buf; +} + +gboolean +col_get_writable(frame_data *fd) +{ + if (fd) { + + return (fd->cinfo ? fd->cinfo->writable : FALSE); + + } + + return FALSE; + +} + +void +col_set_writable(frame_data *fd, gboolean writable) +{ + if (fd->cinfo) { + fd->cinfo->writable = writable; + } +} + +/* Checks to see if a particular packet information element is needed for + the packet list */ +gint +check_col(frame_data *fd, gint el) { + int i; + + if (fd->cinfo && fd->cinfo->writable) { + for (i = 0; i < fd->cinfo->num_cols; i++) { + if (fd->cinfo->fmt_matx[i][el]) + return TRUE; + } + } + return FALSE; +} + +/* Adds a vararg list to a packet info string. */ +void +col_add_fstr(frame_data *fd, gint el, gchar *format, ...) { + va_list ap; + int i; + size_t max_len; + + if (el == COL_INFO) + max_len = COL_MAX_INFO_LEN; + else + max_len = COL_MAX_LEN; + + va_start(ap, format); + for (i = 0; i < fd->cinfo->num_cols; i++) { + if (fd->cinfo->fmt_matx[i][el]) { + vsnprintf(fd->cinfo->col_data[i], max_len, format, ap); + } + } +} + +void +col_add_str(frame_data *fd, gint el, const gchar* str) { + int i; + size_t max_len; + + if (el == COL_INFO) + max_len = COL_MAX_INFO_LEN; + else + max_len = COL_MAX_LEN; + + for (i = 0; i < fd->cinfo->num_cols; i++) { + if (fd->cinfo->fmt_matx[i][el]) { + strncpy(fd->cinfo->col_data[i], str, max_len); + fd->cinfo->col_data[i][max_len - 1] = 0; + } + } +} + +/* Appends a vararg list to a packet info string. */ +void +col_append_fstr(frame_data *fd, gint el, gchar *format, ...) { + va_list ap; + int i; + size_t len, max_len; + + if (el == COL_INFO) + max_len = COL_MAX_INFO_LEN; + else + max_len = COL_MAX_LEN; + + va_start(ap, format); + for (i = 0; i < fd->cinfo->num_cols; i++) { + if (fd->cinfo->fmt_matx[i][el]) { + len = strlen(fd->cinfo->col_data[i]); + vsnprintf(&fd->cinfo->col_data[i][len], max_len - len, format, ap); + } + } +} + +void +col_append_str(frame_data *fd, gint el, gchar* str) { + int i; + size_t len, max_len; + + if (el == COL_INFO) + max_len = COL_MAX_INFO_LEN; + else + max_len = COL_MAX_LEN; + + for (i = 0; i < fd->cinfo->num_cols; i++) { + if (fd->cinfo->fmt_matx[i][el]) { + len = strlen(fd->cinfo->col_data[i]); + strncat(fd->cinfo->col_data[i], str, max_len - len); + fd->cinfo->col_data[i][max_len - 1] = 0; + } + } +} + +/* To do: Add check_col checks to the col_add* routines */ + +static void +col_set_abs_time(frame_data *fd, int col) +{ + struct tm *tmp; + time_t then; + + then = fd->abs_secs; + tmp = localtime(&then); + snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (long)fd->abs_usecs/100); +} + +static void +col_set_rel_time(frame_data *fd, int col) +{ + display_signed_time(fd->cinfo->col_data[col], COL_MAX_LEN, + fd->rel_secs, fd->rel_usecs); +} + +static void +col_set_delta_time(frame_data *fd, int col) +{ + display_signed_time(fd->cinfo->col_data[col], COL_MAX_LEN, + fd->del_secs, fd->del_usecs); +} + +/* Add "command-line-specified" time. + XXX - this is called from "file.c" when the user changes the time + format they want for "command-line-specified" time; it's a bit ugly + that we have to export it, but if we go to a CList-like widget that + invokes callbacks to get the text for the columns rather than + requiring us to stuff the text into the widget from outside, we + might be able to clean this up. */ +void +col_set_cls_time(frame_data *fd, int col) +{ + switch (timestamp_type) { + case ABSOLUTE: + col_set_abs_time(fd, col); + break; + + case RELATIVE: + col_set_rel_time(fd, col); + break; + + case DELTA: + col_set_delta_time(fd, col); + break; + } +} + +static void +col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res) +{ + u_int ipv4_addr; + struct e_in6_addr ipv6_addr; + struct atalk_ddp_addr ddp_addr; + struct sna_fid_type_4_addr sna_fid_type_4_addr; + + switch (addr->type) { + + case AT_ETHER: + if (is_res) + strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN); + else + strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN); + break; + + case AT_IPv4: + memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr); + if (is_res) + strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN); + else + strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN); + break; + + case AT_IPv6: + memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr); + if (is_res) + strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN); + else + strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN); + break; + + case AT_IPX: + strncpy(fd->cinfo->col_data[col], + ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN); + break; + + case AT_SNA: + switch (addr->len) { + + case 1: + snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]); + break; + + case 2: + snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", + pntohs(&addr->data[0])); + break; + + case SNA_FID_TYPE_4_ADDR_LEN: + memcpy(&sna_fid_type_4_addr, addr->data, SNA_FID_TYPE_4_ADDR_LEN); + strncpy(fd->cinfo->col_data[col], + sna_fid_type_4_addr_to_str(&sna_fid_type_4_addr), COL_MAX_LEN); + break; + } + break; + + case AT_ATALK: + memcpy(&ddp_addr, addr->data, sizeof ddp_addr); + strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr), + COL_MAX_LEN); + break; + + case AT_VINES: + strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]), + COL_MAX_LEN); + break; + + default: + break; + } + fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0'; +} + +static void +col_set_port(frame_data *fd, int col, port_type ptype, guint32 port, + gboolean is_res) +{ + switch (ptype) { + + case PT_SCTP: + if (is_res) + strncpy(fd->cinfo->col_data[col], get_sctp_port(port), COL_MAX_LEN); + else + snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port); + break; + + case PT_TCP: + if (is_res) + strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN); + else + snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port); + break; + + case PT_UDP: + if (is_res) + strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN); + else + snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port); + break; + + default: + break; + } + fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0'; +} + +void +fill_in_columns(frame_data *fd) +{ + int i; + + for (i = 0; i < fd->cinfo->num_cols; i++) { + switch (fd->cinfo->col_fmt[i]) { + + case COL_NUMBER: + snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num); + break; + + case COL_CLS_TIME: + col_set_cls_time(fd, i); + break; + + case COL_ABS_TIME: + col_set_abs_time(fd, i); + break; + + case COL_REL_TIME: + col_set_rel_time(fd, i); + break; + + case COL_DELTA_TIME: + col_set_delta_time(fd, i); + break; + + case COL_DEF_SRC: + case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */ + col_set_addr(fd, i, &pi.src, TRUE); + break; + + case COL_UNRES_SRC: + col_set_addr(fd, i, &pi.src, FALSE); + break; + + case COL_DEF_DL_SRC: + case COL_RES_DL_SRC: + col_set_addr(fd, i, &pi.dl_src, TRUE); + break; + + case COL_UNRES_DL_SRC: + col_set_addr(fd, i, &pi.dl_src, FALSE); + break; + + case COL_DEF_NET_SRC: + case COL_RES_NET_SRC: + col_set_addr(fd, i, &pi.net_src, TRUE); + break; + + case COL_UNRES_NET_SRC: + col_set_addr(fd, i, &pi.net_src, FALSE); + break; + + case COL_DEF_DST: + case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */ + col_set_addr(fd, i, &pi.dst, TRUE); + break; + + case COL_UNRES_DST: + col_set_addr(fd, i, &pi.dst, FALSE); + break; + + case COL_DEF_DL_DST: + case COL_RES_DL_DST: + col_set_addr(fd, i, &pi.dl_dst, TRUE); + break; + + case COL_UNRES_DL_DST: + col_set_addr(fd, i, &pi.dl_dst, FALSE); + break; + + case COL_DEF_NET_DST: + case COL_RES_NET_DST: + col_set_addr(fd, i, &pi.net_dst, TRUE); + break; + + case COL_UNRES_NET_DST: + col_set_addr(fd, i, &pi.net_dst, FALSE); + break; + + case COL_DEF_SRC_PORT: + case COL_RES_SRC_PORT: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */ + col_set_port(fd, i, pi.ptype, pi.srcport, TRUE); + break; + + case COL_UNRES_SRC_PORT: + col_set_port(fd, i, pi.ptype, pi.srcport, FALSE); + break; + + case COL_DEF_DST_PORT: + case COL_RES_DST_PORT: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */ + col_set_port(fd, i, pi.ptype, pi.destport, TRUE); + break; + + case COL_UNRES_DST_PORT: + col_set_port(fd, i, pi.ptype, pi.destport, FALSE); + break; + + case COL_PROTOCOL: /* currently done by dissectors */ + case COL_INFO: /* currently done by dissectors */ + break; + + case COL_PACKET_LENGTH: + snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len); + break; + + case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */ + break; + } + } +} + +void blank_packetinfo(void) +{ + pi.dl_src.type = AT_NONE; + pi.dl_dst.type = AT_NONE; + pi.net_src.type = AT_NONE; + pi.net_dst.type = AT_NONE; + pi.src.type = AT_NONE; + pi.dst.type = AT_NONE; + pi.ipproto = 0; + pi.ptype = PT_NONE; + pi.srcport = 0; + pi.destport = 0; + pi.current_proto = "<Missing Protocol Name>"; + pi.p2p_dir = P2P_DIR_UNKNOWN; +} + + +/* Allow protocols to register "init" routines, which are called before + we make a pass through a capture file and dissect all its packets + (e.g., when we read in a new capture file, or run a "filter packets" + or "colorize packets" pass over the current capture file). */ +static GSList *init_routines; + +void +register_init_routine(void (*func)(void)) +{ + init_routines = g_slist_append(init_routines, func); +} + +/* Call all the registered "init" routines. */ +static void +call_init_routine(gpointer routine, gpointer dummy) +{ + void (*func)(void) = routine; + + (*func)(); +} + +void +init_all_protocols(void) +{ + g_slist_foreach(init_routines, &call_init_routine, NULL); +} + +/* this routine checks the frame type from the cf structure */ +void +dissect_packet(union wtap_pseudo_header *pseudo_header, const u_char *pd, + frame_data *fd, proto_tree *tree) +{ + proto_tree *fh_tree; + proto_item *ti; + struct timeval tv; + static tvbuff_t *tvb; + + blank_packetinfo(); + + if (fd->lnk_t == WTAP_ENCAP_LAPD || + fd->lnk_t == WTAP_ENCAP_PPP_WITH_PHDR) { + + pi.p2p_dir = pseudo_header->p2p.sent ? P2P_DIR_SENT : P2P_DIR_RECV; + } + + /* Put in frame header information. */ + if (tree) { + ti = proto_tree_add_protocol_format(tree, proto_frame, NullTVB, 0, fd->cap_len, + "Frame %u (%u on wire, %u captured)", fd->num, + fd->pkt_len, fd->cap_len); + + fh_tree = proto_item_add_subtree(ti, ett_frame); + + tv.tv_sec = fd->abs_secs; + tv.tv_usec = fd->abs_usecs; + + proto_tree_add_time(fh_tree, hf_frame_arrival_time, NullTVB, + 0, 0, &tv); + + tv.tv_sec = fd->del_secs; + tv.tv_usec = fd->del_usecs; + + proto_tree_add_time(fh_tree, hf_frame_time_delta, NullTVB, + 0, 0, &tv); + + proto_tree_add_uint(fh_tree, hf_frame_number, NullTVB, + 0, 0, fd->num); + + proto_tree_add_uint_format(fh_tree, hf_frame_packet_len, NullTVB, + 0, 0, fd->pkt_len, "Packet Length: %d byte%s", fd->pkt_len, + plurality(fd->pkt_len, "", "s")); + + proto_tree_add_uint_format(fh_tree, hf_frame_capture_len, NullTVB, + 0, 0, fd->cap_len, "Capture Length: %d byte%s", fd->cap_len, + plurality(fd->cap_len, "", "s")); + + /* Check for existences of P2P pseudo header */ + if (fd->lnk_t == WTAP_ENCAP_LAPD || fd->lnk_t == WTAP_ENCAP_PPP_WITH_PHDR) { + proto_tree_add_uint(fh_tree, hf_frame_p2p_dir, NullTVB, + 0, 0, pi.p2p_dir); + } + } + + + /* Set the initial payload to the packet length, and the initial + captured payload to the capture length (other protocols may + reduce them if their headers say they're less). */ + pi.len = fd->pkt_len; + pi.captured_len = fd->cap_len; + + pi.fd = fd; + pi.pseudo_header = pseudo_header; + pi.current_proto = "Frame"; + + col_set_writable(fd, TRUE); + + TRY { + tvb = tvb_new_real_data(pd, fd->cap_len, fd->pkt_len); + pi.compat_top_tvb = tvb; + + switch (fd->lnk_t) { + case WTAP_ENCAP_ETHERNET : + dissect_eth(tvb, &pi, tree); + break; + case WTAP_ENCAP_FDDI : + dissect_fddi(tvb, &pi, tree, FALSE); + break; + case WTAP_ENCAP_FDDI_BITSWAPPED : + dissect_fddi(tvb, &pi, tree, TRUE); + break; + case WTAP_ENCAP_TOKEN_RING : + dissect_tr(tvb, &pi, tree); + break; + case WTAP_ENCAP_NULL : + dissect_null(tvb, &pi, tree); + break; + case WTAP_ENCAP_PPP : + case WTAP_ENCAP_PPP_WITH_PHDR : + dissect_ppp(tvb, &pi, tree); + break; + case WTAP_ENCAP_LAPB : + dissect_lapb(tvb, &pi, tree); + break; + case WTAP_ENCAP_RAW_IP : + dissect_raw(tvb, &pi, tree); + break; + case WTAP_ENCAP_LINUX_ATM_CLIP : + dissect_clip(tvb, &pi, tree); + break; + case WTAP_ENCAP_ATM_SNIFFER : + dissect_atm(tvb, &pi, tree); + break; + case WTAP_ENCAP_ASCEND : + dissect_ascend(tvb, &pi, tree); + break; + case WTAP_ENCAP_LAPD : + dissect_lapd(tvb, &pi, tree); + break; + case WTAP_ENCAP_V120 : + dissect_v120(tvb, &pi, tree); + break; + case WTAP_ENCAP_ATM_RFC1483: + dissect_llc(tvb, &pi, tree); + break; + default: + g_assert_not_reached(); + break; + } + } + CATCH(BoundsError) { + proto_tree_add_protocol_format(tree, proto_short, NullTVB, 0, 0, + "[Short Frame: %s]", pi.current_proto ); + } + CATCH(ReportedBoundsError) { + proto_tree_add_protocol_format(tree, proto_malformed, NullTVB, 0, 0, + "[Malformed Frame: %s]", pi.current_proto ); + } + ENDTRY; + + /* Free all tvb's created from this tvb, unless dissector + * wanted to store the pointer (in which case, the dissector + * would have incremented the usage count on that tvbuff_t*) */ + tvb_free_chain(tvb); + + fd->flags.visited = 1; +} + +gint p_compare(gconstpointer a, gconstpointer b) +{ + + if (((frame_proto_data *)a) -> proto > ((frame_proto_data *)b) -> proto) + return 1; + else if (((frame_proto_data *)a) -> proto == ((frame_proto_data *)b) -> proto) + return 0; + else + return -1; + +} + +void +p_add_proto_data(frame_data *fd, int proto, void *proto_data) +{ + frame_proto_data *p1 = g_mem_chunk_alloc(frame_proto_data_area); + + g_assert(p1 != NULL); + + p1 -> proto = proto; + p1 -> proto_data = proto_data; + + /* Add it to the GSLIST */ + + fd -> pfd = g_slist_insert_sorted(fd -> pfd, + (gpointer *)p1, + p_compare); + +} + +void * +p_get_proto_data(frame_data *fd, int proto) +{ + frame_proto_data temp, *p1; + GSList *item; + + temp.proto = proto; + temp.proto_data = NULL; + + item = g_slist_find_custom(fd->pfd, (gpointer *)&temp, p_compare); + + if (item) { + p1 = (frame_proto_data *)item->data; + return p1->proto_data; + } + + return NULL; + +} + +void +p_rem_proto_data(frame_data *fd, int proto) +{ + frame_proto_data temp; + GSList *item; + + temp.proto = proto; + temp.proto_data = NULL; + + item = g_slist_find_custom(fd->pfd, (gpointer *)&temp, p_compare); + + if (item) { + + fd->pfd = g_slist_remove(fd->pfd, item); + + } + +} + +void +proto_register_frame(void) +{ + static hf_register_info hf[] = { + { &hf_frame_arrival_time, + { "Arrival Time", "frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, + ""}}, + + { &hf_frame_time_delta, + { "Time delta from previous packet", "frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL, + 0x0, + "" }}, + + { &hf_frame_number, + { "Frame Number", "frame.number", FT_UINT32, BASE_DEC, NULL, 0x0, + "" }}, + + { &hf_frame_packet_len, + { "Total Frame Length", "frame.pkt_len", FT_UINT32, BASE_DEC, NULL, 0x0, + "" }}, + + { &hf_frame_capture_len, + { "Capture Frame Length", "frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0, + "" }}, + + { &hf_frame_p2p_dir, + { "Point-to-Point Direction", "frame.p2p_dir", FT_UINT8, BASE_DEC, VALS(p2p_dirs), 0x0, + "" }}, + }; + static gint *ett[] = { + &ett_frame, + }; + + proto_frame = proto_register_protocol("Frame", "frame"); + proto_register_field_array(proto_frame, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + proto_short = proto_register_protocol("Short Frame", "short"); + proto_malformed = proto_register_protocol("Malformed Frame", "malformed"); + register_init_routine(&packet_init_protocol); + +} + +/*********************** code added for sub-dissector lookup *********************/ + +static GHashTable *dissector_tables = NULL; + +/* + * XXX - for now, we support having both "old" dissectors, with packet + * data pointer, packet offset, frame_data pointer, and protocol tree + * pointer arguments, and "new" dissectors, with tvbuff pointer, + * packet_info pointer, and protocol tree pointer arguments. + * + * Nuke this and go back to storing a pointer to the dissector when + * the last old-style dissector is gone. + */ +typedef struct { + gboolean is_old_dissector; + union { + old_dissector_t old; + dissector_t new; + } dissector; +} dtbl_entry_t; + +/* Finds a dissector table by field name. */ +static dissector_table_t +find_dissector_table(const char *name) +{ + g_assert(dissector_tables); + return g_hash_table_lookup( dissector_tables, name ); +} + +/* add an entry, lookup the dissector table for the specified field name, */ +/* if a valid table found, add the subdissector */ +void +old_dissector_add(const char *name, guint32 pattern, old_dissector_t dissector) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); + dtbl_entry->is_old_dissector = TRUE; + dtbl_entry->dissector.old = dissector; + +/* do the table insertion */ + g_hash_table_insert( sub_dissectors, GUINT_TO_POINTER( pattern), + (gpointer)dtbl_entry); +} + +void +dissector_add(const char *name, guint32 pattern, dissector_t dissector) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); + dtbl_entry->is_old_dissector = FALSE; + dtbl_entry->dissector.new = dissector; + +/* do the table insertion */ + g_hash_table_insert( sub_dissectors, GUINT_TO_POINTER( pattern), + (gpointer)dtbl_entry); +} + +/* delete the entry for this dissector at this pattern */ + +/* NOTE: this doesn't use the dissector call variable. It is included to */ +/* be consistant with the dissector_add and more importantly to be used */ +/* if the technique of adding a temporary dissector is implemented. */ +/* If temporary dissectors are deleted, then the original dissector must */ +/* be available. */ +void +old_dissector_delete(const char *name, guint32 pattern, old_dissector_t dissector) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + /* + * Find the entry. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + + if (dtbl_entry != NULL) { + /* + * Found - remove it. + */ + g_hash_table_remove(sub_dissectors, GUINT_TO_POINTER(pattern)); + + /* + * Now free up the entry. + */ + g_free(dtbl_entry); + } +} + +void +dissector_delete(const char *name, guint32 pattern, dissector_t dissector) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + /* + * Find the entry. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + + if (dtbl_entry != NULL) { + /* + * Found - remove it. + */ + g_hash_table_remove(sub_dissectors, GUINT_TO_POINTER(pattern)); + + /* + * Now free up the entry. + */ + g_free(dtbl_entry); + } +} + +/* Look for a given port in a given dissector table and, if found, call + the dissector with the arguments supplied, and return TRUE, otherwise + return FALSE. + + If the arguments supplied don't match the arguments to the dissector, + do the appropriate translation. */ +gboolean +old_dissector_try_port(dissector_table_t sub_dissectors, guint32 port, + const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + dtbl_entry_t *dtbl_entry; + tvbuff_t *tvb; + + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(port)); + if (dtbl_entry != NULL) { + pi.match_port = port; + if (dtbl_entry->is_old_dissector) + (*dtbl_entry->dissector.old)(pd, offset, fd, tree); + else { + /* + * Old dissector calling new dissector; use + * "tvb_create_from_top()" to remap. + * + * XXX - what about the "pd" argument? Do + * any dissectors not just pass that along and + * let the "offset" argument handle stepping + * through the packet? + */ + tvb = tvb_create_from_top(offset); + (*dtbl_entry->dissector.new)(tvb, &pi, tree); + } + return TRUE; + } else + return FALSE; +} + +gboolean +dissector_try_port(dissector_table_t sub_dissectors, guint32 port, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + dtbl_entry_t *dtbl_entry; + const guint8 *pd; + int offset; + + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(port)); + if (dtbl_entry != NULL) { + pi.match_port = port; + if (dtbl_entry->is_old_dissector) { + /* + * New dissector calling old dissector; use + * "tvb_compat()" to remap. + */ + tvb_compat(tvb, &pd, &offset); + (*dtbl_entry->dissector.old)(pd, offset, pinfo->fd, + tree); + } else + (*dtbl_entry->dissector.new)(tvb, pinfo, tree); + return TRUE; + } else + return FALSE; +} + +dissector_table_t +register_dissector_table(const char *name) +{ + dissector_table_t sub_dissectors; + + /* Create our hash-of-hashes if it doesn't already exist */ + if (!dissector_tables) { + dissector_tables = g_hash_table_new( g_str_hash, g_str_equal ); + g_assert(dissector_tables); + } + + /* Make sure the registration is unique */ + g_assert(!g_hash_table_lookup( dissector_tables, name )); + + /* Create and register the dissector table for this name; returns */ + /* a pointer to the dissector table. */ + sub_dissectors = g_hash_table_new( g_direct_hash, g_direct_equal ); + g_hash_table_insert( dissector_tables, (gpointer)name, (gpointer) sub_dissectors ); + return sub_dissectors; +} + +static GHashTable *heur_dissector_lists = NULL; + +/* + * XXX - for now, we support having both "old" dissectors, with packet + * data pointer, packet offset, frame_data pointer, and protocol tree + * pointer arguments, and "new" dissectors, with tvbuff pointer, + * packet_info pointer, and protocol tree pointer arguments. + * + * Nuke this and go back to storing a pointer to the dissector when + * the last old-style dissector is gone. + */ +typedef struct { + gboolean is_old_dissector; + union { + old_heur_dissector_t old; + heur_dissector_t new; + } dissector; +} heur_dtbl_entry_t; + +/* Finds a heuristic dissector table by field name. */ +static heur_dissector_list_t * +find_heur_dissector_list(const char *name) +{ + g_assert(heur_dissector_lists != NULL); + return g_hash_table_lookup(heur_dissector_lists, name); +} + +void +old_heur_dissector_add(const char *name, old_heur_dissector_t dissector) +{ + heur_dissector_list_t *sub_dissectors = find_heur_dissector_list(name); + heur_dtbl_entry_t *dtbl_entry; + + /* sanity check */ + g_assert(sub_dissectors != NULL); + + dtbl_entry = g_malloc(sizeof (heur_dtbl_entry_t)); + dtbl_entry->is_old_dissector = TRUE; + dtbl_entry->dissector.old = dissector; + + /* do the table insertion */ + *sub_dissectors = g_slist_append(*sub_dissectors, (gpointer)dtbl_entry); +} + +void +heur_dissector_add(const char *name, heur_dissector_t dissector) +{ + heur_dissector_list_t *sub_dissectors = find_heur_dissector_list(name); + heur_dtbl_entry_t *dtbl_entry; + + /* sanity check */ + g_assert(sub_dissectors != NULL); + + dtbl_entry = g_malloc(sizeof (heur_dtbl_entry_t)); + dtbl_entry->is_old_dissector = FALSE; + dtbl_entry->dissector.new = dissector; + + /* do the table insertion */ + *sub_dissectors = g_slist_append(*sub_dissectors, (gpointer)dtbl_entry); +} + +gboolean +old_dissector_try_heuristic(heur_dissector_list_t sub_dissectors, + const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + GSList *entry; + heur_dtbl_entry_t *dtbl_entry; + tvbuff_t *tvb = NULL; + + for (entry = sub_dissectors; entry != NULL; entry = g_slist_next(entry)) { + dtbl_entry = (heur_dtbl_entry_t *)entry->data; + if (dtbl_entry->is_old_dissector) { + if ((*dtbl_entry->dissector.old)(pd, offset, fd, tree)) + return TRUE; + } else { + /* + * Old dissector calling new dissector; use + * "tvb_create_from_top()" to remap. + * + * XXX - what about the "pd" argument? Do + * any dissectors not just pass that along and + * let the "offset" argument handle stepping + * through the packet? + */ + if (tvb == NULL) + tvb = tvb_create_from_top(offset); + if ((*dtbl_entry->dissector.new)(tvb, &pi, tree)) + return TRUE; + } + } + return FALSE; +} + +gboolean +dissector_try_heuristic(heur_dissector_list_t sub_dissectors, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + GSList *entry; + heur_dtbl_entry_t *dtbl_entry; + const guint8 *pd = NULL; + int offset; + + for (entry = sub_dissectors; entry != NULL; entry = g_slist_next(entry)) { + dtbl_entry = (heur_dtbl_entry_t *)entry->data; + if (dtbl_entry->is_old_dissector) { + /* + * New dissector calling old dissector; use + * "tvb_compat()" to remap. + */ + if (pd == NULL) + tvb_compat(tvb, &pd, &offset); + if ((*dtbl_entry->dissector.old)(pd, offset, pinfo->fd, + tree)) + return TRUE; + } else { + if ((*dtbl_entry->dissector.new)(tvb, pinfo, tree)) + return TRUE; + } + } + return FALSE; +} + +void +register_heur_dissector_list(const char *name, heur_dissector_list_t *sub_dissectors) +{ + /* Create our hash-of-hashes if it doesn't already exist */ + if (heur_dissector_lists == NULL) { + heur_dissector_lists = g_hash_table_new(g_str_hash, g_str_equal); + g_assert(heur_dissector_lists != NULL); + } + + /* Make sure the registration is unique */ + g_assert(g_hash_table_lookup(heur_dissector_lists, name) == NULL); + + *sub_dissectors = NULL; /* initially empty */ + g_hash_table_insert(heur_dissector_lists, (gpointer)name, + (gpointer) sub_dissectors); +} diff --git a/epan/packet.h b/epan/packet.h new file mode 100644 index 0000000000..19623772dc --- /dev/null +++ b/epan/packet.h @@ -0,0 +1,371 @@ +/* packet.h + * Definitions for packet disassembly structures and routines + * + * $Id: packet.h,v 1.1 2000/09/27 05:18:06 gram Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@zing.org> + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef __PACKET_H__ +#define __PACKET_H__ + +#include "wiretap/wtap.h" +#include "proto.h" +#include "tvbuff.h" +#include "pint.h" + +#define hi_nibble(b) (((b) & 0xf0) >> 4) +#define lo_nibble(b) ((b) & 0x0f) + +/* Useful when you have an array whose size you can tell at compile-time */ +#define array_length(x) (sizeof x / sizeof x[0]) + +/* Useful when highlighting regions inside a dissect_*() function. With this + * macro, you can highlight from an arbitrary offset to the end of the + * packet (which may come before the end of the frame). + * See old_dissect_data() for an example. + */ +#define END_OF_FRAME (pi.captured_len - offset) + +/* Check whether the "len" bytes of data starting at "offset" is + * entirely inside the captured data for this packet. */ +#define BYTES_ARE_IN_FRAME(offset, len) ((offset) + (len) <= pi.captured_len) + +/* Check whether there's any data at all starting at "offset". */ +#define IS_DATA_IN_FRAME(offset) ((offset) < pi.captured_len) + +/* To pass one of two strings, singular or plural */ +#define plurality(d,s,p) ((d) == 1 ? (s) : (p)) + +typedef struct _column_info { + gint num_cols; /* Number of columns */ + gint *col_fmt; /* Format of column */ + gboolean **fmt_matx; /* Specifies which formats apply to a column */ + gint *col_width; /* Column widths to use during a "-S" capture */ + gchar **col_title; /* Column titles */ + gchar **col_data; /* Column data */ + gboolean writable; /* Are we stil writing to the columns? */ +} column_info; + +#define COL_MAX_LEN 256 +#define COL_MAX_INFO_LEN 4096 + +typedef struct _packet_counts { + gint sctp; + gint tcp; + gint udp; + gint icmp; + gint ospf; + gint gre; + gint netbios; + gint ipx; + gint vines; + gint other; + gint total; +} packet_counts; + +/* Types of character encodings */ +typedef enum { + CHAR_ASCII = 0, /* ASCII */ + CHAR_EBCDIC = 1 /* EBCDIC */ +} char_enc; + +/* XXX - some of this stuff is used only while a packet is being dissected; + should we keep around a separate data structure for that, to save + memory? */ +typedef struct _frame_data { + struct _frame_data *next; /* Next element in list */ + struct _frame_data *prev; /* Previous element in list */ + GSList *pfd; /* Per frame proto data */ + guint32 num; /* Frame number */ + guint32 pkt_len; /* Packet length */ + guint32 cap_len; /* Amount actually captured */ + gint32 rel_secs; /* Relative seconds (yes, it can be negative) */ + gint32 rel_usecs; /* Relative microseconds (yes, it can be negative) */ + guint32 abs_secs; /* Absolute seconds */ + guint32 abs_usecs; /* Absolute microseconds */ + gint32 del_secs; /* Delta seconds (yes, it can be negative) */ + gint32 del_usecs; /* Delta microseconds (yes, it can be negative) */ + long file_off; /* File offset */ + column_info *cinfo; /* Column formatting information */ + int lnk_t; /* Per-packet encapsulation/data-link type */ + struct { + unsigned int passed_dfilter : 1; /* 1 = display, 0 = no display */ + unsigned int encoding : 2; /* Character encoding (ASCII, EBCDIC...) */ + unsigned int visited : 1; /* Has this packet been visited yet? 1=Yes,0=No*/ + unsigned int marked : 1; /* 1 = marked by user, 0 = normal */ + } flags; +} frame_data; + +/* Types of addresses Ethereal knows about. */ +typedef enum { + AT_NONE, /* no link-layer address */ + AT_ETHER, /* MAC (Ethernet, 802.x, FDDI) address */ + AT_IPv4, /* IPv4 */ + AT_IPv6, /* IPv6 */ + AT_IPX, /* IPX */ + AT_SNA, /* SNA */ + AT_ATALK, /* Appletalk DDP */ + AT_VINES /* Banyan Vines */ +} address_type; + +typedef struct _address { + address_type type; /* type of address */ + int len; /* length of address, in bytes */ + const guint8 *data; /* bytes that constitute address */ +} address; + +#define SET_ADDRESS(addr, addr_type, addr_len, addr_data) { \ + (addr)->type = (addr_type); \ + (addr)->len = (addr_len); \ + (addr)->data = (addr_data); \ + } + +/* Types of port numbers Ethereal knows about. */ +typedef enum { + PT_NONE, /* no port number */ + PT_SCTP, /* SCTP */ + PT_TCP, /* TCP */ + PT_UDP, /* UDP */ + PT_NCP /* NCP connection */ +} port_type; + +#define P2P_DIR_UNKNOWN -1 +#define P2P_DIR_SENT 0 +#define P2P_DIR_RECV 1 + +typedef struct _packet_info { + const char *current_proto; /* name of protocol currently being dissected */ + frame_data *fd; + tvbuff_t *compat_top_tvb; /* only needed while converting Ethereal to use tvbuffs */ + union wtap_pseudo_header *pseudo_header; + int len; + int captured_len; + address dl_src; /* link-layer source address */ + address dl_dst; /* link-layer destination address */ + address net_src; /* network-layer source address */ + address net_dst; /* network-layer destination address */ + address src; /* source address (net if present, DL otherwise )*/ + address dst; /* destination address (net if present, DL otherwise )*/ + guint32 ipproto; + port_type ptype; /* type of the following two port numbers */ + guint32 srcport; /* source port */ + guint32 destport; /* destination port */ + guint32 match_port; + int iplen; + int iphdrlen; + int p2p_dir; +} packet_info; + +extern packet_info pi; + +/* Struct for the match_strval function */ + +typedef struct _value_string { + guint32 value; + gchar *strptr; +} value_string; + +/* Struct for boolean enumerations */ +typedef struct true_false_string { + char *true_string; + char *false_string; +} true_false_string; + +/* Hash table for matching port numbers and dissectors */ +typedef GHashTable* dissector_table_t; + +/* types for sub-dissector lookup */ +typedef void (*old_dissector_t)(const u_char *, int, frame_data *, proto_tree *); +typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); + +/* a protocol uses the function to register a sub-dissector table */ +dissector_table_t register_dissector_table(const char *name); + +/* Add a sub-dissector to a dissector table. Called by the protocol routine */ +/* that wants to register a sub-dissector. */ +void old_dissector_add(const char *abbrev, guint32 pattern, old_dissector_t dissector); +void dissector_add(const char *abbrev, guint32 pattern, dissector_t dissector); + +/* Add a sub-dissector to a dissector table. Called by the protocol routine */ +/* that wants to de-register a sub-dissector. */ +void old_dissector_delete(const char *name, guint32 pattern, old_dissector_t dissector); +void dissector_delete(const char *name, guint32 pattern, dissector_t dissector); + +/* Look for a given port in a given dissector table and, if found, call + the dissector with the arguments supplied, and return TRUE, otherwise + return FALSE. */ +gboolean old_dissector_try_port(dissector_table_t sub_dissectors, guint32 port, + const u_char *pd, int offset, frame_data *fd, proto_tree *tree); +gboolean dissector_try_port(dissector_table_t sub_dissectors, guint32 port, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* List of "heuristic" dissectors (which get handed a packet, look at it, + and either recognize it as being for their protocol, dissect it, and + return TRUE, or don't recognize it and return FALSE) to be called + by another dissector. */ +typedef GSList *heur_dissector_list_t; + +/* Type of a heuristic dissector */ +typedef gboolean (*old_heur_dissector_t)(const u_char *, int, frame_data *, + proto_tree *); +typedef gboolean (*heur_dissector_t)(tvbuff_t *, packet_info *, + proto_tree *); + +/* A protocol uses this function to register a heuristic dissector list */ +void register_heur_dissector_list(const char *name, heur_dissector_list_t *list); + +/* Add a sub-dissector to a heuristic dissector list. Called by the + protocol routine that wants to register a sub-dissector. */ +void old_heur_dissector_add(const char *name, old_heur_dissector_t dissector); +void heur_dissector_add(const char *name, heur_dissector_t dissector); + +/* Try all the dissectors in a given heuristic dissector list until + we find one that recognizes the protocol, in which case we return + TRUE, or we run out of dissectors, in which case we return FALSE. */ +gboolean old_dissector_try_heuristic(heur_dissector_list_t sub_dissectors, + const u_char *pd, int offset, frame_data *fd, proto_tree *tree); +gboolean dissector_try_heuristic(heur_dissector_list_t sub_dissectors, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Utility routines used by packet*.c */ +gchar* ether_to_str(const guint8 *); +gchar* ether_to_str_punct(const guint8 *, char); +gchar* ip_to_str(const guint8 *); +struct e_in6_addr; +gchar* ip6_to_str(struct e_in6_addr *); +gchar* ipx_addr_to_str(guint32, const guint8 *); +gchar* abs_time_to_str(struct timeval*); +gchar* rel_time_to_str(struct timeval*); +gchar* time_secs_to_str(guint32); +gchar* bytes_to_str(const guint8 *, int); +gchar* val_to_str(guint32, const value_string *, const char *); +gchar* match_strval(guint32, const value_string*); +char * decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width); +const char *decode_boolean_bitfield(guint32 val, guint32 mask, int width, + const char *truedesc, const char *falsedesc); +const char *decode_enumerated_bitfield(guint32 val, guint32 mask, int width, + const value_string *tab, const char *fmt); +const char *decode_numeric_bitfield(guint32 val, guint32 mask, int width, + const char *fmt); + +void col_set_writable(frame_data *fd, gboolean writable); +gint check_col(frame_data *, gint); +#if __GNUC__ == 2 +void col_add_fstr(frame_data *, gint, gchar *, ...) + __attribute__((format (printf, 3, 4))); +void col_append_fstr(frame_data *, gint, gchar *, ...) + __attribute__((format (printf, 3, 4))); +#else +void col_add_fstr(frame_data *, gint, gchar *, ...); +void col_append_fstr(frame_data *, gint, gchar *, ...); +#endif +void col_add_str(frame_data *, gint, const gchar *); +void col_append_str(frame_data *, gint, gchar *); +void col_set_cls_time(frame_data *, int); +void fill_in_columns(frame_data *); + +void p_add_proto_data(frame_data *, int, void *); +void *p_get_proto_data(frame_data *, int); + +void blank_packetinfo(void); + +/* Do all one-time initialization. */ +void dissect_init(void); + +void dissect_cleanup(void); + +/* Allow protocols to register "init" routines, which are called before + we make a pass through a capture file and dissect all its packets + (e.g., when we read in a new capture file, or run a "filter packets" + or "colorize packets" pass over the current capture file). */ +void register_init_routine(void (*func)(void)); + +/* Call all the registered "init" routines. */ +void init_all_protocols(void); + +void init_dissect_rpc(void); + +/* + * Routines should take four args: packet data *, offset, frame_data *, + * tree * + * They should never modify the packet data. + */ +void dissect_packet(union wtap_pseudo_header *, const u_char *, frame_data *, + proto_tree *); +void old_dissect_data(const u_char *, int, frame_data *, proto_tree *); +void dissect_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + + +/* These functions are in ethertype.c */ +void capture_ethertype(guint16 etype, int offset, + const u_char *pd, packet_counts *ld); +void ethertype(guint16 etype, tvbuff_t*, int offset_after_ethertype, + packet_info *pinfo, proto_tree *tree, + proto_tree *fh_tree, int item_id); +extern const value_string etype_vals[]; + +/* ipproto.c */ +extern const char *ipprotostr(int proto); + +/* + * All of the possible columns in summary listing. + * + * NOTE: The SRC and DST entries MUST remain in this order, or else you + * need to fix the offset #defines before get_column_format! + */ +enum { + COL_NUMBER, /* Packet list item number */ + COL_CLS_TIME, /* Command line-specified time (default relative) */ + COL_REL_TIME, /* Relative time */ + COL_ABS_TIME, /* Absolute time */ + COL_DELTA_TIME, /* Delta time */ + COL_DEF_SRC, /* Source address */ + COL_RES_SRC, /* Resolved source */ + COL_UNRES_SRC, /* Unresolved source */ + COL_DEF_DL_SRC, /* Data link layer source address */ + COL_RES_DL_SRC, /* Resolved DL source */ + COL_UNRES_DL_SRC, /* Unresolved DL source */ + COL_DEF_NET_SRC, /* Network layer source address */ + COL_RES_NET_SRC, /* Resolved net source */ + COL_UNRES_NET_SRC, /* Unresolved net source */ + COL_DEF_DST, /* Destination address */ + COL_RES_DST, /* Resolved dest */ + COL_UNRES_DST, /* Unresolved dest */ + COL_DEF_DL_DST, /* Data link layer dest address */ + COL_RES_DL_DST, /* Resolved DL dest */ + COL_UNRES_DL_DST, /* Unresolved DL dest */ + COL_DEF_NET_DST, /* Network layer dest address */ + COL_RES_NET_DST, /* Resolved net dest */ + COL_UNRES_NET_DST, /* Unresolved net dest */ + COL_DEF_SRC_PORT, /* Source port */ + COL_RES_SRC_PORT, /* Resolved source port */ + COL_UNRES_SRC_PORT, /* Unresolved source port */ + COL_DEF_DST_PORT, /* Destination port */ + COL_RES_DST_PORT, /* Resolved dest port */ + COL_UNRES_DST_PORT, /* Unresolved dest port */ + COL_PROTOCOL, /* Protocol */ + COL_INFO, /* Description */ + COL_PACKET_LENGTH, /* Packet length in bytes */ + NUM_COL_FMTS /* Should always be last */ +}; + +#endif /* packet.h */ |