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_PACKET_LEN 16384
166 #define ISERIES_MAX_TRACE_LEN 99999999
167 #define ISERIES_PKT_ALLOC_SIZE (pkt_len*2)+1
168 #define ISERIES_FORMAT_ASCII 1
169 #define ISERIES_FORMAT_UNICODE 2
172 * Magic strings - "COMMUNICATIONS TRACE", in ASCII and little-endian UCS-2.
174 static const char iseries_hdr_magic_ascii[] = {
181 static const char iseries_hdr_magic_le_ucs_2[] = {
182 'C', 0x0, 'O', 0x0, 'M', 0x0, 'M', 0x0,
183 'U', 0x0, 'N', 0x0, 'I', 0x0, 'C', 0x0,
184 'A', 0x0, 'T', 0x0, 'I', 0x0, 'O', 0x0,
185 'N', 0x0, 'S', 0x0, ' ', 0x0, 'T', 0x0,
186 'R', 0x0, 'A', 0x0, 'C', 0x0, 'E', 0x0
190 gboolean have_date; /* TRUE if we found a capture start date */
191 int year, month, day; /* The start date */
192 int format; /* Trace format type */
195 static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
196 gint64 *data_offset);
197 static gboolean iseries_seek_read (wtap * wth, gint64 seek_off,
198 struct wtap_pkthdr *phdr,
199 Buffer * buf, int *err, gchar ** err_info);
200 static gboolean iseries_check_file_type (wtap * wth, int *err, gchar **err_info,
202 static gint64 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info);
203 static gboolean iseries_parse_packet (wtap * wth, FILE_T fh,
204 struct wtap_pkthdr *phdr,
205 Buffer * buf, int *err, gchar ** err_info);
206 static int iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes);
207 static gboolean iseries_parse_hex_string (const char * ascii, guint8 * buf,
211 * XXX - it would probably be cleaner to use a UCS-2 flavor of file_gets(),
212 * rather than file_gets(), if we're reading a UCS-2 file.
215 iseries_open (wtap * wth, int *err, gchar ** err_info)
218 char magic[ISERIES_LINE_LENGTH];
221 * Check that file starts with a valid iSeries COMMS TRACE header
222 * by scanning for it in the first line
224 if (!wtap_read_bytes (wth->fh, &magic, sizeof magic, err, err_info))
226 if (*err != WTAP_ERR_SHORT_READ)
227 return WTAP_OPEN_ERROR;
228 return WTAP_OPEN_NOT_MINE;
232 * Check if this is a little-endian UCS-2 Unicode formatted file by scanning
233 * for the magic string
236 while ((unsigned int)offset < (ISERIES_LINE_LENGTH - (sizeof iseries_hdr_magic_le_ucs_2)))
238 if (memcmp (magic + offset, iseries_hdr_magic_le_ucs_2, sizeof iseries_hdr_magic_le_ucs_2) == 0) {
239 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
241 return WTAP_OPEN_ERROR;
244 * Do some basic sanity checking to ensure we can handle the
245 * contents of this trace
247 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE))
250 return WTAP_OPEN_NOT_MINE;
252 return WTAP_OPEN_ERROR;
255 wth->file_encap = WTAP_ENCAP_ETHERNET;
256 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
257 wth->snapshot_length = 0;
258 wth->subtype_read = iseries_read;
259 wth->subtype_seek_read = iseries_seek_read;
260 wth->file_tsprec = WTAP_TSPREC_USEC;
262 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
264 return WTAP_OPEN_ERROR;
266 return WTAP_OPEN_MINE;
272 * Check if this is a ASCII formatted file by scanning for the magic string
275 while ((unsigned int)offset < (ISERIES_LINE_LENGTH - sizeof iseries_hdr_magic_ascii))
277 if (memcmp (magic + offset, iseries_hdr_magic_ascii, sizeof iseries_hdr_magic_ascii) == 0)
279 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
281 return WTAP_OPEN_ERROR;
284 * Do some basic sanity checking to ensure we can handle the
285 * contents of this trace
287 if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII))
290 return WTAP_OPEN_NOT_MINE;
292 return WTAP_OPEN_ERROR;
295 wth->file_encap = WTAP_ENCAP_ETHERNET;
296 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
297 wth->snapshot_length = 0;
298 wth->subtype_read = iseries_read;
299 wth->subtype_seek_read = iseries_seek_read;
300 wth->file_tsprec = WTAP_TSPREC_USEC;
302 if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
304 return WTAP_OPEN_ERROR;
306 return WTAP_OPEN_MINE;
311 /* Neither ASCII or UNICODE so not supported */
312 return WTAP_OPEN_NOT_MINE;
316 * Do some basic sanity checking to ensure we can handle the
317 * contents of this trace by checking the header page for
318 * requisit requirements and additional information.
321 iseries_check_file_type (wtap * wth, int *err, gchar **err_info, int format)
323 gboolean is_iseries = FALSE;
325 int num_items_scanned;
326 char buf[ISERIES_LINE_LENGTH], protocol[9];
329 /* Save trace format for passing between packets */
330 iseries = (iseries_t *) g_malloc (sizeof (iseries_t));
331 iseries->have_date = FALSE;
332 iseries->format = format;
334 for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
336 memset(buf, 0x0, sizeof(buf));
337 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
340 *err = file_error (wth->fh, err_info);
341 if (*err == WTAP_ERR_SHORT_READ)
347 * Check that we are dealing with an ETHERNET trace
349 if (iseries->format == ISERIES_FORMAT_UNICODE)
351 iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
353 ascii_strup_inplace (buf);
354 num_items_scanned = sscanf (buf,
355 "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s",
357 if (num_items_scanned == 1)
359 if (memcmp (protocol, "ETHERNET", 8) == 0)
367 * The header is the only place where the date part of the timestamp is held, so
368 * extract it here and store for all packets to access
370 num_items_scanned = sscanf (buf,
371 "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d",
372 &iseries->month, &iseries->day,
374 if (num_items_scanned == 3)
376 iseries->have_date = TRUE;
381 wth->priv = (void *) iseries;
389 * Find the next packet and parse it; called from wtap_read().
392 iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
397 * Locate the next packet
399 offset = iseries_seek_next_packet (wth, err, err_info);
402 *data_offset = offset;
405 * Parse the packet and extract the various fields
407 return iseries_parse_packet (wth, wth->fh, &wth->phdr, wth->frame_buffer,
412 * Seeks to the beginning of the next packet, and returns the
413 * byte offset. Returns -1 on failure or EOF; on EOF, sets
414 * *err to 0, and, on failure, sets *err to the error and *err_info
415 * to null or an additional error string.
418 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info)
420 iseries_t *iseries = (iseries_t *)wth->priv;
421 char buf[ISERIES_LINE_LENGTH],type[5];
422 int line, num_items_scanned;
426 for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
428 if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
431 *err = file_error (wth->fh, err_info);
434 /* Convert UNICODE to ASCII if required and determine */
435 /* the number of bytes to rewind to beginning of record. */
436 if (iseries->format == ISERIES_FORMAT_UNICODE)
438 /* buflen is #bytes to 1st 0x0A */
439 buflen = iseries_UNICODE_to_ASCII ((guint8 *) buf, ISERIES_LINE_LENGTH);
443 /* Else buflen is just length of the ASCII string */
444 buflen = (long) strlen (buf);
446 ascii_strup_inplace (buf);
447 /* If packet header found return the offset */
450 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
451 if (num_items_scanned == 1)
453 /* Rewind to beginning of line */
454 cur_off = file_tell (wth->fh);
457 *err = file_error (wth->fh, err_info);
460 if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
464 return cur_off - buflen;
468 *err = WTAP_ERR_BAD_FILE;
470 g_strdup_printf ("iseries: next packet header not found within %d lines",
471 ISERIES_MAX_TRACE_LEN);
476 * Read packets in random-access fashion
479 iseries_seek_read (wtap * wth, gint64 seek_off, struct wtap_pkthdr *phdr,
480 Buffer * buf, int *err, gchar ** err_info)
483 /* seek to packet location */
484 if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
488 * Parse the packet and extract the various fields
490 return iseries_parse_packet (wth, wth->random_fh, phdr, buf,
495 append_hex_digits(char *ascii_buf, int ascii_offset, int max_offset,
496 char *data, int *err, gchar **err_info)
498 int in_offset, out_offset;
501 gboolean overflow = FALSE;
504 out_offset = ascii_offset;
508 * Process a block of up to 16 hex digits.
509 * The block is terminated early by an end-of-line indication (NUL,
510 * CR, or LF), by a space (which terminates the last block of the
511 * data we're processing), or by a "*", which introduces the ASCII representation
513 * All characters in the block must be upper-case hex digits;
514 * there might or might not be a space *after* a block, but, if so,
515 * that will be skipped over after the block is processed.
517 for (i = 0; i < 16; i++, in_offset++)
520 * If we see an end-of-line indication, or an early-end-of-block
521 * indication (space), we're done. (Only the last block ends
524 c = data[in_offset] & 0xFF;
525 if (c == '\0' || c == ' ' || c == '*' || c == '\r' || c == '\n')
529 if (!g_ascii_isxdigit(c) || g_ascii_islower(c))
532 * Not a hex digit, or a lower-case hex digit.
533 * Treat this as an indication that the line isn't a data
534 * line, so we just ignore it.
536 * XXX - do so only for continuation lines; treat non-hex-digit
537 * characters as errors for other lines?
539 return ascii_offset; /* pretend we appended nothing */
541 if (out_offset >= max_offset)
545 ascii_buf[out_offset] = c;
550 * Skip blanks, if any.
552 for (; (data[in_offset] & 0xFF) == ' '; in_offset++)
557 * If we processed an *odd* number of hex digits, report an error.
561 *err = WTAP_ERR_BAD_FILE;
562 *err_info = g_strdup("iseries: odd number of hex digits in a line");
567 *err = WTAP_ERR_BAD_FILE;
568 *err_info = g_strdup("iseries: more packet data than the packet length indicated");
574 /* Parses a packet. */
576 iseries_parse_packet (wtap * wth, FILE_T fh, struct wtap_pkthdr *phdr,
577 Buffer *buf, int *err, gchar **err_info)
579 iseries_t *iseries = (iseries_t *)wth->priv;
581 gboolean isValid, isCurrentPacket;
582 int num_items_scanned, line, pktline, buflen;
583 int pkt_len, pktnum, hr, min, sec;
584 char direction[2], destmac[13], srcmac[13], type[5], csec[9+1];
585 char data[ISERIES_LINE_LENGTH * 2];
592 * Check for packet headers in first 3 lines this should handle page breaks
593 * situations and the header lines output at each page throw and ensure we
594 * read both the captured and packet lengths.
597 for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++)
599 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
601 *err = file_error (fh, err_info);
604 /* Convert UNICODE data to ASCII */
605 if (iseries->format == ISERIES_FORMAT_UNICODE)
607 iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
609 ascii_strup_inplace (data);
612 "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9[0-9]%*[ \n\t]"
613 "%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s",
614 &pktnum, direction, &pkt_len, &hr, &min, &sec, csec, destmac,
616 if (num_items_scanned == 10)
620 *err = WTAP_ERR_BAD_FILE;
621 *err_info = g_strdup ("iseries: packet header has a negative packet number");
627 *err = WTAP_ERR_BAD_FILE;
628 *err_info = g_strdup ("iseries: packet header has a negative packet length");
634 *err = WTAP_ERR_BAD_FILE;
635 *err_info = g_strdup ("iseries: packet header has a negative hour in the time stamp");
641 *err = WTAP_ERR_BAD_FILE;
642 *err_info = g_strdup ("iseries: packet header has a hour in the time stamp greater than 23");
648 *err = WTAP_ERR_BAD_FILE;
649 *err_info = g_strdup ("iseries: packet header has a negative minute in the time stamp");
655 *err = WTAP_ERR_BAD_FILE;
656 *err_info = g_strdup ("iseries: packet header has a minute in the time stamp greater than 59");
662 *err = WTAP_ERR_BAD_FILE;
663 *err_info = g_strdup ("iseries: packet header has a negative second in the time stamp");
668 * Yes, 60, even though the time-conversion routines on most OSes
669 * might not handle leap seconds.
673 *err = WTAP_ERR_BAD_FILE;
674 *err_info = g_strdup ("iseries: packet header has a second in the time stamp greater than 60");
678 /* OK! We found the packet header line */
681 * XXX - The Capture length returned by the iSeries trace doesn't
682 * seem to include the Ethernet header, so we add its length here.
690 * If no packet header found we exit at this point and inform the user.
694 *err = WTAP_ERR_BAD_FILE;
695 *err_info = g_strdup ("iseries: packet header isn't valid");
699 phdr->rec_type = REC_TYPE_PACKET;
700 phdr->presence_flags = WTAP_HAS_CAP_LEN;
703 * If we have Wiretap Header then populate it here
705 * Timer resolution on the iSeries is hardware dependent. We determine
706 * the resolution based on how many digits we see.
708 if (iseries->have_date)
710 phdr->presence_flags |= WTAP_HAS_TS;
711 tm.tm_year = 100 + iseries->year;
712 tm.tm_mon = iseries->month - 1;
713 tm.tm_mday = iseries->day;
718 phdr->ts.secs = mktime (&tm);
719 csec[sizeof(csec) - 1] = '\0';
720 switch (strlen(csec))
726 phdr->ts.nsecs = atoi(csec) * 100000000;
729 phdr->ts.nsecs = atoi(csec) * 10000000;
732 phdr->ts.nsecs = atoi(csec) * 1000000;
735 phdr->ts.nsecs = atoi(csec) * 100000;
738 phdr->ts.nsecs = atoi(csec) * 10000;
741 phdr->ts.nsecs = atoi(csec) * 1000;
744 phdr->ts.nsecs = atoi(csec) * 100;
747 phdr->ts.nsecs = atoi(csec) * 10;
750 phdr->ts.nsecs = atoi(csec);
756 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
757 phdr->pseudo_header.eth.fcs_len = -1;
759 ascii_buf = (char *)g_malloc (ISERIES_PKT_ALLOC_SIZE);
760 g_snprintf(ascii_buf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s", destmac, srcmac, type);
761 ascii_offset = 14*2; /* 14-byte Ethernet header, 2 characters per byte */
764 * Start reading packet contents
766 isCurrentPacket = TRUE;
768 /* loop through packet lines and breakout when the next packet header is read */
770 while (isCurrentPacket)
773 /* Read the next line */
774 if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
776 *err = file_error (fh, err_info);
779 /* Hit the EOF without an error */
785 /* Convert UNICODE data to ASCII and determine line length */
786 if (iseries->format == ISERIES_FORMAT_UNICODE)
788 buflen = iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
792 /* Else bytes to rewind is just length of ASCII string */
793 buflen = (int) strlen (data);
797 * Skip leading white space.
799 for (offset = 0; g_ascii_isspace(data[offset]); offset++)
803 * The higher-level header information starts at an offset of
804 * 22 characters. The header tags are 14 characters long.
806 * XXX - for IPv6, if the next header isn't the last header,
807 * the intermediate headers do *NOT* appear to be shown in
808 * the dump file *at all*, so the packet *cannot* be
813 if (strncmp(data + 22, "IP Header : ", 14) == 0 ||
814 strncmp(data + 22, "IPv6 Header: ", 14) == 0 ||
815 strncmp(data + 22, "ARP Header : ", 14) == 0 ||
816 strncmp(data + 22, "TCP Header : ", 14) == 0 ||
817 strncmp(data + 22, "UDP Header : ", 14) == 0 ||
818 strncmp(data + 22, "ICMP Header: ", 14) == 0 ||
819 strncmp(data + 22, "ICMPv6 Hdr: ", 14) == 0 ||
820 strncmp(data + 22, "Option Hdr: ", 14) == 0)
822 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
823 ISERIES_PKT_ALLOC_SIZE - 1,
826 if (ascii_offset == -1)
836 * Is this a data line?
838 * The "Data" starts at an offset of 8.
842 if (strncmp(data + 9, "Data . . . . . : ", 18) == 0)
844 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
845 ISERIES_PKT_ALLOC_SIZE - 1,
848 if (ascii_offset == -1)
858 * Is this a continuation of a previous header or data line?
859 * That's blanks followed by hex digits; first try the
860 * "no column separators" form.
862 * Continuations of header lines begin at an offset of 36;
863 * continuations of data lines begin at an offset of 27.
865 if (offset == 36 || offset == 27)
867 ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
868 ISERIES_PKT_ALLOC_SIZE - 1,
871 if (ascii_offset == -1)
880 * If we see the identifier for the next packet then rewind and set
881 * isCurrentPacket FALSE
883 ascii_strup_inplace (data);
884 /* If packet header found return the offset */
887 "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
888 if ((num_items_scanned == 1) && pktline > 1)
890 isCurrentPacket = FALSE;
891 cur_off = file_tell( fh);
895 *err = file_error (fh, err_info);
898 if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
900 /* XXX: need to set err_info ?? */
905 ascii_buf[ascii_offset] = '\0';
908 * Make the captured length be the amount of bytes we've read (which
909 * is half the number of characters of hex dump we have).
911 * XXX - this can happen for IPv6 packets if the next header isn't the
914 phdr->caplen = ((guint32) strlen (ascii_buf))/2;
916 /* Make sure we have enough room for the packet. */
917 ws_buffer_assure_space (buf, ISERIES_MAX_PACKET_LEN);
918 /* Convert ascii data to binary and return in the frame buffer */
919 iseries_parse_hex_string (ascii_buf, ws_buffer_start_ptr (buf), strlen (ascii_buf));
921 /* free buffer allocs and return */
932 * Simple routine to convert an UNICODE buffer to ASCII
934 * XXX - This may be possible with iconv or similar
937 iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
944 for (i = 0; i < bytes; i++)
963 * Simple routine to convert an ASCII hex string to binary data
964 * Requires ASCII hex data and buffer to populate with binary data
967 iseries_parse_hex_string (const char * ascii, guint8 * buf, size_t len)
975 for (i = 0; i < len; i++)
977 hexvalue = g_ascii_xdigit_value(ascii[i]);
980 return FALSE; /* not a valid hex digit */
981 bytevalue = (guint8)(hexvalue << 4);
983 return FALSE; /* only one hex digit of the byte is present */
984 hexvalue = g_ascii_xdigit_value(ascii[i]);
986 return FALSE; /* not a valid hex digit */
987 bytevalue |= (guint8) hexvalue;
988 buf[byte] = bytevalue;
995 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1000 * indent-tabs-mode: nil
1003 * vi: set shiftwidth=2 tabstop=8 expandtab:
1004 * :indentSize=2:tabSize=8:noTabs=true: