nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* editcap.c
2 * Edit capture files. We can delete packets, adjust timestamps, or
3 * simply convert from one format to another format.
4 *
5 * Originally written by Richard Sharpe.
6 * Improved by Guy Harris.
7 * Further improved by Richard Sharpe.
8 *
9 * Copyright 2013, Richard Sharpe <realrichardsharpe[AT]gmail.com>
10 *
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 */
29  
30 #include <config.h>
31  
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdarg.h>
36  
37 /*
38 * Just make sure we include the prototype for strptime as well
39 * (needed for glibc 2.2) but make sure we do this only if not
40 * yet defined.
41 */
42  
43 #ifndef __USE_XOPEN
44 # define __USE_XOPEN
45 #endif
46  
47 #include <time.h>
48 #include <glib.h>
49  
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53  
54 #ifdef HAVE_GETOPT_H
55 #include <getopt.h>
56 #endif
57  
58 #include <wiretap/wtap.h>
59  
60 #include "epan/etypes.h"
61  
62 #ifndef HAVE_GETOPT_LONG
63 #include "wsutil/wsgetopt.h"
64 #endif
65  
66 #ifdef _WIN32
67 #include <wsutil/unicode-utils.h>
68 #include <process.h> /* getpid */
69 #ifdef HAVE_WINSOCK2_H
70 #include <winsock2.h>
71 #endif
72 #endif
73  
74 #ifndef HAVE_STRPTIME
75 # include "wsutil/strptime.h"
76 #endif
77  
78 #include <wsutil/crash_info.h>
79 #include <wsutil/filesystem.h>
80 #include <wsutil/file_util.h>
81 #include <wsutil/md5.h>
82 #include <wsutil/plugins.h>
83 #include <wsutil/privileges.h>
84 #include <wsutil/report_err.h>
85 #include <wsutil/strnatcmp.h>
86 #include <wsutil/str_util.h>
87 #include <ws_version_info.h>
88 #include <wsutil/pint.h>
89 #include <wiretap/wtap_opttypes.h>
90 #include <wiretap/pcapng.h>
91  
92 #include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */
93  
94 /*
95 * Some globals so we can pass things to various routines
96 */
97  
98 struct select_item {
99 gboolean inclusive;
100 guint first, second;
101 };
102  
103 /*
104 * Duplicate frame detection
105 */
106 typedef struct _fd_hash_t {
107 md5_byte_t digest[16];
108 guint32 len;
109 nstime_t frame_time;
110 } fd_hash_t;
111  
112 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
113 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
114  
115 static fd_hash_t fd_hash[MAX_DUP_DEPTH];
116 static int dup_window = DEFAULT_DUP_DEPTH;
117 static int cur_dup_entry = 0;
118  
119 static int ignored_bytes = 0; /* Used with -I */
120  
121 #define ONE_BILLION 1000000000
122  
123 /* Weights of different errors we can introduce */
124 /* We should probably make these command-line arguments */
125 /* XXX - Should we add a bit-level error? */
126 #define ERR_WT_BIT 5 /* Flip a random bit */
127 #define ERR_WT_BYTE 5 /* Substitute a random byte */
128 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
129 #define ERR_WT_FMT 2 /* Substitute "%s" */
130 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
131 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
132  
133 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
134 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
135  
136 struct time_adjustment {
137 nstime_t tv;
138 int is_negative;
139 };
140  
141 typedef struct _chop_t {
142 int len_begin;
143 int off_begin_pos;
144 int off_begin_neg;
145 int len_end;
146 int off_end_pos;
147 int off_end_neg;
148 } chop_t;
149  
150  
151 /* Table of user comments */
152 GTree *frames_user_comments = NULL;
153  
154 #define MAX_SELECTIONS 512
155 static struct select_item selectfrm[MAX_SELECTIONS];
156 static guint max_selected = 0;
157 static int keep_em = 0;
158 #ifdef PCAP_NG_DEFAULT
159 static int out_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAPNG; /* default to pcapng */
160 #else
161 static int out_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAP; /* default to pcap */
162 #endif
163 static int out_frame_type = -2; /* Leave frame type alone */
164 static int verbose = 0; /* Not so verbose */
165 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
166 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
167 static double err_prob = 0.0;
168 static time_t starttime = 0;
169 static time_t stoptime = 0;
170 static gboolean check_startstop = FALSE;
171 static gboolean rem_vlan = FALSE;
172 static gboolean dup_detect = FALSE;
173 static gboolean dup_detect_by_time = FALSE;
174  
175 static int do_strict_time_adjustment = FALSE;
176 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
177 static nstime_t previous_time = {0, 0}; /* previous time */
178  
179 static int find_dct2000_real_data(guint8 *buf);
180 static void handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
181 const struct wtap_pkthdr *in_phdr, guint8 **buf,
182 gboolean adjlen);
183  
184 static gchar *
185 abs_time_to_str_with_sec_resolution(const nstime_t *abs_time)
186 {
187 struct tm *tmp;
188 gchar *buf = (gchar *)g_malloc(16);
189  
190 tmp = localtime(&abs_time->secs);
191  
192 if (tmp) {
193 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
194 tmp->tm_year + 1900,
195 tmp->tm_mon+1,
196 tmp->tm_mday,
197 tmp->tm_hour,
198 tmp->tm_min,
199 tmp->tm_sec);
200 } else {
201 buf[0] = '\0';
202 }
203  
204 return buf;
205 }
206  
207 static gchar *
208 fileset_get_filename_by_pattern(guint idx, const struct wtap_pkthdr *phdr,
209 gchar *fprefix, gchar *fsuffix)
210 {
211 gchar filenum[5+1];
212 gchar *timestr;
213 gchar *abs_str;
214  
215 g_snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES);
216 if (phdr->presence_flags & WTAP_HAS_TS) {
217 timestr = abs_time_to_str_with_sec_resolution(&phdr->ts);
218 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
219 g_free(timestr);
220 } else
221 abs_str = g_strconcat(fprefix, "_", filenum, fsuffix, NULL);
222  
223 return abs_str;
224 }
225  
226 static gboolean
227 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
228 {
229 char *pfx, *last_pathsep;
230 gchar *save_file;
231  
232 save_file = g_strdup(fname);
233 if (save_file == NULL) {
234 fprintf(stderr, "editcap: Out of memory\n");
235 return FALSE;
236 }
237  
238 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
239 pfx = strrchr(save_file,'.');
240 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
241 /* The pathname has a "." in it, and it's in the last component
242 * of the pathname (because there is either only one component,
243 * i.e. last_pathsep is null as there are no path separators,
244 * or the "." is after the path separator before the last
245 * component.
246  
247 * Treat it as a separator between the rest of the file name and
248 * the file name suffix, and arrange that the names given to the
249 * ring buffer files have the specified suffix, i.e. put the
250 * changing part of the name *before* the suffix. */
251 pfx[0] = '\0';
252 *fprefix = g_strdup(save_file);
253 pfx[0] = '.'; /* restore capfile_name */
254 *fsuffix = g_strdup(pfx);
255 } else {
256 /* Either there's no "." in the pathname, or it's in a directory
257 * component, so the last component has no suffix. */
258 *fprefix = g_strdup(save_file);
259 *fsuffix = NULL;
260 }
261 g_free(save_file);
262 return TRUE;
263 }
264  
265 /* Add a selection item, a simple parser for now */
266 static gboolean
267 add_selection(char *sel, guint* max_selection)
268 {
269 char *locn;
270 char *next;
271  
272 if (max_selected >= MAX_SELECTIONS) {
273 /* Let the user know we stopped selecting */
274 fprintf(stderr, "Out of room for packet selections!\n");
275 return(FALSE);
276 }
277  
278 if (verbose)
279 fprintf(stderr, "Add_Selected: %s\n", sel);
280  
281 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
282 if (verbose)
283 fprintf(stderr, "Not inclusive ...");
284  
285 selectfrm[max_selected].inclusive = FALSE;
286 selectfrm[max_selected].first = (guint)strtoul(sel, NULL, 10);
287 if (selectfrm[max_selected].first > *max_selection)
288 *max_selection = selectfrm[max_selected].first;
289  
290 if (verbose)
291 fprintf(stderr, " %u\n", selectfrm[max_selected].first);
292 } else {
293 if (verbose)
294 fprintf(stderr, "Inclusive ...");
295  
296 next = locn + 1;
297 selectfrm[max_selected].inclusive = TRUE;
298 selectfrm[max_selected].first = (guint)strtoul(sel, NULL, 10);
299 selectfrm[max_selected].second = (guint)strtoul(next, NULL, 10);
300  
301 if (selectfrm[max_selected].second == 0)
302 {
303 /* Not a valid number, presume all */
304 selectfrm[max_selected].second = *max_selection = G_MAXUINT;
305 }
306 else if (selectfrm[max_selected].second > *max_selection)
307 *max_selection = selectfrm[max_selected].second;
308  
309 if (verbose)
310 fprintf(stderr, " %u, %u\n", selectfrm[max_selected].first,
311 selectfrm[max_selected].second);
312 }
313  
314 max_selected++;
315 return(TRUE);
316 }
317  
318 /* Was the packet selected? */
319  
320 static int
321 selected(guint recno)
322 {
323 guint i;
324  
325 for (i = 0; i < max_selected; i++) {
326 if (selectfrm[i].inclusive) {
327 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
328 return 1;
329 } else {
330 if (recno == selectfrm[i].first)
331 return 1;
332 }
333 }
334  
335 return 0;
336 }
337  
338 static void
339 set_time_adjustment(char *optarg_str_p)
340 {
341 char *frac, *end;
342 long val;
343 size_t frac_digits;
344  
345 if (!optarg_str_p)
346 return;
347  
348 /* skip leading whitespace */
349 while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
350 optarg_str_p++;
351  
352 /* check for a negative adjustment */
353 if (*optarg_str_p == '-') {
354 time_adj.is_negative = 1;
355 optarg_str_p++;
356 }
357  
358 /* collect whole number of seconds, if any */
359 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
360 val = 0;
361 frac = optarg_str_p;
362 } else {
363 val = strtol(optarg_str_p, &frac, 10);
364 if (frac == NULL || frac == optarg_str_p
365 || val == LONG_MIN || val == LONG_MAX) {
366 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
367 optarg_str_p);
368 exit(1);
369 }
370 if (val < 0) { /* implies '--' since we caught '-' above */
371 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
372 optarg_str_p);
373 exit(1);
374 }
375 }
376 time_adj.tv.secs = val;
377  
378 /* now collect the partial seconds, if any */
379 if (*frac != '\0') { /* chars left, so get fractional part */
380 val = strtol(&(frac[1]), &end, 10);
381 /* if more than 9 fractional digits truncate to 9 */
382 if ((end - &(frac[1])) > 9) {
383 frac[10] = 't'; /* 't' for truncate */
384 val = strtol(&(frac[1]), &end, 10);
385 }
386 if (*frac != '.' || end == NULL || end == frac || val < 0
387 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
388 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
389 optarg_str_p);
390 exit(1);
391 }
392 } else {
393 return; /* no fractional digits */
394 }
395  
396 /* adjust fractional portion from fractional to numerator
397 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
398 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
399 while(frac_digits < 9) { /* this is frac of 10^9 */
400 val *= 10;
401 frac_digits++;
402 }
403  
404 time_adj.tv.nsecs = (int)val;
405 }
406  
407 static void
408 set_strict_time_adj(char *optarg_str_p)
409 {
410 char *frac, *end;
411 long val;
412 size_t frac_digits;
413  
414 if (!optarg_str_p)
415 return;
416  
417 /* skip leading whitespace */
418 while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
419 optarg_str_p++;
420  
421 /*
422 * check for a negative adjustment
423 * A negative strict adjustment value is a flag
424 * to adjust all frames by the specifed delta time.
425 */
426 if (*optarg_str_p == '-') {
427 strict_time_adj.is_negative = 1;
428 optarg_str_p++;
429 }
430  
431 /* collect whole number of seconds, if any */
432 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
433 val = 0;
434 frac = optarg_str_p;
435 } else {
436 val = strtol(optarg_str_p, &frac, 10);
437 if (frac == NULL || frac == optarg_str_p
438 || val == LONG_MIN || val == LONG_MAX) {
439 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
440 optarg_str_p);
441 exit(1);
442 }
443 if (val < 0) { /* implies '--' since we caught '-' above */
444 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
445 optarg_str_p);
446 exit(1);
447 }
448 }
449 strict_time_adj.tv.secs = val;
450  
451 /* now collect the partial seconds, if any */
452 if (*frac != '\0') { /* chars left, so get fractional part */
453 val = strtol(&(frac[1]), &end, 10);
454 /* if more than 9 fractional digits truncate to 9 */
455 if ((end - &(frac[1])) > 9) {
456 frac[10] = 't'; /* 't' for truncate */
457 val = strtol(&(frac[1]), &end, 10);
458 }
459 if (*frac != '.' || end == NULL || end == frac || val < 0
460 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
461 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
462 optarg_str_p);
463 exit(1);
464 }
465 } else {
466 return; /* no fractional digits */
467 }
468  
469 /* adjust fractional portion from fractional to numerator
470 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
471 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
472 while(frac_digits < 9) { /* this is frac of 10^9 */
473 val *= 10;
474 frac_digits++;
475 }
476  
477 strict_time_adj.tv.nsecs = (int)val;
478 }
479  
480 static void
481 set_rel_time(char *optarg_str_p)
482 {
483 char *frac, *end;
484 long val;
485 size_t frac_digits;
486  
487 if (!optarg_str_p)
488 return;
489  
490 /* skip leading whitespace */
491 while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
492 optarg_str_p++;
493  
494 /* ignore negative adjustment */
495 if (*optarg_str_p == '-')
496 optarg_str_p++;
497  
498 /* collect whole number of seconds, if any */
499 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
500 val = 0;
501 frac = optarg_str_p;
502 } else {
503 val = strtol(optarg_str_p, &frac, 10);
504 if (frac == NULL || frac == optarg_str_p
505 || val == LONG_MIN || val == LONG_MAX) {
506 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
507 optarg_str_p);
508 exit(1);
509 }
510 if (val < 0) { /* implies '--' since we caught '-' above */
511 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
512 optarg_str_p);
513 exit(1);
514 }
515 }
516 relative_time_window.secs = val;
517  
518 /* now collect the partial seconds, if any */
519 if (*frac != '\0') { /* chars left, so get fractional part */
520 val = strtol(&(frac[1]), &end, 10);
521 /* if more than 9 fractional digits truncate to 9 */
522 if ((end - &(frac[1])) > 9) {
523 frac[10] = 't'; /* 't' for truncate */
524 val = strtol(&(frac[1]), &end, 10);
525 }
526 if (*frac != '.' || end == NULL || end == frac || val < 0
527 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
528 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
529 optarg_str_p);
530 exit(1);
531 }
532 } else {
533 return; /* no fractional digits */
534 }
535  
536 /* adjust fractional portion from fractional to numerator
537 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
538 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
539 while(frac_digits < 9) { /* this is frac of 10^9 */
540 val *= 10;
541 frac_digits++;
542 }
543  
544 relative_time_window.nsecs = (int)val;
545 }
546  
547 #define LINUX_SLL_OFFSETP 14
548 #define VLAN_SIZE 4
549 static void
550 sll_remove_vlan_info(guint8* fd, guint32* len) {
551 if (pntoh16(fd + LINUX_SLL_OFFSETP) == ETHERTYPE_VLAN) {
552 int rest_len;
553 /* point to start of vlan */
554 fd = fd + LINUX_SLL_OFFSETP;
555 /* bytes to read after vlan info */
556 rest_len = *len - (LINUX_SLL_OFFSETP + VLAN_SIZE);
557 /* remove vlan info from packet */
558 memmove(fd, fd + VLAN_SIZE, rest_len);
559 *len -= 4;
560 }
561 }
562  
563 static void
564 remove_vlan_info(const struct wtap_pkthdr *phdr, guint8* fd, guint32* len) {
565 switch (phdr->pkt_encap) {
566 case WTAP_ENCAP_SLL:
567 sll_remove_vlan_info(fd, len);
568 break;
569 default:
570 /* no support for current pkt_encap */
571 break;
572 }
573 }
574  
575 static gboolean
576 is_duplicate(guint8* fd, guint32 len) {
577 int i;
578 md5_state_t ms;
579  
580 /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
581 guint32 new_len;
582 guint8 *new_fd;
583  
584 new_fd = &fd[ignored_bytes];
585 new_len = len - (ignored_bytes);
586  
587 cur_dup_entry++;
588 if (cur_dup_entry >= dup_window)
589 cur_dup_entry = 0;
590  
591 /* Calculate our digest */
592 md5_init(&ms);
593 md5_append(&ms, new_fd, new_len);
594 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
595  
596 fd_hash[cur_dup_entry].len = len;
597  
598 /* Look for duplicates */
599 for (i = 0; i < dup_window; i++) {
600 if (i == cur_dup_entry)
601 continue;
602  
603 if (fd_hash[i].len == fd_hash[cur_dup_entry].len
604 && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
605 return TRUE;
606 }
607 }
608  
609 return FALSE;
610 }
611  
612 static gboolean
613 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
614 int i;
615 md5_state_t ms;
616  
617 /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
618 guint32 new_len;
619 guint8 *new_fd;
620  
621 new_fd = &fd[ignored_bytes];
622 new_len = len - (ignored_bytes);
623  
624 cur_dup_entry++;
625 if (cur_dup_entry >= dup_window)
626 cur_dup_entry = 0;
627  
628 /* Calculate our digest */
629 md5_init(&ms);
630 md5_append(&ms, new_fd, new_len);
631 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
632  
633 fd_hash[cur_dup_entry].len = len;
634 fd_hash[cur_dup_entry].frame_time.secs = current->secs;
635 fd_hash[cur_dup_entry].frame_time.nsecs = current->nsecs;
636  
637 /*
638 * Look for relative time related duplicates.
639 * This is hopefully a reasonably efficient mechanism for
640 * finding duplicates by rel time in the fd_hash[] cache.
641 * We check starting from the most recently added hash
642 * entries and work backwards towards older packets.
643 * This approach allows the dup test to be terminated
644 * when the relative time of a cached entry is found to
645 * be beyond the dup time window.
646 *
647 * Of course this assumes that the input trace file is
648 * "well-formed" in the sense that the packet timestamps are
649 * in strict chronologically increasing order (which is NOT
650 * always the case!!).
651 *
652 * The fd_hash[] table was deliberately created large (1,000,000).
653 * Looking for time related duplicates in large trace files with
654 * non-fractional dup time window values can potentially take
655 * a long time to complete.
656 */
657  
658 for (i = cur_dup_entry - 1;; i--) {
659 nstime_t delta;
660 int cmp;
661  
662 if (i < 0)
663 i = dup_window - 1;
664  
665 if (i == cur_dup_entry) {
666 /*
667 * We've decremented back to where we started.
668 * Check no more!
669 */
670 break;
671 }
672  
673 if (nstime_is_unset(&(fd_hash[i].frame_time))) {
674 /*
675 * We've decremented to an unused fd_hash[] entry.
676 * Check no more!
677 */
678 break;
679 }
680  
681 nstime_delta(&delta, current, &fd_hash[i].frame_time);
682  
683 if (delta.secs < 0 || delta.nsecs < 0) {
684 /*
685 * A negative delta implies that the current packet
686 * has an absolute timestamp less than the cached packet
687 * that it is being compared to. This is NOT a normal
688 * situation since trace files usually have packets in
689 * chronological order (oldest to newest).
690 *
691 * There are several possible ways to deal with this:
692 * 1. 'continue' dup checking with the next cached frame.
693 * 2. 'break' from looking for a duplicate of the current frame.
694 * 3. Take the absolute value of the delta and see if that
695 * falls within the specifed dup time window.
696 *
697 * Currently this code does option 1. But it would pretty
698 * easy to add yet-another-editcap-option to select one of
699 * the other behaviors for dealing with out-of-sequence
700 * packets.
701 */
702 continue;
703 }
704  
705 cmp = nstime_cmp(&delta, &relative_time_window);
706  
707 if (cmp > 0) {
708 /*
709 * The delta time indicates that we are now looking at
710 * cached packets beyond the specified dup time window.
711 * Check no more!
712 */
713 break;
714 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len
715 && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
716 return TRUE;
717 }
718 }
719  
720 return FALSE;
721 }
722  
723 static void
724 print_usage(FILE *output)
725 {
726 fprintf(output, "\n");
727 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
728 fprintf(output, "\n");
729 fprintf(output, "<infile> and <outfile> must both be present.\n");
730 fprintf(output, "A single packet or a range of packets can be selected.\n");
731 fprintf(output, "\n");
732 fprintf(output, "Packet selection:\n");
733 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
734 fprintf(output, " -A <start time> only output packets whose timestamp is after (or equal\n");
735 fprintf(output, " to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
736 fprintf(output, " -B <stop time> only output packets whose timestamp is before the\n");
737 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
738 fprintf(output, "\n");
739 fprintf(output, "Duplicate packet removal:\n");
740 fprintf(output, " --novlan remove vlan info from packets before checking for duplicates.\n");
741 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
742 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
743 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
744 fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
745 fprintf(output, " useful to print MD5 hashes.\n");
746 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
747 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
748 fprintf(output, " A <dup time window> is specified in relative seconds\n");
749 fprintf(output, " (e.g. 0.000001).\n");
750 fprintf(output, " -a <framenum>:<comment> Add or replace comment for given frame number\n");
751 fprintf(output, "\n");
752 fprintf(output, " -I <bytes to ignore> ignore the specified bytes at the beginning of\n");
753 fprintf(output, " the frame during MD5 hash calculation\n");
754 fprintf(output, " Useful to remove duplicated packets taken on\n");
755 fprintf(output, " several routers(differents mac addresses for \n");
756 fprintf(output, " example)\n");
757 fprintf(output, " e.g. -I 26 in case of Ether/IP/ will ignore \n");
758 fprintf(output, " ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n");
759 fprintf(output, "\n");
760 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
761 fprintf(output, " other editcap options except -v may not always work as expected.\n");
762 fprintf(output, " Specifically the -r, -t or -S options will very likely NOT have the\n");
763 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
764 fprintf(output, "\n");
765 fprintf(output, "Packet manipulation:\n");
766 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
767 fprintf(output, " -C [offset:]<choplen> chop each packet by <choplen> bytes. Positive values\n");
768 fprintf(output, " chop at the packet beginning, negative values at the\n");
769 fprintf(output, " packet end. If an optional offset precedes the length,\n");
770 fprintf(output, " then the bytes chopped will be offset from that value.\n");
771 fprintf(output, " Positive offsets are from the packet beginning,\n");
772 fprintf(output, " negative offsets are from the packet end. You can use\n");
773 fprintf(output, " this option more than once, allowing up to 2 chopping\n");
774 fprintf(output, " regions within a packet provided that at least 1\n");
775 fprintf(output, " choplen is positive and at least 1 is negative.\n");
776 fprintf(output, " -L adjust the frame (i.e. reported) length when chopping\n");
777 fprintf(output, " and/or snapping\n");
778 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n");
779 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
780 fprintf(output, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
781 fprintf(output, " strict chronological increasing order. The <strict\n");
782 fprintf(output, " adjustment> is specified in relative seconds with\n");
783 fprintf(output, " values of 0 or 0.000001 being the most reasonable.\n");
784 fprintf(output, " A negative adjustment value will modify timestamps so\n");
785 fprintf(output, " that each packet's delta time is the absolute value\n");
786 fprintf(output, " of the adjustment specified. A value of -0 will set\n");
787 fprintf(output, " all packets to the timestamp of the first packet.\n");
788 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.) that\n");
789 fprintf(output, " a particular packet byte will be randomly changed.\n");
790 fprintf(output, " -o <change offset> When used in conjunction with -E, skip some bytes from the\n");
791 fprintf(output, " beginning of the packet. This allows one to preserve some\n");
792 fprintf(output, " bytes, in order to have some headers untouched.\n");
793 fprintf(output, "\n");
794 fprintf(output, "Output File(s):\n");
795 fprintf(output, " -c <packets per file> split the packet output to different files based on\n");
796 fprintf(output, " uniform packet counts with a maximum of\n");
797 fprintf(output, " <packets per file> each.\n");
798 fprintf(output, " -i <seconds per file> split the packet output to different files based on\n");
799 fprintf(output, " uniform time intervals with a maximum of\n");
800 fprintf(output, " <seconds per file> each.\n");
801 fprintf(output, " -F <capture type> set the output file type; default is pcapng. An empty\n");
802 fprintf(output, " \"-F\" option will list the file types.\n");
803 fprintf(output, " -T <encap type> set the output file encapsulation type; default is the\n");
804 fprintf(output, " same as the input file. An empty \"-T\" option will\n");
805 fprintf(output, " list the encapsulation types.\n");
806 fprintf(output, "\n");
807 fprintf(output, "Miscellaneous:\n");
808 fprintf(output, " -h display this help and exit.\n");
809 fprintf(output, " -v verbose output.\n");
810 fprintf(output, " If -v is used with any of the 'Duplicate Packet\n");
811 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
812 fprintf(output, " and MD5 hashes are printed to standard-error.\n");
813 fprintf(output, "\n");
814 }
815  
816 struct string_elem {
817 const char *sstr; /* The short string */
818 const char *lstr; /* The long string */
819 };
820  
821 static gint
822 string_compare(gconstpointer a, gconstpointer b)
823 {
824 return strcmp(((const struct string_elem *)a)->sstr,
825 ((const struct string_elem *)b)->sstr);
826 }
827  
828 static gint
829 string_nat_compare(gconstpointer a, gconstpointer b)
830 {
831 return ws_ascii_strnatcmp(((const struct string_elem *)a)->sstr,
832 ((const struct string_elem *)b)->sstr);
833 }
834  
835 static void
836 string_elem_print(gpointer data, gpointer not_used _U_)
837 {
838 fprintf(stderr, " %s - %s\n",
839 ((struct string_elem *)data)->sstr,
840 ((struct string_elem *)data)->lstr);
841 }
842  
843 static void
844 list_capture_types(void) {
845 int i;
846 struct string_elem *captypes;
847 GSList *list = NULL;
848  
849 captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES_SUBTYPES);
850 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
851 for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
852 if (wtap_dump_can_open(i)) {
853 captypes[i].sstr = wtap_file_type_subtype_short_string(i);
854 captypes[i].lstr = wtap_file_type_subtype_string(i);
855 list = g_slist_insert_sorted(list, &captypes[i], string_compare);
856 }
857 }
858 g_slist_foreach(list, string_elem_print, NULL);
859 g_slist_free(list);
860 g_free(captypes);
861 }
862  
863 static void
864 list_encap_types(void) {
865 int i;
866 struct string_elem *encaps;
867 GSList *list = NULL;
868  
869 encaps = (struct string_elem *)g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
870 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
871 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
872 encaps[i].sstr = wtap_encap_short_string(i);
873 if (encaps[i].sstr != NULL) {
874 encaps[i].lstr = wtap_encap_string(i);
875 list = g_slist_insert_sorted(list, &encaps[i], string_nat_compare);
876 }
877 }
878 g_slist_foreach(list, string_elem_print, NULL);
879 g_slist_free(list);
880 g_free(encaps);
881 }
882  
883 static int
884 framenum_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
885 {
886 if (GPOINTER_TO_UINT(a) < GPOINTER_TO_UINT(b))
887 return -1;
888  
889 if (GPOINTER_TO_UINT(a) > GPOINTER_TO_UINT(b))
890 return 1;
891  
892 return 0;
893 }
894  
895 #ifdef HAVE_PLUGINS
896 /*
897 * Don't report failures to load plugins because most (non-wiretap) plugins
898 * *should* fail to load (because we're not linked against libwireshark and
899 * dissector plugins need libwireshark).
900 */
901 static void
902 failure_message(const char *msg_format _U_, va_list ap _U_)
903 {
904 }
905 #endif
906  
907 static wtap_dumper *
908 editcap_dump_open(const char *filename, guint32 snaplen,
909 GArray* shb_hdrs,
910 wtapng_iface_descriptions_t *idb_inf,
911 GArray* nrb_hdrs, int *write_err)
912 {
913 wtap_dumper *pdh;
914  
915 if (strcmp(filename, "-") == 0) {
916 /* Write to the standard output. */
917 pdh = wtap_dump_open_stdout_ng(out_file_type_subtype, out_frame_type,
918 snaplen, FALSE /* compressed */,
919 shb_hdrs, idb_inf, nrb_hdrs, write_err);
920 } else {
921 pdh = wtap_dump_open_ng(filename, out_file_type_subtype, out_frame_type,
922 snaplen, FALSE /* compressed */,
923 shb_hdrs, idb_inf, nrb_hdrs, write_err);
924 }
925 return pdh;
926 }
927  
928 int
929 main(int argc, char *argv[])
930 {
931 GString *comp_info_str;
932 GString *runtime_info_str;
933 wtap *wth;
934 int i, j, read_err, write_err;
935 gchar *read_err_info, *write_err_info;
936 int opt;
937 static const struct option long_options[] = {
938 {"novlan", no_argument, NULL, 0x8100},
939 {"help", no_argument, NULL, 'h'},
940 {"version", no_argument, NULL, 'V'},
941 {0, 0, 0, 0 }
942 };
943  
944 char *p;
945 guint32 snaplen = 0; /* No limit */
946 chop_t chop = {0, 0, 0, 0, 0, 0}; /* No chop */
947 gboolean adjlen = FALSE;
948 wtap_dumper *pdh = NULL;
949 unsigned int count = 1;
950 unsigned int duplicate_count = 0;
951 gint64 data_offset;
952 int err_type;
953 guint8 *buf;
954 guint32 read_count = 0;
955 int split_packet_count = 0;
956 int written_count = 0;
957 char *filename = NULL;
958 gboolean ts_okay;
959 int secs_per_block = 0;
960 int block_cnt = 0;
961 nstime_t block_start;
962 gchar *fprefix = NULL;
963 gchar *fsuffix = NULL;
964 guint32 change_offset = 0;
965 guint max_packet_number = 0;
966 const struct wtap_pkthdr *phdr;
967 struct wtap_pkthdr temp_phdr;
968 wtapng_iface_descriptions_t *idb_inf = NULL;
969 GArray *shb_hdrs = NULL;
970 GArray *nrb_hdrs = NULL;
971 char *shb_user_appl;
972  
973 #ifdef HAVE_PLUGINS
974 char* init_progfile_dir_error;
975 #endif
976  
977 #ifdef _WIN32
978 arg_list_utf_16to8(argc, argv);
979 create_app_running_mutex();
980 #endif /* _WIN32 */
981  
982 /* Get the compile-time version information string */
983 comp_info_str = get_compiled_version_info(NULL, NULL);
984  
985 /* Get the run-time version information string */
986 runtime_info_str = get_runtime_version_info(NULL);
987  
988 /* Add it to the information to be reported on a crash. */
989 ws_add_crash_info("Editcap (Wireshark) %s\n"
990 "\n"
991 "%s"
992 "\n"
993 "%s",
994 get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
995  
996 /*
997 * Get credential information for later use.
998 */
999 init_process_policies();
1000 init_open_routines();
1001  
1002 #ifdef HAVE_PLUGINS
1003 /* Register wiretap plugins */
1004 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
1005 g_warning("editcap: init_progfile_dir(): %s", init_progfile_dir_error);
1006 g_free(init_progfile_dir_error);
1007 } else {
1008 /* Register all the plugin types we have. */
1009 wtap_register_plugin_types(); /* Types known to libwiretap */
1010  
1011 init_report_err(failure_message,NULL,NULL,NULL);
1012  
1013 /* Scan for plugins. This does *not* call their registration routines;
1014 that's done later. */
1015 scan_plugins();
1016  
1017 /* Register all libwiretap plugin modules. */
1018 register_all_wiretap_modules();
1019 }
1020 #endif
1021  
1022 /* Process the options */
1023 while ((opt = getopt_long(argc, argv, "a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL)) != -1) {
1024 switch (opt) {
1025 case 0x8100:
1026 {
1027 rem_vlan = TRUE;
1028 break;
1029 }
1030  
1031 case 'a':
1032 {
1033 guint frame_number;
1034 gint string_start_index = 0;
1035  
1036 if ((sscanf(optarg, "%u:%n", &frame_number, &string_start_index) < 1) || (string_start_index == 0)) {
1037 fprintf(stderr, "editcap: \"%s\" isn't a valid <frame>:<comment>\n\n",
1038 optarg);
1039 exit(1);
1040 }
1041  
1042 /* Lazily create the table */
1043 if (!frames_user_comments) {
1044 frames_user_comments = g_tree_new_full(framenum_compare, NULL, NULL, g_free);
1045 }
1046  
1047 /* Insert this entry (framenum -> comment) */
1048 g_tree_replace(frames_user_comments, GUINT_TO_POINTER(frame_number), g_strdup(optarg+string_start_index));
1049 break;
1050 }
1051  
1052 case 'A':
1053 {
1054 struct tm starttm;
1055  
1056 memset(&starttm,0,sizeof(struct tm));
1057  
1058 if (!strptime(optarg,"%Y-%m-%d %T", &starttm)) {
1059 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1060 optarg);
1061 exit(1);
1062 }
1063  
1064 check_startstop = TRUE;
1065 starttm.tm_isdst = -1;
1066  
1067 starttime = mktime(&starttm);
1068 break;
1069 }
1070  
1071 case 'B':
1072 {
1073 struct tm stoptm;
1074  
1075 memset(&stoptm,0,sizeof(struct tm));
1076  
1077 if (!strptime(optarg,"%Y-%m-%d %T", &stoptm)) {
1078 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1079 optarg);
1080 exit(1);
1081 }
1082 check_startstop = TRUE;
1083 stoptm.tm_isdst = -1;
1084 stoptime = mktime(&stoptm);
1085 break;
1086 }
1087  
1088 case 'c':
1089 split_packet_count = (int)strtol(optarg, &p, 10);
1090 if (p == optarg || *p != '\0') {
1091 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
1092 optarg);
1093 exit(1);
1094 }
1095 if (split_packet_count <= 0) {
1096 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
1097 split_packet_count);
1098 exit(1);
1099 }
1100 break;
1101  
1102 case 'C':
1103 {
1104 int choplen = 0, chopoff = 0;
1105  
1106 switch (sscanf(optarg, "%d:%d", &chopoff, &choplen)) {
1107 case 1: /* only the chop length was specififed */
1108 choplen = chopoff;
1109 chopoff = 0;
1110 break;
1111  
1112 case 2: /* both an offset and chop length was specified */
1113 break;
1114  
1115 default:
1116 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length or offset:length\n",
1117 optarg);
1118 exit(1);
1119 break;
1120 }
1121  
1122 if (choplen > 0) {
1123 chop.len_begin += choplen;
1124 if (chopoff > 0)
1125 chop.off_begin_pos += chopoff;
1126 else
1127 chop.off_begin_neg += chopoff;
1128 } else if (choplen < 0) {
1129 chop.len_end += choplen;
1130 if (chopoff > 0)
1131 chop.off_end_pos += chopoff;
1132 else
1133 chop.off_end_neg += chopoff;
1134 }
1135 break;
1136 }
1137  
1138 case 'd':
1139 dup_detect = TRUE;
1140 dup_detect_by_time = FALSE;
1141 dup_window = DEFAULT_DUP_DEPTH;
1142 break;
1143  
1144 case 'D':
1145 dup_detect = TRUE;
1146 dup_detect_by_time = FALSE;
1147 dup_window = (int)strtol(optarg, &p, 10);
1148 if (p == optarg || *p != '\0') {
1149 fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
1150 optarg);
1151 exit(1);
1152 }
1153 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
1154 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
1155 dup_window, MAX_DUP_DEPTH);
1156 exit(1);
1157 }
1158 break;
1159  
1160 case 'E':
1161 err_prob = g_ascii_strtod(optarg, &p);
1162 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
1163 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
1164 optarg);
1165 exit(1);
1166 }
1167 srand( (unsigned int) (time(NULL) + ws_getpid()) );
1168 break;
1169  
1170 case 'F':
1171 out_file_type_subtype = wtap_short_string_to_file_type_subtype(optarg);
1172 if (out_file_type_subtype < 0) {
1173 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
1174 optarg);
1175 list_capture_types();
1176 exit(1);
1177 }
1178 break;
1179  
1180 case 'h':
1181 printf("Editcap (Wireshark) %s\n"
1182 "Edit and/or translate the format of capture files.\n"
1183 "See https://www.wireshark.org for more information.\n",
1184 get_ws_vcs_version_info());
1185 print_usage(stdout);
1186 exit(0);
1187 break;
1188  
1189 case 'i': /* break capture file based on time interval */
1190 secs_per_block = atoi(optarg);
1191 if (secs_per_block <= 0) {
1192 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n",
1193 optarg);
1194 exit(1);
1195 }
1196 break;
1197  
1198 case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */
1199 ignored_bytes = atoi(optarg);
1200 if(ignored_bytes <= 0) {
1201 fprintf(stderr, "editcap: \"%s\" isn't a valid number of bytes to ignore\n", optarg);
1202 exit(1);
1203 }
1204 break;
1205  
1206 case 'L':
1207 adjlen = TRUE;
1208 break;
1209  
1210 case 'o':
1211 change_offset = (guint32)strtol(optarg, &p, 10);
1212 break;
1213  
1214 case 'r':
1215 keep_em = !keep_em; /* Just invert */
1216 break;
1217  
1218 case 's':
1219 snaplen = (guint32)strtol(optarg, &p, 10);
1220 if (p == optarg || *p != '\0') {
1221 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
1222 optarg);
1223 exit(1);
1224 }
1225 break;
1226  
1227 case 'S':
1228 set_strict_time_adj(optarg);
1229 do_strict_time_adjustment = TRUE;
1230 break;
1231  
1232 case 't':
1233 set_time_adjustment(optarg);
1234 break;
1235  
1236 case 'T':
1237 out_frame_type = wtap_short_string_to_encap(optarg);
1238 if (out_frame_type < 0) {
1239 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1240 optarg);
1241 list_encap_types();
1242 exit(1);
1243 }
1244 break;
1245  
1246 case 'v':
1247 verbose = !verbose; /* Just invert */
1248 break;
1249  
1250 case 'V':
1251 show_version("Editcap (Wireshark)", comp_info_str, runtime_info_str);
1252 g_string_free(comp_info_str, TRUE);
1253 g_string_free(runtime_info_str, TRUE);
1254 exit(0);
1255 break;
1256  
1257 case 'w':
1258 dup_detect = FALSE;
1259 dup_detect_by_time = TRUE;
1260 dup_window = MAX_DUP_DEPTH;
1261 set_rel_time(optarg);
1262 break;
1263  
1264 case '?': /* Bad options if GNU getopt */
1265 switch(optopt) {
1266 case'F':
1267 list_capture_types();
1268 break;
1269 case'T':
1270 list_encap_types();
1271 break;
1272 default:
1273 print_usage(stderr);
1274 break;
1275 }
1276 exit(1);
1277 break;
1278 }
1279 } /* processing commmand-line options */
1280  
1281 #ifdef DEBUG
1282 fprintf(stderr, "Optind = %i, argc = %i\n", optind, argc);
1283 #endif
1284  
1285 if ((argc - optind) < 1) {
1286 print_usage(stderr);
1287 exit(1);
1288 }
1289  
1290 if (check_startstop && !stoptime) {
1291 struct tm stoptm;
1292  
1293 /* XXX: will work until 2035 */
1294 memset(&stoptm,0,sizeof(struct tm));
1295 stoptm.tm_year = 135;
1296 stoptm.tm_mday = 31;
1297 stoptm.tm_mon = 11;
1298  
1299 stoptime = mktime(&stoptm);
1300 }
1301  
1302 nstime_set_unset(&block_start);
1303  
1304 if (starttime > stoptime) {
1305 fprintf(stderr, "editcap: start time is after the stop time\n");
1306 exit(1);
1307 }
1308  
1309 if (split_packet_count > 0 && secs_per_block > 0) {
1310 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1311 fprintf(stderr, "editcap: at the same time\n");
1312 exit(1);
1313 }
1314  
1315 wth = wtap_open_offline(argv[optind], WTAP_TYPE_AUTO, &read_err, &read_err_info, FALSE);
1316  
1317 if (!wth) {
1318 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1319 wtap_strerror(read_err));
1320 if (read_err_info != NULL) {
1321 fprintf(stderr, "(%s)\n", read_err_info);
1322 g_free(read_err_info);
1323 }
1324 exit(2);
1325 }
1326  
1327 if (verbose) {
1328 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1329 wtap_file_type_subtype_string(wtap_file_type_subtype(wth)));
1330 }
1331  
1332 shb_hdrs = wtap_file_get_shb_for_new_file(wth);
1333 idb_inf = wtap_file_get_idb_info(wth);
1334 nrb_hdrs = wtap_file_get_nrb_for_new_file(wth);
1335  
1336 /*
1337 * Now, process the rest, if any ... we only write if there is an extra
1338 * argument or so ...
1339 */
1340  
1341 if ((argc - optind) >= 2) {
1342 if (out_frame_type == -2)
1343 out_frame_type = wtap_file_encap(wth);
1344  
1345 for (i = optind + 2; i < argc; i++)
1346 if (add_selection(argv[i], &max_packet_number) == FALSE)
1347 break;
1348  
1349 if (keep_em == FALSE)
1350 max_packet_number = G_MAXUINT;
1351  
1352 if (dup_detect || dup_detect_by_time) {
1353 for (i = 0; i < dup_window; i++) {
1354 memset(&fd_hash[i].digest, 0, 16);
1355 fd_hash[i].len = 0;
1356 nstime_set_unset(&fd_hash[i].frame_time);
1357 }
1358 }
1359  
1360 /* Read all of the packets in turn */
1361 while (wtap_read(wth, &read_err, &read_err_info, &data_offset)) {
1362 if (max_packet_number <= read_count)
1363 break;
1364  
1365 read_count++;
1366  
1367 phdr = wtap_phdr(wth);
1368  
1369 /* Extra actions for the first packet */
1370 if (read_count == 1) {
1371 if (split_packet_count > 0 || secs_per_block > 0) {
1372 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1373 goto error_on_exit;
1374  
1375 filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1376 } else {
1377 filename = g_strdup(argv[optind+1]);
1378 }
1379 g_assert(filename);
1380  
1381 /* If we don't have an application name add Editcap */
1382 if (wtap_block_get_string_option_value(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, &shb_user_appl) != WTAP_OPTTYPE_SUCCESS) {
1383 wtap_block_add_string_option_format(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, "Editcap " VERSION);
1384 }
1385  
1386 pdh = editcap_dump_open(filename,
1387 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1388 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1389  
1390 if (pdh == NULL) {
1391 fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1392 filename, wtap_strerror(write_err));
1393 goto error_on_exit;
1394 }
1395 } /* first packet only handling */
1396  
1397  
1398 buf = wtap_buf_ptr(wth);
1399  
1400 /*
1401 * Not all packets have time stamps. Only process the time
1402 * stamp if we have one.
1403 */
1404 if (phdr->presence_flags & WTAP_HAS_TS) {
1405 if (nstime_is_unset(&block_start)) {
1406 block_start = phdr->ts;
1407 }
1408  
1409 if (secs_per_block > 0) {
1410 while ((phdr->ts.secs - block_start.secs > secs_per_block)
1411 || (phdr->ts.secs - block_start.secs == secs_per_block
1412 && phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1413  
1414 if (!wtap_dump_close(pdh, &write_err)) {
1415 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1416 filename, wtap_strerror(write_err));
1417 goto error_on_exit;
1418 }
1419 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1420 g_free(filename);
1421 filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1422 g_assert(filename);
1423  
1424 if (verbose)
1425 fprintf(stderr, "Continuing writing in file %s\n", filename);
1426  
1427 pdh = editcap_dump_open(filename,
1428 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1429 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1430  
1431 if (pdh == NULL) {
1432 fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1433 filename, wtap_strerror(write_err));
1434 goto error_on_exit;
1435 }
1436 }
1437 }
1438 } /* time stamp handling */
1439  
1440 if (split_packet_count > 0) {
1441 /* time for the next file? */
1442 if (written_count > 0 && written_count % split_packet_count == 0) {
1443 if (!wtap_dump_close(pdh, &write_err)) {
1444 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1445 filename, wtap_strerror(write_err));
1446 goto error_on_exit;
1447 }
1448  
1449 g_free(filename);
1450 filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1451 g_assert(filename);
1452  
1453 if (verbose)
1454 fprintf(stderr, "Continuing writing in file %s\n", filename);
1455  
1456 pdh = editcap_dump_open(filename,
1457 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1458 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1459 if (pdh == NULL) {
1460 fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1461 filename, wtap_strerror(write_err));
1462 goto error_on_exit;
1463 }
1464 }
1465 } /* split packet handling */
1466  
1467 if (check_startstop) {
1468 /*
1469 * Is the packet in the selected timeframe?
1470 * If the packet has no time stamp, the answer is "no".
1471 */
1472 if (phdr->presence_flags & WTAP_HAS_TS)
1473 ts_okay = (phdr->ts.secs >= starttime) && (phdr->ts.secs < stoptime);
1474 else
1475 ts_okay = FALSE;
1476 } else {
1477 /*
1478 * No selected timeframe, so all packets are "in the
1479 * selected timeframe".
1480 */
1481 ts_okay = TRUE;
1482 }
1483  
1484 if (ts_okay && ((!selected(count) && !keep_em)
1485 || (selected(count) && keep_em))) {
1486  
1487 if (verbose && !dup_detect && !dup_detect_by_time)
1488 fprintf(stderr, "Packet: %u\n", count);
1489  
1490 /* We simply write it, perhaps after truncating it; we could
1491 * do other things, like modify it. */
1492  
1493 phdr = wtap_phdr(wth);
1494  
1495 if (snaplen != 0) {
1496 /* Limit capture length to snaplen */
1497 if (phdr->caplen > snaplen) {
1498 /* Copy and change rather than modify returned phdr */
1499 temp_phdr = *phdr;
1500 temp_phdr.caplen = snaplen;
1501 phdr = &temp_phdr;
1502 }
1503 /* If -L, also set reported length to snaplen */
1504 if (adjlen && phdr->len > snaplen) {
1505 /* Copy and change rather than modify returned phdr */
1506 temp_phdr = *phdr;
1507 temp_phdr.len = snaplen;
1508 phdr = &temp_phdr;
1509 }
1510 }
1511  
1512 /* CHOP */
1513 temp_phdr = *phdr;
1514 handle_chopping(chop, &temp_phdr, phdr, &buf, adjlen);
1515 phdr = &temp_phdr;
1516  
1517 if (phdr->presence_flags & WTAP_HAS_TS) {
1518 /* Do we adjust timestamps to ensure strict chronological
1519 * order? */
1520 if (do_strict_time_adjustment) {
1521 if (previous_time.secs || previous_time.nsecs) {
1522 if (!strict_time_adj.is_negative) {
1523 nstime_t current;
1524 nstime_t delta;
1525  
1526 current = phdr->ts;
1527  
1528 nstime_delta(&delta, &current, &previous_time);
1529  
1530 if (delta.secs < 0 || delta.nsecs < 0) {
1531 /*
1532 * A negative delta indicates that the current packet
1533 * has an absolute timestamp less than the previous packet
1534 * that it is being compared to. This is NOT a normal
1535 * situation since trace files usually have packets in
1536 * chronological order (oldest to newest).
1537 */
1538 /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */
1539 temp_phdr = *phdr;
1540 temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1541 temp_phdr.ts.nsecs = previous_time.nsecs;
1542 if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1543 /* carry */
1544 temp_phdr.ts.secs++;
1545 temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1546 } else {
1547 temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1548 }
1549 phdr = &temp_phdr;
1550 }
1551 } else {
1552 /*
1553 * A negative strict time adjustment is requested.
1554 * Unconditionally set each timestamp to previous
1555 * packet's timestamp plus delta.
1556 */
1557 temp_phdr = *phdr;
1558 temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1559 temp_phdr.ts.nsecs = previous_time.nsecs;
1560 if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1561 /* carry */
1562 temp_phdr.ts.secs++;
1563 temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1564 } else {
1565 temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1566 }
1567 phdr = &temp_phdr;
1568 }
1569 }
1570 previous_time = phdr->ts;
1571 }
1572  
1573 if (time_adj.tv.secs != 0) {
1574 temp_phdr = *phdr;
1575 if (time_adj.is_negative)
1576 temp_phdr.ts.secs -= time_adj.tv.secs;
1577 else
1578 temp_phdr.ts.secs += time_adj.tv.secs;
1579 phdr = &temp_phdr;
1580 }
1581  
1582 if (time_adj.tv.nsecs != 0) {
1583 temp_phdr = *phdr;
1584 if (time_adj.is_negative) { /* subtract */
1585 if (temp_phdr.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
1586 temp_phdr.ts.secs--;
1587 temp_phdr.ts.nsecs += ONE_BILLION;
1588 }
1589 temp_phdr.ts.nsecs -= time_adj.tv.nsecs;
1590 } else { /* add */
1591 if (temp_phdr.ts.nsecs + time_adj.tv.nsecs > ONE_BILLION) {
1592 /* carry */
1593 temp_phdr.ts.secs++;
1594 temp_phdr.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION;
1595 } else {
1596 temp_phdr.ts.nsecs += time_adj.tv.nsecs;
1597 }
1598 }
1599 phdr = &temp_phdr;
1600 }
1601 } /* time stamp adjustment */
1602  
1603 /* remove vlan info */
1604 if (rem_vlan) {
1605 /* TODO: keep casting const like this? change pointer instead of value? */
1606 remove_vlan_info(phdr, buf, (guint32 *) &phdr->caplen);
1607 }
1608  
1609 /* suppress duplicates by packet window */
1610 if (dup_detect) {
1611 if (is_duplicate(buf, phdr->caplen)) {
1612 if (verbose) {
1613 fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1614 count, phdr->caplen);
1615 for (i = 0; i < 16; i++)
1616 fprintf(stderr, "%02x",
1617 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1618 fprintf(stderr, "\n");
1619 }
1620 duplicate_count++;
1621 count++;
1622 continue;
1623 } else {
1624 if (verbose) {
1625 fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1626 count, phdr->caplen);
1627 for (i = 0; i < 16; i++)
1628 fprintf(stderr, "%02x",
1629 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1630 fprintf(stderr, "\n");
1631 }
1632 }
1633 } /* suppression of duplicates */
1634  
1635 if (phdr->presence_flags & WTAP_HAS_TS) {
1636 /* suppress duplicates by time window */
1637 if (dup_detect_by_time) {
1638 nstime_t current;
1639  
1640 current.secs = phdr->ts.secs;
1641 current.nsecs = phdr->ts.nsecs;
1642  
1643 if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1644 if (verbose) {
1645 fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1646 count, phdr->caplen);
1647 for (i = 0; i < 16; i++)
1648 fprintf(stderr, "%02x",
1649 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1650 fprintf(stderr, "\n");
1651 }
1652 duplicate_count++;
1653 count++;
1654 continue;
1655 } else {
1656 if (verbose) {
1657 fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1658 count, phdr->caplen);
1659 for (i = 0; i < 16; i++)
1660 fprintf(stderr, "%02x",
1661 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1662 fprintf(stderr, "\n");
1663 }
1664 }
1665 }
1666 } /* suppress duplicates by time window */
1667  
1668 if (change_offset > phdr->caplen) {
1669 fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n",
1670 change_offset, phdr->caplen, count);
1671 }
1672  
1673 /* Random error mutation */
1674 if (err_prob > 0.0 && change_offset <= phdr->caplen) {
1675 int real_data_start = 0;
1676  
1677 /* Protect non-protocol data */
1678 if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000)
1679 real_data_start = find_dct2000_real_data(buf);
1680  
1681 real_data_start += change_offset;
1682  
1683 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1684 if (rand() <= err_prob * RAND_MAX) {
1685 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1686  
1687 if (err_type < ERR_WT_BIT) {
1688 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1689 err_type = ERR_WT_TOTAL;
1690 } else {
1691 err_type -= ERR_WT_BYTE;
1692 }
1693  
1694 if (err_type < ERR_WT_BYTE) {
1695 buf[i] = rand() / (RAND_MAX / 255 + 1);
1696 err_type = ERR_WT_TOTAL;
1697 } else {
1698 err_type -= ERR_WT_BYTE;
1699 }
1700  
1701 if (err_type < ERR_WT_ALNUM) {
1702 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1703 err_type = ERR_WT_TOTAL;
1704 } else {
1705 err_type -= ERR_WT_ALNUM;
1706 }
1707  
1708 if (err_type < ERR_WT_FMT) {
1709 if ((unsigned int)i < phdr->caplen - 2)
1710 g_strlcpy((char*) &buf[i], "%s", 2);
1711 err_type = ERR_WT_TOTAL;
1712 } else {
1713 err_type -= ERR_WT_FMT;
1714 }
1715  
1716 if (err_type < ERR_WT_AA) {
1717 for (j = i; j < (int) phdr->caplen; j++)
1718 buf[j] = 0xAA;
1719 i = phdr->caplen;
1720 }
1721 }
1722 }
1723 } /* random error mutation */
1724  
1725 /* Find a packet comment we may need to write */
1726 if (frames_user_comments) {
1727 const char *comment =
1728 (const char*)g_tree_lookup(frames_user_comments, GUINT_TO_POINTER(read_count));
1729 if (comment != NULL) {
1730 /* Copy and change rather than modify returned phdr */
1731 temp_phdr = *phdr;
1732 temp_phdr.opt_comment = g_strdup(comment);
1733 phdr = &temp_phdr;
1734 }
1735 }
1736  
1737 /* Attempt to dump out current frame to the output file */
1738 if (!wtap_dump(pdh, phdr, buf, &write_err, &write_err_info)) {
1739 switch (write_err) {
1740 case WTAP_ERR_UNWRITABLE_ENCAP:
1741 /*
1742 * This is a problem with the particular frame we're
1743 * writing and the file type and subtype we're
1744 * writing; note that, and report the frame number
1745 * and file type/subtype.
1746 */
1747 fprintf(stderr,
1748 "editcap: Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
1749 read_count, argv[optind],
1750 wtap_file_type_subtype_string(out_file_type_subtype));
1751 break;
1752  
1753 case WTAP_ERR_PACKET_TOO_LARGE:
1754 /*
1755 * This is a problem with the particular frame we're
1756 * writing and the file type and subtype we're
1757 * writing; note that, and report the frame number
1758 * and file type/subtype.
1759 */
1760 fprintf(stderr,
1761 "editcap: Frame %u of \"%s\" is too large for a \"%s\" file.\n",
1762 read_count, argv[optind],
1763 wtap_file_type_subtype_string(out_file_type_subtype));
1764 break;
1765  
1766 case WTAP_ERR_UNWRITABLE_REC_TYPE:
1767 /*
1768 * This is a problem with the particular record we're
1769 * writing and the file type and subtype we're
1770 * writing; note that, and report the record number
1771 * and file type/subtype.
1772 */
1773 fprintf(stderr,
1774 "editcap: Record %u of \"%s\" has a record type that can't be saved in a \"%s\" file.\n",
1775 read_count, argv[optind],
1776 wtap_file_type_subtype_string(out_file_type_subtype));
1777 break;
1778  
1779 case WTAP_ERR_UNWRITABLE_REC_DATA:
1780 /*
1781 * This is a problem with the particular record we're
1782 * writing and the file type and subtype we're
1783 * writing; note that, and report the record number
1784 * and file type/subtype.
1785 */
1786 fprintf(stderr,
1787 "editcap: Record %u of \"%s\" has data that can't be saved in a \"%s\" file.\n(%s)\n",
1788 read_count, argv[optind],
1789 wtap_file_type_subtype_string(out_file_type_subtype),
1790 write_err_info != NULL ? write_err_info : "no information supplied");
1791 g_free(write_err_info);
1792 break;
1793  
1794 default:
1795 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1796 filename, wtap_strerror(write_err));
1797 break;
1798 }
1799 goto error_on_exit;
1800 }
1801 written_count++;
1802 }
1803 count++;
1804 }
1805  
1806 g_free(fprefix);
1807 g_free(fsuffix);
1808  
1809 if (read_err != 0) {
1810 /* Print a message noting that the read failed somewhere along the
1811 * line. */
1812 fprintf(stderr,
1813 "editcap: An error occurred while reading \"%s\": %s.\n",
1814 argv[optind], wtap_strerror(read_err));
1815 if (read_err_info != NULL) {
1816 fprintf(stderr, "(%s)\n", read_err_info);
1817 g_free(read_err_info);
1818 }
1819 }
1820  
1821 if (!pdh) {
1822 /* No valid packages found, open the outfile so we can write an
1823 * empty header */
1824 g_free (filename);
1825 filename = g_strdup(argv[optind+1]);
1826  
1827 pdh = editcap_dump_open(filename,
1828 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1829 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1830 if (pdh == NULL) {
1831 fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1832 filename, wtap_strerror(write_err));
1833 goto error_on_exit;
1834 }
1835 }
1836  
1837 g_free(idb_inf);
1838 idb_inf = NULL;
1839  
1840 if (!wtap_dump_close(pdh, &write_err)) {
1841 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1842 wtap_strerror(write_err));
1843 goto error_on_exit;
1844 }
1845 wtap_block_array_free(shb_hdrs);
1846 shb_hdrs = NULL;
1847 wtap_block_array_free(nrb_hdrs);
1848 nrb_hdrs = NULL;
1849 g_free(filename);
1850  
1851 if (frames_user_comments) {
1852 g_tree_destroy(frames_user_comments);
1853 }
1854 }
1855  
1856 if (dup_detect) {
1857 fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate window of %i packets.\n",
1858 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1859 plurality(duplicate_count, "", "s"), dup_window);
1860 } else if (dup_detect_by_time) {
1861 fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1862 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1863 plurality(duplicate_count, "", "s"),
1864 (long)relative_time_window.secs,
1865 (long int)relative_time_window.nsecs);
1866 }
1867  
1868 return 0;
1869  
1870 error_on_exit:
1871 wtap_block_array_free(shb_hdrs);
1872 wtap_block_array_free(nrb_hdrs);
1873 g_free(idb_inf);
1874 exit(2);
1875 }
1876  
1877 /* Skip meta-information read from file to return offset of real
1878 * protocol data */
1879 static int
1880 find_dct2000_real_data(guint8 *buf)
1881 {
1882 int n = 0;
1883  
1884 for (n = 0; buf[n] != '\0'; n++); /* Context name */
1885 n++;
1886 n++; /* Context port number */
1887 for (; buf[n] != '\0'; n++); /* Timestamp */
1888 n++;
1889 for (; buf[n] != '\0'; n++); /* Protocol name */
1890 n++;
1891 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1892 n++;
1893 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1894 n++;
1895 n += 2; /* Direction & encap */
1896  
1897 return n;
1898 }
1899  
1900 /*
1901 * We support up to 2 chopping regions in a single pass: one specified by the
1902 * positive chop length, and one by the negative chop length.
1903 */
1904 static void
1905 handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
1906 const struct wtap_pkthdr *in_phdr, guint8 **buf,
1907 gboolean adjlen)
1908 {
1909 /* Only packets can be chopped. */
1910 if (in_phdr->rec_type != REC_TYPE_PACKET)
1911 return;
1912  
1913 /* If we're not chopping anything from one side, then the offset for that
1914 * side is meaningless. */
1915 if (chop.len_begin == 0)
1916 chop.off_begin_pos = chop.off_begin_neg = 0;
1917 if (chop.len_end == 0)
1918 chop.off_end_pos = chop.off_end_neg = 0;
1919  
1920 if (chop.off_begin_neg < 0) {
1921 chop.off_begin_pos += in_phdr->caplen + chop.off_begin_neg;
1922 chop.off_begin_neg = 0;
1923 }
1924 if (chop.off_end_pos > 0) {
1925 chop.off_end_neg += chop.off_end_pos - in_phdr->caplen;
1926 chop.off_end_pos = 0;
1927 }
1928  
1929 /* If we've crossed chopping regions, swap them */
1930 if (chop.len_begin && chop.len_end) {
1931 if (chop.off_begin_pos > ((int)in_phdr->caplen + chop.off_end_neg)) {
1932 int tmp_len, tmp_off;
1933  
1934 tmp_off = in_phdr->caplen + chop.off_end_neg + chop.len_end;
1935 tmp_len = -chop.len_end;
1936  
1937 chop.off_end_neg = chop.len_begin + chop.off_begin_pos - in_phdr->caplen;
1938 chop.len_end = -chop.len_begin;
1939  
1940 chop.len_begin = tmp_len;
1941 chop.off_begin_pos = tmp_off;
1942 }
1943 }
1944  
1945 /* Make sure we don't chop off more than we have available */
1946 if (in_phdr->caplen < (guint32)(chop.off_begin_pos - chop.off_end_neg)) {
1947 chop.len_begin = 0;
1948 chop.len_end = 0;
1949 }
1950 if ((guint32)(chop.len_begin - chop.len_end) >
1951 (in_phdr->caplen - (guint32)(chop.off_begin_pos - chop.off_end_neg))) {
1952 chop.len_begin = in_phdr->caplen - (chop.off_begin_pos - chop.off_end_neg);
1953 chop.len_end = 0;
1954 }
1955  
1956 /* Handle chopping from the beginning. Note that if a beginning offset
1957 * was specified, we need to keep that piece */
1958 if (chop.len_begin > 0) {
1959 *out_phdr = *in_phdr;
1960  
1961 if (chop.off_begin_pos > 0) {
1962 memmove(*buf + chop.off_begin_pos,
1963 *buf + chop.off_begin_pos + chop.len_begin,
1964 out_phdr->caplen - chop.len_begin);
1965 } else {
1966 *buf += chop.len_begin;
1967 }
1968 out_phdr->caplen -= chop.len_begin;
1969  
1970 if (adjlen) {
1971 if (in_phdr->len > (guint32)chop.len_begin)
1972 out_phdr->len -= chop.len_begin;
1973 else
1974 out_phdr->len = 0;
1975 }
1976 in_phdr = out_phdr;
1977 }
1978  
1979 /* Handle chopping from the end. Note that if an ending offset was
1980 * specified, we need to keep that piece */
1981 if (chop.len_end < 0) {
1982 *out_phdr = *in_phdr;
1983  
1984 if (chop.off_end_neg < 0) {
1985 memmove(*buf + (gint)out_phdr->caplen + (chop.len_end + chop.off_end_neg),
1986 *buf + (gint)out_phdr->caplen + chop.off_end_neg,
1987 -chop.off_end_neg);
1988 }
1989 out_phdr->caplen += chop.len_end;
1990  
1991 if (adjlen) {
1992 if (((signed int) in_phdr->len + chop.len_end) > 0)
1993 out_phdr->len += chop.len_end;
1994 else
1995 out_phdr->len = 0;
1996 }
1997 /*in_phdr = out_phdr;*/
1998 }
1999 }
2000  
2001 /*
2002 * Editor modelines - http://www.wireshark.org/tools/modelines.html
2003 *
2004 * Local variables:
2005 * c-basic-offset: 4
2006 * tab-width: 8
2007 * indent-tabs-mode: nil
2008 * End:
2009 *
2010 * vi: set shiftwidth=4 tabstop=8 expandtab:
2011 * :indentSize=4:tabSize=8:noTabs=true:
2012 */