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>
161 #include <wsutil/strtoi.h>
163 #define ISERIES_LINE_LENGTH 270
164 #define ISERIES_HDR_LINES_TO_CHECK 100
165 #define ISERIES_PKT_LINES_TO_CHECK 4
166 #define ISERIES_MAX_TRACE_LEN 99999999
167 #define ISERIES_FORMAT_ASCII 1
168 #define ISERIES_FORMAT_UNICODE 2
171 * Magic strings - "COMMUNICATIONS TRACE", in ASCII and little-endian UCS-2.
173 static const char iseries_hdr_magic_ascii[] = {
180 static const char iseries_hdr_magic_le_ucs_2[] = {
181 'C', 0x0, 'O', 0x0, 'M', 0x0, 'M', 0x0,
182 'U', 0x0, 'N', 0x0, 'I', 0x0, 'C', 0x0,
183 'A', 0x0, 'T', 0x0, 'I', 0x0, 'O', 0x0,
184 'N', 0x0, 'S', 0x0, ' ', 0x0, 'T', 0x0,
185 'R', 0x0, 'A', 0x0, 'C', 0x0, 'E', 0x0
189 gboolean have_date; /* TRUE if we found a capture start date */
190 int year, month, day; /* The start date */
191 int format; /* Trace format type */
194 static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
195 gint64 *data_offset);
196 static gboolean iseries_seek_read (wtap * wth, gint64 seek_off,
197 struct wtap_pkthdr *phdr,
198 Buffer * buf, int *err, gchar ** err_info);
199 static gboolean iseries_check_file_type (wtap * wth, int *err, gchar **err_info,
201 static gint64 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info);
202 static gboolean iseries_parse_packet (wtap * wth, FILE_T fh,
203 struct wtap_pkthdr *phdr,
204 Buffer * buf, int *err, gchar ** err_info);
205 static int iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes);
206 static gboolean iseries_parse_hex_string (const char * ascii, guint8 * buf,
210 * XXX - it would probably be cleaner to use a UCS-2 flavor of file_gets(),
211 * rather than file_gets(), if we're reading a UCS-2 file.
214 iseries_open (wtap * wth, int *err, gchar ** err_info)
217 char magic[ISERIES_LINE_LENGTH];
220 * Check that file starts with a valid iSeries COMMS TRACE header
221 * by scanning for it in the first line
223 if (!wtap_read_bytes (wth->fh, &magic, sizeof magic, err, err_info))
225 if (*err != WTAP_ERR_SHORT_READ)
226 return WTAP_OPEN_ERROR;
227 return WTAP_OPEN_NOT_MINE;
231 * Check if this is a little-endian UCS-2 Unicode formatted file by scanning
232 * for the magic string
235 while ((unsigned int)offset < (ISERIES_LINE_LENGTH - (sizeof iseries_hdr_magic_le_ucs_2)))
237 if (memcmp (magic + offset, iseries_hdr_magic_le_ucs_2, sizeof iseries_hdr_magic_le_ucs_2) == 0) {
238 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
240 return WTAP_OPEN_ERROR;
243 * Do some basic sanity checking to ensure we can handle the
244 * contents of this trace
246 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE))
249 return WTAP_OPEN_NOT_MINE;
251 return WTAP_OPEN_ERROR;
254 wth->file_encap = WTAP_ENCAP_ETHERNET;
255 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
256 wth->snapshot_length = 0;
257 wth->subtype_read = iseries_read;
258 wth->subtype_seek_read = iseries_seek_read;
259 wth->file_tsprec = WTAP_TSPREC_USEC;
261 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
263 return WTAP_OPEN_ERROR;
265 return WTAP_OPEN_MINE;
271 * Check if this is a ASCII formatted file by scanning for the magic string
274 while ((unsigned int)offset < (ISERIES_LINE_LENGTH - sizeof iseries_hdr_magic_ascii))
276 if (memcmp (magic + offset, iseries_hdr_magic_ascii, sizeof iseries_hdr_magic_ascii) == 0)
278 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
280 return WTAP_OPEN_ERROR;
283 * Do some basic sanity checking to ensure we can handle the
284 * contents of this trace
286 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII))
289 return WTAP_OPEN_NOT_MINE;
291 return WTAP_OPEN_ERROR;
294 wth->file_encap = WTAP_ENCAP_ETHERNET;
295 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
296 wth->snapshot_length = 0;
297 wth->subtype_read = iseries_read;
298 wth->subtype_seek_read = iseries_seek_read;
299 wth->file_tsprec = WTAP_TSPREC_USEC;
301 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
303 return WTAP_OPEN_ERROR;
305 return WTAP_OPEN_MINE;
310 /* Neither ASCII or UNICODE so not supported */
311 return WTAP_OPEN_NOT_MINE;
315 * Do some basic sanity checking to ensure we can handle the
316 * contents of this trace by checking the header page for
317 * requisit requirements and additional information.
320 iseries_check_file_type (wtap * wth, int *err, gchar **err_info, int format)
322 gboolean is_iseries = FALSE;
324 int num_items_scanned;
325 char buf[ISERIES_LINE_LENGTH], protocol[9];
328 /* Save trace format for passing between packets */
329 iseries = (iseries_t *) g_malloc (sizeof (iseries_t));
330 iseries->have_date = FALSE;
331 iseries->format = format;
333 for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
335 memset(buf, 0x0, sizeof(buf));
336 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
339 *err = file_error (wth->fh, err_info);
340 if (*err == WTAP_ERR_SHORT_READ)
346 * Check that we are dealing with an ETHERNET trace
348 if (iseries->format == ISERIES_FORMAT_UNICODE)
350 iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
352 ascii_strup_inplace (buf);
353 num_items_scanned = sscanf (buf,
354 "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s",
356 if (num_items_scanned == 1)
358 if (memcmp (protocol, "ETHERNET", 8) == 0)
366 * The header is the only place where the date part of the timestamp is held, so
367 * extract it here and store for all packets to access
369 num_items_scanned = sscanf (buf,
370 "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d",
371 &iseries->month, &iseries->day,
373 if (num_items_scanned == 3)
375 iseries->have_date = TRUE;
380 wth->priv = (void *) iseries;
388 * Find the next packet and parse it; called from wtap_read().
391 iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
396 * Locate the next packet
398 offset = iseries_seek_next_packet (wth, err, err_info);
401 *data_offset = offset;
404 * Parse the packet and extract the various fields
406 return iseries_parse_packet (wth, wth->fh, &wth->phdr, wth->frame_buffer,
411 * Seeks to the beginning of the next packet, and returns the
412 * byte offset. Returns -1 on failure or EOF; on EOF, sets
413 * *err to 0, and, on failure, sets *err to the error and *err_info
414 * to null or an additional error string.
417 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info)
419 iseries_t *iseries = (iseries_t *)wth->priv;
420 char buf[ISERIES_LINE_LENGTH],type[5];
421 int line, num_items_scanned;
425 for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
427 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
430 *err = file_error (wth->fh, err_info);
433 /* Convert UNICODE to ASCII if required and determine */
434 /* the number of bytes to rewind to beginning of record. */
435 if (iseries->format == ISERIES_FORMAT_UNICODE)
437 /* buflen is #bytes to 1st 0x0A */
438 buflen = iseries_UNICODE_to_ASCII ((guint8 *) buf, ISERIES_LINE_LENGTH);
442 /* Else buflen is just length of the ASCII string */
443 buflen = (long) strlen (buf);
445 ascii_strup_inplace (buf);
446 /* If packet header found return the offset */
449 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
450 if (num_items_scanned == 1)
452 /* Rewind to beginning of line */
453 cur_off = file_tell (wth->fh);
456 *err = file_error (wth->fh, err_info);
459 if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
463 return cur_off - buflen;
467 *err = WTAP_ERR_BAD_FILE;
469 g_strdup_printf ("iseries: next packet header not found within %d lines",
470 ISERIES_MAX_TRACE_LEN);
475 * Read packets in random-access fashion
478 iseries_seek_read (wtap * wth, gint64 seek_off, struct wtap_pkthdr *phdr,
479 Buffer * buf, int *err, gchar ** err_info)
482 /* seek to packet location */
483 if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
487 * Parse the packet and extract the various fields
489 return iseries_parse_packet (wth, wth->random_fh, phdr, buf,
494 append_hex_digits(char *ascii_buf, int ascii_offset, int max_offset,
495 char *data, int *err, gchar **err_info)
497 int in_offset, out_offset;
500 gboolean overflow = FALSE;
503 out_offset = ascii_offset;
507 * Process a block of up to 16 hex digits.
508 * The block is terminated early by an end-of-line indication (NUL,
509 * CR, or LF), by a space (which terminates the last block of the
510 * data we're processing), or by a "*", which introduces the ASCII representation
512 * All characters in the block must be upper-case hex digits;
513 * there might or might not be a space *after* a block, but, if so,
514 * that will be skipped over after the block is processed.
516 for (i = 0; i < 16; i++, in_offset++)
519 * If we see an end-of-line indication, or an early-end-of-block
520 * indication (space), we're done. (Only the last block ends
523 c = data[in_offset] & 0xFF;
524 if (c == '\0' || c == ' ' || c == '*' || c == '\r' || c == '\n')
528 if (!g_ascii_isxdigit(c) || g_ascii_islower(c))
531 * Not a hex digit, or a lower-case hex digit.
532 * Treat this as an indication that the line isn't a data
533 * line, so we just ignore it.
535 * XXX - do so only for continuation lines; treat non-hex-digit
536 * characters as errors for other lines?
538 return ascii_offset; /* pretend we appended nothing */
540 if (out_offset >= max_offset)
544 ascii_buf[out_offset] = c;
549 * Skip blanks, if any.
551 for (; (data[in_offset] & 0xFF) == ' '; in_offset++)
556 * If we processed an *odd* number of hex digits, report an error.
560 *err = WTAP_ERR_BAD_FILE;
561 *err_info = g_strdup("iseries: odd number of hex digits in a line");
566 *err = WTAP_ERR_BAD_FILE;
567 *err_info = g_strdup("iseries: more packet data than the packet length indicated");
573 /* return the multiplier for nanoseconds */
575 csec_multiplier(guint32 csec)
577 if (csec < 10) return 100000000;
578 if (csec < 100) return 10000000;
579 if (csec < 1000) return 1000000;
580 if (csec < 10000) return 100000;
581 if (csec < 100000) return 10000;
582 if (csec < 1000000) return 1000;
583 if (csec < 10000000) return 100;
584 if (csec < 100000000) return 10;
588 /* Parses a packet. */
590 iseries_parse_packet (wtap * wth, FILE_T fh, struct wtap_pkthdr *phdr,
591 Buffer *buf, int *err, gchar **err_info)
593 iseries_t *iseries = (iseries_t *)wth->priv;
595 gboolean isValid, isCurrentPacket;
596 int num_items_scanned, line, pktline, buflen;
597 int pkt_len, pktnum, hr, min, sec;
598 char direction[2], destmac[13], srcmac[13], type[5];
600 char data[ISERIES_LINE_LENGTH * 2];
607 * Check for packet headers in first 3 lines this should handle page breaks
608 * situations and the header lines output at each page throw and ensure we
609 * read both the captured and packet lengths.
612 for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++)
614 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
616 *err = file_error (fh, err_info);
619 /* Convert UNICODE data to ASCII */
620 if (iseries->format == ISERIES_FORMAT_UNICODE)
622 iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
624 ascii_strup_inplace (data);
627 "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9u%*[ \n\t]"
628 "%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s",
629 &pktnum, direction, &pkt_len, &hr, &min, &sec, &csec, destmac,
631 if (num_items_scanned == 10)
635 *err = WTAP_ERR_BAD_FILE;
636 *err_info = g_strdup ("iseries: packet header has a negative packet number");
642 *err = WTAP_ERR_BAD_FILE;
643 *err_info = g_strdup ("iseries: packet header has a negative packet length");
649 *err = WTAP_ERR_BAD_FILE;
650 *err_info = g_strdup ("iseries: packet header has a negative hour in the time stamp");
656 *err = WTAP_ERR_BAD_FILE;
657 *err_info = g_strdup ("iseries: packet header has a hour in the time stamp greater than 23");
663 *err = WTAP_ERR_BAD_FILE;
664 *err_info = g_strdup ("iseries: packet header has a negative minute in the time stamp");
670 *err = WTAP_ERR_BAD_FILE;
671 *err_info = g_strdup ("iseries: packet header has a minute in the time stamp greater than 59");
677 *err = WTAP_ERR_BAD_FILE;
678 *err_info = g_strdup ("iseries: packet header has a negative second in the time stamp");
683 * Yes, 60, even though the time-conversion routines on most OSes
684 * might not handle leap seconds.
688 *err = WTAP_ERR_BAD_FILE;
689 *err_info = g_strdup ("iseries: packet header has a second in the time stamp greater than 60");
693 if (strlen(destmac) != 12)
695 *err = WTAP_ERR_BAD_FILE;
696 *err_info = g_strdup ("iseries: packet header has a destination MAC address shorter than 6 bytes");
700 if (strlen(srcmac) != 12)
702 *err = WTAP_ERR_BAD_FILE;
703 *err_info = g_strdup ("iseries: packet header has a source MAC address shorter than 6 bytes");
707 if (strlen(type) != 4)
709 *err = WTAP_ERR_BAD_FILE;
710 *err_info = g_strdup ("iseries: packet header has an Ethernet type/length field than 2 bytes");
714 /* OK! We found the packet header line */
717 * XXX - The Capture length returned by the iSeries trace doesn't
718 * seem to include the Ethernet header, so we add its length here.
720 * Check the length first, just in case it's *so* big that, after
721 * adding the Ethernet header length, it overflows.
723 if (pkt_len > WTAP_MAX_PACKET_SIZE_STANDARD - 14)
726 * Probably a corrupt capture file; don't blow up trying
727 * to allocate space for an immensely-large packet, and
728 * don't think it's a really *small* packet because it
729 * overflowed. (Calculate the size as a 64-bit value in
730 * the error message, to avoid an overflow.)
732 *err = WTAP_ERR_BAD_FILE;
733 *err_info = g_strdup_printf("iseries: File has %" G_GUINT64_FORMAT "-byte packet, bigger than maximum of %u",
734 (guint64)pkt_len + 14,
735 WTAP_MAX_PACKET_SIZE_STANDARD);
744 * If no packet header found we exit at this point and inform the user.
748 *err = WTAP_ERR_BAD_FILE;
749 *err_info = g_strdup ("iseries: packet header isn't valid");
753 phdr->rec_type = REC_TYPE_PACKET;
754 phdr->presence_flags = WTAP_HAS_CAP_LEN;
757 * If we have Wiretap Header then populate it here
759 * Timer resolution on the iSeries is hardware dependent. We determine
760 * the resolution based on how many digits we see.
762 if (iseries->have_date)
764 phdr->presence_flags |= WTAP_HAS_TS;
765 tm.tm_year = 100 + iseries->year;
766 tm.tm_mon = iseries->month - 1;
767 tm.tm_mday = iseries->day;
772 phdr->ts.secs = mktime (&tm);
773 phdr->ts.nsecs = csec * csec_multiplier(csec);
777 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
778 phdr->pseudo_header.eth.fcs_len = -1;
781 * Allocate a buffer big enough to hold the claimed packet length
782 * worth of byte values; each byte will be two hex digits, so the
783 * buffer's size should be twice the packet length.
785 * (There is no need to null-terminate the buffer.)
787 ascii_buf = (char *)g_malloc (pkt_len*2);
791 * Copy in the Ethernet header.
793 * The three fields have already been checked to have the right length
794 * (6 bytes, hence 12 characters, of hex-dump destination and source
795 * addresses, and 2 bytes, hence 4 characters, of hex-dump type/length).
797 * pkt_len is guaranteed to be >= 14, so 2*pkt_len is guaranteed to be
798 * >= 28, so we don't need to do any bounds checking.
800 memcpy(&ascii_buf[0], destmac, 12);
802 memcpy(&ascii_buf[12], srcmac, 12);
804 memcpy(&ascii_buf[24], type, 4);
808 * Start reading packet contents
810 isCurrentPacket = TRUE;
812 /* loop through packet lines and breakout when the next packet header is read */
814 while (isCurrentPacket)
817 /* Read the next line */
818 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
820 *err = file_error (fh, err_info);
823 /* Hit the EOF without an error */
829 /* Convert UNICODE data to ASCII and determine line length */
830 if (iseries->format == ISERIES_FORMAT_UNICODE)
832 buflen = iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
836 /* Else bytes to rewind is just length of ASCII string */
837 buflen = (int) strlen (data);
841 * Skip leading white space.
843 for (offset = 0; g_ascii_isspace(data[offset]); offset++)
847 * The higher-level header information starts at an offset of
848 * 22 characters. The header tags are 14 characters long.
850 * XXX - for IPv6, if the next header isn't the last header,
851 * the intermediate headers do *NOT* appear to be shown in
852 * the dump file *at all*, so the packet *cannot* be
857 if (strncmp(data + 22, "IP Header : ", 14) == 0 ||
858 strncmp(data + 22, "IPv6 Header: ", 14) == 0 ||
859 strncmp(data + 22, "ARP Header : ", 14) == 0 ||
860 strncmp(data + 22, "TCP Header : ", 14) == 0 ||
861 strncmp(data + 22, "UDP Header : ", 14) == 0 ||
862 strncmp(data + 22, "ICMP Header: ", 14) == 0 ||
863 strncmp(data + 22, "ICMPv6 Hdr: ", 14) == 0 ||
864 strncmp(data + 22, "Option Hdr: ", 14) == 0)
866 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
870 if (ascii_offset == -1)
880 * Is this a data line?
882 * The "Data" starts at an offset of 8.
886 if (strncmp(data + 9, "Data . . . . . : ", 18) == 0)
888 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
892 if (ascii_offset == -1)
902 * Is this a continuation of a previous header or data line?
903 * That's blanks followed by hex digits; first try the
904 * "no column separators" form.
906 * Continuations of header lines begin at an offset of 36;
907 * continuations of data lines begin at an offset of 27.
909 if (offset == 36 || offset == 27)
911 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
915 if (ascii_offset == -1)
924 * If we see the identifier for the next packet then rewind and set
925 * isCurrentPacket FALSE
927 ascii_strup_inplace (data);
928 /* If packet header found return the offset */
931 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
932 if ((num_items_scanned == 1) && pktline > 1)
934 isCurrentPacket = FALSE;
935 cur_off = file_tell( fh);
939 *err = file_error (fh, err_info);
942 if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
944 /* XXX: need to set err_info ?? */
951 * Make the captured length be the amount of bytes we've read (which
952 * is half the number of characters of hex dump we have).
954 * XXX - this can happen for IPv6 packets if the next header isn't the
957 phdr->caplen = ((guint32) ascii_offset)/2;
959 /* Make sure we have enough room for the packet. */
960 ws_buffer_assure_space (buf, phdr->caplen);
961 /* Convert ascii data to binary and return in the frame buffer */
962 iseries_parse_hex_string (ascii_buf, ws_buffer_start_ptr (buf), ascii_offset);
964 /* free buffer allocs and return */
975 * Simple routine to convert an UNICODE buffer to ASCII
977 * XXX - This may be possible with iconv or similar
980 iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
987 for (i = 0; i < bytes; i++)
1006 * Simple routine to convert an ASCII hex string to binary data
1007 * Requires ASCII hex data and buffer to populate with binary data
1010 iseries_parse_hex_string (const char * ascii, guint8 * buf, size_t len)
1018 for (i = 0; i < len; i++)
1020 hexvalue = g_ascii_xdigit_value(ascii[i]);
1023 return FALSE; /* not a valid hex digit */
1024 bytevalue = (guint8)(hexvalue << 4);
1026 return FALSE; /* only one hex digit of the byte is present */
1027 hexvalue = g_ascii_xdigit_value(ascii[i]);
1029 return FALSE; /* not a valid hex digit */
1030 bytevalue |= (guint8) hexvalue;
1031 buf[byte] = bytevalue;
1038 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1043 * indent-tabs-mode: nil
1046 * vi: set shiftwidth=2 tabstop=8 expandtab:
1047 * :indentSize=2:tabSize=8:noTabs=true: