4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
10 #include "catapult_dct2000.h"
16 #include <wsutil/strtoi.h>
19 #include "file_wrappers.h"
21 #define MAX_FIRST_LINE_LENGTH 150
22 #define MAX_TIMESTAMP_LINE_LENGTH 50
23 #define MAX_LINE_LENGTH 131072
24 #define MAX_SECONDS_CHARS 16
25 #define MAX_TIMESTAMP_LEN (MAX_SECONDS_CHARS+5)
26 #define MAX_SUBSECOND_DECIMALS 4
27 #define MAX_CONTEXT_NAME 64
28 #define MAX_PROTOCOL_NAME 64
29 #define MAX_PORT_DIGITS 2
30 #define MAX_VARIANT_DIGITS 16
31 #define MAX_OUTHDR_NAME 256
32 #define AAL_HEADER_CHARS 12
34 /* 's' or 'r' of a packet as read from .out file */
35 typedef enum packet_direction_t
42 /***********************************************************************/
43 /* For each line, store (in case we need to dump): */
44 /* - String before time field */
45 /* - Whether or not " l " appears after timestamp */
53 /*******************************************************************/
54 /* Information stored external to a file (wtap) needed for reading and dumping */
55 typedef struct dct2000_file_externals
57 /* Remember the time at the start of capture */
62 * The following information is needed only for dumping.
64 * XXX - Wiretap is not *supposed* to require that a packet being
65 * dumped come from a file of the same type that you currently have
66 * open; this should be fixed.
69 /* Buffer to hold first line, including magic and format number */
70 char firstline
[MAX_FIRST_LINE_LENGTH
];
73 /* Buffer to hold second line with formatted file creation data/time */
74 char secondline
[MAX_TIMESTAMP_LINE_LENGTH
];
75 int secondline_length
;
77 /* Hash table to store text prefix data part of displayed packets.
78 Records (file offset -> line_prefix_info_t)
80 GHashTable
*packet_prefix_table
;
81 } dct2000_file_externals_t
;
83 /* 'Magic number' at start of Catapult DCT2000 .out files. */
84 static const char catapult_dct2000_magic
[] = "Session Transcript";
86 /************************************************************/
87 /* Functions called from wiretap core */
88 static bool catapult_dct2000_read(wtap
*wth
, wtap_rec
*rec
,
89 Buffer
*buf
, int *err
, char **err_info
,
90 int64_t *data_offset
);
91 static bool catapult_dct2000_seek_read(wtap
*wth
, int64_t seek_off
,
93 Buffer
*buf
, int *err
,
95 static void catapult_dct2000_close(wtap
*wth
);
97 static bool catapult_dct2000_dump(wtap_dumper
*wdh
, const wtap_rec
*rec
,
98 const uint8_t *pd
, int *err
, char **err_info
);
101 /************************************************************/
102 /* Private helper functions */
103 static bool read_new_line(FILE_T fh
, int *length
,
104 char *buf
, size_t bufsize
, int *err
,
106 static bool parse_line(char *linebuff
, int line_length
,
107 int *seconds
, int *useconds
,
108 long *before_time_offset
, long *after_time_offset
,
111 packet_direction_t
*direction
,
112 int *encap
, bool *is_comment
, bool *is_sprint
,
113 char *aal_header_chars
,
114 char *context_name
, uint8_t *context_portp
,
115 char *protocol_name
, char *variant_name
,
117 static bool process_parsed_line(wtap
*wth
,
118 const dct2000_file_externals_t
*file_externals
,
120 Buffer
*buf
, int64_t file_offset
,
121 char *linebuff
, long dollar_offset
,
122 int seconds
, int useconds
,
123 char *timestamp_string
,
124 packet_direction_t direction
, int encap
,
125 char *context_name
, uint8_t context_port
,
126 char *protocol_name
, char *variant_name
,
127 char *outhdr_name
, char *aal_header_chars
,
128 bool is_comment
, int data_chars
,
129 int *err
, char **err_info
);
130 static uint8_t hex_from_char(char c
);
131 static void prepare_hex_byte_from_chars_table(void);
132 static uint8_t hex_byte_from_chars(char *c
);
133 static char char_from_hex(uint8_t hex
);
135 static void set_aal_info(union wtap_pseudo_header
*pseudo_header
,
136 packet_direction_t direction
,
137 char *aal_header_chars
);
138 static void set_isdn_info(union wtap_pseudo_header
*pseudo_header
,
139 packet_direction_t direction
);
140 static void set_ppp_info(union wtap_pseudo_header
*pseudo_header
,
141 packet_direction_t direction
);
143 static int packet_offset_equal(const void *v
, const void *v2
);
144 static unsigned packet_offset_hash_func(const void *v
);
146 static bool get_file_time_stamp(const char *linebuff
, time_t *secs
, uint32_t *usecs
);
147 static gboolean
free_line_prefix_info(void *key
, void *value
, void *user_data
);
149 static int dct2000_file_type_subtype
= -1;
151 void register_dct2000(void);
154 /********************************************/
155 /* Open file (for reading) */
156 /********************************************/
158 catapult_dct2000_open(wtap
*wth
, int *err
, char **err_info
)
162 int firstline_length
= 0;
163 dct2000_file_externals_t
*file_externals
;
164 static char linebuff
[MAX_LINE_LENGTH
];
165 static bool hex_byte_table_values_set
= false;
167 /* Clear errno before reading from the file */
171 /********************************************************************/
172 /* First line needs to contain at least as many characters as magic */
174 if (!read_new_line(wth
->fh
, &firstline_length
, linebuff
,
175 sizeof linebuff
, err
, err_info
)) {
176 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
) {
177 return WTAP_OPEN_ERROR
;
180 return WTAP_OPEN_NOT_MINE
;
183 if (((size_t)firstline_length
< strlen(catapult_dct2000_magic
)) ||
184 firstline_length
>= MAX_FIRST_LINE_LENGTH
) {
186 return WTAP_OPEN_NOT_MINE
;
189 /* This file is not for us if it doesn't match our signature */
190 if (memcmp(catapult_dct2000_magic
, linebuff
, strlen(catapult_dct2000_magic
)) != 0) {
191 return WTAP_OPEN_NOT_MINE
;
194 /* Make sure table is ready for use */
195 if (!hex_byte_table_values_set
) {
196 prepare_hex_byte_from_chars_table();
197 hex_byte_table_values_set
= true;
200 /*********************************************************************/
201 /* Need entry in file_externals table */
203 /* Allocate a new file_externals structure for this file */
204 file_externals
= g_new0(dct2000_file_externals_t
, 1);
206 /* Copy this first line into buffer so could write out later */
207 (void) g_strlcpy(file_externals
->firstline
, linebuff
, firstline_length
+1);
208 file_externals
->firstline_length
= firstline_length
;
211 /***********************************************************/
212 /* Second line contains file timestamp */
213 /* Store this offset in file_externals */
215 if (!read_new_line(wth
->fh
, &(file_externals
->secondline_length
),
216 linebuff
, sizeof linebuff
, err
, err_info
)) {
217 g_free(file_externals
);
218 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
) {
219 return WTAP_OPEN_ERROR
;
222 return WTAP_OPEN_NOT_MINE
;
225 if ((file_externals
->secondline_length
>= MAX_TIMESTAMP_LINE_LENGTH
) ||
226 (!get_file_time_stamp(linebuff
, ×tamp
, &usecs
))) {
228 /* Give up if file time line wasn't valid */
229 g_free(file_externals
);
230 return WTAP_OPEN_NOT_MINE
;
233 /* Fill in timestamp */
234 file_externals
->start_secs
= timestamp
;
235 file_externals
->start_usecs
= usecs
;
237 /* Copy this second line into buffer so could write out later */
238 (void) g_strlcpy(file_externals
->secondline
, linebuff
, file_externals
->secondline_length
+1);
241 /************************************************************/
242 /* File is for us. Fill in details so packets can be read */
244 /* Set our file type */
245 wth
->file_type_subtype
= dct2000_file_type_subtype
;
247 /* Use our own encapsulation to send all packets to our stub dissector */
248 wth
->file_encap
= WTAP_ENCAP_CATAPULT_DCT2000
;
250 /* Callbacks for reading operations */
251 wth
->subtype_read
= catapult_dct2000_read
;
252 wth
->subtype_seek_read
= catapult_dct2000_seek_read
;
253 wth
->subtype_close
= catapult_dct2000_close
;
255 /* Choose microseconds (have 4 decimal places...) */
256 wth
->file_tsprec
= WTAP_TSPREC_USEC
;
259 /***************************************************************/
260 /* Initialise packet_prefix_table (index is offset into file) */
261 file_externals
->packet_prefix_table
=
262 g_hash_table_new(packet_offset_hash_func
, packet_offset_equal
);
264 /* Set this wtap to point to the file_externals */
265 wth
->priv
= (void*)file_externals
;
270 * Add an IDB; we don't know how many interfaces were
271 * involved, so we just say one interface, about which
272 * we only know the link-layer type, snapshot length,
273 * and time stamp resolution.
275 wtap_add_generated_idb(wth
);
277 return WTAP_OPEN_MINE
;
280 /* Ugly, but much faster than using snprintf! */
281 static void write_timestamp_string(char *timestamp_string
, int secs
, int tenthousandths
)
287 timestamp_string
[idx
++] = ((secs
% 10)) + '0';
289 else if (secs
< 100) {
290 timestamp_string
[idx
++] = ( secs
/ 10) + '0';
291 timestamp_string
[idx
++] = ((secs
% 10)) + '0';
293 else if (secs
< 1000) {
294 timestamp_string
[idx
++] = ((secs
) / 100) + '0';
295 timestamp_string
[idx
++] = ((secs
% 100)) / 10 + '0';
296 timestamp_string
[idx
++] = ((secs
% 10)) + '0';
298 else if (secs
< 10000) {
299 timestamp_string
[idx
++] = ((secs
) / 1000) + '0';
300 timestamp_string
[idx
++] = ((secs
% 1000)) / 100 + '0';
301 timestamp_string
[idx
++] = ((secs
% 100)) / 10 + '0';
302 timestamp_string
[idx
++] = ((secs
% 10)) + '0';
304 else if (secs
< 100000) {
305 timestamp_string
[idx
++] = ((secs
) / 10000) + '0';
306 timestamp_string
[idx
++] = ((secs
% 10000)) / 1000 + '0';
307 timestamp_string
[idx
++] = ((secs
% 1000)) / 100 + '0';
308 timestamp_string
[idx
++] = ((secs
% 100)) / 10 + '0';
309 timestamp_string
[idx
++] = ((secs
% 10)) + '0';
311 else if (secs
< 1000000) {
312 timestamp_string
[idx
++] = ((secs
) / 100000) + '0';
313 timestamp_string
[idx
++] = ((secs
% 100000)) / 10000 + '0';
314 timestamp_string
[idx
++] = ((secs
% 10000)) / 1000 + '0';
315 timestamp_string
[idx
++] = ((secs
% 1000)) / 100 + '0';
316 timestamp_string
[idx
++] = ((secs
% 100)) / 10 + '0';
317 timestamp_string
[idx
++] = ((secs
% 10)) + '0';
320 snprintf(timestamp_string
, MAX_TIMESTAMP_LEN
, "%d.%04d", secs
, tenthousandths
);
324 timestamp_string
[idx
++] = '.';
325 timestamp_string
[idx
++] = ( tenthousandths
/ 1000) + '0';
326 timestamp_string
[idx
++] = ((tenthousandths
% 1000) / 100) + '0';
327 timestamp_string
[idx
++] = ((tenthousandths
% 100) / 10) + '0';
328 timestamp_string
[idx
++] = ((tenthousandths
% 10)) + '0';
329 timestamp_string
[idx
] = '\0';
332 /**************************************************/
333 /* Read packet function. */
334 /* Look for and read the next usable packet */
335 /* - return true and details if found */
336 /**************************************************/
338 catapult_dct2000_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
339 int *err
, char **err_info
, int64_t *data_offset
)
341 long dollar_offset
, before_time_offset
, after_time_offset
;
342 packet_direction_t direction
;
345 /* Get wtap external structure for this wtap */
346 dct2000_file_externals_t
*file_externals
=
347 (dct2000_file_externals_t
*)wth
->priv
;
349 /* Search for a line containing a usable packet */
351 int line_length
, seconds
, useconds
, data_chars
;
352 bool is_comment
= false;
353 bool is_sprint
= false;
355 static char linebuff
[MAX_LINE_LENGTH
+1];
356 char aal_header_chars
[AAL_HEADER_CHARS
];
357 char context_name
[MAX_CONTEXT_NAME
];
358 uint8_t context_port
= 0;
359 char protocol_name
[MAX_PROTOCOL_NAME
+1];
360 char variant_name
[MAX_VARIANT_DIGITS
+1];
361 char outhdr_name
[MAX_OUTHDR_NAME
+1];
363 /* Get starting offset of the line we're about to read */
364 this_offset
= file_tell(wth
->fh
);
366 /* Read a new line from file into linebuff */
367 if (!read_new_line(wth
->fh
, &line_length
, linebuff
,
368 sizeof linebuff
, err
, err_info
)) {
370 return false; /* error */
372 /* No more lines can be read, so quit. */
376 /* Try to parse the line as a frame record */
377 if (parse_line(linebuff
, line_length
, &seconds
, &useconds
,
378 &before_time_offset
, &after_time_offset
,
380 &data_chars
, &direction
, &encap
, &is_comment
, &is_sprint
,
382 context_name
, &context_port
,
383 protocol_name
, variant_name
, outhdr_name
)) {
384 line_prefix_info_t
*line_prefix_info
;
385 int64_t *pkey
= NULL
;
386 char timestamp_string
[MAX_TIMESTAMP_LEN
+1];
387 write_timestamp_string(timestamp_string
, seconds
, useconds
/100);
389 /* Set data_offset to the beginning of the line we're returning.
390 This will be the seek_off parameter when this frame is re-read.
392 *data_offset
= this_offset
;
394 if (!process_parsed_line(wth
, file_externals
,
395 rec
, buf
, this_offset
,
396 linebuff
, dollar_offset
,
400 context_name
, context_port
,
401 protocol_name
, variant_name
,
402 outhdr_name
, aal_header_chars
,
403 is_comment
, data_chars
,
407 /* Store the packet prefix in the hash table */
408 line_prefix_info
= g_new(line_prefix_info_t
,1);
410 /* Create and use buffer for contents before time */
411 line_prefix_info
->before_time
= (char *)g_malloc(before_time_offset
+1);
412 memcpy(line_prefix_info
->before_time
, linebuff
, before_time_offset
);
413 line_prefix_info
->before_time
[before_time_offset
] = '\0';
415 /* There is usually a ' l ' between the timestamp and the data. Set flag to record this. */
416 line_prefix_info
->has_l
= ((size_t)(dollar_offset
- after_time_offset
-1) == strlen(" l ")) &&
417 (strncmp(linebuff
+after_time_offset
, " l ", 3) == 0);
419 /* Add packet entry into table */
420 pkey
= (int64_t *)g_malloc(sizeof(*pkey
));
422 g_hash_table_insert(file_externals
->packet_prefix_table
, pkey
, line_prefix_info
);
424 /* OK, we have packet details to return */
429 /* No packet details to return... */
434 /**************************************************/
435 /* Read & seek function. */
436 /**************************************************/
438 catapult_dct2000_seek_read(wtap
*wth
, int64_t seek_off
,
439 wtap_rec
*rec
, Buffer
*buf
,
440 int *err
, char **err_info
)
443 long dollar_offset
, before_time_offset
, after_time_offset
;
444 static char linebuff
[MAX_LINE_LENGTH
+1];
445 char aal_header_chars
[AAL_HEADER_CHARS
];
446 char context_name
[MAX_CONTEXT_NAME
];
447 uint8_t context_port
= 0;
448 char protocol_name
[MAX_PROTOCOL_NAME
+1];
449 char variant_name
[MAX_VARIANT_DIGITS
+1];
450 char outhdr_name
[MAX_OUTHDR_NAME
+1];
451 bool is_comment
= false;
452 bool is_sprint
= false;
453 packet_direction_t direction
;
455 int seconds
, useconds
, data_chars
;
457 /* Get wtap external structure for this wtap */
458 dct2000_file_externals_t
*file_externals
=
459 (dct2000_file_externals_t
*)wth
->priv
;
464 /* Seek to beginning of packet */
465 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1) {
469 /* Re-read whole line (this really should succeed) */
470 if (!read_new_line(wth
->random_fh
, &length
, linebuff
,
471 sizeof linebuff
, err
, err_info
)) {
475 /* Try to parse this line again (should succeed as re-reading...) */
476 if (parse_line(linebuff
, length
, &seconds
, &useconds
,
477 &before_time_offset
, &after_time_offset
,
479 &data_chars
, &direction
, &encap
, &is_comment
, &is_sprint
,
481 context_name
, &context_port
,
482 protocol_name
, variant_name
, outhdr_name
)) {
484 char timestamp_string
[MAX_TIMESTAMP_LEN
+1];
485 write_timestamp_string(timestamp_string
, seconds
, useconds
/100);
487 if (!process_parsed_line(wth
, file_externals
,
489 linebuff
, dollar_offset
,
493 context_name
, context_port
,
494 protocol_name
, variant_name
,
495 outhdr_name
, aal_header_chars
,
496 is_comment
, data_chars
,
505 /* If get here, must have failed */
507 *err_info
= ws_strdup_printf("catapult dct2000: seek_read failed to read/parse "
508 "line at position %" PRId64
,
514 /***************************************************************************/
515 /* Free dct2000-specific capture info from file that was open for reading */
516 /***************************************************************************/
518 catapult_dct2000_close(wtap
*wth
)
520 /* Get externals for this file */
521 dct2000_file_externals_t
*file_externals
=
522 (dct2000_file_externals_t
*)wth
->priv
;
524 /* Free up its line prefix values */
525 g_hash_table_foreach_remove(file_externals
->packet_prefix_table
,
526 free_line_prefix_info
, NULL
);
527 /* Free up its line prefix table */
528 g_hash_table_destroy(file_externals
->packet_prefix_table
);
534 /***************************/
536 /***************************/
539 bool first_packet_written
;
543 /*****************************************************/
544 /* The file that we are writing to has been opened. */
545 /* Set other dump callbacks. */
546 /*****************************************************/
548 catapult_dct2000_dump_open(wtap_dumper
*wdh
, int *err _U_
, char **err_info _U_
)
550 /* Fill in other dump callbacks */
551 wdh
->subtype_write
= catapult_dct2000_dump
;
556 /*********************************************************/
557 /* Respond to queries about which encap types we support */
559 /*********************************************************/
561 catapult_dct2000_dump_can_write_encap(int encap
)
564 case WTAP_ENCAP_CATAPULT_DCT2000
:
565 /* We support this */
569 /* But can't write to any other formats... */
570 return WTAP_ERR_UNWRITABLE_ENCAP
;
575 /*****************************************/
576 /* Write a single packet out to the file */
577 /*****************************************/
580 catapult_dct2000_dump(wtap_dumper
*wdh
, const wtap_rec
*rec
,
581 const uint8_t *pd
, int *err
, char **err_info _U_
)
583 const union wtap_pseudo_header
*pseudo_header
= &rec
->rec_header
.packet_header
.pseudo_header
;
585 line_prefix_info_t
*prefix
= NULL
;
586 char time_string
[MAX_TIMESTAMP_LEN
];
588 bool is_sprint
= false;
589 dct2000_dump_t
*dct2000
;
590 int consecutive_slashes
=0;
593 /******************************************************/
594 /* Get the file_externals structure for this file */
595 /* Find wtap external structure for this wtap */
596 dct2000_file_externals_t
*file_externals
=
597 (dct2000_file_externals_t
*)pseudo_header
->dct2000
.wth
->priv
;
599 /* We can only write packet records. */
600 if (rec
->rec_type
!= REC_TYPE_PACKET
) {
601 *err
= WTAP_ERR_UNWRITABLE_REC_TYPE
;
606 * Make sure this packet doesn't have a link-layer type that
607 * differs from the one for the file (which should always
608 * be WTAP_ENCAP_CATAPULT_DCT2000).
610 if (wdh
->file_encap
!= rec
->rec_header
.packet_header
.pkt_encap
) {
611 *err
= WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED
;
615 dct2000
= (dct2000_dump_t
*)wdh
->priv
;
616 if (dct2000
== NULL
) {
618 /* Write out saved first line */
619 if (!wtap_dump_file_write(wdh
, file_externals
->firstline
,
620 file_externals
->firstline_length
, err
)) {
623 if (!wtap_dump_file_write(wdh
, "\n", 1, err
)) {
627 /* Also write out saved second line with timestamp corresponding to the
628 opening time of the log.
630 if (!wtap_dump_file_write(wdh
, file_externals
->secondline
,
631 file_externals
->secondline_length
, err
)) {
634 if (!wtap_dump_file_write(wdh
, "\n", 1, err
)) {
638 /* Allocate the dct2000-specific dump structure */
639 dct2000
= g_new(dct2000_dump_t
, 1);
640 wdh
->priv
= (void *)dct2000
;
642 /* Copy time of beginning of file */
643 dct2000
->start_time
.secs
= file_externals
->start_secs
;
644 dct2000
->start_time
.nsecs
=
645 (file_externals
->start_usecs
* 1000);
647 /* Set flag so don't write header out again */
648 dct2000
->first_packet_written
= true;
652 /******************************************************************/
653 /* Write out this packet's prefix, including calculated timestamp */
655 /* Look up line data prefix using stored offset */
656 prefix
= (line_prefix_info_t
*)g_hash_table_lookup(file_externals
->packet_prefix_table
,
657 (const void*)&(pseudo_header
->dct2000
.seek_off
));
659 /* Write out text before timestamp */
660 if (!wtap_dump_file_write(wdh
, prefix
->before_time
,
661 strlen(prefix
->before_time
), err
)) {
665 /* Can infer from prefix if this is a comment (whose payload is displayed differently) */
666 /* This is much faster than strstr() for "/////" */
667 p_c
= prefix
->before_time
;
668 while (p_c
&& (*p_c
!= '/')) {
671 while (p_c
&& (*p_c
== '/')) {
672 consecutive_slashes
++;
675 is_comment
= (consecutive_slashes
== 5);
677 /* Calculate time of this packet to write, relative to start of dump */
678 if (rec
->ts
.nsecs
>= dct2000
->start_time
.nsecs
) {
679 write_timestamp_string(time_string
,
680 (int)(rec
->ts
.secs
- dct2000
->start_time
.secs
),
681 (rec
->ts
.nsecs
- dct2000
->start_time
.nsecs
) / 100000);
684 write_timestamp_string(time_string
,
685 (int)(rec
->ts
.secs
- dct2000
->start_time
.secs
-1),
686 ((1000000000 + (rec
->ts
.nsecs
/ 100000)) - (dct2000
->start_time
.nsecs
/ 100000)) % 10000);
689 /* Write out the calculated timestamp */
690 if (!wtap_dump_file_write(wdh
, time_string
, strlen(time_string
), err
)) {
694 /* Write out text between timestamp and start of hex data */
696 if (!wtap_dump_file_write(wdh
, " l ", 3, err
)) {
701 /****************************************************************/
702 /* Need to skip stub header at start of pd before we reach data */
705 for (n
=0; pd
[n
] != '\0'; n
++);
708 /* Context port number */
712 for (; pd
[n
] != '\0'; n
++);
717 is_sprint
= (strcmp((const char *)pd
+n
, "sprint") == 0);
719 for (; pd
[n
] != '\0'; n
++);
722 /* Variant number (as string) */
723 for (; pd
[n
] != '\0'; n
++);
726 /* Outhdr (as string) */
727 for (; pd
[n
] != '\0'; n
++);
730 /* Direction & encap */
734 /**************************************/
735 /* Remainder is encapsulated protocol */
736 if (!wtap_dump_file_write(wdh
, is_sprint
? " " : "$", 1, err
)) {
741 /* Each binary byte is written out as 2 hex string chars */
742 for (; n
< rec
->rec_header
.packet_header
.len
; n
++) {
744 c
[0] = char_from_hex((uint8_t)(pd
[n
] >> 4));
745 c
[1] = char_from_hex((uint8_t)(pd
[n
] & 0x0f));
747 /* Write both hex chars of byte together */
748 if (!wtap_dump_file_write(wdh
, c
, 2, err
)) {
755 if (!wtap_dump_file_write(wdh
, pd
+n
, rec
->rec_header
.packet_header
.len
-n
, err
)) {
761 if (!wtap_dump_file_write(wdh
, "\n", 1, err
)) {
769 /****************************/
770 /* Private helper functions */
771 /****************************/
773 /**********************************************************************/
774 /* Read a new line from the file, starting at offset. */
775 /* - writes data to its argument linebuff */
776 /* - on return 'offset' will point to the next position to read from */
777 /* - return true if this read is successful */
778 /**********************************************************************/
780 read_new_line(FILE_T fh
, int *length
,
781 char *linebuff
, size_t linebuffsize
, int *err
, char **err_info
)
784 int64_t pos_before
= file_tell(fh
);
786 if (file_gets(linebuff
, (int)linebuffsize
- 1, fh
) == NULL
) {
787 /* No characters found, or error */
788 *err
= file_error(fh
, err_info
);
792 /* Set length (avoiding strlen()) and offset.. */
793 *length
= (int)(file_tell(fh
) - pos_before
);
795 /* ...but don't want to include newline in line length */
796 if (*length
> 0 && linebuff
[*length
-1] == '\n') {
797 linebuff
[*length
-1] = '\0';
798 *length
= *length
- 1;
800 /* Nor do we want '\r' (as will be written when log is created on windows) */
801 if (*length
> 0 && linebuff
[*length
-1] == '\r') {
802 linebuff
[*length
-1] = '\0';
803 *length
= *length
- 1;
810 /**********************************************************************/
811 /* Parse a line from buffer, by identifying: */
812 /* - context, port and direction of packet */
814 /* - data position and length */
815 /* Return true if this packet looks valid and can be displayed */
816 /**********************************************************************/
818 parse_line(char *linebuff
, int line_length
,
819 int *seconds
, int *useconds
,
820 long *before_time_offset
, long *after_time_offset
,
821 long *data_offset
, int *data_chars
,
822 packet_direction_t
*direction
,
823 int *encap
, bool *is_comment
, bool *is_sprint
,
824 char *aal_header_chars
,
825 char *context_name
, uint8_t *context_portp
,
826 char *protocol_name
, char *variant_name
,
831 char port_number_string
[MAX_PORT_DIGITS
+1];
837 char seconds_buff
[MAX_SECONDS_CHARS
+1];
839 char subsecond_decimals_buff
[MAX_SUBSECOND_DECIMALS
+1];
840 int subsecond_decimals_chars
;
841 bool skip_first_byte
= false;
842 bool atm_header_present
= false;
847 /* Read context name until find '.' */
848 for (n
=0; (n
< MAX_CONTEXT_NAME
) && (n
+1 < line_length
) && (linebuff
[n
] != '.'); n
++) {
849 if (linebuff
[n
] == '/') {
850 context_name
[n
] = '\0';
852 /* If not a comment (/////), not a valid line */
853 if (strncmp(linebuff
+n
, "/////", 5) != 0) {
857 /* There is no variant, outhdr, etc. Set protocol to be a comment */
858 (void) g_strlcpy(protocol_name
, "comment", MAX_PROTOCOL_NAME
);
862 if (!g_ascii_isalnum(linebuff
[n
]) && (linebuff
[n
] != '_') && (linebuff
[n
] != '-')) {
865 context_name
[n
] = linebuff
[n
];
867 if (n
== MAX_CONTEXT_NAME
|| (n
+1 >= line_length
)) {
871 /* Reset strings (that won't be set by comments) */
872 variant_name
[0] = '\0';
873 outhdr_name
[0] = '\0';
874 port_number_string
[0] = '\0';
876 if (!(*is_comment
)) {
877 /* '.' must follow context name */
878 if (linebuff
[n
] != '.') {
881 context_name
[n
] = '\0';
885 /* Now read port number */
886 for (port_digits
= 0;
887 (linebuff
[n
] != '/') && (port_digits
<= MAX_PORT_DIGITS
) && (n
+1 < line_length
);
888 n
++, port_digits
++) {
890 if (!g_ascii_isdigit(linebuff
[n
])) {
893 port_number_string
[port_digits
] = linebuff
[n
];
895 if (port_digits
> MAX_PORT_DIGITS
|| (n
+1 >= line_length
)) {
899 /* Slash char must follow port number */
900 if (linebuff
[n
] != '/')
904 port_number_string
[port_digits
] = '\0';
905 if (port_digits
== 1) {
906 *context_portp
= port_number_string
[0] - '0';
909 /* Everything in here is a digit, so we don't need to check
910 whether what follows the number is anything other than
912 if (!ws_strtou8(port_number_string
, NULL
, context_portp
)) {
919 /* Now for the protocol name */
920 for (protocol_chars
= 0;
921 (linebuff
[n
] != '/') && (protocol_chars
< MAX_PROTOCOL_NAME
) && (n
< line_length
);
922 n
++, protocol_chars
++) {
924 if (!g_ascii_isalnum(linebuff
[n
]) && (linebuff
[n
] != '_') && (linebuff
[n
] != '.')) {
927 protocol_name
[protocol_chars
] = linebuff
[n
];
929 if (protocol_chars
== MAX_PROTOCOL_NAME
|| n
>= line_length
) {
930 /* If doesn't fit, fail rather than truncate */
933 protocol_name
[protocol_chars
] = '\0';
935 /* Slash char must follow protocol name */
936 if (linebuff
[n
] != '/') {
943 /* Following the / is the variant number. No digits indicate 1 */
944 for (variant_digits
= 0;
945 (g_ascii_isdigit(linebuff
[n
])) && (variant_digits
<= MAX_VARIANT_DIGITS
) && (n
+1 < line_length
);
946 n
++, variant_digits
++) {
948 if (!g_ascii_isdigit(linebuff
[n
])) {
951 variant_name
[variant_digits
] = linebuff
[n
];
953 if (variant_digits
> MAX_VARIANT_DIGITS
|| (n
+1 >= line_length
)) {
957 if (variant_digits
> 0) {
958 variant_name
[variant_digits
] = '\0';
959 if (variant_digits
== 1) {
960 variant
= variant_name
[0] - '0';
963 if (!ws_strtoi32(variant_name
, NULL
, &variant
)) {
969 variant_name
[0] = '1';
970 variant_name
[1] = '\0';
974 /* Outheader values may follow */
975 if (linebuff
[n
] == ',') {
979 for (outhdr_chars
= 0;
980 (g_ascii_isdigit(linebuff
[n
]) || linebuff
[n
] == ',') &&
981 (outhdr_chars
<= MAX_OUTHDR_NAME
) && (n
+1 < line_length
);
982 n
++, outhdr_chars
++) {
984 if (!g_ascii_isdigit(linebuff
[n
]) && (linebuff
[n
] != ',')) {
987 outhdr_name
[outhdr_chars
] = linebuff
[n
];
989 if (outhdr_chars
> MAX_OUTHDR_NAME
|| (n
+1 >= line_length
)) {
992 /* Terminate (possibly empty) string */
993 outhdr_name
[outhdr_chars
] = '\0';
998 /******************************************************************/
999 /* Now check whether we know how to use a packet of this protocol */
1001 if ((strcmp(protocol_name
, "ip") == 0) ||
1002 (strcmp(protocol_name
, "sctp") == 0) ||
1003 (strcmp(protocol_name
, "gre") == 0) ||
1004 (strcmp(protocol_name
, "mipv6") == 0) ||
1005 (strcmp(protocol_name
, "igmp") == 0)) {
1007 *encap
= WTAP_ENCAP_RAW_IP
;
1010 /* FP may be carried over ATM, which has separate atm header to parse */
1012 if ((strcmp(protocol_name
, "fp") == 0) ||
1013 (strncmp(protocol_name
, "fp_r", 4) == 0)) {
1015 if ((variant
> 256) && (variant
% 256 == 3)) {
1016 /* FP over udp is contained in IPPrim... */
1020 /* FP over AAL0 or AAL2 */
1021 *encap
= WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
;
1022 atm_header_present
= true;
1025 else if (strcmp(protocol_name
, "fpiur_r5") == 0) {
1026 /* FP (IuR) over AAL2 */
1027 *encap
= WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
;
1028 atm_header_present
= true;
1032 if (strcmp(protocol_name
, "ppp") == 0) {
1033 *encap
= WTAP_ENCAP_PPP
;
1036 if (strcmp(protocol_name
, "isdn_l3") == 0) {
1037 /* TODO: find out what this byte means... */
1038 skip_first_byte
= true;
1039 *encap
= WTAP_ENCAP_ISDN
;
1042 if (strcmp(protocol_name
, "isdn_l2") == 0) {
1043 *encap
= WTAP_ENCAP_ISDN
;
1046 if (strcmp(protocol_name
, "ethernet") == 0) {
1047 *encap
= WTAP_ENCAP_ETHERNET
;
1050 if ((strcmp(protocol_name
, "saalnni_sscop") == 0) ||
1051 (strcmp(protocol_name
, "saaluni_sscop") == 0)) {
1053 *encap
= DCT2000_ENCAP_SSCOP
;
1056 if (strcmp(protocol_name
, "frelay_l2") == 0) {
1057 *encap
= WTAP_ENCAP_FRELAY
;
1060 if (strcmp(protocol_name
, "ss7_mtp2") == 0) {
1061 *encap
= DCT2000_ENCAP_MTP2
;
1064 if ((strcmp(protocol_name
, "nbap") == 0) ||
1065 (strcmp(protocol_name
, "nbap_r4") == 0) ||
1066 (strncmp(protocol_name
, "nbap_sscfuni", strlen("nbap_sscfuni")) == 0)) {
1068 /* The entire message in these cases is nbap, so use an encap value. */
1069 *encap
= DCT2000_ENCAP_NBAP
;
1072 /* Not a supported board port protocol/encap, but can show as raw data or
1073 in some cases find protocol embedded inside primitive */
1074 *encap
= DCT2000_ENCAP_UNHANDLED
;
1078 /* Find separate ATM header if necessary */
1079 if (atm_header_present
) {
1080 int header_chars_seen
= 0;
1082 /* Scan ahead to the next $ */
1083 for (; (linebuff
[n
] != '$') && (n
+1 < line_length
); n
++);
1086 if (n
+1 >= line_length
) {
1090 /* Read consecutive hex chars into atm header buffer */
1092 ((n
< line_length
) &&
1093 (linebuff
[n
] >= '0') && (linebuff
[n
] <= '?') &&
1094 (header_chars_seen
< AAL_HEADER_CHARS
));
1095 n
++, header_chars_seen
++) {
1097 aal_header_chars
[header_chars_seen
] = linebuff
[n
];
1098 /* Next 6 characters after '9' are mapped to a->f */
1099 if (!g_ascii_isdigit(linebuff
[n
])) {
1100 aal_header_chars
[header_chars_seen
] = 'a' + (linebuff
[n
] - '9') -1;
1104 if (header_chars_seen
!= AAL_HEADER_CHARS
|| n
>= line_length
) {
1112 /* If there is a number, skip all info to next '/'.
1113 TODO: for IP encapsulation, should store PDCP ueid, drb in pseudo info
1114 and display dct2000 dissector... */
1115 if (g_ascii_isdigit(linebuff
[n
])) {
1116 while ((n
+1 < line_length
) && linebuff
[n
] != '/') {
1122 while ((n
+1 < line_length
) && linebuff
[n
] == '/') {
1126 /* Skip a space that may happen here */
1127 if ((n
+1 < line_length
) && linebuff
[n
] == ' ') {
1131 /* Next character gives direction of message (must be 's' or 'r') */
1132 if (!(*is_comment
)) {
1133 if (linebuff
[n
] == 's') {
1137 if (linebuff
[n
] == 'r') {
1138 *direction
= received
;
1151 /*********************************************************************/
1152 /* Find and read the timestamp */
1154 /* Now scan to the next digit, which should be the start of the timestamp */
1155 /* This will involve skipping " tm " */
1157 for (; ((linebuff
[n
] != 't') || (linebuff
[n
+1] != 'm')) && (n
+1 < line_length
); n
++);
1158 if (n
>= line_length
) {
1162 for (; (n
< line_length
) && !g_ascii_isdigit(linebuff
[n
]); n
++);
1163 if (n
>= line_length
) {
1167 *before_time_offset
= n
;
1170 for (seconds_chars
= 0;
1171 (linebuff
[n
] != '.') &&
1172 (seconds_chars
<= MAX_SECONDS_CHARS
) &&
1174 n
++, seconds_chars
++) {
1176 if (!g_ascii_isdigit(linebuff
[n
])) {
1177 /* Found a non-digit before decimal point. Fail */
1180 seconds_buff
[seconds_chars
] = linebuff
[n
];
1182 if (seconds_chars
> MAX_SECONDS_CHARS
|| n
>= line_length
) {
1183 /* Didn't fit in buffer. Fail rather than use truncated */
1187 /* Convert found value into number */
1188 seconds_buff
[seconds_chars
] = '\0';
1189 /* Already know they are digits, so avoid expense of ws_strtoi32() */
1192 for (int d
=seconds_chars
-1; d
>= 0; d
--) {
1193 *seconds
+= ((seconds_buff
[d
]-'0')*multiplier
);
1197 /* The decimal point must follow the last of the seconds digits */
1198 if (linebuff
[n
] != '.') {
1204 /* Subsecond decimal digits (expect 4-digit accuracy) */
1205 for (subsecond_decimals_chars
= 0;
1206 (linebuff
[n
] != ' ') &&
1207 (subsecond_decimals_chars
<= MAX_SUBSECOND_DECIMALS
) &&
1209 n
++, subsecond_decimals_chars
++) {
1211 if (!g_ascii_isdigit(linebuff
[n
])) {
1214 subsecond_decimals_buff
[subsecond_decimals_chars
] = linebuff
[n
];
1216 if (subsecond_decimals_chars
!= MAX_SUBSECOND_DECIMALS
|| n
>= line_length
) {
1217 /* There should be exactly 4 subsecond digits - give up if not */
1220 /* Convert found value into microseconds */
1221 subsecond_decimals_buff
[subsecond_decimals_chars
] = '\0';
1222 /* Already know they are digits, so avoid expense of ws_strtoi32() */
1223 *useconds
= ((subsecond_decimals_buff
[0]-'0') * 100000) +
1224 ((subsecond_decimals_buff
[1]-'0') * 10000) +
1225 ((subsecond_decimals_buff
[2]-'0') * 1000) +
1226 ((subsecond_decimals_buff
[3]-'0') * 100);
1228 /* Space character must follow end of timestamp */
1229 if (linebuff
[n
] != ' ') {
1233 *after_time_offset
= n
++;
1235 /* If we have a string message, it could either be a comment (with '$') or
1236 a sprint line (no '$') */
1238 if (strncmp(linebuff
+n
, "l $", 3) != 0) {
1240 (void) g_strlcpy(protocol_name
, "sprint", MAX_PROTOCOL_NAME
);
1244 if (!(*is_sprint
)) {
1245 /* Now skip ahead to find start of data (marked by '$') */
1246 for (; (linebuff
[n
] != '$') && (linebuff
[n
] != '\'') && (n
+1 < line_length
); n
++);
1247 if ((linebuff
[n
] == '\'') || (n
+1 >= line_length
)) {
1254 /* Set offset to data start within line */
1257 /* Set number of chars that comprise the hex string protocol data */
1258 *data_chars
= line_length
- n
;
1260 /* May need to skip first byte (2 hex string chars) */
1261 if (skip_first_byte
) {
1269 /***********************************/
1270 /* Process results of parse_line() */
1271 /***********************************/
1273 process_parsed_line(wtap
*wth
, const dct2000_file_externals_t
*file_externals
,
1275 Buffer
*buf
, int64_t file_offset
,
1276 char *linebuff
, long dollar_offset
,
1277 int seconds
, int useconds
, char *timestamp_string
,
1278 packet_direction_t direction
, int encap
,
1279 char *context_name
, uint8_t context_port
,
1280 char *protocol_name
, char *variant_name
,
1281 char *outhdr_name
, char *aal_header_chars
,
1282 bool is_comment
, int data_chars
,
1283 int *err
, char **err_info
)
1286 int stub_offset
= 0;
1288 uint8_t *frame_buffer
;
1290 rec
->rec_type
= REC_TYPE_PACKET
;
1291 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
1292 rec
->presence_flags
= WTAP_HAS_TS
;
1294 /* Make sure all packets go to Catapult DCT2000 dissector */
1295 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_CATAPULT_DCT2000
;
1297 /* Fill in timestamp (capture base + packet offset) */
1298 rec
->ts
.secs
= file_externals
->start_secs
+ seconds
;
1299 if ((file_externals
->start_usecs
+ useconds
) >= 1000000) {
1303 ((file_externals
->start_usecs
+ useconds
) % 1000000) *1000;
1306 * Calculate the length of the stub info and the packet data.
1307 * The packet data length is half bytestring length.
1309 rec
->rec_header
.packet_header
.caplen
= (unsigned)strlen(context_name
)+1 + /* Context name */
1311 (unsigned)strlen(timestamp_string
)+1 + /* timestamp */
1312 (unsigned)strlen(variant_name
)+1 + /* variant */
1313 (unsigned)strlen(outhdr_name
)+1 + /* outhdr */
1314 (unsigned)strlen(protocol_name
)+1 + /* Protocol name */
1317 (is_comment
? data_chars
: (data_chars
/2));
1318 if (rec
->rec_header
.packet_header
.caplen
> WTAP_MAX_PACKET_SIZE_STANDARD
) {
1320 * Probably a corrupt capture file; return an error,
1321 * so that our caller doesn't blow up trying to allocate
1322 * space for an immensely-large packet.
1324 *err
= WTAP_ERR_BAD_FILE
;
1325 *err_info
= ws_strdup_printf("catapult dct2000: File has %u-byte packet, bigger than maximum of %u",
1326 rec
->rec_header
.packet_header
.caplen
, WTAP_MAX_PACKET_SIZE_STANDARD
);
1329 rec
->rec_header
.packet_header
.len
= rec
->rec_header
.packet_header
.caplen
;
1331 /*****************************/
1332 /* Get the data buffer ready */
1333 ws_buffer_assure_space(buf
, rec
->rec_header
.packet_header
.caplen
);
1334 frame_buffer
= ws_buffer_start_ptr(buf
);
1336 /******************************************/
1337 /* Write the stub info to the data buffer */
1340 length
= g_strlcpy((char*)frame_buffer
, context_name
, MAX_CONTEXT_NAME
+1);
1341 stub_offset
+= (int)(length
+ 1);
1343 /* Context port number */
1344 frame_buffer
[stub_offset
] = context_port
;
1347 /* Timestamp within file (terminated string) */
1348 length
= g_strlcpy((char*)&frame_buffer
[stub_offset
], timestamp_string
, MAX_TIMESTAMP_LEN
+1);
1349 stub_offset
+= (int)(length
+ 1);
1351 /* Protocol name (terminated string) */
1352 length
= g_strlcpy((char*)&frame_buffer
[stub_offset
], protocol_name
, MAX_PROTOCOL_NAME
+1);
1353 stub_offset
+= (int)(length
+ 1);
1355 /* Protocol variant number (as terminated string) */
1356 length
= g_strlcpy((char*)&frame_buffer
[stub_offset
], variant_name
, MAX_VARIANT_DIGITS
+1);
1357 stub_offset
+= (int)(length
+ 1);
1359 /* Outhdr (terminated string) */
1360 length
= g_strlcpy((char*)&frame_buffer
[stub_offset
], outhdr_name
, MAX_OUTHDR_NAME
+1);
1361 stub_offset
+= (int)(length
+ 1);
1364 frame_buffer
[stub_offset
++] = direction
;
1367 frame_buffer
[stub_offset
++] = (uint8_t)encap
;
1370 /***********************************************************/
1371 /* Copy packet data into buffer, converting from ascii hex */
1372 for (n
=0; n
< data_chars
; n
+=2) {
1373 frame_buffer
[stub_offset
+ n
/2] =
1374 hex_byte_from_chars(linebuff
+dollar_offset
+n
);
1378 /***********************************************************/
1379 /* Copy packet data into buffer, just copying ascii chars */
1380 for (n
=0; n
< data_chars
; n
++) {
1381 frame_buffer
[stub_offset
+ n
] = linebuff
[dollar_offset
+n
];
1385 /*****************************************/
1386 /* Set packet pseudo-header if necessary */
1387 rec
->rec_header
.packet_header
.pseudo_header
.dct2000
.seek_off
= file_offset
;
1388 rec
->rec_header
.packet_header
.pseudo_header
.dct2000
.wth
= wth
;
1391 case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
:
1392 set_aal_info(&rec
->rec_header
.packet_header
.pseudo_header
, direction
, aal_header_chars
);
1394 case WTAP_ENCAP_ISDN
:
1395 set_isdn_info(&rec
->rec_header
.packet_header
.pseudo_header
, direction
);
1397 case WTAP_ENCAP_PPP
:
1398 set_ppp_info(&rec
->rec_header
.packet_header
.pseudo_header
, direction
);
1402 /* Other supported types don't need to set anything here... */
1409 /*********************************************/
1410 /* Fill in atm pseudo-header with known info */
1411 /*********************************************/
1413 set_aal_info(union wtap_pseudo_header
*pseudo_header
,
1414 packet_direction_t direction
,
1415 char *aal_header_chars
)
1417 /* 'aal_head_chars' has this format (for AAL2 at least):
1418 Global Flow Control (4 bits) | VPI (8 bits) | VCI (16 bits) |
1419 Payload Type (4 bits) | Padding (3 bits?) | Link? (1 bit) |
1420 Channel Identifier (8 bits) | ...
1423 /* Indicate that this is a reassembled PDU */
1424 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.flags
= 0x00;
1426 /* Channel 0 is DTE->DCE, 1 is DCE->DTE. Always set 0 for now.
1427 TODO: Can we infer the correct value here?
1428 Meanwhile, just use the direction to make them distinguishable...
1430 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.channel
= (direction
== received
);
1432 /* Assume always AAL2 for FP */
1433 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.aal
= AAL_2
;
1435 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.type
= TRAF_UMTS_FP
;
1436 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.subtype
= TRAF_ST_UNKNOWN
;
1438 /* vpi is 8 bits (2nd & 3rd nibble) */
1439 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.vpi
=
1440 hex_byte_from_chars(aal_header_chars
+1);
1442 /* vci is next 16 bits */
1443 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.vci
=
1444 ((hex_from_char(aal_header_chars
[3]) << 12) |
1445 (hex_from_char(aal_header_chars
[4]) << 8) |
1446 (hex_from_char(aal_header_chars
[5]) << 4) |
1447 hex_from_char(aal_header_chars
[6]));
1449 /* 0 means we don't know how many cells the frame comprises. */
1450 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.cells
= 0;
1452 /* cid is usually last byte. Unless last char is not hex digit, in which
1453 case cid is derived from last char in ascii */
1454 if (g_ascii_isalnum(aal_header_chars
[11])) {
1455 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.aal2_cid
=
1456 hex_byte_from_chars(aal_header_chars
+10);
1459 pseudo_header
->dct2000
.inner_pseudo_header
.atm
.aal2_cid
=
1460 (int)aal_header_chars
[11] - '0';
1465 /**********************************************/
1466 /* Fill in isdn pseudo-header with known info */
1467 /**********************************************/
1469 set_isdn_info(union wtap_pseudo_header
*pseudo_header
,
1470 packet_direction_t direction
)
1472 /* This field is used to set the 'Source' and 'Destination' columns to
1473 'User' or 'Network'. If we assume that we're simulating the network,
1474 treat Received messages as being destined for the network.
1476 pseudo_header
->dct2000
.inner_pseudo_header
.isdn
.uton
= (direction
== received
);
1478 /* This corresponds to the circuit ID. 0 is treated as LAPD,
1479 everything else would be treated as a B-channel
1481 pseudo_header
->dct2000
.inner_pseudo_header
.isdn
.channel
= 0;
1485 /*********************************************/
1486 /* Fill in ppp pseudo-header with known info */
1487 /*********************************************/
1489 set_ppp_info(union wtap_pseudo_header
*pseudo_header
,
1490 packet_direction_t direction
)
1492 /* Set direction. */
1493 pseudo_header
->dct2000
.inner_pseudo_header
.p2p
.sent
= (direction
== sent
);
1497 /********************************************************/
1498 /* Return hex nibble equivalent of hex string character */
1499 /********************************************************/
1501 hex_from_char(char c
)
1503 if ((c
>= '0') && (c
<= '9')) {
1507 if ((c
>= 'a') && (c
<= 'f')) {
1508 return 0x0a + (c
- 'a');
1511 /* Not a valid hex string character */
1517 /* Table allowing fast lookup from a pair of ascii hex characters to a uint8_t */
1518 static uint8_t s_tableValues
[256][256];
1520 /* Prepare table values so ready so don't need to check inside hex_byte_from_chars() */
1521 static void prepare_hex_byte_from_chars_table(void)
1523 const unsigned char hex_char_array
[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1524 'a', 'b', 'c', 'd', 'e', 'f' };
1527 for (i
=0; i
< 16; i
++) {
1528 for (j
=0; j
< 16; j
++) {
1529 s_tableValues
[hex_char_array
[i
]][hex_char_array
[j
]] = i
*16 + j
;
1534 /* Extract and return a byte value from 2 ascii hex chars, starting from the given pointer */
1535 static uint8_t hex_byte_from_chars(char *c
)
1537 /* Return value from quick table lookup */
1538 return s_tableValues
[(unsigned char)c
[0]][(unsigned char)c
[1]];
1543 /********************************************************/
1544 /* Return character corresponding to hex nibble value */
1545 /********************************************************/
1547 char_from_hex(uint8_t hex
)
1549 static const char hex_lookup
[16] =
1550 { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
1556 return hex_lookup
[hex
];
1559 /***********************************************/
1560 /* Equality test for packet prefix hash tables */
1561 /***********************************************/
1563 packet_offset_equal(const void *v
, const void *v2
)
1565 /* Dereferenced pointers must have same int64_t offset value */
1566 return (*(const int64_t*)v
== *(const int64_t*)v2
);
1570 /********************************************/
1571 /* Hash function for packet-prefix hash table */
1572 /********************************************/
1574 packet_offset_hash_func(const void *v
)
1576 /* Use low-order bits of int64_t offset value */
1577 return (unsigned)(*(const int64_t*)v
);
1581 /************************************************************************/
1582 /* Parse year, month, day, hour, minute, seconds out of formatted line. */
1583 /* Set secs and usecs as output */
1584 /* Return false if no valid time can be read */
1585 /************************************************************************/
1587 get_file_time_stamp(const char *linebuff
, time_t *secs
, uint32_t *usecs
)
1590 #define MAX_MONTH_LETTERS 9
1591 char month
[MAX_MONTH_LETTERS
+1];
1593 int day
, year
, hour
, minute
, second
;
1596 /* If line longer than expected, file is probably not correctly formatted */
1597 if (strlen(linebuff
) > MAX_TIMESTAMP_LINE_LENGTH
) {
1601 /********************************************************/
1602 /* Scan for all fields */
1603 scan_found
= sscanf(linebuff
, "%9s %2d, %4d %2d:%2d:%2d.%4u",
1604 month
, &day
, &year
, &hour
, &minute
, &second
, usecs
);
1605 if (scan_found
!= 7) {
1606 /* Give up if not all found */
1610 if (strcmp(month
, "January" ) == 0) tm
.tm_mon
= 0;
1611 else if (strcmp(month
, "February" ) == 0) tm
.tm_mon
= 1;
1612 else if (strcmp(month
, "March" ) == 0) tm
.tm_mon
= 2;
1613 else if (strcmp(month
, "April" ) == 0) tm
.tm_mon
= 3;
1614 else if (strcmp(month
, "May" ) == 0) tm
.tm_mon
= 4;
1615 else if (strcmp(month
, "June" ) == 0) tm
.tm_mon
= 5;
1616 else if (strcmp(month
, "July" ) == 0) tm
.tm_mon
= 6;
1617 else if (strcmp(month
, "August" ) == 0) tm
.tm_mon
= 7;
1618 else if (strcmp(month
, "September") == 0) tm
.tm_mon
= 8;
1619 else if (strcmp(month
, "October" ) == 0) tm
.tm_mon
= 9;
1620 else if (strcmp(month
, "November" ) == 0) tm
.tm_mon
= 10;
1621 else if (strcmp(month
, "December" ) == 0) tm
.tm_mon
= 11;
1623 /* Give up if not found a properly-formatted date */
1627 /******************************************************/
1628 /* Fill in remaining fields and return it in a time_t */
1629 tm
.tm_year
= year
- 1900;
1634 tm
.tm_isdst
= -1; /* daylight saving time info not known */
1636 /* Get seconds from this time */
1637 *secs
= mktime(&tm
);
1639 /* Multiply 4 digits given to get micro-seconds */
1640 *usecs
= *usecs
* 100;
1645 /* Free the data allocated inside a line_prefix_info_t */
1647 free_line_prefix_info(void *key
, void *value
,
1648 void *user_data _U_
)
1650 line_prefix_info_t
*info
= (line_prefix_info_t
*)value
;
1652 /* Free the 64-bit key value */
1656 g_free(info
->before_time
);
1658 /* And the structure itself */
1661 /* Item will always be removed from table */
1665 static const struct supported_block_type dct2000_blocks_supported
[] = {
1667 * We support packet blocks, with no comments or other options.
1669 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
1672 static const struct file_type_subtype_info dct2000_info
= {
1673 "Catapult DCT2000 trace (.out format)", "dct2000", "out", NULL
,
1674 false, BLOCKS_SUPPORTED(dct2000_blocks_supported
),
1675 catapult_dct2000_dump_can_write_encap
, catapult_dct2000_dump_open
, NULL
1678 void register_dct2000(void)
1680 dct2000_file_type_subtype
= wtap_register_file_type_subtype(&dct2000_info
);
1683 * Register name for backwards compatibility with the
1684 * wtap_filetypes table in Lua.
1686 wtap_register_backwards_compatibility_lua_name("CATAPULT_DCT2000",
1687 dct2000_file_type_subtype
);
1691 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1696 * indent-tabs-mode: nil
1699 * vi: set shiftwidth=4 tabstop=8 expandtab:
1700 * :indentSize=4:tabSize=8:noTabs=true: