4 * Copyright (c) 2011 by Martin Warnes <Martin_Warnes@uk.ibm.com>
6 * Based on toshiba.c and vms.c
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * This module will read the contents of the iSeries (OS/400) Communication trace
25 * Both ASCII & Unicode (little-endian UCS-2) formatted traces are supported.
27 * iSeries Comms traces consist of a header page and a subsequent number of packet records
29 * The header page contains details on the options set during running of the trace,
30 * currently the following options are a requirement for this module:
32 * 1. Object protocol = ETHERNET (Default)
33 * 2. ASCII or Unicode file formats.
35 * The above can be acheived by passing option ASCII(*YES) with the trace command
39 /* iSeries header page
41 COMMUNICATIONS TRACE Title: OS400 - OS400 trace 10/28/05 11:44:50 Page: 1
42 Trace Description . . . . . : OS400 - OS400 trace
43 Configuration object . . . . : ETH0
44 Type . . . . . . . . . . . . : 1 1=Line, 2=Network Interface
46 Object protocol . . . . . . : ETHERNET
47 Start date/Time . . . . . . : 10/28/05 11:43:00.341
48 End date/Time . . . . . . . : 10/28/05 11:44:22.148
49 Bytes collected . . . . . . : 11999
50 Buffer size . . . . . . . . : 2048 kilobytes
51 Data direction . . . . . . . : 3 1=Sent, 2=Received, 3=Both
52 Stop on buffer full . . . . : Y Y=Yes, N=No
53 Number of bytes to trace
54 Beginning bytes . . . . . : *MAX Value, *CALC, *MAX
55 Ending bytes . . . . . . : *CALC Value, *CALC
56 Controller name . . . . . . : *ALL *ALL, name
57 Data representation . . . . : 1 1=ASCII, 2=EBCDIC, 3=*CALC
58 Format SNA data only . . . . : N Y=Yes, N=No
59 Format RR, RNR commands . . : N Y=Yes, N=No
60 Format TCP/IP data only . . : Y Y=Yes, N=No
61 IP address . . . . . . . . : *ALL *ALL, address
62 IP address . . . . . . . . : *ALL *ALL, address
63 IP port . . . . . . . . . : *ALL *ALL, IP port
64 Format UI data only . . . . : N Y=Yes, N=No
65 Select Ethernet data . . . . : 3 1=802.3, 2=ETHV2, 3=Both
66 Format Broadcast data . . . : Y Y=Yes, N=No
69 /* iSeries IPv4 formatted packet records consist of a packet header line
70 * identifying the packet number, direction, size, timestamp,
71 * source/destination MAC addresses and packet type.
73 * Thereafter there will be a formated display of the headers above
74 * the link layer, such as ARP, IP, TCP, UDP, and ICMP (all but
75 * ICMP have either been seen in captures or on pages such as the ones
78 * http://www-912.ibm.com/s_dir/SLKBase.nsf/1ac66549a21402188625680b0002037e/e05fb0515bc3449686256ce600512c37?OpenDocument
82 * 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
84 * so we cannot assume that "IP Header" or "TCP Header" will appear). The
85 * formatted display includes lines that show the contents of some of the
86 * fields in the header, as well as hex strings dumps of the headers
87 * themselves, with tags such as "IP Header :", "ARP Header :",
88 * "TCP Header :", "UDP Header :", and (presumably) "ICMP Header:".
90 * If the packet contains data this is displayed as 4 groups of 16 hex digits
91 * followed by an ASCII representaion of the data line.
93 * Information from the packet header line, higher-level headers and, if
94 * available, data lines are extracted by the module for displaying.
97 Record Data Record Controller Destination Source Frame
98 Number S/R Length Timer Name MAC Address MAC Address Format
99 ------ --- ------ --------------- ---------- ------------ ------------ ------
100 8 S 145 11:43:59.82956 0006299C14AE 0006299C14FE ETHV2 Type: 0800
101 Frame Type : IP DSCP: 0 ECN: 00-NECT Length: 145 Protocol: TCP Datagram ID: 388B
102 Src Addr: 10.20.144.150 Dest Addr: 10.20.144.151 Fragment Flags: DON'T,LAST
103 IP Header : 45000091388B40004006CC860A1490960A149097
105 TCP . . . : Src Port: 6006,Unassigned Dest Port: 35366,Unassigned
106 SEQ Number: 2666470699 ('9EEF1D2B'X) ACK Number: 2142147535 ('7FAE93CF'X)
107 Code Bits: ACK PSH Window: 32648 TCP Option: NO OP
108 TCP Header : 17768A269EEF1D2B7FAE93CF80187F885B5600000101080A0517E0F805166DE0
109 Data . . . . . : 5443503200020010 0000004980000000 B800000080470103 01001E0000002000 *TCP2.......I*...*...*G........ .*
110 002F010080000004 0300800700C00600 4002008000000304 00800000060FB067 *./..*.....*..*..@..*.....*....*G*
111 FC276228786B3EB0 EF34F5F1D27EF8DF 20926820E7B322AA 739F1FB20D **'B(XK>**4***.** *H **"*S*.*. *
114 /* iSeries IPv6 formatted traces are similar to the IPv4 version above,
115 * except that the higher-level headers have "IPv6 Header:" and
116 * "ICMPv6 Hdr:", and data data is no longer output in groups of 16 hex
120 Record Data Record Destination Source Frame
121 Number S/R Length Timer MAC Address MAC Address Format
122 ------ --- ------ ------------ ------------ ------------ ------
123 218 S 1488 15:01:14.389 0011BC358680 00096B6BD918 ETHV2 Type: 86DD
124 IPv6 Data: Ver: 06 Traffic Class: 00 Flow Label: 000000
125 Payload Length: 1448 Next Header: 06,TCP Hop Limit: 64
126 Src Addr: fd00:0:0:20f2::122
127 Dest Addr: fd00:0:0:20a0::155
128 IPv6 Header: 6000000005A80640FD000000000020F20000000000000122FD000000000020A0
130 TCP . . . : Src Port: 21246,Unassigned Dest Port: 13601,Unassigned
131 SEQ Number: 2282300877 ('880925CD'X) ACK Number: 3259003715 ('C2407343'X)
132 Code Bits: ACK Window: 65535 TCP Option: NO OP
133 TCP Header : 52FE3521880925CDC24073438010FFFFCFBB00000101080A0E15127000237A08
134 Data . . . . . : 54435032000200140000061880000000ECBEB867F0000000004CE640E6C1D9D5 *TCP2........*...***g*....L*@*****
135 C9D5C740E3C8C9E240C9E240E3C8C540E6C1D9D5C9D5C740C6C9C5D3C4404040 ****@****@**@***@*******@*****@@@*
136 4040404040404040404040404040404040404040404040404040404040404040 *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
139 /* iSeries unformatted packet record consist of the same header record as
140 * the formatted trace but all other records are simply unformatted data
141 * containing higher-level headers and packet data combined.
143 Record Data Record Controller Destination Source Frame Number Number Poll/
144 Number S/R Length Timer Name MAC Address MAC Address Format Command Sent Received Final DSAP SSAP
145 ------ --- ------ --------------- ---------- ------------ ------------ ------ ------- ------ -------- ----- ---- ----
146 1 R 64 12:19:29.97108 000629ECF48E 0006D78E23C2 ETHV2 Type: 0800
147 Data . . . . . : 4500003C27954000 3A06CE3D9797440F 0A5964EAC4F50554 58C9915500000000 *E..<'*@.:.*=**D..YD***.TX**U....*
148 A00216D06A200000 020405B40402080A 1104B6C000000000 010303000B443BF1 **..*J .....*......**.........D;**
152 #include "wtap-int.h"
154 #include "file_wrappers.h"
160 #include <wsutil/str_util.h>
162 #define ISERIES_LINE_LENGTH 270
163 #define ISERIES_HDR_LINES_TO_CHECK 100
164 #define ISERIES_PKT_LINES_TO_CHECK 4
165 #define ISERIES_MAX_TRACE_LEN 99999999
166 #define ISERIES_FORMAT_ASCII 1
167 #define ISERIES_FORMAT_UNICODE 2
170 * Magic strings - "COMMUNICATIONS TRACE", in ASCII and little-endian UCS-2.
172 static const char iseries_hdr_magic_ascii[] = {
179 static const char iseries_hdr_magic_le_ucs_2[] = {
180 'C', 0x0, 'O', 0x0, 'M', 0x0, 'M', 0x0,
181 'U', 0x0, 'N', 0x0, 'I', 0x0, 'C', 0x0,
182 'A', 0x0, 'T', 0x0, 'I', 0x0, 'O', 0x0,
183 'N', 0x0, 'S', 0x0, ' ', 0x0, 'T', 0x0,
184 'R', 0x0, 'A', 0x0, 'C', 0x0, 'E', 0x0
188 gboolean have_date; /* TRUE if we found a capture start date */
189 int year, month, day; /* The start date */
190 int format; /* Trace format type */
193 static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
194 gint64 *data_offset);
195 static gboolean iseries_seek_read (wtap * wth, gint64 seek_off,
196 struct wtap_pkthdr *phdr,
197 Buffer * buf, int *err, gchar ** err_info);
198 static gboolean iseries_check_file_type (wtap * wth, int *err, gchar **err_info,
200 static gint64 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info);
201 static gboolean iseries_parse_packet (wtap * wth, FILE_T fh,
202 struct wtap_pkthdr *phdr,
203 Buffer * buf, int *err, gchar ** err_info);
204 static int iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes);
205 static gboolean iseries_parse_hex_string (const char * ascii, guint8 * buf,
209 * XXX - it would probably be cleaner to use a UCS-2 flavor of file_gets(),
210 * rather than file_gets(), if we're reading a UCS-2 file.
213 iseries_open (wtap * wth, int *err, gchar ** err_info)
216 char magic[ISERIES_LINE_LENGTH];
219 * Check that file starts with a valid iSeries COMMS TRACE header
220 * by scanning for it in the first line
222 if (!wtap_read_bytes (wth->fh, &magic, sizeof magic, err, err_info))
224 if (*err != WTAP_ERR_SHORT_READ)
225 return WTAP_OPEN_ERROR;
226 return WTAP_OPEN_NOT_MINE;
230 * Check if this is a little-endian UCS-2 Unicode formatted file by scanning
231 * for the magic string
234 while ((unsigned int)offset < (ISERIES_LINE_LENGTH - (sizeof iseries_hdr_magic_le_ucs_2)))
236 if (memcmp (magic + offset, iseries_hdr_magic_le_ucs_2, sizeof iseries_hdr_magic_le_ucs_2) == 0) {
237 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
239 return WTAP_OPEN_ERROR;
242 * Do some basic sanity checking to ensure we can handle the
243 * contents of this trace
245 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE))
248 return WTAP_OPEN_NOT_MINE;
250 return WTAP_OPEN_ERROR;
253 wth->file_encap = WTAP_ENCAP_ETHERNET;
254 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
255 wth->snapshot_length = 0;
256 wth->subtype_read = iseries_read;
257 wth->subtype_seek_read = iseries_seek_read;
258 wth->file_tsprec = WTAP_TSPREC_USEC;
260 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
262 return WTAP_OPEN_ERROR;
264 return WTAP_OPEN_MINE;
270 * Check if this is a ASCII formatted file by scanning for the magic string
273 while ((unsigned int)offset < (ISERIES_LINE_LENGTH - sizeof iseries_hdr_magic_ascii))
275 if (memcmp (magic + offset, iseries_hdr_magic_ascii, sizeof iseries_hdr_magic_ascii) == 0)
277 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
279 return WTAP_OPEN_ERROR;
282 * Do some basic sanity checking to ensure we can handle the
283 * contents of this trace
285 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII))
288 return WTAP_OPEN_NOT_MINE;
290 return WTAP_OPEN_ERROR;
293 wth->file_encap = WTAP_ENCAP_ETHERNET;
294 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
295 wth->snapshot_length = 0;
296 wth->subtype_read = iseries_read;
297 wth->subtype_seek_read = iseries_seek_read;
298 wth->file_tsprec = WTAP_TSPREC_USEC;
300 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
302 return WTAP_OPEN_ERROR;
304 return WTAP_OPEN_MINE;
309 /* Neither ASCII or UNICODE so not supported */
310 return WTAP_OPEN_NOT_MINE;
314 * Do some basic sanity checking to ensure we can handle the
315 * contents of this trace by checking the header page for
316 * requisit requirements and additional information.
319 iseries_check_file_type (wtap * wth, int *err, gchar **err_info, int format)
321 gboolean is_iseries = FALSE;
323 int num_items_scanned;
324 char buf[ISERIES_LINE_LENGTH], protocol[9];
327 /* Save trace format for passing between packets */
328 iseries = (iseries_t *) g_malloc (sizeof (iseries_t));
329 iseries->have_date = FALSE;
330 iseries->format = format;
332 for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
334 memset(buf, 0x0, sizeof(buf));
335 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
338 *err = file_error (wth->fh, err_info);
339 if (*err == WTAP_ERR_SHORT_READ)
345 * Check that we are dealing with an ETHERNET trace
347 if (iseries->format == ISERIES_FORMAT_UNICODE)
349 iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
351 ascii_strup_inplace (buf);
352 num_items_scanned = sscanf (buf,
353 "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s",
355 if (num_items_scanned == 1)
357 if (memcmp (protocol, "ETHERNET", 8) == 0)
365 * The header is the only place where the date part of the timestamp is held, so
366 * extract it here and store for all packets to access
368 num_items_scanned = sscanf (buf,
369 "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d",
370 &iseries->month, &iseries->day,
372 if (num_items_scanned == 3)
374 iseries->have_date = TRUE;
379 wth->priv = (void *) iseries;
387 * Find the next packet and parse it; called from wtap_read().
390 iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
395 * Locate the next packet
397 offset = iseries_seek_next_packet (wth, err, err_info);
400 *data_offset = offset;
403 * Parse the packet and extract the various fields
405 return iseries_parse_packet (wth, wth->fh, &wth->phdr, wth->frame_buffer,
410 * Seeks to the beginning of the next packet, and returns the
411 * byte offset. Returns -1 on failure or EOF; on EOF, sets
412 * *err to 0, and, on failure, sets *err to the error and *err_info
413 * to null or an additional error string.
416 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info)
418 iseries_t *iseries = (iseries_t *)wth->priv;
419 char buf[ISERIES_LINE_LENGTH],type[5];
420 int line, num_items_scanned;
424 for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
426 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
429 *err = file_error (wth->fh, err_info);
432 /* Convert UNICODE to ASCII if required and determine */
433 /* the number of bytes to rewind to beginning of record. */
434 if (iseries->format == ISERIES_FORMAT_UNICODE)
436 /* buflen is #bytes to 1st 0x0A */
437 buflen = iseries_UNICODE_to_ASCII ((guint8 *) buf, ISERIES_LINE_LENGTH);
441 /* Else buflen is just length of the ASCII string */
442 buflen = (long) strlen (buf);
444 ascii_strup_inplace (buf);
445 /* If packet header found return the offset */
448 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
449 if (num_items_scanned == 1)
451 /* Rewind to beginning of line */
452 cur_off = file_tell (wth->fh);
455 *err = file_error (wth->fh, err_info);
458 if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
462 return cur_off - buflen;
466 *err = WTAP_ERR_BAD_FILE;
468 g_strdup_printf ("iseries: next packet header not found within %d lines",
469 ISERIES_MAX_TRACE_LEN);
474 * Read packets in random-access fashion
477 iseries_seek_read (wtap * wth, gint64 seek_off, struct wtap_pkthdr *phdr,
478 Buffer * buf, int *err, gchar ** err_info)
481 /* seek to packet location */
482 if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
486 * Parse the packet and extract the various fields
488 return iseries_parse_packet (wth, wth->random_fh, phdr, buf,
493 append_hex_digits(char *ascii_buf, int ascii_offset, int max_offset,
494 char *data, int *err, gchar **err_info)
496 int in_offset, out_offset;
499 gboolean overflow = FALSE;
502 out_offset = ascii_offset;
506 * Process a block of up to 16 hex digits.
507 * The block is terminated early by an end-of-line indication (NUL,
508 * CR, or LF), by a space (which terminates the last block of the
509 * data we're processing), or by a "*", which introduces the ASCII representation
511 * All characters in the block must be upper-case hex digits;
512 * there might or might not be a space *after* a block, but, if so,
513 * that will be skipped over after the block is processed.
515 for (i = 0; i < 16; i++, in_offset++)
518 * If we see an end-of-line indication, or an early-end-of-block
519 * indication (space), we're done. (Only the last block ends
522 c = data[in_offset] & 0xFF;
523 if (c == '\0' || c == ' ' || c == '*' || c == '\r' || c == '\n')
527 if (!g_ascii_isxdigit(c) || g_ascii_islower(c))
530 * Not a hex digit, or a lower-case hex digit.
531 * Treat this as an indication that the line isn't a data
532 * line, so we just ignore it.
534 * XXX - do so only for continuation lines; treat non-hex-digit
535 * characters as errors for other lines?
537 return ascii_offset; /* pretend we appended nothing */
539 if (out_offset >= max_offset)
543 ascii_buf[out_offset] = c;
548 * Skip blanks, if any.
550 for (; (data[in_offset] & 0xFF) == ' '; in_offset++)
555 * If we processed an *odd* number of hex digits, report an error.
559 *err = WTAP_ERR_BAD_FILE;
560 *err_info = g_strdup("iseries: odd number of hex digits in a line");
565 *err = WTAP_ERR_BAD_FILE;
566 *err_info = g_strdup("iseries: more packet data than the packet length indicated");
572 /* Parses a packet. */
574 iseries_parse_packet (wtap * wth, FILE_T fh, struct wtap_pkthdr *phdr,
575 Buffer *buf, int *err, gchar **err_info)
577 iseries_t *iseries = (iseries_t *)wth->priv;
579 gboolean isValid, isCurrentPacket;
580 int num_items_scanned, line, pktline, buflen;
581 int pkt_len, pktnum, hr, min, sec;
582 char direction[2], destmac[13], srcmac[13], type[5], csec[9+1];
583 char data[ISERIES_LINE_LENGTH * 2];
590 * Check for packet headers in first 3 lines this should handle page breaks
591 * situations and the header lines output at each page throw and ensure we
592 * read both the captured and packet lengths.
595 for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++)
597 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
599 *err = file_error (fh, err_info);
602 /* Convert UNICODE data to ASCII */
603 if (iseries->format == ISERIES_FORMAT_UNICODE)
605 iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
607 ascii_strup_inplace (data);
610 "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9[0-9]%*[ \n\t]"
611 "%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s",
612 &pktnum, direction, &pkt_len, &hr, &min, &sec, csec, destmac,
614 if (num_items_scanned == 10)
618 *err = WTAP_ERR_BAD_FILE;
619 *err_info = g_strdup ("iseries: packet header has a negative packet number");
625 *err = WTAP_ERR_BAD_FILE;
626 *err_info = g_strdup ("iseries: packet header has a negative packet length");
632 *err = WTAP_ERR_BAD_FILE;
633 *err_info = g_strdup ("iseries: packet header has a negative hour in the time stamp");
639 *err = WTAP_ERR_BAD_FILE;
640 *err_info = g_strdup ("iseries: packet header has a hour in the time stamp greater than 23");
646 *err = WTAP_ERR_BAD_FILE;
647 *err_info = g_strdup ("iseries: packet header has a negative minute in the time stamp");
653 *err = WTAP_ERR_BAD_FILE;
654 *err_info = g_strdup ("iseries: packet header has a minute in the time stamp greater than 59");
660 *err = WTAP_ERR_BAD_FILE;
661 *err_info = g_strdup ("iseries: packet header has a negative second in the time stamp");
666 * Yes, 60, even though the time-conversion routines on most OSes
667 * might not handle leap seconds.
671 *err = WTAP_ERR_BAD_FILE;
672 *err_info = g_strdup ("iseries: packet header has a second in the time stamp greater than 60");
676 if (strlen(destmac) != 12)
678 *err = WTAP_ERR_BAD_FILE;
679 *err_info = g_strdup ("iseries: packet header has a destination MAC address shorter than 6 bytes");
683 if (strlen(srcmac) != 12)
685 *err = WTAP_ERR_BAD_FILE;
686 *err_info = g_strdup ("iseries: packet header has a source MAC address shorter than 6 bytes");
690 if (strlen(type) != 4)
692 *err = WTAP_ERR_BAD_FILE;
693 *err_info = g_strdup ("iseries: packet header has an Ethernet type/length field than 2 bytes");
697 /* OK! We found the packet header line */
700 * XXX - The Capture length returned by the iSeries trace doesn't
701 * seem to include the Ethernet header, so we add its length here.
703 * Check the length first, just in case it's *so* big that, after
704 * adding the Ethernet header length, it overflows.
706 if (pkt_len > WTAP_MAX_PACKET_SIZE - 14)
709 * Probably a corrupt capture file; don't blow up trying
710 * to allocate space for an immensely-large packet, and
711 * don't think it's a really *small* packet because it
712 * overflowed. (Calculate the size as a 64-bit value in
713 * the error message, to avoid an overflow.)
715 *err = WTAP_ERR_BAD_FILE;
716 *err_info = g_strdup_printf("iseries: File has %" G_GUINT64_FORMAT "-byte packet, bigger than maximum of %u",
717 (guint64)pkt_len + 14,
718 WTAP_MAX_PACKET_SIZE);
727 * If no packet header found we exit at this point and inform the user.
731 *err = WTAP_ERR_BAD_FILE;
732 *err_info = g_strdup ("iseries: packet header isn't valid");
736 phdr->rec_type = REC_TYPE_PACKET;
737 phdr->presence_flags = WTAP_HAS_CAP_LEN;
740 * If we have Wiretap Header then populate it here
742 * Timer resolution on the iSeries is hardware dependent. We determine
743 * the resolution based on how many digits we see.
745 if (iseries->have_date)
747 phdr->presence_flags |= WTAP_HAS_TS;
748 tm.tm_year = 100 + iseries->year;
749 tm.tm_mon = iseries->month - 1;
750 tm.tm_mday = iseries->day;
755 phdr->ts.secs = mktime (&tm);
756 csec[sizeof(csec) - 1] = '\0';
757 switch (strlen(csec))
763 phdr->ts.nsecs = atoi(csec) * 100000000;
766 phdr->ts.nsecs = atoi(csec) * 10000000;
769 phdr->ts.nsecs = atoi(csec) * 1000000;
772 phdr->ts.nsecs = atoi(csec) * 100000;
775 phdr->ts.nsecs = atoi(csec) * 10000;
778 phdr->ts.nsecs = atoi(csec) * 1000;
781 phdr->ts.nsecs = atoi(csec) * 100;
784 phdr->ts.nsecs = atoi(csec) * 10;
787 phdr->ts.nsecs = atoi(csec);
793 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
794 phdr->pseudo_header.eth.fcs_len = -1;
797 * Allocate a buffer big enough to hold the claimed packet length
798 * worth of byte values; each byte will be two hex digits, so the
799 * buffer's size should be twice the packet length.
801 * (There is no need to null-terminate the buffer.)
803 ascii_buf = (char *)g_malloc (pkt_len*2);
807 * Copy in the Ethernet header.
809 * The three fields have already been checked to have the right length
810 * (6 bytes, hence 12 characters, of hex-dump destination and source
811 * addresses, and 2 bytes, hence 4 characters, of hex-dump type/length).
813 * pkt_len is guaranteed to be >= 14, so 2*pkt_len is guaranteed to be
814 * >= 28, so we don't need to do any bounds checking.
816 memcpy(&ascii_buf[0], destmac, 12);
818 memcpy(&ascii_buf[12], srcmac, 12);
820 memcpy(&ascii_buf[24], type, 4);
824 * Start reading packet contents
826 isCurrentPacket = TRUE;
828 /* loop through packet lines and breakout when the next packet header is read */
830 while (isCurrentPacket)
833 /* Read the next line */
834 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
836 *err = file_error (fh, err_info);
839 /* Hit the EOF without an error */
845 /* Convert UNICODE data to ASCII and determine line length */
846 if (iseries->format == ISERIES_FORMAT_UNICODE)
848 buflen = iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
852 /* Else bytes to rewind is just length of ASCII string */
853 buflen = (int) strlen (data);
857 * Skip leading white space.
859 for (offset = 0; g_ascii_isspace(data[offset]); offset++)
863 * The higher-level header information starts at an offset of
864 * 22 characters. The header tags are 14 characters long.
866 * XXX - for IPv6, if the next header isn't the last header,
867 * the intermediate headers do *NOT* appear to be shown in
868 * the dump file *at all*, so the packet *cannot* be
873 if (strncmp(data + 22, "IP Header : ", 14) == 0 ||
874 strncmp(data + 22, "IPv6 Header: ", 14) == 0 ||
875 strncmp(data + 22, "ARP Header : ", 14) == 0 ||
876 strncmp(data + 22, "TCP Header : ", 14) == 0 ||
877 strncmp(data + 22, "UDP Header : ", 14) == 0 ||
878 strncmp(data + 22, "ICMP Header: ", 14) == 0 ||
879 strncmp(data + 22, "ICMPv6 Hdr: ", 14) == 0 ||
880 strncmp(data + 22, "Option Hdr: ", 14) == 0)
882 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
886 if (ascii_offset == -1)
896 * Is this a data line?
898 * The "Data" starts at an offset of 8.
902 if (strncmp(data + 9, "Data . . . . . : ", 18) == 0)
904 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
908 if (ascii_offset == -1)
918 * Is this a continuation of a previous header or data line?
919 * That's blanks followed by hex digits; first try the
920 * "no column separators" form.
922 * Continuations of header lines begin at an offset of 36;
923 * continuations of data lines begin at an offset of 27.
925 if (offset == 36 || offset == 27)
927 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
931 if (ascii_offset == -1)
940 * If we see the identifier for the next packet then rewind and set
941 * isCurrentPacket FALSE
943 ascii_strup_inplace (data);
944 /* If packet header found return the offset */
947 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
948 if ((num_items_scanned == 1) && pktline > 1)
950 isCurrentPacket = FALSE;
951 cur_off = file_tell( fh);
955 *err = file_error (fh, err_info);
958 if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
960 /* XXX: need to set err_info ?? */
967 * Make the captured length be the amount of bytes we've read (which
968 * is half the number of characters of hex dump we have).
970 * XXX - this can happen for IPv6 packets if the next header isn't the
973 phdr->caplen = ((guint32) ascii_offset)/2;
975 /* Make sure we have enough room for the packet. */
976 ws_buffer_assure_space (buf, phdr->caplen);
977 /* Convert ascii data to binary and return in the frame buffer */
978 iseries_parse_hex_string (ascii_buf, ws_buffer_start_ptr (buf), ascii_offset);
980 /* free buffer allocs and return */
991 * Simple routine to convert an UNICODE buffer to ASCII
993 * XXX - This may be possible with iconv or similar
996 iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
1003 for (i = 0; i < bytes; i++)
1022 * Simple routine to convert an ASCII hex string to binary data
1023 * Requires ASCII hex data and buffer to populate with binary data
1026 iseries_parse_hex_string (const char * ascii, guint8 * buf, size_t len)
1034 for (i = 0; i < len; i++)
1036 hexvalue = g_ascii_xdigit_value(ascii[i]);
1039 return FALSE; /* not a valid hex digit */
1040 bytevalue = (guint8)(hexvalue << 4);
1042 return FALSE; /* only one hex digit of the byte is present */
1043 hexvalue = g_ascii_xdigit_value(ascii[i]);
1045 return FALSE; /* not a valid hex digit */
1046 bytevalue |= (guint8) hexvalue;
1047 buf[byte] = bytevalue;
1054 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1059 * indent-tabs-mode: nil
1062 * vi: set shiftwidth=2 tabstop=8 expandtab:
1063 * :indentSize=2:tabSize=8:noTabs=true: