Store pointers to previously displayed and captured packet, not nstime_t deltas.
[metze/wireshark/wip.git] / epan / frame_data.c
1 /* frame_data.c
2  * Routines for packet disassembly
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  *
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.
15  *
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.
20  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <wiretap/wtap.h>
29 #include <epan/frame_data.h>
30 #include <epan/packet.h>
31 #include <epan/emem.h>
32 #include <epan/timestamp.h>
33
34 #include <glib.h>
35
36 /* Protocol-specific data attached to a frame_data structure - protocol
37    index and opaque pointer. */
38 typedef struct _frame_proto_data {
39   int proto;
40   void *proto_data;
41 } frame_proto_data;
42
43 /* XXX - I declared this static, because it only seems to be used by
44  * p_get_proto_data and p_add_proto_data
45  */
46 static gint p_compare(gconstpointer a, gconstpointer b)
47 {
48   const frame_proto_data *ap = (const frame_proto_data *)a;
49   const frame_proto_data *bp = (const frame_proto_data *)b;
50
51   if (ap -> proto > bp -> proto)
52     return 1;
53   else if (ap -> proto == bp -> proto)
54     return 0;
55   else
56     return -1;
57
58 }
59
60 void
61 p_add_proto_data(frame_data *fd, int proto, void *proto_data)
62 {
63   frame_proto_data *p1 = se_alloc(sizeof(frame_proto_data));
64
65   p1->proto = proto;
66   p1->proto_data = proto_data;
67
68   /* Add it to the GSLIST */
69
70   fd -> pfd = g_slist_insert_sorted(fd -> pfd,
71                     (gpointer *)p1,
72                     p_compare);
73 }
74
75 void *
76 p_get_proto_data(frame_data *fd, int proto)
77 {
78   frame_proto_data temp, *p1;
79   GSList *item;
80
81   temp.proto = proto;
82   temp.proto_data = NULL;
83
84   item = g_slist_find_custom(fd->pfd, (gpointer *)&temp, p_compare);
85
86   if (item) {
87     p1 = (frame_proto_data *)item->data;
88     return p1->proto_data;
89   }
90
91   return NULL;
92
93 }
94
95 void
96 p_remove_proto_data(frame_data *fd, int proto)
97 {
98   frame_proto_data temp;
99   GSList *item;
100
101   temp.proto = proto;
102   temp.proto_data = NULL;
103
104   item = g_slist_find_custom(fd->pfd, (gpointer *)&temp, p_compare);
105
106   if (item) {
107     fd->pfd = g_slist_remove(fd->pfd, item->data);
108   }
109 }
110
111 #define COMPARE_FRAME_NUM()     ((fdata1->num < fdata2->num) ? -1 : \
112                                  (fdata1->num > fdata2->num) ? 1 : \
113                                  0)
114
115 #define COMPARE_NUM(f)  ((fdata1->f < fdata2->f) ? -1 : \
116                          (fdata1->f > fdata2->f) ? 1 : \
117                          COMPARE_FRAME_NUM())
118
119 /* Compare time stamps.
120    A packet whose time is a reference time is considered to have
121    a lower time stamp than any frame with a non-reference time;
122    if both packets' times are reference times, we compare the
123    times of the packets. */
124 #define COMPARE_TS_REAL(time1, time2) \
125                 ((fdata1->flags.ref_time && !fdata2->flags.ref_time) ? -1 : \
126                  (!fdata1->flags.ref_time && fdata2->flags.ref_time) ? 1 : \
127                  ((time1).secs < (time2).secs) ? -1 : \
128                  ((time1).secs > (time2).secs) ? 1 : \
129                  ((time1).nsecs < (time2).nsecs) ? -1 :\
130                  ((time1).nsecs > (time2).nsecs) ? 1 : \
131                  COMPARE_FRAME_NUM())
132
133 #define COMPARE_TS(ts) COMPARE_TS_REAL(fdata1->ts, fdata2->ts)
134
135 void
136 frame_delta_abs_time(const frame_data *fdata, const frame_data *prev, nstime_t *delta)
137 {
138         if (prev) {
139                 nstime_delta(delta, &fdata->abs_ts, &prev->abs_ts);
140         } else {
141                 /* If we don't have the time stamp of the previous packet,
142                    it's because we have no displayed/captured packets prior to this.
143                    Set the delta time to zero. */
144                 nstime_set_zero(delta);
145         }
146 }
147
148 static gint
149 frame_data_time_delta_compare(const frame_data *fdata1, const frame_data *fdata2)
150 {
151         nstime_t del_cap_ts1, del_cap_ts2;
152
153         frame_delta_abs_time(fdata1, fdata1->prev_cap, &del_cap_ts1);
154         frame_delta_abs_time(fdata2, fdata2->prev_cap, &del_cap_ts2);
155
156         return COMPARE_TS_REAL(del_cap_ts1, del_cap_ts2);
157 }
158
159 static gint
160 frame_data_time_delta_dis_compare(const frame_data *fdata1, const frame_data *fdata2)
161 {
162         nstime_t del_dis_ts1, del_dis_ts2;
163
164         frame_delta_abs_time(fdata1, fdata1->prev_dis, &del_dis_ts1);
165         frame_delta_abs_time(fdata2, fdata2->prev_dis, &del_dis_ts2);
166
167         return COMPARE_TS_REAL(del_dis_ts1, del_dis_ts2);
168 }
169
170 gint
171 frame_data_compare(const frame_data *fdata1, const frame_data *fdata2, int field)
172 {
173     switch (field) {
174         case COL_NUMBER:
175             return COMPARE_FRAME_NUM();
176
177         case COL_CLS_TIME:
178             switch (timestamp_get_type()) {
179                 case TS_ABSOLUTE:
180                 case TS_ABSOLUTE_WITH_DATE:
181                 case TS_UTC:
182                 case TS_UTC_WITH_DATE:
183                 case TS_EPOCH:
184                     return COMPARE_TS(abs_ts);
185
186                 case TS_RELATIVE:
187                     return COMPARE_TS(rel_ts);
188
189                 case TS_DELTA:
190                     return frame_data_time_delta_compare(fdata1, fdata2);
191
192                 case TS_DELTA_DIS:
193                     return frame_data_time_delta_dis_compare(fdata1, fdata2);
194
195                 case TS_NOT_SET:
196                     return 0;
197             }
198             return 0;
199
200         case COL_ABS_TIME:
201         case COL_ABS_DATE_TIME:
202         case COL_UTC_TIME:
203         case COL_UTC_DATE_TIME:
204             return COMPARE_TS(abs_ts);
205
206         case COL_REL_TIME:
207             return COMPARE_TS(rel_ts);
208
209         case COL_DELTA_TIME:
210             return frame_data_time_delta_compare(fdata1, fdata2);
211
212         case COL_DELTA_TIME_DIS:
213             return frame_data_time_delta_dis_compare(fdata1, fdata2);
214
215         case COL_PACKET_LENGTH:
216             return COMPARE_NUM(pkt_len);
217
218         case COL_CUMULATIVE_BYTES:
219             return COMPARE_NUM(cum_bytes);
220
221     }
222     g_return_val_if_reached(0);
223 }
224
225 void
226 frame_data_init(frame_data *fdata, guint32 num,
227                 const struct wtap_pkthdr *phdr, gint64 offset,
228                 guint32 cum_bytes)
229 {
230   fdata->pfd = NULL;
231   fdata->num = num;
232   fdata->interface_id = phdr->interface_id;
233   fdata->pkt_len = phdr->len;
234   fdata->cum_bytes = cum_bytes + phdr->len;
235   fdata->cap_len = phdr->caplen;
236   fdata->file_off = offset;
237   fdata->subnum = 0;
238   /* To save some memory, we coerce it into a gint16 */
239   g_assert(phdr->pkt_encap <= G_MAXINT16);
240   fdata->lnk_t = (gint16) phdr->pkt_encap;
241   fdata->flags.passed_dfilter = 0;
242   fdata->flags.dependent_of_displayed = 0;
243   fdata->flags.encoding = PACKET_CHAR_ENC_CHAR_ASCII;
244   fdata->flags.visited = 0;
245   fdata->flags.marked = 0;
246   fdata->flags.ref_time = 0;
247   fdata->flags.ignored = 0;
248   fdata->flags.has_ts = (phdr->presence_flags & WTAP_HAS_TS) ? 1 : 0;
249   fdata->flags.has_if_id = (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) ? 1 : 0;
250   fdata->color_filter = NULL;
251   fdata->abs_ts.secs = phdr->ts.secs;
252   fdata->abs_ts.nsecs = phdr->ts.nsecs;
253   fdata->shift_offset.secs = 0;
254   fdata->shift_offset.nsecs = 0;
255   fdata->rel_ts.secs = 0;
256   fdata->rel_ts.nsecs = 0;
257   fdata->prev_dis = NULL;
258   fdata->prev_cap = NULL;
259   fdata->opt_comment = phdr->opt_comment;
260 }
261
262 void
263 frame_data_set_before_dissect(frame_data *fdata,
264                 nstime_t *elapsed_time,
265                 nstime_t *first_ts,
266                 const frame_data *prev_dis,
267                 const frame_data *prev_cap)
268 {
269   /* If we don't have the time stamp of the first packet in the
270      capture, it's because this is the first packet.  Save the time
271      stamp of this packet as the time stamp of the first packet. */
272   if (nstime_is_unset(first_ts))
273     *first_ts = fdata->abs_ts;
274
275   /* if this frames is marked as a reference time frame, reset
276      firstsec and firstusec to this frame */
277   if(fdata->flags.ref_time)
278     *first_ts = fdata->abs_ts;
279
280   /* Get the time elapsed between the first packet and this packet. */
281   nstime_delta(&fdata->rel_ts, &fdata->abs_ts, first_ts);
282
283   /* If it's greater than the current elapsed time, set the elapsed time
284      to it (we check for "greater than" so as not to be confused by
285      time moving backwards). */
286   if ((gint32)elapsed_time->secs < fdata->rel_ts.secs
287     || ((gint32)elapsed_time->secs == fdata->rel_ts.secs && (gint32)elapsed_time->nsecs < fdata->rel_ts.nsecs)) {
288     *elapsed_time = fdata->rel_ts;
289   }
290
291   fdata->prev_dis = prev_dis;
292   fdata->prev_cap = prev_cap;
293 }
294
295 void
296 frame_data_set_after_dissect(frame_data *fdata,
297                 guint32 *cum_bytes)
298 {
299   /* This frame either passed the display filter list or is marked as
300      a time reference frame.  All time reference frames are displayed
301      even if they dont pass the display filter */
302   if(fdata->flags.ref_time){
303     /* if this was a TIME REF frame we should reset the cul bytes field */
304     *cum_bytes = fdata->pkt_len;
305     fdata->cum_bytes = *cum_bytes;
306   } else {
307     /* increase cum_bytes with this packets length */
308     *cum_bytes += fdata->pkt_len;
309     fdata->cum_bytes = *cum_bytes;
310   }
311 }
312
313 void
314 frame_data_cleanup(frame_data *fdata)
315 {
316   if (fdata->pfd) {
317     g_slist_free(fdata->pfd);
318     fdata->pfd = NULL;
319   }
320
321   /* XXX, frame_data_cleanup() is called when redissecting (rescan_packets()),
322    *      which might be triggered by lot of things, like: preferences change, setting manual address resolve, etc.. (grep by redissect_packets)
323    *      fdata->opt_comment can be set by user, which we must not discard when redissecting.
324    */
325 #if 0
326   if (fdata->opt_comment) {
327     g_free(fdata->opt_comment);
328     fdata->opt_comment = NULL;
329   }
330 #endif
331 }