From Jakub Zawadzki via bug #4289: (Fix for) Frame arrival times (pcap)
[metze/wireshark/wip.git] / text2pcap.c
1 /**-*-C-*-**********************************************************************
2  *
3  * text2pcap.c
4  *
5  * Utility to convert an ASCII hexdump into a libpcap-format capture file
6  *
7  * (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
8  *
9  * $Id$
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
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (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
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  *
29  *******************************************************************************/
30
31 /*******************************************************************************
32  *
33  * This utility reads in an ASCII hexdump of this common format:
34  *
35  * 00000000  00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
36  * 00000010  03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3...\7f..
37  * 00000020  03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
38  * 00000030  01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
39  *
40  * Each bytestring line consists of an offset, one or more bytes, and
41  * text at the end. An offset is defined as a hex string of more than
42  * two characters. A byte is defined as a hex string of exactly two
43  * characters. The text at the end is ignored, as is any text before
44  * the offset. Bytes read from a bytestring line are added to the
45  * current packet only if all the following conditions are satisfied:
46  *
47  * - No text appears between the offset and the bytes (any bytes appearing after
48  *   such text would be ignored)
49  *
50  * - The offset must be arithmetically correct, i.e. if the offset is 00000020, then
51  *   exactly 32 bytes must have been read into this packet before this. If the offset
52  *   is wrong, the packet is immediately terminated
53  *
54  * A packet start is signalled by a zero offset.
55  *
56  * Lines starting with #TEXT2PCAP are directives. These allow the user
57  * to embed instructions into the capture file which allows text2pcap
58  * to take some actions (e.g. specifying the encapsulation
59  * etc.). Currently no directives are implemented.
60  *
61  * Lines beginning with # which are not directives are ignored as
62  * comments. Currently all non-hexdump text is ignored by text2pcap;
63  * in the future, text processing may be added, but lines prefixed
64  * with '#' will still be ignored.
65  *
66  * The output is a libpcap packet containing Ethernet frames by
67  * default. This program takes options which allow the user to add
68  * dummy Ethernet, IP and UDP or TCP headers to the packets in order
69  * to allow dumps of L3 or higher protocols to be decoded.
70  *
71  * Considerable flexibility is built into this code to read hexdumps
72  * of slightly different formats. For example, any text prefixing the
73  * hexdump line is dropped (including mail forwarding '>'). The offset
74  * can be any hex number of four digits or greater.
75  *
76  * This converter cannot read a single packet greater than 64K. Packet
77  * snaplength is automatically set to 64K.
78  */
79
80 #ifdef HAVE_CONFIG_H
81 # include "config.h"
82 #endif
83
84 /*
85  * Just make sure we include the prototype for strptime as well
86  * (needed for glibc 2.2) but make sure we do this only if not
87  * yet defined.
88  */
89 #ifndef __USE_XOPEN
90 #  define __USE_XOPEN
91 #endif
92 #ifndef _XOPEN_SOURCE
93 #  define _XOPEN_SOURCE
94 #endif
95
96 /*
97  * Defining _XOPEN_SOURCE is needed on some platforms, e.g. platforms
98  * using glibc, to expand the set of things system header files define.
99  *
100  * Unfortunately, on other platforms, such as some versions of Solaris
101  * (including Solaris 10), it *reduces* that set as well, causing
102  * strptime() not to be declared, presumably because the version of the
103  * X/Open spec that _XOPEN_SOURCE implies doesn't include strptime() and
104  * blah blah blah namespace pollution blah blah blah.
105  *
106  * So we define __EXTENSIONS__ so that "strptime()" is declared.
107  */
108 #ifndef __EXTENSIONS__
109 #  define __EXTENSIONS__
110 #endif
111
112 #include <ctype.h>
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <string.h>
116 #include <wsutil/file_util.h>
117
118 #include <time.h>
119 #include <glib.h>
120
121 #ifdef HAVE_UNISTD_H
122 # include <unistd.h>
123 #endif
124
125 #include <errno.h>
126 #include <assert.h>
127
128 #ifdef HAVE_GETOPT_H
129 #include <getopt.h>
130 #else
131 #include "wsgetopt.h"
132 #endif
133
134 #ifdef NEED_STRPTIME_H
135 # include "strptime.h"
136 #endif
137
138 #include "text2pcap.h"
139
140 /*--- Options --------------------------------------------------------------------*/
141
142 /* Debug level */
143 static int debug = 0;
144 /* Be quiet */
145 static int quiet = FALSE;
146
147 /* Dummy Ethernet header */
148 static int hdr_ethernet = FALSE;
149 static unsigned long hdr_ethernet_proto = 0;
150
151 /* Dummy IP header */
152 static int hdr_ip = FALSE;
153 static long hdr_ip_proto = 0;
154
155 /* Dummy UDP header */
156 static int hdr_udp = FALSE;
157 static unsigned long hdr_dest_port = 0;
158 static unsigned long hdr_src_port = 0;
159
160 /* Dummy TCP header */
161 static int hdr_tcp = FALSE;
162
163 /* Dummy SCTP header */
164 static int hdr_sctp = FALSE;
165 static unsigned long hdr_sctp_src  = 0;
166 static unsigned long hdr_sctp_dest = 0;
167 static unsigned long hdr_sctp_tag  = 0;
168
169 /* Dummy DATA chunk header */
170 static int hdr_data_chunk = FALSE;
171 static unsigned char  hdr_data_chunk_type = 0;
172 static unsigned char  hdr_data_chunk_bits = 3;
173 static unsigned long  hdr_data_chunk_tsn  = 0;
174 static unsigned short hdr_data_chunk_sid  = 0;
175 static unsigned short hdr_data_chunk_ssn  = 0;
176 static unsigned long  hdr_data_chunk_ppid = 0;
177
178
179 /*--- Local date -----------------------------------------------------------------*/
180
181 /* This is where we store the packet currently being built */
182 #define MAX_PACKET 64000
183 static unsigned char packet_buf[MAX_PACKET];
184 static unsigned long curr_offset = 0;
185 static unsigned long max_offset = MAX_PACKET;
186 static unsigned long packet_start = 0;
187 static void start_new_packet (void);
188
189 /* This buffer contains strings present before the packet offset 0 */
190 #define PACKET_PREAMBLE_MAX_LEN 2048
191 static unsigned char packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
192 static int packet_preamble_len = 0;
193
194 /* Number of packets read and written */
195 static unsigned long num_packets_read = 0;
196 static unsigned long num_packets_written = 0;
197
198 /* Time code of packet, derived from packet_preamble */
199 static time_t ts_sec  = 0;
200 static guint32 ts_usec = 0;
201 static char *ts_fmt = NULL;
202 static struct tm timecode_default;
203
204 /* Input file */
205 static const char *input_filename;
206 static FILE *input_file = NULL;
207 /* Output file */
208 static const char *output_filename;
209 static FILE *output_file = NULL;
210
211 /* Offset base to parse */
212 static unsigned long offset_base = 16;
213
214 extern FILE *yyin;
215
216 /* ----- State machine -----------------------------------------------------------*/
217
218 /* Current state of parser */
219 typedef enum {
220     INIT,             /* Waiting for start of new packet */
221     START_OF_LINE,    /* Starting from beginning of line */
222     READ_OFFSET,      /* Just read the offset */
223     READ_BYTE,        /* Just read a byte */
224     READ_TEXT         /* Just read text - ignore until EOL */
225 } parser_state_t;
226 static parser_state_t state = INIT;
227
228 static const char *state_str[] = {"Init",
229                            "Start-of-line",
230                            "Offset",
231                            "Byte",
232                            "Text"
233 };
234
235 static const char *token_str[] = {"",
236                            "Byte",
237                            "Offset",
238                            "Directive",
239                            "Text",
240                            "End-of-line"
241 };
242
243 /* ----- Skeleton Packet Headers --------------------------------------------------*/
244
245 typedef struct {
246     guint8  dest_addr[6];
247     guint8  src_addr[6];
248     guint16 l3pid;
249 } hdr_ethernet_t;
250
251 static hdr_ethernet_t HDR_ETHERNET = {
252     {0x02, 0x02, 0x02, 0x02, 0x02, 0x02},
253     {0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
254     0};
255
256 typedef struct {
257     guint8  ver_hdrlen;
258     guint8  dscp;
259     guint16 packet_length;
260     guint16 identification;
261     guint8  flags;
262     guint8  fragment;
263     guint8  ttl;
264     guint8  protocol;
265     guint16 hdr_checksum;
266     guint32 src_addr;
267     guint32 dest_addr;
268 } hdr_ip_t;
269
270 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0, 0x01010101, 0x02020202};
271
272 static struct {                 /* pseudo header for checksum calculation */
273         guint32 src_addr;
274         guint32 dest_addr;
275         guint8  zero;
276         guint8  protocol;
277         guint16 length;
278 } pseudoh;
279
280 typedef struct {
281     guint16 source_port;
282     guint16 dest_port;
283     guint16 length;
284     guint16 checksum;
285 } hdr_udp_t;
286
287 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
288
289 typedef struct {
290     guint16 source_port;
291     guint16 dest_port;
292     guint32 seq_num;
293     guint32 ack_num;
294     guint8  hdr_length;
295     guint8  flags;
296     guint16 window;
297     guint16 checksum;
298     guint16 urg;
299 } hdr_tcp_t;
300
301 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
302
303 typedef struct {
304     guint16 src_port;
305     guint16 dest_port;
306     guint32 tag;
307     guint32 checksum;
308 } hdr_sctp_t;
309
310 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
311
312 typedef struct {
313     guint8  type;
314     guint8  bits;
315     guint16 length;
316     guint32 tsn;
317     guint16 sid;
318     guint16 ssn;
319     guint32 ppid;
320 } hdr_data_chunk_t;
321
322 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
323
324 static char tempbuf[64];
325
326 /*----------------------------------------------------------------------
327  * Stuff for writing a PCap file
328  */
329 #define PCAP_MAGIC                      0xa1b2c3d4
330
331 /* "libpcap" file header (minus magic number). */
332 struct pcap_hdr {
333     guint32     magic;          /* magic */
334     guint16     version_major;  /* major version number */
335     guint16     version_minor;  /* minor version number */
336     guint32     thiszone;       /* GMT to local correction */
337     guint32     sigfigs;        /* accuracy of timestamps */
338     guint32     snaplen;        /* max length of captured packets, in octets */
339     guint32     network;        /* data link type */
340 };
341
342 /* "libpcap" record header. */
343 struct pcaprec_hdr {
344     guint32     ts_sec;         /* timestamp seconds */
345     guint32     ts_usec;        /* timestamp microseconds */
346     guint32     incl_len;       /* number of octets of packet saved in file */
347     guint32     orig_len;       /* actual length of packet */
348 };
349
350 /* Link-layer type; see net/bpf.h for details */
351 static unsigned long pcap_link_type = 1;   /* Default is DLT-EN10MB */
352
353 /*----------------------------------------------------------------------
354  * Parse a single hex number
355  * Will abort the program if it can't parse the number
356  * Pass in TRUE if this is an offset, FALSE if not
357  */
358 static unsigned long
359 parse_num (const char *str, int offset)
360 {
361     unsigned long num;
362     char *c;
363
364     num = strtoul(str, &c, offset ? offset_base : 16);
365     if (c==str) {
366         fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
367         exit(-1);
368     }
369     return num;
370 }
371
372 /*----------------------------------------------------------------------
373  * Write this byte into current packet
374  */
375 static void
376 write_byte (const char *str)
377 {
378     unsigned long num;
379
380     num = parse_num(str, FALSE);
381     packet_buf[curr_offset] = (unsigned char) num;
382     curr_offset ++;
383     if (curr_offset >= max_offset) /* packet full */
384             start_new_packet();
385 }
386
387 /*----------------------------------------------------------------------
388  * Remove bytes from the current packet
389  */
390 static void
391 unwrite_bytes (unsigned long nbytes)
392 {
393     curr_offset -= nbytes;
394 }
395
396 /*----------------------------------------------------------------------
397  * Compute one's complement checksum (from RFC1071)
398  */
399 static guint16
400 in_checksum (void *buf, unsigned long count)
401 {
402     unsigned long sum = 0;
403     guint16 *addr = buf;
404
405     while( count > 1 )  {
406         /*  This is the inner loop */
407         sum += g_ntohs(* (guint16 *) addr);
408         addr++;
409         count -= 2;
410     }
411
412     /*  Add left-over byte, if any */
413     if( count > 0 )
414         sum += g_ntohs(* (guint8 *) addr);
415
416     /*  Fold 32-bit sum to 16 bits */
417     while (sum>>16)
418         sum = (sum & 0xffff) + (sum >> 16);
419
420     return g_htons(~sum);
421 }
422
423 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
424  * That code is copyrighted by D. Otis and has been modified.
425  */
426
427 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
428 static guint32 crc_c[256] =
429 {
430 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
431 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
432 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
433 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
434 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
435 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
436 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
437 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
438 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
439 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
440 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
441 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
442 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
443 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
444 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
445 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
446 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
447 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
448 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
449 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
450 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
451 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
452 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
453 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
454 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
455 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
456 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
457 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
458 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
459 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
460 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
461 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
462 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
463 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
464 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
465 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
466 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
467 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
468 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
469 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
470 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
471 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
472 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
473 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
474 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
475 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
476 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
477 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
478 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
479 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
480 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
481 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
482 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
483 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
484 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
485 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
486 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
487 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
488 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
489 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
490 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
491 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
492 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
493 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
494 };
495
496 static guint32
497 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
498 {
499   unsigned int i;
500   guint32 crc32;
501
502   crc32 = crc32_init;
503   for (i = 0; i < len; i++)
504     CRC32C(crc32, buf[i]);
505
506   return ( crc32 );
507 }
508
509 static guint32
510 finalize_crc32c(guint32 crc32)
511 {
512   guint32 result;
513   guint8 byte0,byte1,byte2,byte3;
514
515   result = ~crc32;
516   byte0 = result & 0xff;
517   byte1 = (result>>8) & 0xff;
518   byte2 = (result>>16) & 0xff;
519   byte3 = (result>>24) & 0xff;
520   result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
521   return ( result );
522 }
523
524 static unsigned long
525 number_of_padding_bytes (unsigned long length)
526 {
527   unsigned long remainder;
528
529   remainder = length % 4;
530
531   if (remainder == 0)
532     return 0;
533   else
534     return 4 - remainder;
535 }
536
537 /*----------------------------------------------------------------------
538  * Write current packet out
539  */
540 static void
541 write_current_packet (void)
542 {
543     int length = 0;
544     int proto_length = 0;
545     int ip_length = 0;
546     int eth_trailer_length = 0;
547     int i, padding_length;
548     guint32 u;
549     struct pcaprec_hdr ph;
550
551     if (curr_offset > 0) {
552         /* Write the packet */
553
554         /* Compute packet length */
555         length = curr_offset;
556         if (hdr_data_chunk) { length += sizeof(HDR_DATA_CHUNK) + number_of_padding_bytes(curr_offset); }
557         if (hdr_sctp) { length += sizeof(HDR_SCTP); }
558         if (hdr_udp) { length += sizeof(HDR_UDP); proto_length = length; }
559         if (hdr_tcp) { length += sizeof(HDR_TCP); proto_length = length; }
560         if (hdr_ip) { length += sizeof(HDR_IP); ip_length = length; }
561         if (hdr_ethernet) {
562             length += sizeof(HDR_ETHERNET);
563             /* Pad trailer */
564             if (length < 60) {
565                 eth_trailer_length = 60 - length;
566                 length = 60;
567             }
568         }
569
570         /* Write PCAP header */
571         ph.ts_sec = (guint32)ts_sec;
572         ph.ts_usec = ts_usec;
573         if (ts_fmt == NULL) { ts_usec++; }      /* fake packet counter */
574         ph.incl_len = length;
575         ph.orig_len = length;
576         fwrite(&ph, sizeof(ph), 1, output_file);
577
578         /* Write Ethernet header */
579         if (hdr_ethernet) {
580             HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
581             fwrite(&HDR_ETHERNET, sizeof(HDR_ETHERNET), 1, output_file);
582         }
583
584         /* Write IP header */
585         if (hdr_ip) {
586             HDR_IP.packet_length = g_htons(ip_length);
587             HDR_IP.protocol = (guint8) hdr_ip_proto;
588             HDR_IP.hdr_checksum = 0;
589             HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
590             fwrite(&HDR_IP, sizeof(HDR_IP), 1, output_file);
591         }
592
593         /* initialize pseudo header for checksum calculation */
594         pseudoh.src_addr    = HDR_IP.src_addr;
595         pseudoh.dest_addr   = HDR_IP.dest_addr;
596         pseudoh.zero        = 0;
597         pseudoh.protocol    = (guint8) hdr_ip_proto;
598         pseudoh.length      = g_htons(proto_length);
599
600         /* Write UDP header */
601         if (hdr_udp) {
602             HDR_UDP.source_port = g_htons(hdr_src_port);
603             HDR_UDP.dest_port = g_htons(hdr_dest_port);
604             HDR_UDP.length = g_htons(proto_length);
605
606             HDR_UDP.checksum = 0;
607             u = g_ntohs(in_checksum(&pseudoh, sizeof(pseudoh))) +
608                     g_ntohs(in_checksum(&HDR_UDP, sizeof(HDR_UDP))) +
609                     g_ntohs(in_checksum(packet_buf, curr_offset));
610             HDR_UDP.checksum = g_htons((u & 0xffff) + (u>>16));
611             if (HDR_UDP.checksum == 0) /* differenciate between 'none' and 0 */
612                     HDR_UDP.checksum = g_htons(1);
613
614             fwrite(&HDR_UDP, sizeof(HDR_UDP), 1, output_file);
615         }
616
617         /* Write TCP header */
618         if (hdr_tcp) {
619             HDR_TCP.source_port = g_htons(hdr_src_port);
620             HDR_TCP.dest_port = g_htons(hdr_dest_port);
621             /* HDR_TCP.seq_num already correct */
622             HDR_TCP.window = g_htons(0x2000);
623
624             HDR_TCP.checksum = 0;
625             u = g_ntohs(in_checksum(&pseudoh, sizeof(pseudoh))) +
626                     g_ntohs(in_checksum(&HDR_TCP, sizeof(HDR_TCP))) +
627                     g_ntohs(in_checksum(packet_buf, curr_offset));
628             HDR_TCP.checksum = g_htons((u & 0xffff) + (u>>16));
629             if (HDR_TCP.checksum == 0) /* differenciate between 'none' and 0 */
630                     HDR_TCP.checksum = g_htons(1);
631
632             fwrite(&HDR_TCP, sizeof(HDR_TCP), 1, output_file);
633         }
634
635         /* Compute DATA chunk header and append padding */
636         if (hdr_data_chunk) {
637             HDR_DATA_CHUNK.type   = hdr_data_chunk_type;
638             HDR_DATA_CHUNK.bits   = hdr_data_chunk_bits;
639             HDR_DATA_CHUNK.length = g_htons(curr_offset + sizeof(HDR_DATA_CHUNK));
640             HDR_DATA_CHUNK.tsn    = g_htonl(hdr_data_chunk_tsn);
641             HDR_DATA_CHUNK.sid    = g_htons(hdr_data_chunk_sid);
642             HDR_DATA_CHUNK.ssn    = g_htons(hdr_data_chunk_ssn);
643             HDR_DATA_CHUNK.ppid   = g_htonl(hdr_data_chunk_ppid);
644
645             padding_length = number_of_padding_bytes(curr_offset);
646             for (i=0; i<padding_length; i++)
647               write_byte("0");
648         }
649
650         /* Write SCTP header */
651         if (hdr_sctp) {
652             HDR_SCTP.src_port  = g_htons(hdr_sctp_src);
653             HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
654             HDR_SCTP.tag       = g_htonl(hdr_sctp_tag);
655             HDR_SCTP.checksum  = g_htonl(0);
656             HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
657             if (hdr_data_chunk)
658               HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
659             HDR_SCTP.checksum  = g_htonl(finalize_crc32c(crc32c(packet_buf, curr_offset, HDR_SCTP.checksum)));
660
661             fwrite(&HDR_SCTP, sizeof(HDR_SCTP), 1, output_file);
662         }
663
664         /* Write DATA chunk header */
665         if (hdr_data_chunk) {
666             fwrite(&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), 1, output_file);
667         }
668         /* Write packet */
669         fwrite(packet_buf, curr_offset, 1, output_file);
670
671         /* Write Ethernet trailer */
672         if (hdr_ethernet && eth_trailer_length > 0) {
673             memset(tempbuf, 0, eth_trailer_length);
674             fwrite(tempbuf, eth_trailer_length, 1, output_file);
675         }
676
677         if (!quiet)
678             fprintf(stderr, "Wrote packet of %lu bytes at %u\n", curr_offset, g_ntohl(HDR_TCP.seq_num));
679         num_packets_written ++;
680     }
681
682     HDR_TCP.seq_num = g_htonl(g_ntohl(HDR_TCP.seq_num) + curr_offset);
683
684     packet_start += curr_offset;
685     curr_offset = 0;
686 }
687
688 /*----------------------------------------------------------------------
689  * Write the PCap file header
690  */
691 static void
692 write_file_header (void)
693 {
694     struct pcap_hdr fh;
695
696     fh.magic = PCAP_MAGIC;
697     fh.version_major = 2;
698     fh.version_minor = 4;
699     fh.thiszone = 0;
700     fh.sigfigs = 0;
701     fh.snaplen = 102400;
702     fh.network = pcap_link_type;
703
704     fwrite(&fh, sizeof(fh), 1, output_file);
705 }
706
707 /*----------------------------------------------------------------------
708  * Append a token to the packet preamble.
709  */
710 static void
711 append_to_preamble(char *str)
712 {
713     size_t toklen;
714
715     if (packet_preamble_len != 0) {
716         if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
717             return;     /* no room to add more preamble */
718         /* Add a blank separator between the previous token and this token. */
719         packet_preamble[packet_preamble_len++] = ' ';
720     }
721     toklen = strlen(str);
722     if (toklen != 0) {
723         if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
724             return;     /* no room to add the token to the preamble */
725         g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
726         packet_preamble_len += (int) toklen;
727         if (debug >= 2) {
728                 char *c;
729                 char xs[PACKET_PREAMBLE_MAX_LEN];
730                 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
731                 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
732                 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
733         }
734     }
735 }
736
737 /*----------------------------------------------------------------------
738  * Parse the preamble to get the timecode.
739  */
740
741 static void
742 parse_preamble (void)
743 {
744         struct tm timecode;
745         char *subsecs;
746         char *p;
747         int  subseclen;
748         int  i;
749
750         /*
751          * If no "-t" flag was specified, don't attempt to parse a packet
752          * preamble to extract a time stamp.
753          */
754         if (ts_fmt == NULL)
755             return;
756
757         /*
758          * Initialize to today localtime, just in case not all fields
759          * of the date and time are specified.
760          */
761
762         timecode = timecode_default;
763         ts_usec = 0;
764
765         /*
766          * Null-terminate the preamble.
767          */
768         packet_preamble[packet_preamble_len] = '\0';
769
770         /* Ensure preamble has more than two chars before atempting to parse.
771          * This should cover line breaks etc that get counted.
772          */
773         if ( strlen(packet_preamble) > 2 ) {
774                 /* Get Time leaving subseconds */
775                 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
776                 if (subsecs != NULL) {
777                         /* Get the long time from the tm structure */
778                         /*  (will return -1 if failure)            */
779                         ts_sec  = mktime( &timecode );
780                 } else
781                         ts_sec = -1;    /* we failed to parse it */
782
783                 /* This will ensure incorrectly parsed dates get set to zero */
784                 if ( -1 == ts_sec )
785                 {
786                         /* Sanitize - remove all '\r' */
787                         char *c;
788                         while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
789                         fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n   (defaulting to Jan 1,1970 00:00:00 GMT)\n",
790                                  packet_preamble, ts_fmt);
791                         if (debug >= 2) {
792                                 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
793                                         timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
794                                         timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
795                         }
796                         ts_sec  = 0;  /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
797                         ts_usec = 0;
798                 }
799                 else
800                 {
801                         /* Parse subseconds */
802                         ts_usec = strtol(subsecs, &p, 10);
803                         if (subsecs == p) {
804                                 /* Error */
805                                 ts_usec = 0;
806                         } else {
807                                 /*
808                                  * Convert that number to a number
809                                  * of microseconds; if it's N digits
810                                  * long, it's in units of 10^(-N) seconds,
811                                  * so, to convert it to units of
812                                  * 10^-6 seconds, we multiply by
813                                  * 10^(6-N).
814                                  */
815                                 subseclen = (int) (p - subsecs);
816                                 if (subseclen > 6) {
817                                         /*
818                                          * *More* than 6 digits; 6-N is
819                                          * negative, so we divide by
820                                          * 10^(N-6).
821                                          */
822                                         for (i = subseclen - 6; i != 0; i--)
823                                                 ts_usec /= 10;
824                                 } else if (subseclen < 6) {
825                                         for (i = 6 - subseclen; i != 0; i--)
826                                                 ts_usec *= 10;
827                                 }
828                         }
829                 }
830         }
831         if (debug >= 2) {
832                 char *c;
833                 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
834                 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
835                 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
836         }
837
838
839         /* Clear Preamble */
840         packet_preamble_len = 0;
841 }
842
843 /*----------------------------------------------------------------------
844  * Start a new packet
845  */
846 static void
847 start_new_packet (void)
848 {
849     if (debug>=1)
850         fprintf(stderr, "Start new packet\n");
851
852     /* Write out the current packet, if required */
853     write_current_packet();
854     num_packets_read ++;
855
856     /* Ensure we parse the packet preamble as it may contain the time */
857     parse_preamble();
858 }
859
860 /*----------------------------------------------------------------------
861  * Process a directive
862  */
863 static void
864 process_directive (char *str)
865 {
866     fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10);
867
868 }
869
870 /*----------------------------------------------------------------------
871  * Parse a single token (called from the scanner)
872  */
873 void
874 parse_token (token_t token, char *str)
875 {
876     unsigned long num;
877
878     /*
879      * This is implemented as a simple state machine of five states.
880      * State transitions are caused by tokens being received from the
881      * scanner. The code should be self_documenting.
882      */
883
884     if (debug>=2) {
885         /* Sanitize - remove all '\r' */
886         char *c;
887         if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
888
889         fprintf(stderr, "(%s, %s \"%s\") -> (",
890                 state_str[state], token_str[token], str ? str : "");
891     }
892
893     switch(state) {
894
895     /* ----- Waiting for new packet -------------------------------------------*/
896     case INIT:
897         switch(token) {
898         case T_TEXT:
899             append_to_preamble(str);
900             break;
901         case T_DIRECTIVE:
902             process_directive(str);
903             break;
904         case T_OFFSET:
905             num = parse_num(str, TRUE);
906             if (num==0) {
907                 /* New packet starts here */
908                 start_new_packet();
909                 state = READ_OFFSET;
910             }
911             break;
912         default:
913             break;
914         }
915         break;
916
917     /* ----- Processing packet, start of new line -----------------------------*/
918     case START_OF_LINE:
919         switch(token) {
920         case T_TEXT:
921             append_to_preamble(str);
922             break;
923         case T_DIRECTIVE:
924             process_directive(str);
925             break;
926         case T_OFFSET:
927             num = parse_num(str, TRUE);
928             if (num==0) {
929                 /* New packet starts here */
930                 start_new_packet();
931                 packet_start = 0;
932                 state = READ_OFFSET;
933             } else if ((num - packet_start) != curr_offset) {
934                 /*
935                  * The offset we read isn't the one we expected.
936                  * This may only mean that we mistakenly interpreted
937                  * some text as byte values (e.g., if the text dump
938                  * of packet data included a number with spaces around
939                  * it).  If the offset is less than what we expected,
940                  * assume that's the problem, and throw away the putative
941                  * extra byte values.
942                  */
943                 if (num < curr_offset) {
944                     unwrite_bytes(curr_offset - num);
945                     state = READ_OFFSET;
946                 } else {
947                     /* Bad offset; switch to INIT state */
948                     if (debug>=1)
949                         fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n",
950                                 curr_offset, num);
951                     write_current_packet();
952                     state = INIT;
953                 }
954             } else
955                 state = READ_OFFSET;
956             break;
957         default:
958             break;
959         }
960         break;
961
962     /* ----- Processing packet, read offset -----------------------------------*/
963     case READ_OFFSET:
964         switch(token) {
965         case T_BYTE:
966             /* Record the byte */
967             state = READ_BYTE;
968             write_byte(str);
969             break;
970         case T_TEXT:
971         case T_DIRECTIVE:
972         case T_OFFSET:
973             state = READ_TEXT;
974             break;
975         case T_EOL:
976             state = START_OF_LINE;
977             break;
978         default:
979             break;
980         }
981         break;
982
983     /* ----- Processing packet, read byte -------------------------------------*/
984     case READ_BYTE:
985         switch(token) {
986         case T_BYTE:
987             /* Record the byte */
988             write_byte(str);
989             break;
990         case T_TEXT:
991         case T_DIRECTIVE:
992         case T_OFFSET:
993             state = READ_TEXT;
994             break;
995         case T_EOL:
996             state = START_OF_LINE;
997             break;
998         default:
999             break;
1000         }
1001         break;
1002
1003     /* ----- Processing packet, read text -------------------------------------*/
1004     case READ_TEXT:
1005         switch(token) {
1006         case T_EOL:
1007             state = START_OF_LINE;
1008             break;
1009         default:
1010             break;
1011         }
1012         break;
1013
1014     default:
1015         fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1016         exit(-1);
1017     }
1018
1019     if (debug>=2)
1020         fprintf(stderr, ", %s)\n", state_str[state]);
1021
1022 }
1023
1024 /*----------------------------------------------------------------------
1025  * Print usage string and exit
1026  */
1027 static void
1028 usage (void)
1029 {
1030     fprintf(stderr,
1031             "Text2pcap %s"
1032 #ifdef SVNVERSION
1033             " (" SVNVERSION " from " SVNPATH ")"
1034 #endif
1035             "\n"
1036             "Generate a capture file from an ASCII hexdump of packets.\n"
1037             "See http://www.wireshark.org for more information.\n"
1038             "\n"
1039             "Usage: text2pcap [options] <infile> <outfile>\n"
1040             "\n"
1041             "where  <infile> specifies input  filename (use - for standard input)\n"
1042             "      <outfile> specifies output filename (use - for standard output)\n"
1043             "\n"
1044             "Input:\n"
1045             "  -o hex|oct|dec         parse offsets as (h)ex, (o)ctal or (d)ecimal; default is hex.\n"
1046             "  -t <timefmt>           treat the text before the packet as a date/time code;\n"
1047             "                         the specified argument is a format string of the sort\n"
1048             "                         supported by strptime.\n"
1049             "                         Example: The time \"10:15:14.5476\" has the format code\n"
1050             "                         \"%%H:%%M:%%S.\"\n"
1051             "                         NOTE: The subsecond component delimiter must be given\n"
1052             "                          (.) but no pattern is required; the remaining number\n"
1053             "                          is assumed to be fractions of a second.\n"
1054             "                         NOTE: Date/time fields from the current date/time are\n"
1055             "                         used as the default for unspecified fields.\n"
1056             "\n"
1057             "Output:\n"
1058             "  -l <typenum>           link-layer type number; default is 1 (Ethernet).\n"
1059             "                         See the file net/bpf.h for list of numbers.\n"
1060             "                         Use this option if your dump is a complete hex dump\n"
1061             "                         of an encapsulated packet and you wish to specify\n"
1062             "                         the exact type of encapsulation.\n"
1063             "                         Example: -l 7 for ARCNet packets.\n"
1064             "  -m <max-packet>        max packet length in output; default is %d\n"
1065             "\n"
1066             "Prepend dummy header:\n"
1067             "  -e <l3pid>             prepend dummy Ethernet II header with specified L3PID\n"
1068             "                         (in HEX).\n"
1069             "                         Example: -e 0x806 to specify an ARP packet.\n"
1070             "  -i <proto>             prepend dummy IP header with specified IP protocol\n"
1071             "                         (in DECIMAL).\n"
1072             "                         Automatically prepends Ethernet header as well.\n"
1073             "                         Example: -i 46\n"
1074             "  -u <srcp>,<destp>      prepend dummy UDP header with specified\n"
1075             "                         dest and source ports (in DECIMAL).\n"
1076             "                         Automatically prepends Ethernet & IP headers as well.\n"
1077             "                         Example: -u 1000 69 to make the packets look like TFTP/UDP packets.\n" 
1078             "  -T <srcp>,<destp>      prepend dummy TCP header with specified\n"
1079             "                         dest and source ports (in DECIMAL).\n"
1080             "                         Automatically prepends Ethernet & IP headers as well.\n"
1081             "                         Example: -T 50,60\n"
1082             "  -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1083             "                         dest/source ports and verification tag (in DECIMAL).\n"
1084             "                         Automatically prepends Ethernet & IP headers as well.\n"
1085             "                         Example: -s 30,40,34\n"
1086             "  -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1087             "                         dest/source ports and verification tag 0.\n"
1088             "                         Automatically prepends a dummy SCTP DATA\n"
1089             "                         chunk header with payload protocol identifier ppi.\n"
1090             "                         Example: -S 30,40,34\n"
1091             "\n"
1092             "Miscellaneous:\n"
1093             "  -h                     display this help and exit.\n"
1094             "  -d                     show detailed debug of parser states.\n"
1095             "  -q                     generate no output at all (automatically turns off -d).\n"
1096             "",
1097             VERSION, MAX_PACKET);
1098
1099     exit(-1);
1100 }
1101
1102 /*----------------------------------------------------------------------
1103  * Parse CLI options
1104  */
1105 static void
1106 parse_options (int argc, char *argv[])
1107 {
1108     int c;
1109     char *p;
1110
1111     /* Scan CLI parameters */
1112     while ((c = getopt(argc, argv, "dhqe:i:l:m:o:u:s:S:t:T:")) != -1) {
1113         switch(c) {
1114         case '?': usage(); break;
1115         case 'h': usage(); break;
1116         case 'd': if (!quiet) debug++; break;
1117         case 'q': quiet = TRUE; debug = FALSE; break;
1118         case 'l': pcap_link_type = strtol(optarg, NULL, 0); break;
1119         case 'm': max_offset = strtol(optarg, NULL, 0); break;
1120         case 'o':
1121             if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1122                 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1123                 usage();
1124             }
1125                         switch(optarg[0]) {
1126                         case 'o': offset_base = 8; break;
1127                         case 'h': offset_base = 16; break;
1128                         case 'd': offset_base = 10; break;
1129                         }
1130             break;
1131         case 'e':
1132             hdr_ethernet = TRUE;
1133             if (sscanf(optarg, "%lx", &hdr_ethernet_proto) < 1) {
1134                 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1135                 usage();
1136             }
1137             break;
1138
1139         case 'i':
1140             hdr_ip = TRUE;
1141             hdr_ip_proto = strtol(optarg, &p, 10);
1142             if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1143                   hdr_ip_proto > 255) {
1144                 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1145                 usage();
1146             }
1147             hdr_ethernet = TRUE;
1148             hdr_ethernet_proto = 0x800;
1149             break;
1150
1151         case 's':
1152             hdr_sctp       = TRUE;
1153             hdr_sctp_src   = strtol(optarg, &p, 10);
1154             if (p == optarg || (*p != ',' && *p != '\0')) {
1155                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1156                 usage();
1157             }
1158             if (*p == '\0') {
1159                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1160                 usage();
1161             }
1162             p++;
1163             optarg = p;
1164             hdr_sctp_dest = strtol(optarg, &p, 10);
1165             if (p == optarg || (*p != ',' && *p != '\0')) {
1166                 fprintf(stderr, "Bad dest port for '-s'\n");
1167                 usage();
1168             }
1169             if (*p == '\0') {
1170                 fprintf(stderr, "No tag specified for '-%c'\n", c);
1171                 usage();
1172             }
1173             p++;
1174             optarg = p;
1175             hdr_sctp_tag = strtol(optarg, &p, 10);
1176             if (p == optarg || *p != '\0') {
1177                 fprintf(stderr, "Bad tag for '-%c'\n", c);
1178                 usage();
1179             }
1180
1181             hdr_ip = TRUE;
1182             hdr_ip_proto = 132;
1183             hdr_ethernet = TRUE;
1184             hdr_ethernet_proto = 0x800;
1185             break;
1186         case 'S':
1187             hdr_sctp       = TRUE;
1188             hdr_data_chunk = TRUE;
1189             hdr_sctp_src   = strtol(optarg, &p, 10);
1190             if (p == optarg || (*p != ',' && *p != '\0')) {
1191                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1192                 usage();
1193             }
1194             if (*p == '\0') {
1195                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1196                 usage();
1197             }
1198             p++;
1199             optarg = p;
1200             hdr_sctp_dest = strtol(optarg, &p, 10);
1201             if (p == optarg || (*p != ',' && *p != '\0')) {
1202                 fprintf(stderr, "Bad dest port for '-s'\n");
1203                 usage();
1204             }
1205             if (*p == '\0') {
1206                 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1207                 usage();
1208             }
1209             p++;
1210             optarg = p;
1211             hdr_data_chunk_ppid = strtoul(optarg, &p, 10);
1212             if (p == optarg || *p != '\0') {
1213                 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1214                 usage();
1215             }
1216
1217             hdr_ip = TRUE;
1218             hdr_ip_proto = 132;
1219             hdr_ethernet = TRUE;
1220             hdr_ethernet_proto = 0x800;
1221             break;
1222
1223         case 't':
1224             ts_fmt = optarg;
1225             break;
1226
1227         case 'u':
1228             hdr_udp = TRUE;
1229             hdr_tcp = FALSE;
1230             hdr_src_port = strtol(optarg, &p, 10);
1231             if (p == optarg || (*p != ',' && *p != '\0')) {
1232                 fprintf(stderr, "Bad src port for '-u'\n");
1233                 usage();
1234             }
1235             if (*p == '\0') {
1236                 fprintf(stderr, "No dest port specified for '-u'\n");
1237                 usage();
1238             }
1239             p++;
1240             optarg = p;
1241             hdr_dest_port = strtol(optarg, &p, 10);
1242             if (p == optarg || *p != '\0') {
1243                 fprintf(stderr, "Bad dest port for '-u'\n");
1244                 usage();
1245             }
1246             hdr_ip = TRUE;
1247             hdr_ip_proto = 17;
1248             hdr_ethernet = TRUE;
1249             hdr_ethernet_proto = 0x800;
1250             break;
1251
1252         case 'T':
1253             hdr_tcp = TRUE;
1254             hdr_udp = FALSE;
1255             hdr_src_port = strtol(optarg, &p, 10);
1256             if (p == optarg || (*p != ',' && *p != '\0')) {
1257                 fprintf(stderr, "Bad src port for '-T'\n");
1258                 usage();
1259             }
1260             if (*p == '\0') {
1261                 fprintf(stderr, "No dest port specified for '-u'\n");
1262                 usage();
1263             }
1264             p++;
1265             optarg = p;
1266             hdr_dest_port = strtol(optarg, &p, 10);
1267             if (p == optarg || *p != '\0') {
1268                 fprintf(stderr, "Bad dest port for '-T'\n");
1269                 usage();
1270             }
1271             hdr_ip = TRUE;
1272             hdr_ip_proto = 6;
1273             hdr_ethernet = TRUE;
1274             hdr_ethernet_proto = 0x800;
1275             break;
1276
1277         default:
1278             usage();
1279         }
1280     }
1281
1282     if (optind >= argc || argc-optind < 2) {
1283         fprintf(stderr, "Must specify input and output filename\n");
1284         usage();
1285     }
1286
1287     if (strcmp(argv[optind], "-")) {
1288         input_filename = g_strdup(argv[optind]);
1289         input_file = ws_fopen(input_filename, "rb");
1290         if (!input_file) {
1291             fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1292                     input_filename, strerror(errno));
1293             exit(-1);
1294         }
1295     } else {
1296         input_filename = "Standard input";
1297         input_file = stdin;
1298     }
1299
1300     if (strcmp(argv[optind+1], "-")) {
1301         output_filename = g_strdup(argv[optind+1]);
1302         output_file = ws_fopen(output_filename, "wb");
1303         if (!output_file) {
1304             fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1305                     output_filename, strerror(errno));
1306             exit(-1);
1307         }
1308     } else {
1309         output_filename = "Standard output";
1310         output_file = stdout;
1311     }
1312
1313     /* Some validation */
1314     if (pcap_link_type != 1 && hdr_ethernet) {
1315         fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1316         exit(-1);
1317     }
1318
1319     /* Set up our variables */
1320     if (!input_file) {
1321         input_file = stdin;
1322         input_filename = "Standard input";
1323     }
1324     if (!output_file) {
1325         output_file = stdout;
1326         output_filename = "Standard output";
1327     }
1328
1329     ts_sec = time(0);           /* initialize to current time */
1330     timecode_default = *localtime(&ts_sec);
1331     timecode_default.tm_isdst = -1;     /* Unknown for now, depends on time given to the strptime() function */
1332
1333     /* Display summary of our state */
1334     if (!quiet) {
1335         fprintf(stderr, "Input from: %s\n", input_filename);
1336         fprintf(stderr, "Output to: %s\n", output_filename);
1337
1338         if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0lX\n",
1339                                   hdr_ethernet_proto);
1340         if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1341                             hdr_ip_proto);
1342         if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %ld. Dest port: %ld\n",
1343                              hdr_src_port, hdr_dest_port);
1344         if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %ld. Dest port: %ld\n",
1345                              hdr_src_port, hdr_dest_port);
1346         if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %ld. Dest port: %ld. Tag: %ld\n",
1347                               hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1348         if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %lu. SID: %d. SSN: %d. PPID: %lu\n",
1349                                     hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1350     }
1351 }
1352
1353 int main(int argc, char *argv[])
1354 {
1355     parse_options(argc, argv);
1356
1357     assert(input_file != NULL);
1358     assert(output_file != NULL);
1359
1360     write_file_header();
1361
1362     yyin = input_file;
1363     yylex();
1364
1365     write_current_packet();
1366     if (debug)
1367         fprintf(stderr, "\n-------------------------\n");
1368     if (!quiet) {
1369     fprintf(stderr, "Read %ld potential packet%s, wrote %ld packet%s\n",
1370             num_packets_read,    (num_packets_read==1)   ?"":"s",
1371             num_packets_written, (num_packets_written==1)?"":"s");
1372     }
1373     return 0;
1374 }