dmp: Enhance ack framenum links.
[metze/wireshark/wip.git] / epan / frame_data.c
1 /* frame_data.c
2  * Routines for packet disassembly
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <glib.h>
27
28 #include <epan/epan.h>
29 #include <wiretap/wtap.h>
30 #include <epan/frame_data.h>
31 #include <epan/packet.h>
32 #include <epan/wmem/wmem.h>
33 #include <epan/timestamp.h>
34 #include <epan/packet_info.h>
35
36
37 /* Protocol-specific data attached to a frame_data structure - protocol
38    index and opaque pointer. */
39 typedef struct _frame_proto_data {
40   int   proto;
41   guint32 key;
42   void *proto_data;
43 } frame_proto_data;
44
45 /* XXX - I declared this static, because it only seems to be used by
46  * p_get_proto_data and p_add_proto_data
47  */
48 static gint
49 p_compare(gconstpointer a, gconstpointer b)
50 {
51   const frame_proto_data *ap = (const frame_proto_data *)a;
52   const frame_proto_data *bp = (const frame_proto_data *)b;
53
54   if (ap -> proto > bp -> proto){
55     return 1;
56   }else if (ap -> proto == bp -> proto){
57     if (ap -> key > bp -> key){
58       return 1;
59     }else if (ap -> key == bp -> key){
60       return 0;
61     }
62     return -1;
63   }else{
64     return -1;
65   }
66 }
67
68 void
69 p_add_proto_data(wmem_allocator_t *tmp_scope, struct _packet_info* pinfo, int proto, guint32 key, void *proto_data)
70 {
71   frame_proto_data *p1;
72   GSList** proto_list;
73   wmem_allocator_t *scope;
74
75   if (tmp_scope == pinfo->pool) {
76     scope = tmp_scope;
77     proto_list = &pinfo->proto_data;
78   } else {
79     scope = wmem_file_scope();
80     proto_list = &pinfo->fd->pfd;
81   }
82
83   p1 = (frame_proto_data *)wmem_alloc(scope, sizeof(frame_proto_data));
84
85   p1->proto = proto;
86   p1->key = key;
87   p1->proto_data = proto_data;
88
89   /* Add it to the GSLIST */
90   *proto_list = g_slist_prepend(*proto_list,
91                     (gpointer *)p1);
92 }
93
94 void *
95 p_get_proto_data(wmem_allocator_t *scope, struct _packet_info* pinfo, int proto, guint32 key)
96 {
97   frame_proto_data  temp, *p1;
98   GSList           *item;
99
100   temp.proto = proto;
101   temp.key = key;
102   temp.proto_data = NULL;
103
104   if (scope == pinfo->pool) {
105     item = g_slist_find_custom(pinfo->proto_data, (gpointer *)&temp, p_compare);
106   } else {
107     item = g_slist_find_custom(pinfo->fd->pfd, (gpointer *)&temp, p_compare);
108   }
109
110   if (item) {
111     p1 = (frame_proto_data *)item->data;
112     return p1->proto_data;
113   }
114
115   return NULL;
116
117 }
118
119 void
120 p_remove_proto_data(wmem_allocator_t *scope, struct _packet_info* pinfo, int proto, guint32 key)
121 {
122   frame_proto_data  temp;
123   GSList           *item;
124   GSList** proto_list;
125
126   temp.proto = proto;
127   temp.key = key;
128   temp.proto_data = NULL;
129
130   if (scope == pinfo->pool) {
131     item = g_slist_find_custom(pinfo->fd->pfd, (gpointer *)&temp, p_compare);
132     proto_list = &pinfo->proto_data;
133   } else {
134     item = g_slist_find_custom(pinfo->fd->pfd, (gpointer *)&temp, p_compare);
135     proto_list = &pinfo->fd->pfd;
136   }
137
138   if (item) {
139     *proto_list = g_slist_remove(*proto_list, item->data);
140   }
141
142 }
143
144 gchar *
145 p_get_proto_name_and_key(wmem_allocator_t *scope, struct _packet_info* pinfo, guint pfd_index){
146   frame_proto_data  *temp;
147
148   if (scope == pinfo->pool) {
149     temp = (frame_proto_data*)g_slist_nth_data(pinfo->proto_data, pfd_index);
150   } else {
151     temp = (frame_proto_data*)g_slist_nth_data(pinfo->fd->pfd, pfd_index);
152   }
153
154   return wmem_strdup_printf(wmem_packet_scope(),"[%s, key %u]",proto_get_protocol_name(temp->proto), temp->key);
155 }
156
157 #define COMPARE_FRAME_NUM()     ((fdata1->num < fdata2->num) ? -1 : \
158                                  (fdata1->num > fdata2->num) ? 1 : \
159                                  0)
160
161 #define COMPARE_NUM(f)  ((fdata1->f < fdata2->f) ? -1 : \
162                          (fdata1->f > fdata2->f) ? 1 : \
163                          COMPARE_FRAME_NUM())
164
165 /* Compare time stamps.
166    A packet whose time is a reference time is considered to have
167    a lower time stamp than any frame with a non-reference time;
168    if both packets' times are reference times, we compare the
169    times of the packets. */
170 #define COMPARE_TS_REAL(time1, time2) \
171                 ((fdata1->flags.ref_time && !fdata2->flags.ref_time) ? -1 : \
172                  (!fdata1->flags.ref_time && fdata2->flags.ref_time) ? 1 : \
173                  ((time1).secs < (time2).secs) ? -1 : \
174                  ((time1).secs > (time2).secs) ? 1 : \
175                  ((time1).nsecs < (time2).nsecs) ? -1 :\
176                  ((time1).nsecs > (time2).nsecs) ? 1 : \
177                  COMPARE_FRAME_NUM())
178
179 #define COMPARE_TS(ts) COMPARE_TS_REAL(fdata1->ts, fdata2->ts)
180
181 void
182 frame_delta_abs_time(const struct epan_session *epan, const frame_data *fdata, guint32 prev_num, nstime_t *delta)
183 {
184   const nstime_t *prev_abs_ts = (prev_num) ? epan_get_frame_ts(epan, prev_num) : NULL;
185
186   if (prev_abs_ts) {
187     nstime_delta(delta, &fdata->abs_ts, prev_abs_ts);
188   } else {
189     /* If we don't have the time stamp of the previous packet,
190        it's because we have no displayed/captured packets prior to this.
191        Set the delta time to zero. */
192     nstime_set_zero(delta);
193   }
194 }
195
196 static gint
197 frame_data_time_delta_compare(const struct epan_session *epan, const frame_data *fdata1, const frame_data *fdata2)
198 {
199   nstime_t del_cap_ts1, del_cap_ts2;
200
201   frame_delta_abs_time(epan, fdata1, fdata1->num - 1, &del_cap_ts1);
202   frame_delta_abs_time(epan, fdata2, fdata2->num - 1, &del_cap_ts2);
203
204   return COMPARE_TS_REAL(del_cap_ts1, del_cap_ts2);
205 }
206
207 static gint
208 frame_data_time_delta_rel_compare(const struct epan_session *epan, const frame_data *fdata1, const frame_data *fdata2)
209 {
210   nstime_t del_rel_ts1, del_rel_ts2;
211
212   frame_delta_abs_time(epan, fdata1, fdata1->frame_ref_num, &del_rel_ts1);
213   frame_delta_abs_time(epan, fdata2, fdata2->frame_ref_num, &del_rel_ts2);
214
215   return COMPARE_TS_REAL(del_rel_ts1, del_rel_ts2);
216 }
217
218 static gint
219 frame_data_time_delta_dis_compare(const struct epan_session *epan, const frame_data *fdata1, const frame_data *fdata2)
220 {
221   nstime_t del_dis_ts1, del_dis_ts2;
222
223   frame_delta_abs_time(epan, fdata1, fdata1->prev_dis_num, &del_dis_ts1);
224   frame_delta_abs_time(epan, fdata2, fdata2->prev_dis_num, &del_dis_ts2);
225
226   return COMPARE_TS_REAL(del_dis_ts1, del_dis_ts2);
227 }
228
229 gint
230 frame_data_compare(const struct epan_session *epan, const frame_data *fdata1, const frame_data *fdata2, int field)
231 {
232   switch (field) {
233   case COL_NUMBER:
234     return COMPARE_FRAME_NUM();
235
236   case COL_CLS_TIME:
237     switch (timestamp_get_type()) {
238     case TS_ABSOLUTE:
239     case TS_ABSOLUTE_WITH_YMD:
240     case TS_ABSOLUTE_WITH_YDOY:
241     case TS_UTC:
242     case TS_UTC_WITH_YMD:
243     case TS_UTC_WITH_YDOY:
244     case TS_EPOCH:
245       return COMPARE_TS(abs_ts);
246
247     case TS_RELATIVE:
248       return frame_data_time_delta_rel_compare(epan, fdata1, fdata2);
249
250     case TS_DELTA:
251       return frame_data_time_delta_compare(epan, fdata1, fdata2);
252
253     case TS_DELTA_DIS:
254       return frame_data_time_delta_dis_compare(epan, fdata1, fdata2);
255
256     case TS_NOT_SET:
257       return 0;
258     }
259     return 0;
260
261   case COL_ABS_TIME:
262   case COL_ABS_YMD_TIME:
263   case COL_ABS_YDOY_TIME:
264   case COL_UTC_TIME:
265   case COL_UTC_YMD_TIME:
266   case COL_UTC_YDOY_TIME:
267     return COMPARE_TS(abs_ts);
268
269   case COL_REL_TIME:
270     return frame_data_time_delta_rel_compare(epan, fdata1, fdata2);
271
272   case COL_DELTA_TIME:
273     return frame_data_time_delta_compare(epan, fdata1, fdata2);
274
275   case COL_DELTA_TIME_DIS:
276     return frame_data_time_delta_dis_compare(epan, fdata1, fdata2);
277
278   case COL_PACKET_LENGTH:
279     return COMPARE_NUM(pkt_len);
280
281   case COL_CUMULATIVE_BYTES:
282     return COMPARE_NUM(cum_bytes);
283
284   }
285   g_return_val_if_reached(0);
286 }
287
288 void
289 frame_data_init(frame_data *fdata, guint32 num,
290                 const struct wtap_pkthdr *phdr, gint64 offset,
291                 guint32 cum_bytes)
292 {
293   fdata->pfd = NULL;
294   fdata->num = num;
295   fdata->pkt_len = phdr->len;
296   fdata->cum_bytes = cum_bytes + phdr->len;
297   fdata->cap_len = phdr->caplen;
298   fdata->file_off = offset;
299   fdata->subnum = 0;
300   /* To save some memory, we coerce it into a gint16 */
301   g_assert(phdr->pkt_encap <= G_MAXINT16);
302   fdata->lnk_t = (gint16) phdr->pkt_encap;
303   fdata->flags.passed_dfilter = 0;
304   fdata->flags.dependent_of_displayed = 0;
305   fdata->flags.encoding = PACKET_CHAR_ENC_CHAR_ASCII;
306   fdata->flags.visited = 0;
307   fdata->flags.marked = 0;
308   fdata->flags.ref_time = 0;
309   fdata->flags.ignored = 0;
310   fdata->flags.has_ts = (phdr->presence_flags & WTAP_HAS_TS) ? 1 : 0;
311   fdata->flags.has_phdr_comment = (phdr->opt_comment != NULL);
312   fdata->flags.has_user_comment = 0;
313   fdata->tsprec = (gint16)phdr->pkt_tsprec;
314   fdata->color_filter = NULL;
315   fdata->abs_ts.secs = phdr->ts.secs;
316   fdata->abs_ts.nsecs = phdr->ts.nsecs;
317   fdata->shift_offset.secs = 0;
318   fdata->shift_offset.nsecs = 0;
319   fdata->frame_ref_num = 0;
320   fdata->prev_dis_num = 0;
321 }
322
323 void
324 frame_data_set_before_dissect(frame_data *fdata,
325                 nstime_t *elapsed_time,
326                 const frame_data **frame_ref,
327                 const frame_data *prev_dis)
328 {
329   nstime_t rel_ts;
330
331   /* Don't have the reference frame, set to current */
332   if (*frame_ref == NULL)
333     *frame_ref = fdata;
334
335   /* if this frames is marked as a reference time frame,
336      set reference frame this frame */
337   if(fdata->flags.ref_time)
338     *frame_ref = fdata;
339
340   /* Get the time elapsed between the first packet and this packet. */
341   nstime_delta(&rel_ts, &fdata->abs_ts, &(*frame_ref)->abs_ts);
342
343   /* If it's greater than the current elapsed time, set the elapsed time
344      to it (we check for "greater than" so as not to be confused by
345      time moving backwards). */
346   if ((gint32)elapsed_time->secs < rel_ts.secs
347     || ((gint32)elapsed_time->secs == rel_ts.secs && (gint32)elapsed_time->nsecs < rel_ts.nsecs)) {
348     *elapsed_time = rel_ts;
349   }
350
351   fdata->frame_ref_num = (*frame_ref != fdata) ? (*frame_ref)->num : 0;
352   fdata->prev_dis_num = (prev_dis) ? prev_dis->num : 0;
353 }
354
355 void
356 frame_data_set_after_dissect(frame_data *fdata,
357                 guint32 *cum_bytes)
358 {
359   /* This frame either passed the display filter list or is marked as
360      a time reference frame.  All time reference frames are displayed
361      even if they don't pass the display filter */
362   if(fdata->flags.ref_time){
363     /* if this was a TIME REF frame we should reset the cul bytes field */
364     *cum_bytes = fdata->pkt_len;
365     fdata->cum_bytes = *cum_bytes;
366   } else {
367     /* increase cum_bytes with this packets length */
368     *cum_bytes += fdata->pkt_len;
369     fdata->cum_bytes = *cum_bytes;
370   }
371 }
372
373 void
374 frame_data_reset(frame_data *fdata)
375 {
376   fdata->flags.visited = 0;
377   fdata->subnum = 0;
378
379   if (fdata->pfd) {
380     g_slist_free(fdata->pfd);
381     fdata->pfd = NULL;
382   }
383 }
384
385 void
386 frame_data_destroy(frame_data *fdata)
387 {
388   if (fdata->pfd) {
389     g_slist_free(fdata->pfd);
390     fdata->pfd = NULL;
391   }
392 }
393
394 /*
395  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
396  *
397  * Local variables:
398  * c-basic-offset: 2
399  * tab-width: 8
400  * indent-tabs-mode: nil
401  * End:
402  *
403  * vi: set shiftwidth=2 tabstop=8 expandtab:
404  * :indentSize=2:tabSize=8:noTabs=true:
405  */