4 * Copyright (c) 2011 by Martin Warnes <Martin_Warnes@uk.ibm.com>
6 * Based on toshiba.c and vms.c
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 * This module will read the contents of the iSeries (OS/400) Communication trace
13 * Both ASCII & Unicode (little-endian UCS-2) formatted traces are supported.
15 * iSeries Comms traces consist of a header page and a subsequent number of packet records
17 * The header page contains details on the options set during running of the trace,
18 * currently the following options are a requirement for this module:
20 * 1. Object protocol = ETHERNET (Default)
21 * 2. ASCII or Unicode file formats.
23 * The above can be achieved by passing option ASCII(*YES) with the trace command
27 /* iSeries header page
29 COMMUNICATIONS TRACE Title: OS400 - OS400 trace 10/28/05 11:44:50 Page: 1
30 Trace Description . . . . . : OS400 - OS400 trace
31 Configuration object . . . . : ETH0
32 Type . . . . . . . . . . . . : 1 1=Line, 2=Network Interface
34 Object protocol . . . . . . : ETHERNET
35 Start date/Time . . . . . . : 10/28/05 11:43:00.341
36 End date/Time . . . . . . . : 10/28/05 11:44:22.148
37 Bytes collected . . . . . . : 11999
38 Buffer size . . . . . . . . : 2048 kilobytes
39 Data direction . . . . . . . : 3 1=Sent, 2=Received, 3=Both
40 Stop on buffer full . . . . : Y Y=Yes, N=No
41 Number of bytes to trace
42 Beginning bytes . . . . . : *MAX Value, *CALC, *MAX
43 Ending bytes . . . . . . : *CALC Value, *CALC
44 Controller name . . . . . . : *ALL *ALL, name
45 Data representation . . . . : 1 1=ASCII, 2=EBCDIC, 3=*CALC
46 Format SNA data only . . . . : N Y=Yes, N=No
47 Format RR, RNR commands . . : N Y=Yes, N=No
48 Format TCP/IP data only . . : Y Y=Yes, N=No
49 IP address . . . . . . . . : *ALL *ALL, address
50 IP address . . . . . . . . : *ALL *ALL, address
51 IP port . . . . . . . . . : *ALL *ALL, IP port
52 Format UI data only . . . . : N Y=Yes, N=No
53 Select Ethernet data . . . . : 3 1=802.3, 2=ETHV2, 3=Both
54 Format Broadcast data . . . : Y Y=Yes, N=No
57 /* iSeries IPv4 formatted packet records consist of a packet header line
58 * identifying the packet number, direction, size, timestamp,
59 * source/destination MAC addresses and packet type.
61 * Thereafter there will be a formatted display of the headers above
62 * the link layer, such as ARP, IP, TCP, UDP, and ICMP (all but
63 * ICMP have either been seen in captures or on pages such as the ones
66 * http://www-912.ibm.com/s_dir/SLKBase.nsf/1ac66549a21402188625680b0002037e/e05fb0515bc3449686256ce600512c37?OpenDocument
70 * http://publib.boulder.ibm.com/infocenter/javasdk/v5r0/index.jsp?topic=%2Fcom.ibm.java.doc.diagnostics.50%2Fdiag%2Fproblem_determination%2Fi5os_perf_io_commstrace.html
72 * so we cannot assume that "IP Header" or "TCP Header" will appear). The
73 * formatted display includes lines that show the contents of some of the
74 * fields in the header, as well as hex strings dumps of the headers
75 * themselves, with tags such as "IP Header :", "ARP Header :",
76 * "TCP Header :", "UDP Header :", and (presumably) "ICMP Header:".
78 * If the packet contains data this is displayed as 4 groups of 16 hex digits
79 * followed by an ASCII representation of the data line.
81 * Information from the packet header line, higher-level headers and, if
82 * available, data lines are extracted by the module for displaying.
85 Record Data Record Controller Destination Source Frame
86 Number S/R Length Timer Name MAC Address MAC Address Format
87 ------ --- ------ --------------- ---------- ------------ ------------ ------
88 8 S 145 11:43:59.82956 0006299C14AE 0006299C14FE ETHV2 Type: 0800
89 Frame Type : IP DSCP: 0 ECN: 00-NECT Length: 145 Protocol: TCP Datagram ID: 388B
90 Src Addr: 10.20.144.150 Dest Addr: 10.20.144.151 Fragment Flags: DON'T,LAST
91 IP Header : 45000091388B40004006CC860A1490960A149097
93 TCP . . . : Src Port: 6006,Unassigned Dest Port: 35366,Unassigned
94 SEQ Number: 2666470699 ('9EEF1D2B'X) ACK Number: 2142147535 ('7FAE93CF'X)
95 Code Bits: ACK PSH Window: 32648 TCP Option: NO OP
96 TCP Header : 17768A269EEF1D2B7FAE93CF80187F885B5600000101080A0517E0F805166DE0
97 Data . . . . . : 5443503200020010 0000004980000000 B800000080470103 01001E0000002000 *TCP2.......I*...*...*G........ .*
98 002F010080000004 0300800700C00600 4002008000000304 00800000060FB067 *./..*.....*..*..@..*.....*....*G*
99 FC276228786B3EB0 EF34F5F1D27EF8DF 20926820E7B322AA 739F1FB20D **'B(XK>**4***.** *H **"*S*.*. *
102 /* iSeries IPv6 formatted traces are similar to the IPv4 version above,
103 * except that the higher-level headers have "IPv6 Header:" and
104 * "ICMPv6 Hdr:", and data is no longer output in groups of 16 hex
108 Record Data Record Destination Source Frame
109 Number S/R Length Timer MAC Address MAC Address Format
110 ------ --- ------ ------------ ------------ ------------ ------
111 218 S 1488 15:01:14.389 0011BC358680 00096B6BD918 ETHV2 Type: 86DD
112 IPv6 Data: Ver: 06 Traffic Class: 00 Flow Label: 000000
113 Payload Length: 1448 Next Header: 06,TCP Hop Limit: 64
114 Src Addr: fd00:0:0:20f2::122
115 Dest Addr: fd00:0:0:20a0::155
116 IPv6 Header: 6000000005A80640FD000000000020F20000000000000122FD000000000020A0
118 TCP . . . : Src Port: 21246,Unassigned Dest Port: 13601,Unassigned
119 SEQ Number: 2282300877 ('880925CD'X) ACK Number: 3259003715 ('C2407343'X)
120 Code Bits: ACK Window: 65535 TCP Option: NO OP
121 TCP Header : 52FE3521880925CDC24073438010FFFFCFBB00000101080A0E15127000237A08
122 Data . . . . . : 54435032000200140000061880000000ECBEB867F0000000004CE640E6C1D9D5 *TCP2........*...***g*....L*@*****
123 C9D5C740E3C8C9E240C9E240E3C8C540E6C1D9D5C9D5C740C6C9C5D3C4404040 ****@****@**@***@*******@*****@@@*
124 4040404040404040404040404040404040404040404040404040404040404040 *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
127 /* iSeries unformatted packet record consist of the same header record as
128 * the formatted trace but all other records are simply unformatted data
129 * containing higher-level headers and packet data combined.
131 Record Data Record Controller Destination Source Frame Number Number Poll/
132 Number S/R Length Timer Name MAC Address MAC Address Format Command Sent Received Final DSAP SSAP
133 ------ --- ------ --------------- ---------- ------------ ------------ ------ ------- ------ -------- ----- ---- ----
134 1 R 64 12:19:29.97108 000629ECF48E 0006D78E23C2 ETHV2 Type: 0800
135 Data . . . . . : 4500003C27954000 3A06CE3D9797440F 0A5964EAC4F50554 58C9915500000000 *E..<'*@.:.*=**D..YD***.TX**U....*
136 A00216D06A200000 020405B40402080A 1104B6C000000000 010303000B443BF1 **..*J .....*......**.........D;**
141 #include "wtap-int.h"
142 #include "file_wrappers.h"
147 #include <wsutil/str_util.h>
148 #include <wsutil/strtoi.h>
149 #include <wsutil/ws_assert.h>
151 #define ISERIES_LINE_LENGTH 270
152 #define ISERIES_HDR_LINES_TO_CHECK 100
153 #define ISERIES_PKT_LINES_TO_CHECK 4
154 #define ISERIES_MAX_TRACE_LEN 99999999
155 #define ISERIES_FORMAT_ASCII 1
156 #define ISERIES_FORMAT_UNICODE 2
159 * Magic strings - "COMMUNICATIONS TRACE", in ASCII and little-endian UCS-2.
161 static const char iseries_hdr_magic_ascii
[] = {
168 static const char iseries_hdr_magic_le_ucs_2
[] = {
169 'C', 0x0, 'O', 0x0, 'M', 0x0, 'M', 0x0,
170 'U', 0x0, 'N', 0x0, 'I', 0x0, 'C', 0x0,
171 'A', 0x0, 'T', 0x0, 'I', 0x0, 'O', 0x0,
172 'N', 0x0, 'S', 0x0, ' ', 0x0, 'T', 0x0,
173 'R', 0x0, 'A', 0x0, 'C', 0x0, 'E', 0x0
177 bool have_date
; /* true if we found a capture start date */
178 int year
, month
, day
; /* The start date */
179 int format
; /* Trace format type */
182 static bool iseries_read (wtap
* wth
, wtap_rec
*rec
, Buffer
*buf
,
183 int *err
, char ** err_info
, int64_t *data_offset
);
184 static bool iseries_seek_read (wtap
* wth
, int64_t seek_off
,
186 Buffer
* buf
, int *err
, char ** err_info
);
187 static bool iseries_check_file_type (wtap
* wth
, int *err
, char **err_info
,
189 static int64_t iseries_seek_next_packet (wtap
* wth
, int *err
, char **err_info
);
190 static bool iseries_parse_packet (wtap
* wth
, FILE_T fh
,
192 Buffer
* buf
, int *err
, char ** err_info
);
193 static int iseries_UNICODE_to_ASCII (uint8_t * buf
, unsigned bytes
);
194 static bool iseries_parse_hex_string (const char * ascii
, uint8_t * buf
,
197 static int iseries_file_type_subtype
= -1;
198 static int iseries_unicode_file_type_subtype
= -1;
200 void register_iseries(void);
203 * XXX - it would probably be cleaner to use a UCS-2 flavor of file_gets(),
204 * rather than file_gets(), if we're reading a UCS-2 file.
207 iseries_open (wtap
* wth
, int *err
, char ** err_info
)
210 char magic
[ISERIES_LINE_LENGTH
];
213 * Check that file starts with a valid iSeries COMMS TRACE header
214 * by scanning for it in the first line
216 if (!wtap_read_bytes (wth
->fh
, &magic
, sizeof magic
, err
, err_info
))
218 if (*err
!= WTAP_ERR_SHORT_READ
)
219 return WTAP_OPEN_ERROR
;
220 return WTAP_OPEN_NOT_MINE
;
224 * Check if this is a little-endian UCS-2 Unicode formatted file by scanning
225 * for the magic string
228 while ((unsigned int)offset
< (ISERIES_LINE_LENGTH
- (sizeof iseries_hdr_magic_le_ucs_2
)))
230 if (memcmp (magic
+ offset
, iseries_hdr_magic_le_ucs_2
, sizeof iseries_hdr_magic_le_ucs_2
) == 0) {
231 if (file_seek (wth
->fh
, 0, SEEK_SET
, err
) == -1)
233 return WTAP_OPEN_ERROR
;
236 * Do some basic sanity checking to ensure we can handle the
237 * contents of this trace
239 if (!iseries_check_file_type (wth
, err
, err_info
, ISERIES_FORMAT_UNICODE
))
242 return WTAP_OPEN_NOT_MINE
;
244 return WTAP_OPEN_ERROR
;
247 wth
->file_encap
= WTAP_ENCAP_ETHERNET
;
248 wth
->file_type_subtype
= iseries_unicode_file_type_subtype
;
249 wth
->snapshot_length
= 0;
250 wth
->subtype_read
= iseries_read
;
251 wth
->subtype_seek_read
= iseries_seek_read
;
252 wth
->file_tsprec
= WTAP_TSPREC_USEC
;
254 if (file_seek (wth
->fh
, 0, SEEK_SET
, err
) == -1)
256 return WTAP_OPEN_ERROR
;
260 * Add an IDB; we don't know how many interfaces were
261 * involved, so we just say one interface, about which
262 * we only know the link-layer type, snapshot length,
263 * and time stamp resolution.
265 wtap_add_generated_idb(wth
);
267 return WTAP_OPEN_MINE
;
273 * Check if this is a ASCII formatted file by scanning for the magic string
276 while ((unsigned int)offset
< (ISERIES_LINE_LENGTH
- sizeof iseries_hdr_magic_ascii
))
278 if (memcmp (magic
+ offset
, iseries_hdr_magic_ascii
, sizeof iseries_hdr_magic_ascii
) == 0)
280 if (file_seek (wth
->fh
, 0, SEEK_SET
, err
) == -1)
282 return WTAP_OPEN_ERROR
;
285 * Do some basic sanity checking to ensure we can handle the
286 * contents of this trace
288 if (!iseries_check_file_type (wth
, err
, err_info
, ISERIES_FORMAT_ASCII
))
291 return WTAP_OPEN_NOT_MINE
;
293 return WTAP_OPEN_ERROR
;
296 wth
->file_encap
= WTAP_ENCAP_ETHERNET
;
297 wth
->file_type_subtype
= iseries_file_type_subtype
;
298 wth
->snapshot_length
= 0;
299 wth
->subtype_read
= iseries_read
;
300 wth
->subtype_seek_read
= iseries_seek_read
;
301 wth
->file_tsprec
= WTAP_TSPREC_USEC
;
303 if (file_seek (wth
->fh
, 0, SEEK_SET
, err
) == -1)
305 return WTAP_OPEN_ERROR
;
309 * Add an IDB; we don't know how many interfaces were
310 * involved, so we just say one interface, about which
311 * we only know the link-layer type, snapshot length,
312 * and time stamp resolution.
314 wtap_add_generated_idb(wth
);
316 return WTAP_OPEN_MINE
;
321 /* Neither ASCII or UNICODE so not supported */
322 return WTAP_OPEN_NOT_MINE
;
326 * Do some basic sanity checking to ensure we can handle the
327 * contents of this trace by checking the header page for
328 * requisite requirements and additional information.
331 iseries_check_file_type (wtap
* wth
, int *err
, char **err_info
, int format
)
333 bool is_iseries
= false;
335 int num_items_scanned
;
336 char buf
[ISERIES_LINE_LENGTH
], protocol
[9];
339 /* Save trace format for passing between packets */
340 iseries
= g_new(iseries_t
, 1);
341 iseries
->have_date
= false;
342 iseries
->format
= format
;
344 for (line
= 0; line
< ISERIES_HDR_LINES_TO_CHECK
; line
++)
346 memset(buf
, 0x0, sizeof(buf
));
347 if (file_gets (buf
, ISERIES_LINE_LENGTH
, wth
->fh
) == NULL
)
350 *err
= file_error (wth
->fh
, err_info
);
351 if (*err
== WTAP_ERR_SHORT_READ
)
357 * Check that we are dealing with an ETHERNET trace
359 if (iseries
->format
== ISERIES_FORMAT_UNICODE
)
361 iseries_UNICODE_to_ASCII ((uint8_t *)buf
, ISERIES_LINE_LENGTH
);
363 ascii_strup_inplace (buf
);
364 num_items_scanned
= sscanf (buf
,
365 "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s",
367 if (num_items_scanned
== 1)
369 if (memcmp (protocol
, "ETHERNET", 8) == 0)
377 * The header is the only place where the date part of the timestamp is held, so
378 * extract it here and store for all packets to access
380 num_items_scanned
= sscanf (buf
,
381 "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d",
382 &iseries
->month
, &iseries
->day
,
384 if (num_items_scanned
== 3)
386 iseries
->have_date
= true;
391 wth
->priv
= (void *) iseries
;
399 * Find the next packet and parse it; called from wtap_read().
402 iseries_read (wtap
* wth
, wtap_rec
*rec
, Buffer
*buf
, int *err
,
403 char ** err_info
, int64_t *data_offset
)
408 * Locate the next packet
410 offset
= iseries_seek_next_packet (wth
, err
, err_info
);
413 *data_offset
= offset
;
416 * Parse the packet and extract the various fields
418 return iseries_parse_packet (wth
, wth
->fh
, rec
, buf
, err
, err_info
);
422 * Seeks to the beginning of the next packet, and returns the
423 * byte offset. Returns -1 on failure or EOF; on EOF, sets
424 * *err to 0, and, on failure, sets *err to the error and *err_info
425 * to null or an additional error string.
428 iseries_seek_next_packet (wtap
* wth
, int *err
, char **err_info
)
430 iseries_t
*iseries
= (iseries_t
*)wth
->priv
;
431 char buf
[ISERIES_LINE_LENGTH
],type
[5];
432 int line
, num_items_scanned
;
436 for (line
= 0; line
< ISERIES_MAX_TRACE_LEN
; line
++)
438 if (file_gets (buf
, ISERIES_LINE_LENGTH
, wth
->fh
) == NULL
)
441 *err
= file_error (wth
->fh
, err_info
);
444 /* Convert UNICODE to ASCII if required and determine */
445 /* the number of bytes to rewind to beginning of record. */
446 if (iseries
->format
== ISERIES_FORMAT_UNICODE
)
448 /* buflen is #bytes to 1st 0x0A */
449 buflen
= iseries_UNICODE_to_ASCII ((uint8_t *) buf
, ISERIES_LINE_LENGTH
);
453 /* Else buflen is just length of the ASCII string */
454 buflen
= (long) strlen (buf
);
456 ascii_strup_inplace (buf
);
457 /* Check we have enough data in the line */
462 /* If packet header found return the offset */
465 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type
);
466 if (num_items_scanned
== 1)
468 /* Rewind to beginning of line */
469 cur_off
= file_tell (wth
->fh
);
472 *err
= file_error (wth
->fh
, err_info
);
475 if (file_seek (wth
->fh
, cur_off
- buflen
, SEEK_SET
, err
) == -1)
479 return cur_off
- buflen
;
483 *err
= WTAP_ERR_BAD_FILE
;
485 ws_strdup_printf ("iseries: next packet header not found within %d lines",
486 ISERIES_MAX_TRACE_LEN
);
491 * Read packets in random-access fashion
494 iseries_seek_read (wtap
* wth
, int64_t seek_off
, wtap_rec
*rec
,
495 Buffer
* buf
, int *err
, char ** err_info
)
498 /* seek to packet location */
499 if (file_seek (wth
->random_fh
, seek_off
- 1, SEEK_SET
, err
) == -1)
503 * Parse the packet and extract the various fields
505 return iseries_parse_packet (wth
, wth
->random_fh
, rec
, buf
,
510 append_hex_digits(char *ascii_buf
, int ascii_offset
, int max_offset
,
511 char *data
, int *err
, char **err_info
)
513 int in_offset
, out_offset
;
516 bool overflow
= false;
519 out_offset
= ascii_offset
;
523 * Process a block of up to 16 hex digits.
524 * The block is terminated early by an end-of-line indication (NUL,
525 * CR, or LF), by a space (which terminates the last block of the
526 * data we're processing), or by a "*", which introduces the ASCII representation
528 * All characters in the block must be upper-case hex digits;
529 * there might or might not be a space *after* a block, but, if so,
530 * that will be skipped over after the block is processed.
532 for (i
= 0; i
< 16; i
++, in_offset
++)
535 * If we see an end-of-line indication, or an early-end-of-block
536 * indication (space), we're done. (Only the last block ends
539 c
= data
[in_offset
] & 0xFF;
540 if (c
== '\0' || c
== ' ' || c
== '*' || c
== '\r' || c
== '\n')
544 if (!g_ascii_isxdigit(c
) || g_ascii_islower(c
))
547 * Not a hex digit, or a lower-case hex digit.
548 * Treat this as an indication that the line isn't a data
549 * line, so we just ignore it.
551 * XXX - do so only for continuation lines; treat non-hex-digit
552 * characters as errors for other lines?
554 return ascii_offset
; /* pretend we appended nothing */
556 if (out_offset
>= max_offset
)
560 ascii_buf
[out_offset
] = c
;
565 * Skip blanks, if any.
567 for (; (data
[in_offset
] & 0xFF) == ' '; in_offset
++)
572 * If we processed an *odd* number of hex digits, report an error.
576 *err
= WTAP_ERR_BAD_FILE
;
577 *err_info
= g_strdup("iseries: odd number of hex digits in a line");
582 *err
= WTAP_ERR_BAD_FILE
;
583 *err_info
= g_strdup("iseries: more packet data than the packet length indicated");
589 /* return the multiplier for nanoseconds */
591 csec_multiplier(uint32_t csec
)
593 if (csec
< 10) return 100000000;
594 if (csec
< 100) return 10000000;
595 if (csec
< 1000) return 1000000;
596 if (csec
< 10000) return 100000;
597 if (csec
< 100000) return 10000;
598 if (csec
< 1000000) return 1000;
599 if (csec
< 10000000) return 100;
600 if (csec
< 100000000) return 10;
604 /* Parses a packet. */
606 iseries_parse_packet (wtap
* wth
, FILE_T fh
, wtap_rec
*rec
,
607 Buffer
*buf
, int *err
, char **err_info
)
609 iseries_t
*iseries
= (iseries_t
*)wth
->priv
;
611 bool isValid
, isCurrentPacket
;
612 int num_items_scanned
, line
, pktline
, buflen
;
613 int pkt_len
, pktnum
, hr
, min
, sec
;
614 char direction
[2], destmac
[13], srcmac
[13], type
[5];
616 char data
[ISERIES_LINE_LENGTH
* 2];
623 * Check for packet headers in first 3 lines this should handle page breaks
624 * situations and the header lines output at each page throw and ensure we
625 * read both the captured and packet lengths.
628 for (line
= 1; line
< ISERIES_PKT_LINES_TO_CHECK
; line
++)
630 if (file_gets (data
, ISERIES_LINE_LENGTH
, fh
) == NULL
)
632 *err
= file_error (fh
, err_info
);
635 /* Convert UNICODE data to ASCII */
636 if (iseries
->format
== ISERIES_FORMAT_UNICODE
)
638 iseries_UNICODE_to_ASCII ((uint8_t *)data
, ISERIES_LINE_LENGTH
);
640 ascii_strup_inplace (data
);
643 "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9u%*[ \n\t]"
644 "%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s",
645 &pktnum
, direction
, &pkt_len
, &hr
, &min
, &sec
, &csec
, destmac
,
647 if (num_items_scanned
== 10)
651 *err
= WTAP_ERR_BAD_FILE
;
652 *err_info
= g_strdup ("iseries: packet header has a negative packet number");
658 *err
= WTAP_ERR_BAD_FILE
;
659 *err_info
= g_strdup ("iseries: packet header has a negative packet length");
665 *err
= WTAP_ERR_BAD_FILE
;
666 *err_info
= g_strdup ("iseries: packet header has a negative hour in the time stamp");
672 *err
= WTAP_ERR_BAD_FILE
;
673 *err_info
= g_strdup ("iseries: packet header has a hour in the time stamp greater than 23");
679 *err
= WTAP_ERR_BAD_FILE
;
680 *err_info
= g_strdup ("iseries: packet header has a negative minute in the time stamp");
686 *err
= WTAP_ERR_BAD_FILE
;
687 *err_info
= g_strdup ("iseries: packet header has a minute in the time stamp greater than 59");
693 *err
= WTAP_ERR_BAD_FILE
;
694 *err_info
= g_strdup ("iseries: packet header has a negative second in the time stamp");
699 * Yes, 60, even though the time-conversion routines on most OSes
700 * might not handle leap seconds.
704 *err
= WTAP_ERR_BAD_FILE
;
705 *err_info
= g_strdup ("iseries: packet header has a second in the time stamp greater than 60");
709 if (strlen(destmac
) != 12)
711 *err
= WTAP_ERR_BAD_FILE
;
712 *err_info
= g_strdup ("iseries: packet header has a destination MAC address shorter than 6 bytes");
716 if (strlen(srcmac
) != 12)
718 *err
= WTAP_ERR_BAD_FILE
;
719 *err_info
= g_strdup ("iseries: packet header has a source MAC address shorter than 6 bytes");
723 if (strlen(type
) != 4)
725 *err
= WTAP_ERR_BAD_FILE
;
726 *err_info
= g_strdup ("iseries: packet header has an Ethernet type/length field than 2 bytes");
730 /* OK! We found the packet header line */
733 * XXX - The Capture length returned by the iSeries trace doesn't
734 * seem to include the Ethernet header, so we add its length here.
736 * Check the length first, just in case it's *so* big that, after
737 * adding the Ethernet header length, it overflows.
739 if ((unsigned)pkt_len
> WTAP_MAX_PACKET_SIZE_STANDARD
- 14)
742 * Probably a corrupt capture file; don't blow up trying
743 * to allocate space for an immensely-large packet, and
744 * don't think it's a really *small* packet because it
745 * overflowed. (Calculate the size as a 64-bit value in
746 * the error message, to avoid an overflow.)
748 *err
= WTAP_ERR_BAD_FILE
;
749 *err_info
= ws_strdup_printf("iseries: File has %" PRIu64
"-byte packet, bigger than maximum of %u",
750 (uint64_t)pkt_len
+ 14,
751 WTAP_MAX_PACKET_SIZE_STANDARD
);
760 * If no packet header found we exit at this point and inform the user.
764 *err
= WTAP_ERR_BAD_FILE
;
765 *err_info
= g_strdup ("iseries: packet header isn't valid");
769 rec
->rec_type
= REC_TYPE_PACKET
;
770 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
771 rec
->presence_flags
= WTAP_HAS_CAP_LEN
;
774 * If we have Wiretap Header then populate it here
776 * Timer resolution on the iSeries is hardware dependent. We determine
777 * the resolution based on how many digits we see.
779 if (iseries
->have_date
)
781 rec
->presence_flags
|= WTAP_HAS_TS
;
782 tm
.tm_year
= 100 + iseries
->year
;
783 tm
.tm_mon
= iseries
->month
- 1;
784 tm
.tm_mday
= iseries
->day
;
789 rec
->ts
.secs
= mktime (&tm
);
790 rec
->ts
.nsecs
= csec
* csec_multiplier(csec
);
793 rec
->rec_header
.packet_header
.len
= pkt_len
;
794 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_ETHERNET
;
795 rec
->rec_header
.packet_header
.pseudo_header
.eth
.fcs_len
= -1;
798 * Allocate a buffer big enough to hold the claimed packet length
799 * worth of byte values; each byte will be two hex digits, so the
800 * buffer's size should be twice the packet length.
802 * (There is no need to null-terminate the buffer.)
804 ascii_buf
= (char *)g_malloc (pkt_len
*2);
808 * Copy in the Ethernet header.
810 * The three fields have already been checked to have the right length
811 * (6 bytes, hence 12 characters, of hex-dump destination and source
812 * addresses, and 2 bytes, hence 4 characters, of hex-dump type/length).
814 * pkt_len is guaranteed to be >= 14, so 2*pkt_len is guaranteed to be
815 * >= 28, so we don't need to do any bounds checking.
817 memcpy(&ascii_buf
[0], destmac
, 12);
819 memcpy(&ascii_buf
[12], srcmac
, 12);
821 memcpy(&ascii_buf
[24], type
, 4);
825 * Start reading packet contents
827 isCurrentPacket
= true;
829 /* loop through packet lines and breakout when the next packet header is read */
831 while (isCurrentPacket
)
834 /* Read the next line */
835 if (file_gets (data
, ISERIES_LINE_LENGTH
, fh
) == NULL
)
837 *err
= file_error (fh
, err_info
);
840 /* Hit the EOF without an error */
846 /* Convert UNICODE data to ASCII and determine line length */
847 if (iseries
->format
== ISERIES_FORMAT_UNICODE
)
849 buflen
= iseries_UNICODE_to_ASCII ((uint8_t *)data
, ISERIES_LINE_LENGTH
);
853 /* Else bytes to rewind is just length of ASCII string */
854 buflen
= (int) strlen (data
);
858 * Skip leading white space.
860 for (offset
= 0; g_ascii_isspace(data
[offset
]); offset
++)
864 * The higher-level header information starts at an offset of
865 * 22 characters. The header tags are 14 characters long.
867 * XXX - for IPv6, if the next header isn't the last header,
868 * the intermediate headers do *NOT* appear to be shown in
869 * the dump file *at all*, so the packet *cannot* be
874 if (strncmp(data
+ 22, "IP Header : ", 14) == 0 ||
875 strncmp(data
+ 22, "IPv6 Header: ", 14) == 0 ||
876 strncmp(data
+ 22, "ARP Header : ", 14) == 0 ||
877 strncmp(data
+ 22, "TCP Header : ", 14) == 0 ||
878 strncmp(data
+ 22, "UDP Header : ", 14) == 0 ||
879 strncmp(data
+ 22, "ICMP Header: ", 14) == 0 ||
880 strncmp(data
+ 22, "ICMPv6 Hdr: ", 14) == 0 ||
881 strncmp(data
+ 22, "Option Hdr: ", 14) == 0)
883 ascii_offset
= append_hex_digits(ascii_buf
, ascii_offset
,
887 if (ascii_offset
== -1)
897 * Is this a data line?
899 * The "Data" starts at an offset of 8.
903 if (strncmp(data
+ 9, "Data . . . . . : ", 18) == 0)
905 ascii_offset
= append_hex_digits(ascii_buf
, ascii_offset
,
909 if (ascii_offset
== -1)
919 * Is this a continuation of a previous header or data line?
920 * That's blanks followed by hex digits; first try the
921 * "no column separators" form.
923 * Continuations of header lines begin at an offset of 36;
924 * continuations of data lines begin at an offset of 27.
926 if (offset
== 36 || offset
== 27)
928 ascii_offset
= append_hex_digits(ascii_buf
, ascii_offset
,
932 if (ascii_offset
== -1)
941 * If we see the identifier for the next packet then rewind and set
942 * isCurrentPacket false
944 ascii_strup_inplace (data
);
945 /* If packet header found return the offset */
948 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type
);
949 if ((num_items_scanned
== 1) && pktline
> 1)
951 isCurrentPacket
= false;
952 cur_off
= file_tell( fh
);
956 *err
= file_error (fh
, err_info
);
959 if (file_seek (fh
, cur_off
- buflen
, SEEK_SET
, err
) == -1)
961 /* XXX: need to set err_info ?? */
968 * Make the captured length be the amount of bytes we've read (which
969 * is half the number of characters of hex dump we have).
971 * XXX - this can happen for IPv6 packets if the next header isn't the
974 rec
->rec_header
.packet_header
.caplen
= ((uint32_t) ascii_offset
)/2;
976 /* Make sure we have enough room for the packet. */
977 ws_buffer_assure_space (buf
, rec
->rec_header
.packet_header
.caplen
);
978 /* Convert ascii data to binary and return in the frame buffer */
979 iseries_parse_hex_string (ascii_buf
, ws_buffer_start_ptr (buf
), ascii_offset
);
981 /* free buffer allocs and return */
992 * Simple routine to convert an UNICODE buffer to ASCII
994 * XXX - This may be possible with iconv or similar
997 iseries_UNICODE_to_ASCII (uint8_t * buf
, unsigned bytes
)
1004 for (i
= 0; i
< bytes
; i
++)
1019 ws_assert(bufptr
< buf
+ bytes
);
1025 * Simple routine to convert an ASCII hex string to binary data
1026 * Requires ASCII hex data and buffer to populate with binary data
1029 iseries_parse_hex_string (const char * ascii
, uint8_t * buf
, size_t len
)
1037 for (i
= 0; i
< len
; i
++)
1039 hexvalue
= g_ascii_xdigit_value(ascii
[i
]);
1042 return false; /* not a valid hex digit */
1043 bytevalue
= (uint8_t)(hexvalue
<< 4);
1045 return false; /* only one hex digit of the byte is present */
1046 hexvalue
= g_ascii_xdigit_value(ascii
[i
]);
1048 return false; /* not a valid hex digit */
1049 bytevalue
|= (uint8_t) hexvalue
;
1050 buf
[byte
] = bytevalue
;
1056 static const struct supported_block_type iseries_blocks_supported
[] = {
1058 * We support packet blocks, with no comments or other options.
1060 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
1063 static const struct file_type_subtype_info iseries_info
= {
1064 "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "txt", NULL
,
1065 false, BLOCKS_SUPPORTED(iseries_blocks_supported
),
1069 static const struct supported_block_type iseries_unicode_blocks_supported
[] = {
1071 * We support packet blocks, with no comments or other options.
1073 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
1076 static const struct file_type_subtype_info iseries_unicode_info
= {
1077 "IBM iSeries comm. trace (Unicode)", "iseries_unicode", "txt", NULL
,
1078 false, BLOCKS_SUPPORTED(iseries_unicode_blocks_supported
),
1082 void register_iseries(void)
1084 iseries_file_type_subtype
= wtap_register_file_type_subtype(&iseries_info
);
1085 iseries_unicode_file_type_subtype
= wtap_register_file_type_subtype(&iseries_unicode_info
);
1088 * Register names for backwards compatibility with the
1089 * wtap_filetypes table in Lua.
1091 wtap_register_backwards_compatibility_lua_name("ISERIES",
1092 iseries_file_type_subtype
);
1093 wtap_register_backwards_compatibility_lua_name("ISERIES_UNICODE",
1094 iseries_unicode_file_type_subtype
);
1098 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1103 * indent-tabs-mode: nil
1106 * vi: set shiftwidth=2 tabstop=8 expandtab:
1107 * :indentSize=2:tabSize=8:noTabs=true: