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