6 * Copyright (c) 2011 by Martin Warnes <Martin_Warnes@uk.ibm.com>
8 * Based on toshiba.c and vms.c
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * This module will read the contents of the iSeries (OS/400) Communication trace
27 * Both ASCII & Unicode formatted traces are supported.
29 * iSeries Comms traces consist of a header page and a subsequent number of packet records
31 * The header page contains details on the options set during running of the trace,
32 * currently the following options are a requirement for this module:
34 * 1. Object protocol = ETHERNET (Default)
35 * 2. ASCII or UNICODE file formats.
37 * The above can be acheived by passing option ASCII(*YES) with the trace command
41 /* iSeries header page
43 COMMUNICATIONS TRACE Title: OS400 - OS400 trace 10/28/05 11:44:50 Page: 1
44 Trace Description . . . . . : OS400 - OS400 trace
45 Configuration object . . . . : ETH0
46 Type . . . . . . . . . . . . : 1 1=Line, 2=Network Interface
48 Object protocol . . . . . . : ETHERNET
49 Start date/Time . . . . . . : 10/28/05 11:43:00.341
50 End date/Time . . . . . . . : 10/28/05 11:44:22.148
51 Bytes collected . . . . . . : 11999
52 Buffer size . . . . . . . . : 2048 kilobytes
53 Data direction . . . . . . . : 3 1=Sent, 2=Received, 3=Both
54 Stop on buffer full . . . . : Y Y=Yes, N=No
55 Number of bytes to trace
56 Beginning bytes . . . . . : *MAX Value, *CALC, *MAX
57 Ending bytes . . . . . . : *CALC Value, *CALC
58 Controller name . . . . . . : *ALL *ALL, name
59 Data representation . . . . : 1 1=ASCII, 2=EBCDIC, 3=*CALC
60 Format SNA data only . . . . : N Y=Yes, N=No
61 Format RR, RNR commands . . : N Y=Yes, N=No
62 Format TCP/IP data only . . : Y Y=Yes, N=No
63 IP address . . . . . . . . : *ALL *ALL, address
64 IP address . . . . . . . . : *ALL *ALL, address
65 IP port . . . . . . . . . : *ALL *ALL, IP port
66 Format UI data only . . . . : N Y=Yes, N=No
67 Select Ethernet data . . . . : 3 1=802.3, 2=ETHV2, 3=Both
68 Format Broadcast data . . . : Y Y=Yes, N=No
71 /* iSeries IPv4 formatted packet records consist of a header line identifying the packet number,direction,size,
72 * timestamp,source/destination MAC addresses and packet type.
74 * Thereafter there will be a formated display of the IP and TCP headers as well as a hex string dump
75 * of the headers themselves displayed in the the "IP Header" and "TCP header" fields.
77 * If the packet contains data this is displayed as 4 groups of 16 hex digits followed by an ASCII
78 * representaion of the data line.
80 * Information from the header line, IP header, TCP header and if available data lines are extracted
81 * by the module for displaying.
84 Record Data Record Controller Destination Source Frame
85 Number S/R Length Timer Name MAC Address MAC Address Format
86 ------ --- ------ --------------- ---------- ------------ ------------ ------
87 8 S 145 11:43:59.82956 0006299C14AE 0006299C14FE ETHV2 Type: 0800
88 Frame Type : IP DSCP: 0 ECN: 00-NECT Length: 145 Protocol: TCP Datagram ID: 388B
89 Src Addr: 10.20.144.150 Dest Addr: 10.20.144.151 Fragment Flags: DON'T,LAST
90 IP Header : 45000091388B40004006CC860A1490960A149097
92 TCP . . . : Src Port: 6006,Unassigned Dest Port: 35366,Unassigned
93 SEQ Number: 2666470699 ('9EEF1D2B'X) ACK Number: 2142147535 ('7FAE93CF'X)
94 Code Bits: ACK PSH Window: 32648 TCP Option: NO OP
95 TCP Header : 17768A269EEF1D2B7FAE93CF80187F885B5600000101080A0517E0F805166DE0
96 Data . . . . . : 5443503200020010 0000004980000000 B800000080470103 01001E0000002000 *TCP2.......I*...*...*G........ .*
97 002F010080000004 0300800700C00600 4002008000000304 00800000060FB067 *./..*.....*..*..@..*.....*....*G*
98 FC276228786B3EB0 EF34F5F1D27EF8DF 20926820E7B322AA 739F1FB20D **'B(XK>**4***.** *H **"*S*.*. *
101 /* iSeries IPv6 formatted traces are similar to the IPv4 version above but data is no longer output as 4 hex sections
104 Record Data Record Destination Source Frame
105 Number S/R Length Timer MAC Address MAC Address Format
106 ------ --- ------ ------------ ------------ ------------ ------
107 218 S 1488 15:01:14.389 0011BC358680 00096B6BD918 ETHV2 Type: 86DD
108 IPv6 Data: Ver: 06 Traffic Class: 00 Flow Label: 000000
109 Payload Length: 1448 Next Header: 06,TCP Hop Limit: 64
110 Src Addr: fd00:0:0:20f2::122
111 Dest Addr: fd00:0:0:20a0::155
112 IPv6 Header: 6000000005A80640FD000000000020F20000000000000122FD000000000020A0
114 TCP . . . : Src Port: 21246,Unassigned Dest Port: 13601,Unassigned
115 SEQ Number: 2282300877 ('880925CD'X) ACK Number: 3259003715 ('C2407343'X)
116 Code Bits: ACK Window: 65535 TCP Option: NO OP
117 TCP Header : 52FE3521880925CDC24073438010FFFFCFBB00000101080A0E15127000237A08
118 Data . . . . . : 54435032000200140000061880000000ECBEB867F0000000004CE640E6C1D9D5 *TCP2........*...***g*....L*@*****
119 C9D5C740E3C8C9E240C9E240E3C8C540E6C1D9D5C9D5C740C6C9C5D3C4404040 ****@****@**@***@*******@*****@@@*
120 4040404040404040404040404040404040404040404040404040404040404040 *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
123 /* iSeries unformatted packet record consist of the same header record as the formatted trace but all
124 * other records are simply unformatted data containing IP, TCP and packet data combined.
126 Record Data Record Controller Destination Source Frame Number Number Poll/
127 Number S/R Length Timer Name MAC Address MAC Address Format Command Sent Received Final DSAP SSAP
128 ------ --- ------ --------------- ---------- ------------ ------------ ------ ------- ------ -------- ----- ---- ----
129 1 R 64 12:19:29.97108 000629ECF48E 0006D78E23C2 ETHV2 Type: 0800
130 Data . . . . . : 4500003C27954000 3A06CE3D9797440F 0A5964EAC4F50554 58C9915500000000 *E..<'*@.:.*=**D..YD***.TX**U....*
131 A00216D06A200000 020405B40402080A 1104B6C000000000 010303000B443BF1 **..*J .....*......**.........D;**
137 #include "wtap-int.h"
140 #include "file_wrappers.h"
148 #include <wsutil/str_util.h>
150 #define ISERIES_HDR_MAGIC_STR "COMMUNICATIONS TRACE"
151 #define ISERIES_HDR_MAGIC_LEN 20
152 #define ISERIES_UNICODE_HDR_MAGIC_LEN 17
153 #define ISERIES_PKT_MAGIC_STR "ETHV2"
154 #define ISERIES_PKT_MAGIC_LEN 5
155 #define ISERIES_LINE_LENGTH 270
156 #define ISERIES_HDR_LINES_TO_CHECK 100
157 #define ISERIES_PKT_LINES_TO_CHECK 4
158 #define ISERIES_MAX_PACKET_LEN 16384
159 #define ISERIES_MAX_TRACE_LEN 99999999
160 #define ISERIES_PKT_ALLOC_SIZE (cap_len*2)+1
161 #define ISERIES_FORMAT_ASCII 1
162 #define ISERIES_FORMAT_UNICODE 2
165 gboolean have_date; /* TRUE if we found a capture start date */
166 int year, month, day; /* The start date */
167 gboolean tcp_formatted; /* TCP/IP data formated Y/N */
168 gboolean ipv6_trace; /* IPv4 or IPv6 */
169 int format; /* Trace format type */
172 static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
173 gint64 *data_offset);
174 static gboolean iseries_seek_read (wtap * wth, gint64 seek_off,
175 union wtap_pseudo_header *pseudo_header,
176 guint8 * pd, int len, int *err,
178 static gboolean iseries_check_file_type (wtap * wth, int *err, gchar **err_info,
180 static gint64 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info);
181 static int iseries_parse_packet (wtap * wth, FILE_T fh,
182 union wtap_pseudo_header *pseudo_header,
183 guint8 * pd, int *err, gchar ** err_info);
184 static int iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes);
185 static gboolean iseries_parse_hex_string (const char * ascii, guint8 * buf,
189 iseries_open (wtap * wth, int *err, gchar ** err_info)
193 char magic[ISERIES_LINE_LENGTH];
194 char unicodemagic[ISERIES_UNICODE_HDR_MAGIC_LEN] =
195 { '\x43', '\x00', '\x4F', '\x00', '\x4D',
196 '\x00', '\x4D', '\x00', '\x55', '\x00', '\x4E', '\x00', '\x49', '\x00',
197 '\x43', '\x00', '\x41'
201 * Check that file starts with a valid iSeries COMMS TRACE header
202 * by scanning for it in the first line
204 errno = WTAP_ERR_CANT_READ;
205 bytes_read = file_read (&magic, sizeof magic, wth->fh);
206 if (bytes_read != sizeof magic)
208 *err = file_error (wth->fh, err_info);
215 * Check if this is a UNICODE formatted file by scanning for the magic string
218 while (offset < ISERIES_LINE_LENGTH - ISERIES_UNICODE_HDR_MAGIC_LEN)
220 if (memcmp (magic + offset, unicodemagic, ISERIES_UNICODE_HDR_MAGIC_LEN) == 0) {
221 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
226 * Do some basic sanity checking to ensure we can handle the
227 * contents of this trace
229 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE))
236 wth->data_offset = 0;
237 wth->file_encap = WTAP_ENCAP_ETHERNET;
238 wth->file_type = WTAP_FILE_ISERIES;
239 wth->snapshot_length = 0;
240 wth->subtype_read = iseries_read;
241 wth->subtype_seek_read = iseries_seek_read;
242 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
243 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
253 * Check if this is a ASCII formatted file by scanning for the magic string
256 while (offset < ISERIES_LINE_LENGTH - ISERIES_HDR_MAGIC_LEN)
258 if (memcmp (magic + offset, ISERIES_HDR_MAGIC_STR, ISERIES_HDR_MAGIC_LEN) == 0) {
260 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
265 * Do some basic sanity checking to ensure we can handle the
266 * contents of this trace
268 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII))
275 wth->data_offset = 0;
276 wth->file_encap = WTAP_ENCAP_ETHERNET;
277 wth->file_type = WTAP_FILE_ISERIES;
278 wth->snapshot_length = 0;
279 wth->subtype_read = iseries_read;
280 wth->subtype_seek_read = iseries_seek_read;
281 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
282 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
291 /* Neither ASCII or UNICODE so not supported */
296 * Do some basic sanity checking to ensure we can handle the
297 * contents of this trace by checking the header page for
298 * requisit requirements and additional information.
301 iseries_check_file_type (wtap * wth, int *err, gchar **err_info, int format)
304 int num_items_scanned;
305 char buf[ISERIES_LINE_LENGTH], protocol[9], type[5], work[2] = "";
308 /* Save trace format for passing between packets */
309 iseries = (iseries_t *) g_malloc (sizeof (iseries_t));
310 wth->priv = (void *)iseries;
311 iseries->have_date = FALSE;
312 iseries->format = format;
313 iseries->tcp_formatted = FALSE;
314 iseries->ipv6_trace = FALSE;
316 for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
318 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) != NULL)
321 * Check that we are dealing with an ETHERNET trace
323 if (iseries->format == ISERIES_FORMAT_UNICODE)
325 iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
327 ascii_strup_inplace(buf);
328 num_items_scanned = sscanf (buf,
329 "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s",
331 if (num_items_scanned == 1)
333 if (memcmp (protocol, "ETHERNET", 8) != 0)
338 * The header is the only place where the date part of the timestamp is held, so
339 * extract it here and store for all packets to access
341 num_items_scanned = sscanf (buf,
342 "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d",
343 &iseries->month, &iseries->day,
345 if (num_items_scanned == 3)
347 iseries->have_date = TRUE;
352 * Determine if this is a IPv4 or IPv6 trace
356 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
357 if (num_items_scanned == 1)
359 if (strncmp (type, "0800", 1) == 0)
361 iseries->ipv6_trace = FALSE;
363 if (strncmp (type, "86DD", 1) == 0)
365 iseries->ipv6_trace = TRUE;
370 * Determine if the data has been formatted
373 num_items_scanned = sscanf (buf,
374 "%*[ \n\t]IPV6 HEADER%1s",
376 if (num_items_scanned == 1)
378 iseries->tcp_formatted = TRUE;
382 num_items_scanned = sscanf (buf,
383 "%*[ \n\t]IP HEADER %1s",
385 if (num_items_scanned == 1)
387 iseries->tcp_formatted = TRUE;
395 if (file_eof (wth->fh))
398 *err = file_error (wth->fh, err_info);
407 * Find the next packet and parse it; called from wtap_read().
410 iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
416 * Locate the next packet
418 offset = iseries_seek_next_packet (wth, err, err_info);
423 * Parse the packet and extract the various fields
426 iseries_parse_packet (wth, wth->fh, &wth->pseudo_header, NULL, err,
431 wth->data_offset = offset;
432 *data_offset = offset;
437 * Seeks to the beginning of the next packet, and returns the
438 * byte offset. Returns -1 on failure, and sets "*err" to the error
439 * and "*err_info" to null or an additional error string.
442 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info)
444 iseries_t *iseries = (iseries_t *)wth->priv;
445 char buf[ISERIES_LINE_LENGTH],type[5];
446 int line, num_items_scanned;
451 * Seeks to the beginning of the next packet, and returns the
452 * byte offset. Returns -1 on failure, and sets "*err" to the error
453 * and "*err_info" to null or an additional error string.
455 for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
457 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) != NULL)
460 /* Convert UNICODE to ASCII if required and determine */
461 /* the number of bytes to rewind to beginning of record. */
462 if (iseries->format == ISERIES_FORMAT_UNICODE)
464 /* buflen is #bytes to 1st 0x0A */
465 buflen = iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
469 /* Else buflen is just length of the ASCII string */
470 buflen = (long) strlen (buf);
472 ascii_strup_inplace(buf);
473 /* If packet header found return the offset */
476 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
477 if (num_items_scanned == 1)
479 /* Rewind to beginning of line */
480 cur_off = file_tell (wth->fh);
483 *err = file_error (wth->fh, err_info);
486 if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
490 return cur_off - buflen;
493 /* Otherwise we got an error or reached EOF */
496 if (file_eof (wth->fh))
503 /* We got an error. */
504 *err = file_error (wth->fh, err_info);
514 * Read packets in random-access fashion
517 iseries_seek_read (wtap * wth, gint64 seek_off,
518 union wtap_pseudo_header *pseudo_header, guint8 * pd,
519 int len, int *err, gchar ** err_info)
523 /* seek to packet location */
524 if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
528 * Parse the packet and extract the various fields
530 pkt_len = iseries_parse_packet (wth, wth->random_fh, pseudo_header, pd,
537 *err = WTAP_ERR_BAD_RECORD;
540 ("iseries: requested length %d doesn't match record length %d",
548 /* Parses a packet. */
550 iseries_parse_packet (wtap * wth, FILE_T fh,
551 union wtap_pseudo_header *pseudo_header, guint8 * pd,
552 int *err, gchar ** err_info)
554 iseries_t *iseries = (iseries_t *)wth->priv;
556 gboolean isValid, isCurrentPacket, IPread, TCPread, isDATA, isDataHandled;
557 int num_items_scanned, line, pktline, buflen;
559 int cap_len, pktnum, hr, min, sec, csec;
560 char direction[2], destmac[13], srcmac[13], type[5], ipheader[41],
562 char hex1[17], hex2[17], hex3[17], hex4[17];
563 char data[ISERIES_LINE_LENGTH * 2];
565 char *tcpdatabuf, *workbuf, *asciibuf;
569 * Check for packet headers in first 3 lines this should handle page breaks
570 * situations and the header lines output at each page throw and ensure we
571 * read both the captured and packet lengths.
574 for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++)
576 cur_off = file_tell (fh);
577 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
579 *err = file_error (fh, err_info);
582 *err = WTAP_ERR_SHORT_READ;
586 /* Convert UNICODE data to ASCII */
587 if (iseries->format == ISERIES_FORMAT_UNICODE)
589 iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
591 ascii_strup_inplace(data);
594 "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9d%*[ \n\t]%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s",
595 &pktnum, direction, &cap_len, &hr, &min, &sec, &csec, destmac,
597 if (num_items_scanned == 10)
599 /* OK! We found the packet header line */
602 * XXX - The Capture length returned by the iSeries trace doesn't seem to include the src/dest MAC
603 * addresses or the packet type. So we add them here.
611 * If no packet header found we exit at this point and inform the user.
615 *err = WTAP_ERR_BAD_RECORD;
616 *err_info = g_strdup ("iseries: packet header isn't valid");
621 * If we have Wiretap Header then populate it here
623 * XXX - Timer resolution on the iSeries is hardware dependant; the value for csec may be
624 * different on other platforms though all the traces I've seen seem to show resolution
625 * to Milliseconds (i.e HH:MM:SS.nnnnn) or Nanoseconds (i.e HH:MM:SS.nnnnnn)
627 if (iseries->have_date)
629 tm.tm_year = 100 + iseries->year;
630 tm.tm_mon = iseries->month - 1;
631 tm.tm_mday = iseries->day;
636 wth->phdr.ts.secs = mktime (&tm);
637 /* Handle Millisecond precision for timer */
640 wth->phdr.ts.nsecs = csec * 1000;
642 /* Handle Nanosecond precision for timer */
645 wth->phdr.ts.nsecs = csec * 10000;
649 wth->phdr.caplen = cap_len;
650 wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
651 pseudo_header->eth.fcs_len = -1;
654 * Start Reading packet contents
656 isCurrentPacket = TRUE;
661 * Allocate 2 work buffers to handle concatentation of the hex data block
663 tcpdatabuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
664 g_snprintf (tcpdatabuf, 1, "%s", "");
665 workbuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
666 g_snprintf (workbuf, 1, "%s", "");
667 /* loop through packet lines and breakout when the next packet header is read */
669 while (isCurrentPacket)
672 /* Read the next line */
673 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
681 *err = file_error (fh, err_info);
684 *err = WTAP_ERR_SHORT_READ;
690 /* Convert UNICODE data to ASCII and determine line length */
691 if (iseries->format == ISERIES_FORMAT_UNICODE)
693 buflen = iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
697 /* Else bytes to rewind is just length of ASCII string */
698 buflen = (int) strlen (data);
702 * Decode data for IPv4 traces and unformatted IPv6 traces
704 if ((!iseries->ipv6_trace) || ((iseries->ipv6_trace) && (!iseries->tcp_formatted)))
706 /* If this is a IP header hex string then set flag */
707 num_items_scanned = sscanf (data + 22, "IP Header%*[ .:\n\t]%40s", ipheader);
708 if (num_items_scanned == 1)
713 /* If this is TCP header hex string then set flag */
714 num_items_scanned = sscanf (data + 22, "TCP Header%*[ .:\n\t]%80s", tcpheader);
715 if (num_items_scanned == 1)
721 * If there is data in the packet handle it here.
723 * The data header line will have the "Data . . " identifier, subsequent lines don't
726 sscanf (data + 27, "%16[A-F0-9] %16[A-F0-9] %16[A-F0-9] %16[A-F0-9]",
727 hex1, hex2, hex3, hex4);
728 if (num_items_scanned > 0)
732 * Scan the data line for data blocks, depending on the number of blocks scanned
733 * add them along with current tcpdata buffer to the work buffer and then copy
734 * work buffer to tcpdata buffer to continue building up tcpdata buffer to contain
735 * a single hex string.
737 switch (num_items_scanned)
740 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s", tcpdatabuf,
744 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s",
745 tcpdatabuf, hex1, hex2);
748 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s",
749 tcpdatabuf, hex1, hex2, hex3);
752 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s",
753 tcpdatabuf, hex1, hex2, hex3, hex4);
755 memcpy (tcpdatabuf, workbuf, ISERIES_PKT_ALLOC_SIZE);
760 * Decode data for IPv6 formatted traces
762 if ((iseries->ipv6_trace) && (iseries->tcp_formatted))
765 * If there are IPv6 headers in the packet handle it here.
767 * iSeries IPv6 headers are aligned after column 36 and appears as a single hex string
768 * of 16,32,48 or 64 bytes
772 sscanf (data + 35, "%*[ \n\t]%16[A-F0-9]%16[A-F0-9]%16[A-F0-9]%16[A-F0-9]",
773 hex1, hex2, hex3, hex4);
774 if (num_items_scanned > 0)
778 * Scan the data line for data blocks, depending on the number of blocks scanned
779 * add them along with current tcpdata buffer to the work buffer and then copy
780 * work buffer to tcpdata buffer to continue building up tcpdata buffer to contain
781 * a single hex string.
783 switch (num_items_scanned)
786 if (strlen(hex1)==16)
788 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s", tcpdatabuf,
794 if ((strlen(hex1)==16) && (strlen(hex2)==16))
796 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s",
797 tcpdatabuf, hex1, hex2);
802 if ((strlen(hex1)==16) && (strlen(hex2)==16) && (strlen(hex3)==16))
804 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s",
805 tcpdatabuf, hex1, hex2, hex3);
810 if ((strlen(hex1)==16) && (strlen(hex2)==16) && (strlen(hex3)==16) && (strlen(hex4)==16))
812 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s",
813 tcpdatabuf, hex1, hex2, hex3, hex4);
817 memcpy (tcpdatabuf, workbuf, ISERIES_PKT_ALLOC_SIZE);
820 * If there is data in the packet handle it here.
822 * The data header line will have the "Data . . " identifier, subsequent lines don't
823 * Check to ensure we haven't already captured and used this data block already above
826 sscanf (data + 26, "%*[ \n\t]%16[A-F0-9]%16[A-F0-9]%16[A-F0-9]%16[A-F0-9]",
827 hex1, hex2, hex3, hex4);
828 if ((num_items_scanned > 0) && (isDataHandled==FALSE))
832 * Scan the data line for data blocks, depending on the number of blocks scanned
833 * add them along with current tcpdata buffer to the work buffer and then copy
834 * work buffer to tcpdata buffer to continue building up tcpdata buffer to contain
835 * a single hex string.
837 switch (num_items_scanned)
840 if (strlen(hex1)==16)
842 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s", tcpdatabuf,
847 if ((strlen(hex1)==16) && (strlen(hex2)==16))
849 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s",
850 tcpdatabuf, hex1, hex2);
854 if ((strlen(hex1)==16) && (strlen(hex2)==16) && (strlen(hex3)==16))
856 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s",
857 tcpdatabuf, hex1, hex2, hex3);
861 if ((strlen(hex1)==16) && (strlen(hex2)==16) && (strlen(hex3)==16) && (strlen(hex4)==16))
863 g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s",
864 tcpdatabuf, hex1, hex2, hex3, hex4);
867 memcpy (tcpdatabuf, workbuf, ISERIES_PKT_ALLOC_SIZE);
872 * If we see the identifier for the next packet then rewind and set
873 * isCurrentPacket FALSE
875 ascii_strup_inplace(data);
876 /* If packet header found return the offset */
879 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
880 if ((num_items_scanned == 1) && pktline > 1)
882 isCurrentPacket = FALSE;
883 cur_off = file_tell (fh);
887 *err = file_error (fh, err_info);
890 if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
898 * For a IPV4 formated trace ensure we have read at least the IP and TCP headers otherwise
899 * exit and pass error message to user.
901 if ((iseries->tcp_formatted) && (iseries->ipv6_trace == FALSE))
905 *err = WTAP_ERR_BAD_RECORD;
906 *err_info = g_strdup ("iseries: IP header isn't valid");
911 *err = WTAP_ERR_BAD_RECORD;
912 *err_info = g_strdup ("iseries: TCP header isn't valid");
918 * Create a buffer to hold all the ASCII Hex data and populate with all the
921 asciibuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
924 /* packet contained data */
925 if ((iseries->tcp_formatted) && (iseries->ipv6_trace == FALSE))
927 /* build string for formatted fields */
928 g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s%s",
929 destmac, srcmac, type, ipheader, tcpheader, tcpdatabuf);
933 /* build string for unformatted data fields and IPV6 data*/
934 g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s", destmac,
935 srcmac, type, tcpdatabuf);
940 /* No data in the packet */
941 g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s", destmac,
942 srcmac, type, ipheader, tcpheader);
946 * Note: iSeries comms traces pad data blocks out with zeros
947 * Extract the packet length from the actual IP header; this may
948 * differ from the capture length reported by the formatted trace.
949 * IPv4 and IPv6 headers contain the length at different offsets so
950 * read from the correct location.
952 if (!iseries->ipv6_trace)
954 num_items_scanned = sscanf (asciibuf + 32, "%4x", &pkt_len);
955 wth->phdr.len = pkt_len + 14;
959 num_items_scanned = sscanf (asciibuf + 36, "%4x", &pkt_len);
960 wth->phdr.len = pkt_len + 14;
962 if (wth->phdr.caplen > wth->phdr.len)
963 wth->phdr.len = wth->phdr.caplen;
965 /* Make sure we have enough room for the packet, only create buffer if none supplied */
968 buffer_assure_space (wth->frame_buffer, ISERIES_MAX_PACKET_LEN);
969 buf = buffer_start_ptr (wth->frame_buffer);
970 /* Convert ascii data to binary and return in the frame buffer */
971 iseries_parse_hex_string (asciibuf, buf, (int) strlen (asciibuf));
975 /* Convert ascii data to binary and return in the frame buffer */
976 iseries_parse_hex_string (asciibuf, pd, (int) strlen (asciibuf));
979 /* free buffers allocs and return */
984 return wth->phdr.len;
988 * Simple routine to convert an UNICODE buffer to ASCII
990 * XXX - This may be possible with iconv or similar
993 iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
999 for (i = 0; i < bytes; i++)
1018 * Simple routine to convert an ASCII hex string to binary data
1019 * Requires ASCII hex data and buffer to populate with binary data
1022 iseries_parse_hex_string (const char * ascii, guint8 * buf, int len)
1034 hexvalue = g_ascii_xdigit_value(ascii[i]);
1037 return FALSE; /* not a valid hex digit */
1038 bytevalue = (guint8)(hexvalue << 4);
1040 return FALSE; /* only one hex digit of the byte is present */
1041 hexvalue = g_ascii_xdigit_value(ascii[i]);
1044 return FALSE; /* not a valid hex digit */
1045 bytevalue |= (guint8) hexvalue;
1046 buf[byte] = bytevalue;