/* frame_tvbuff.c * Implements a tvbuff for frame * * Wireshark - Network traffic analyzer * By Gerald Combs * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include "frame_tvbuff.h" #include "globals.h" #include "wtap-int.h" /* for ->random_fh */ struct tvb_frame { struct tvbuff tvb; Buffer *buf; /* Packet data */ wtap *wth; /**< Wiretap session */ gint64 file_off; /**< File offset */ guint offset; }; static gboolean frame_read(struct tvb_frame *frame_tvb, struct wtap_pkthdr *phdr, Buffer *buf) { int err; gchar *err_info; /* sanity check, capture file was closed? */ if (cfile.wth != frame_tvb->wth) return FALSE; /* XXX, what if phdr->caplen isn't equal to * frame_tvb->tvb.length + frame_tvb->offset? */ if (!wtap_seek_read(frame_tvb->wth, frame_tvb->file_off, phdr, buf, &err, &err_info)) { /* XXX - report error! */ switch (err) { case WTAP_ERR_BAD_FILE: g_free(err_info); break; } return FALSE; } return TRUE; } static void frame_cache(struct tvb_frame *frame_tvb) { struct wtap_pkthdr phdr; /* Packet header */ wtap_phdr_init(&phdr); if (frame_tvb->buf == NULL) { frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer)); /* XXX, register frame_tvb to some list which frees from time to time not used buffers :] */ ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset); if (!frame_read(frame_tvb, &phdr, frame_tvb->buf)) { /* TODO: THROW(???); */ } } frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset; wtap_phdr_cleanup(&phdr); } static void frame_free(tvbuff_t *tvb) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; if (frame_tvb->buf) { ws_buffer_free(frame_tvb->buf); g_free(frame_tvb->buf); } } static const guint8 * frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; frame_cache(frame_tvb); return tvb->real_data + abs_offset; } static void * frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; frame_cache(frame_tvb); return memcpy(target, tvb->real_data + abs_offset, abs_length); } static gint frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; const guint8 *result; frame_cache(frame_tvb); result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit); if (result) return (gint) (result - tvb->real_data); else return -1; } static gint frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; frame_cache(frame_tvb); return tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle); } static guint frame_offset(const tvbuff_t *tvb _U_, const guint counter) { /* XXX: frame_tvb->offset */ return counter; } static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length); static const struct tvb_ops tvb_frame_ops = { sizeof(struct tvb_frame), /* size */ frame_free, /* free */ frame_offset, /* offset */ frame_get_ptr, /* get_ptr */ frame_memcpy, /* memcpy */ frame_find_guint8, /* find_guint8 */ frame_pbrk_guint8, /* pbrk_guint8 */ frame_clone, /* clone */ }; /* based on tvb_new_real_data() */ tvbuff_t * frame_tvbuff_new(const frame_data *fd, const guint8 *buf) { struct tvb_frame *frame_tvb; tvbuff_t *tvb; tvb = tvb_new(&tvb_frame_ops); /* * XXX - currently, the length arguments in * tvbuff structure are signed, but the captured * and reported length values are unsigned; this means * that length values > 2^31 - 1 will appear as * negative lengths * * Captured length values that large will already * have been filtered out by the Wiretap modules * (the file will be reported as corrupted), to * avoid trying to allocate large chunks of data. * * Reported length values will not have been * filtered out, and should not be filtered out, * as those lengths are not necessarily invalid. * * For now, we clip the reported length at G_MAXINT * * (XXX, is this still a problem?) There was an exception when we call * tvb_new_real_data() now there's no one */ tvb->real_data = buf; tvb->length = fd->cap_len; tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len; tvb->initialized = TRUE; /* * This is the top-level real tvbuff for this data source, * so its data source tvbuff is itself. */ tvb->ds_tvb = tvb; frame_tvb = (struct tvb_frame *) tvb; /* XXX, wtap_can_seek() */ if (cfile.wth && cfile.wth->random_fh #ifdef WANT_PACKET_EDITOR && fd->file_off != -1 /* generic clone for modified packets */ #endif ) { frame_tvb->wth = cfile.wth; frame_tvb->file_off = fd->file_off; frame_tvb->offset = 0; } else frame_tvb->wth = NULL; frame_tvb->buf = NULL; return tvb; } tvbuff_t * frame_tvbuff_new_buffer(const frame_data *fd, Buffer *buf) { return frame_tvbuff_new(fd, ws_buffer_start_ptr(buf)); } static tvbuff_t * frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; tvbuff_t *cloned_tvb; struct tvb_frame *cloned_frame_tvb; /* file not seekable */ if (!frame_tvb->wth) return NULL; abs_offset += frame_tvb->offset; cloned_tvb = tvb_new(&tvb_frame_ops); /* data will be read when needed */ cloned_tvb->real_data = NULL; cloned_tvb->length = abs_length; cloned_tvb->reported_length = abs_length; /* XXX? */ cloned_tvb->initialized = TRUE; /* * This is the top-level real tvbuff for this data source, * so its data source tvbuff is itself. */ cloned_tvb->ds_tvb = cloned_tvb; cloned_frame_tvb = (struct tvb_frame *) cloned_tvb; cloned_frame_tvb->wth = frame_tvb->wth; cloned_frame_tvb->file_off = frame_tvb->file_off; cloned_frame_tvb->offset = abs_offset; cloned_frame_tvb->buf = NULL; return cloned_tvb; } /* based on tvb_new_real_data() */ tvbuff_t * file_tvbuff_new(const frame_data *fd, const guint8 *buf) { struct tvb_frame *frame_tvb; tvbuff_t *tvb; tvb = tvb_new(&tvb_frame_ops); /* * XXX - currently, the length arguments in * tvbuff structure are signed, but the captured * and reported length values are unsigned; this means * that length values > 2^31 - 1 will appear as * negative lengths * * Captured length values that large will already * have been filtered out by the Wiretap modules * (the file will be reported as corrupted), to * avoid trying to allocate large chunks of data. * * Reported length values will not have been * filtered out, and should not be filtered out, * as those lengths are not necessarily invalid. * * For now, we clip the reported length at G_MAXINT * * (XXX, is this still a problem?) There was an exception when we call * tvb_new_real_data() now there's no one */ tvb->real_data = buf; tvb->length = fd->cap_len; tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len; tvb->initialized = TRUE; /* * This is the top-level real tvbuff for this data source, * so its data source tvbuff is itself. */ tvb->ds_tvb = tvb; frame_tvb = (struct tvb_frame *) tvb; /* XXX, wtap_can_seek() */ if (cfile.wth && cfile.wth->random_fh #ifdef WANT_PACKET_EDITOR && fd->file_off != -1 /* generic clone for modified packets */ #endif ) { frame_tvb->wth = cfile.wth; frame_tvb->file_off = fd->file_off; frame_tvb->offset = 0; } else frame_tvb->wth = NULL; frame_tvb->buf = NULL; return tvb; } tvbuff_t * file_tvbuff_new_buffer(const frame_data *fd, Buffer *buf) { return frame_tvbuff_new(fd, ws_buffer_start_ptr(buf)); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */