Bugfixes of ASTERIX I034
[metze/wireshark/wip.git] / frame_tvbuff.c
1 /* frame_tvbuff.c
2  * Implements a tvbuff for frame
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <config.h>
12
13 #include <glib.h>
14
15 #include <epan/packet.h>
16 #include <epan/tvbuff-int.h>
17 #include <epan/tvbuff.h>
18
19 #include "frame_tvbuff.h"
20
21 #include "wiretap/wtap-int.h" /* for ->random_fh */
22
23 struct tvb_frame {
24         struct tvbuff tvb;
25
26         Buffer *buf;         /* Packet data */
27
28         const struct packet_provider_data *prov;        /* provider of packet information */
29         gint64 file_off;     /**< File offset */
30
31         guint offset;
32 };
33
34 static gboolean
35 frame_read(struct tvb_frame *frame_tvb, wtap_rec *rec, Buffer *buf)
36 {
37         int    err;
38         gchar *err_info;
39
40         /* XXX, what if phdr->caplen isn't equal to
41          * frame_tvb->tvb.length + frame_tvb->offset?
42          */
43         if (!wtap_seek_read(frame_tvb->prov->wth, frame_tvb->file_off, rec, buf, &err, &err_info)) {
44                 /* XXX - report error! */
45                 switch (err) {
46                         case WTAP_ERR_BAD_FILE:
47                                 g_free(err_info);
48                                 break;
49                 }
50                 return FALSE;
51         }
52         return TRUE;
53 }
54
55 static GPtrArray *buffer_cache = NULL;
56
57 static void
58 frame_cache(struct tvb_frame *frame_tvb)
59 {
60         wtap_rec rec; /* Record metadata */
61
62         wtap_rec_init(&rec);
63
64         if (frame_tvb->buf == NULL) {
65                 if (G_UNLIKELY(!buffer_cache)) buffer_cache = g_ptr_array_sized_new(1024);
66
67                 if (buffer_cache->len > 0) {
68                         frame_tvb->buf = (struct Buffer *) g_ptr_array_remove_index(buffer_cache, buffer_cache->len - 1);
69                 } else {
70                         frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer));
71                 }
72
73                 ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset);
74
75                 if (!frame_read(frame_tvb, &rec, frame_tvb->buf))
76                         { /* TODO: THROW(???); */ }
77         }
78
79         frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
80
81         wtap_rec_cleanup(&rec);
82 }
83
84 static void
85 frame_free(tvbuff_t *tvb)
86 {
87         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
88
89         if (frame_tvb->buf) {
90                 ws_buffer_free(frame_tvb->buf);
91                 g_ptr_array_add(buffer_cache, frame_tvb->buf);
92         }
93 }
94
95 static const guint8 *
96 frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_)
97 {
98         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
99
100         frame_cache(frame_tvb);
101
102         return tvb->real_data + abs_offset;
103 }
104
105 static void *
106 frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
107 {
108         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
109
110         frame_cache(frame_tvb);
111
112         return memcpy(target, tvb->real_data + abs_offset, abs_length);
113 }
114
115 static gint
116 frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
117 {
118         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
119         const guint8 *result;
120
121         frame_cache(frame_tvb);
122
123         result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit);
124         if (result)
125                 return (gint) (result - tvb->real_data);
126         else
127                 return -1;
128 }
129
130 static gint
131 frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
132 {
133         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
134
135         frame_cache(frame_tvb);
136
137         return tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle);
138 }
139
140 static guint
141 frame_offset(const tvbuff_t *tvb _U_, const guint counter)
142 {
143         /* XXX: frame_tvb->offset */
144         return counter;
145 }
146
147 static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length);
148
149 static const struct tvb_ops tvb_frame_ops = {
150         sizeof(struct tvb_frame), /* size */
151
152         frame_free,           /* free */
153         frame_offset,         /* offset */
154         frame_get_ptr,        /* get_ptr */
155         frame_memcpy,         /* memcpy */
156         frame_find_guint8,    /* find_guint8 */
157         frame_pbrk_guint8,    /* pbrk_guint8 */
158         frame_clone,          /* clone */
159 };
160
161 /* based on tvb_new_real_data() */
162 tvbuff_t *
163 frame_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
164     const guint8 *buf)
165 {
166         struct tvb_frame *frame_tvb;
167         tvbuff_t *tvb;
168
169         tvb = tvb_new(&tvb_frame_ops);
170
171         /*
172          * XXX - currently, the length arguments in
173          * tvbuff structure are signed, but the captured
174          * and reported length values are unsigned; this means
175          * that length values > 2^31 - 1 will appear as
176          * negative lengths
177          *
178          * Captured length values that large will already
179          * have been filtered out by the Wiretap modules
180          * (the file will be reported as corrupted), to
181          * avoid trying to allocate large chunks of data.
182          *
183          * Reported length values will not have been
184          * filtered out, and should not be filtered out,
185          * as those lengths are not necessarily invalid.
186          *
187          * For now, we clip the reported length at G_MAXINT
188          *
189          * (XXX, is this still a problem?) There was an exception when we call
190          * tvb_new_real_data() now there's no one
191          */
192
193         tvb->real_data        = buf;
194         tvb->length           = fd->cap_len;
195         tvb->reported_length  = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
196         tvb->contained_length = tvb->reported_length;
197         tvb->initialized      = TRUE;
198
199         /*
200          * This is the top-level real tvbuff for this data source,
201          * so its data source tvbuff is itself.
202          */
203         tvb->ds_tvb = tvb;
204
205         frame_tvb = (struct tvb_frame *) tvb;
206
207         /* XXX, wtap_can_seek() */
208         if (prov->wth && prov->wth->random_fh) {
209                 frame_tvb->prov = prov;
210                 frame_tvb->file_off = fd->file_off;
211                 frame_tvb->offset = 0;
212         } else
213                 frame_tvb->prov = NULL;
214
215         frame_tvb->buf = NULL;
216
217         return tvb;
218 }
219
220 tvbuff_t *
221 frame_tvbuff_new_buffer(const struct packet_provider_data *prov,
222     const frame_data *fd, Buffer *buf)
223 {
224         return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
225 }
226
227 static tvbuff_t *
228 frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
229 {
230         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
231
232         tvbuff_t *cloned_tvb;
233         struct tvb_frame *cloned_frame_tvb;
234
235         /* file not seekable */
236         if (!frame_tvb->prov)
237                 return NULL;
238
239         abs_offset += frame_tvb->offset;
240
241         cloned_tvb = tvb_new(&tvb_frame_ops);
242
243         /* data will be read when needed */
244         cloned_tvb->real_data        = NULL;
245         cloned_tvb->length           = abs_length;
246         cloned_tvb->reported_length  = abs_length; /* XXX? */
247         cloned_tvb->contained_length = cloned_tvb->reported_length;
248         cloned_tvb->initialized      = TRUE;
249
250         /*
251          * This is the top-level real tvbuff for this data source,
252          * so its data source tvbuff is itself.
253          */
254         cloned_tvb->ds_tvb = cloned_tvb;
255
256         cloned_frame_tvb = (struct tvb_frame *) cloned_tvb;
257         cloned_frame_tvb->prov = frame_tvb->prov;
258         cloned_frame_tvb->file_off = frame_tvb->file_off;
259         cloned_frame_tvb->offset = abs_offset;
260         cloned_frame_tvb->buf = NULL;
261
262         return cloned_tvb;
263 }
264
265
266 /* based on tvb_new_real_data() */
267 tvbuff_t *
268 file_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
269     const guint8 *buf)
270 {
271         struct tvb_frame *frame_tvb;
272         tvbuff_t *tvb;
273
274         tvb = tvb_new(&tvb_frame_ops);
275
276         /*
277          * XXX - currently, the length arguments in
278          * tvbuff structure are signed, but the captured
279          * and reported length values are unsigned; this means
280          * that length values > 2^31 - 1 will appear as
281          * negative lengths
282          *
283          * Captured length values that large will already
284          * have been filtered out by the Wiretap modules
285          * (the file will be reported as corrupted), to
286          * avoid trying to allocate large chunks of data.
287          *
288          * Reported length values will not have been
289          * filtered out, and should not be filtered out,
290          * as those lengths are not necessarily invalid.
291          *
292          * For now, we clip the reported length at G_MAXINT
293          *
294          * (XXX, is this still a problem?) There was an exception when we call
295          * tvb_new_real_data() now there's no one
296          */
297
298         tvb->real_data        = buf;
299         tvb->length           = fd->cap_len;
300         tvb->reported_length  = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
301         tvb->contained_length = tvb->reported_length;
302         tvb->initialized      = TRUE;
303
304         /*
305          * This is the top-level real tvbuff for this data source,
306          * so its data source tvbuff is itself.
307          */
308         tvb->ds_tvb = tvb;
309
310         frame_tvb = (struct tvb_frame *) tvb;
311
312         /* XXX, wtap_can_seek() */
313         if (prov->wth && prov->wth->random_fh) {
314                 frame_tvb->prov = prov;
315                 frame_tvb->file_off = fd->file_off;
316                 frame_tvb->offset = 0;
317         } else
318                 frame_tvb->prov = NULL;
319
320         frame_tvb->buf = NULL;
321
322         return tvb;
323 }
324
325 tvbuff_t *
326 file_tvbuff_new_buffer(const struct packet_provider_data *prov,
327     const frame_data *fd, Buffer *buf)
328 {
329         return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
330 }
331
332 /*
333  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
334  *
335  * Local variables:
336  * c-basic-offset: 8
337  * tab-width: 8
338  * indent-tabs-mode: t
339  * End:
340  *
341  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
342  * :indentSize=8:tabSize=8:noTabs=false:
343  */