[Automatic update for 2018-02-04]
[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+
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, struct wtap_pkthdr *phdr, 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, phdr, 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         struct wtap_pkthdr phdr; /* Packet header */
61
62         wtap_phdr_init(&phdr);
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, &phdr, 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_phdr_cleanup(&phdr);
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->initialized     = TRUE;
197
198         /*
199          * This is the top-level real tvbuff for this data source,
200          * so its data source tvbuff is itself.
201          */
202         tvb->ds_tvb = tvb;
203
204         frame_tvb = (struct tvb_frame *) tvb;
205
206         /* XXX, wtap_can_seek() */
207         if (prov->wth && prov->wth->random_fh) {
208                 frame_tvb->prov = prov;
209                 frame_tvb->file_off = fd->file_off;
210                 frame_tvb->offset = 0;
211         } else
212                 frame_tvb->prov = NULL;
213
214         frame_tvb->buf = NULL;
215
216         return tvb;
217 }
218
219 tvbuff_t *
220 frame_tvbuff_new_buffer(const struct packet_provider_data *prov,
221     const frame_data *fd, Buffer *buf)
222 {
223         return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
224 }
225
226 static tvbuff_t *
227 frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
228 {
229         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
230
231         tvbuff_t *cloned_tvb;
232         struct tvb_frame *cloned_frame_tvb;
233
234         /* file not seekable */
235         if (!frame_tvb->prov)
236                 return NULL;
237
238         abs_offset += frame_tvb->offset;
239
240         cloned_tvb = tvb_new(&tvb_frame_ops);
241
242         /* data will be read when needed */
243         cloned_tvb->real_data       = NULL;
244         cloned_tvb->length          = abs_length;
245         cloned_tvb->reported_length = abs_length; /* XXX? */
246         cloned_tvb->initialized     = TRUE;
247
248         /*
249          * This is the top-level real tvbuff for this data source,
250          * so its data source tvbuff is itself.
251          */
252         cloned_tvb->ds_tvb = cloned_tvb;
253
254         cloned_frame_tvb = (struct tvb_frame *) cloned_tvb;
255         cloned_frame_tvb->prov = frame_tvb->prov;
256         cloned_frame_tvb->file_off = frame_tvb->file_off;
257         cloned_frame_tvb->offset = abs_offset;
258         cloned_frame_tvb->buf = NULL;
259
260         return cloned_tvb;
261 }
262
263
264 /* based on tvb_new_real_data() */
265 tvbuff_t *
266 file_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
267     const guint8 *buf)
268 {
269         struct tvb_frame *frame_tvb;
270         tvbuff_t *tvb;
271
272         tvb = tvb_new(&tvb_frame_ops);
273
274         /*
275          * XXX - currently, the length arguments in
276          * tvbuff structure are signed, but the captured
277          * and reported length values are unsigned; this means
278          * that length values > 2^31 - 1 will appear as
279          * negative lengths
280          *
281          * Captured length values that large will already
282          * have been filtered out by the Wiretap modules
283          * (the file will be reported as corrupted), to
284          * avoid trying to allocate large chunks of data.
285          *
286          * Reported length values will not have been
287          * filtered out, and should not be filtered out,
288          * as those lengths are not necessarily invalid.
289          *
290          * For now, we clip the reported length at G_MAXINT
291          *
292          * (XXX, is this still a problem?) There was an exception when we call
293          * tvb_new_real_data() now there's no one
294          */
295
296         tvb->real_data       = buf;
297         tvb->length          = fd->cap_len;
298         tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
299         tvb->initialized     = TRUE;
300
301         /*
302          * This is the top-level real tvbuff for this data source,
303          * so its data source tvbuff is itself.
304          */
305         tvb->ds_tvb = tvb;
306
307         frame_tvb = (struct tvb_frame *) tvb;
308
309         /* XXX, wtap_can_seek() */
310         if (prov->wth && prov->wth->random_fh) {
311                 frame_tvb->prov = prov;
312                 frame_tvb->file_off = fd->file_off;
313                 frame_tvb->offset = 0;
314         } else
315                 frame_tvb->prov = NULL;
316
317         frame_tvb->buf = NULL;
318
319         return tvb;
320 }
321
322 tvbuff_t *
323 file_tvbuff_new_buffer(const struct packet_provider_data *prov,
324     const frame_data *fd, Buffer *buf)
325 {
326         return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
327 }
328
329 /*
330  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
331  *
332  * Local variables:
333  * c-basic-offset: 8
334  * tab-width: 8
335  * indent-tabs-mode: t
336  * End:
337  *
338  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
339  * :indentSize=8:tabSize=8:noTabs=false:
340  */