Match "%4x" with an unsigned value in sscanf.
[metze/wireshark/wip.git] / wiretap / iseries.c
1 /* iseries.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 2005 by Martin Warnes <Martin_Warnes@Stercomm.com>
7  *
8  * Based on toshiba.c and vms.c
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 /*
26  * This module will read the contents of the iSeries (OS/400) Communication trace
27  * Both ASCII & Unicode formatted traces are supported.
28  *
29  * iSeries Comms traces consist of a header page and a subsequent number of packet records
30  *
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:
33  *
34  * 1. Object protocol = ETHERNET (Default)
35  * 2. ASCII or UNICODE file formats.
36  *
37  * The above can be acheived by passing option ASCII(*YES) with the trace command
38  *
39  */
40
41 /* iSeries header page
42
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
47                                                  3=Network server
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
69 */
70
71 /* iSeries formatted packet records consist of a header line identifying the packet number,direction,size,
72  * timestamp,source/destination MAC addresses and packet type.
73  *
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.
76  *
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.
79  *
80  * Information from the header line, IP header, TCP header and if available data lines are extracted
81  * by the module for displaying.
82  *
83  *
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
91                       IP Options :  NONE
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*.*.   *
99 */
100
101 /* iSeries unformatted packet record consist of the same header record as the formatted trace but all
102  * other records are simply unformatted data containing IP, TCP and packet data combined.
103  *
104  Record       Data    Record           Controller  Destination   Source        Frame            Number  Number    Poll/
105  Number  S/R  Length  Timer            Name        MAC Address   MAC Address   Format  Command  Sent    Received  Final  DSAP  SSAP
106  ------  ---  ------  ---------------  ----------  ------------  ------------  ------  -------  ------  --------  -----  ----  ----
107       1   R       64  12:19:29.97108               000629ECF48E  0006D78E23C2   ETHV2   Type: 0800
108          Data . . . . . :  4500003C27954000 3A06CE3D9797440F  0A5964EAC4F50554 58C9915500000000   *E..<'*@.:.*=**D..YD***.TX**U....*
109                            A00216D06A200000 020405B40402080A  1104B6C000000000 010303000B443BF1   **..*J .....*......**.........D;**
110 */
111
112 #ifdef HAVE_CONFIG_H
113 #include "config.h"
114 #endif
115 #include "wtap-int.h"
116 #include "buffer.h"
117 #include "iseries.h"
118 #include "file_wrappers.h"
119
120 #include <stdio.h>
121 #include <stdlib.h>
122 #include <string.h>
123 #include <ctype.h>
124 #include <errno.h>
125
126 #define ISERIES_HDR_MAGIC_STR   " COMMUNICATIONS TRACE"
127 #define ISERIES_HDR_MAGIC_LEN   21
128 #define ISERIES_PKT_MAGIC_STR   "ETHV2"
129 #define ISERIES_PKT_MAGIC_LEN   5
130 #define ISERIES_LINE_LENGTH     270
131 #define ISERIES_HDR_LINES_TO_CHECK  50
132 #define ISERIES_PKT_LINES_TO_CHECK  4
133 #define ISERIES_MAX_PACKET_LEN  16384
134 #define ISERIES_MAX_TRACE_LEN   99999999
135 #define ISERIES_PKT_ALLOC_SIZE (cap_len*2)+1
136 #define ISERIES_FORMAT_ASCII    1
137 #define ISERIES_FORMAT_UNICODE  2
138
139 static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
140                               gint64 *data_offset);
141 static gboolean iseries_seek_read (wtap * wth, gint64 seek_off,
142                                    union wtap_pseudo_header *pseudo_header,
143                                    guint8 * pd, int len, int *err,
144                                    gchar ** err_info);
145 static gboolean iseries_check_file_type (wtap * wth, int *err, int format);
146 static gint64 iseries_seek_next_packet (wtap * wth, int *err);
147 static int iseries_parse_packet (wtap * wth, FILE_T fh,
148                                  union wtap_pseudo_header *pseudo_header,
149                                  guint8 * pd, int *err, gchar ** err_info);
150 static int iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes);
151 static gboolean iseries_parse_hex_string (guint8 * ascii, guint8 * buf,
152                                           int len);
153
154 int
155 iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
156 {
157   int bytes_read;
158   char magic[ISERIES_HDR_MAGIC_LEN];
159   /* UNICODE identification */
160   char unicodemagic[ISERIES_HDR_MAGIC_LEN] =
161     { '\xFF', '\xFE', '\x20', '\x00', '\x43', '\x00', '\x4F', '\x00', '\x4D',
162     '\x00', '\x4D', '\x00', '\x55', '\x00', '\x4E', '\x00', '\x49', '\x00',
163     '\x43', '\x00', '\x41'
164   };
165
166   /*
167    * Check that file starts with a valid iSeries COMMS TRACE header
168    */
169   errno = WTAP_ERR_CANT_READ;
170   bytes_read = file_read (&magic, 1, sizeof magic, wth->fh);
171   if (bytes_read != sizeof magic)
172     {
173       *err = file_error (wth->fh);
174       if (*err != 0)
175         return -1;
176       return 0;
177     }
178
179   /* Check if this is an ASCII formatted file */
180   if (memcmp (magic, ISERIES_HDR_MAGIC_STR, ISERIES_HDR_MAGIC_LEN) == 0)
181     {
182       if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
183         {
184           return 0;
185         }
186       /*
187        * Do some basic sanity checking to ensure we can handle the
188        * contents of this trace
189        */
190       if (!iseries_check_file_type (wth, err, ISERIES_FORMAT_ASCII))
191         {
192           if (*err == 0)
193             return 0;
194           else
195             return -1;
196         }
197       wth->data_offset = 0;
198       wth->file_encap = WTAP_ENCAP_PER_PACKET;
199       wth->file_type = WTAP_FILE_ISERIES;
200       wth->snapshot_length = 0;
201       wth->subtype_read = iseries_read;
202       wth->subtype_seek_read = iseries_seek_read;
203       wth->tsprecision = WTAP_FILE_TSPREC_USEC;
204       if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
205         {
206           return 0;
207         }
208       return 1;
209     }
210
211   /* Check if this is a UNICODE formatted file */
212   if (memcmp (magic, unicodemagic, ISERIES_HDR_MAGIC_LEN) == 0)
213     {
214       if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
215         {
216           return 0;
217         }
218       /*
219        * Do some basic sanity checking to ensure we can handle the
220        * contents of this trace
221        */
222       if (!iseries_check_file_type (wth, err, ISERIES_FORMAT_UNICODE))
223         {
224           if (*err == 0)
225             return 0;
226           else
227             return -1;
228         }
229       wth->data_offset = 0;
230       wth->file_encap = WTAP_ENCAP_PER_PACKET;
231       wth->file_type = WTAP_FILE_ISERIES_UNICODE;
232       wth->snapshot_length = 0;
233       wth->subtype_read = iseries_read;
234       wth->subtype_seek_read = iseries_seek_read;
235       wth->tsprecision = WTAP_FILE_TSPREC_USEC;
236       if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
237         {
238           return 0;
239         }
240       return 1;
241     }
242
243   /* Neither ASCII or UNICODE so not supported */
244   return 0;
245 }
246
247 /*
248  * Do some basic sanity checking to ensure we can handle the
249  * contents of this trace by checking the header page for
250  * requisit requirements and additional information.
251  */
252 static gboolean
253 iseries_check_file_type (wtap * wth, int *err, int format)
254 {
255   guint line;
256   int num_items_scanned;
257   char buf[ISERIES_LINE_LENGTH], protocol[9], tcpformat[2];
258   guint8 *sdate;
259
260   /* Save trace format for passing between packets */
261   sdate = g_malloc (10);
262   wth->capture.iseries = g_malloc (sizeof (iseries_t));
263   wth->capture.iseries->sdate = NULL;
264   wth->capture.iseries->format = format;
265   wth->capture.iseries->tcp_formatted = FALSE;
266
267   for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
268     {
269       if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) != NULL)
270         {
271           /*
272            * Check that we are dealing with an ETHERNET trace
273            */
274           if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
275             {
276               iseries_UNICODE_to_ASCII (buf, ISERIES_LINE_LENGTH);
277             }
278           g_strup(buf);
279           num_items_scanned = sscanf (buf,
280                                       "   OBJECT PROTOCOL  . . . . . . :  %8s",
281                                       protocol);
282           if (num_items_scanned == 1)
283             {
284               if (memcmp (protocol, "ETHERNET", 8) != 0)
285                 return FALSE;
286             }
287
288           /*
289            * Determine if the data has been formatted or not
290            */
291           num_items_scanned = sscanf (buf,
292                                       "   FORMAT TCP/IP DATA ONLY  . . :  %1s",
293                                       tcpformat);
294           if (num_items_scanned == 1)
295             {
296               if (strncmp (tcpformat, "Y", 1) == 0)
297                 {
298                   wth->capture.iseries->tcp_formatted = TRUE;
299                 }
300               else
301                 {
302                   wth->capture.iseries->tcp_formatted = FALSE;
303                 }
304             }
305
306           /*
307            * The header is the only place where the date part of the timestamp is held, so
308            * extract it here and store for all packets to access
309            */
310           num_items_scanned = sscanf (buf,
311                                       "   START DATE/TIME  . . . . . . :  %8s",
312                                       sdate);
313           if (num_items_scanned == 1)
314             {
315               wth->capture.iseries->sdate = sdate;
316             }
317
318         }
319       else
320         {
321           /* EOF or error. */
322           if (file_eof (wth->fh))
323             *err = 0;
324           else
325             *err = file_error (wth->fh);
326           return FALSE;
327         }
328     }
329   *err = 0;
330   return TRUE;
331 }
332
333 /*
334  * Find the next packet and parse it; called from wtap_read().
335  */
336 static gboolean
337 iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
338 {
339   gint64 offset;
340   int pkt_len;
341
342   /*
343    * Locate the next packet
344    */
345   offset = iseries_seek_next_packet (wth, err);
346   if (offset < 1)
347     return FALSE;
348
349   /*
350    * Parse the packet and extract the various fields
351    */
352   pkt_len =
353     iseries_parse_packet (wth, wth->fh, &wth->pseudo_header, NULL, err,
354                           err_info);
355   if (pkt_len == -1)
356     return FALSE;
357
358   wth->data_offset = offset;
359   *data_offset = offset;
360   return TRUE;
361 }
362
363 /*
364  * Seeks to the beginning of the next packet, and returns the
365  * byte offset.  Returns -1 on failure, and sets "*err" to the error.
366  */
367 static gint64
368 iseries_seek_next_packet (wtap * wth, int *err)
369 {
370   char buf[ISERIES_LINE_LENGTH];
371   int line;
372   gint64 cur_off;
373   long buflen;
374
375   /*
376    * Seeks to the beginning of the next packet, and returns the
377    * byte offset.  Returns -1 on failure, and sets "*err" to the error.
378    */
379   for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
380     {
381       if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) != NULL)
382         {
383
384           /* Convert UNICODE to ASCII if required and determine    */
385           /* the number of bytes to rewind to beginning of record. */
386           if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
387             {
388               /* buflen is #bytes to 1st 0x0A */
389               buflen = iseries_UNICODE_to_ASCII (buf, ISERIES_LINE_LENGTH);
390             }
391           else
392             {
393               /* Else buflen is just length of the ASCII string */
394               buflen = strlen (buf);
395             }
396           /* If packet header found return the offset */
397           if (strncmp (buf + 80, ISERIES_PKT_MAGIC_STR, ISERIES_PKT_MAGIC_LEN)
398               == 0)
399             {
400               /* Rewind to beginning of line */
401               cur_off = file_tell (wth->fh);
402               if (cur_off == -1)
403                 {
404                   *err = file_error (wth->fh);
405                   return -1;
406                 }
407               if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
408                 {
409                   return -1;
410                 }
411               return cur_off - buflen;
412             }
413         }
414       /* Otherwise we got an error or reached EOF */
415       else
416         {
417           if (file_eof (wth->fh))
418             {
419               *err = 0;
420             }
421           else
422             {
423               /* We (presumably) got an error (there's no equivalent to "ferror()"
424                  in zlib, alas, so we don't have a wrapper to check for an error). */
425               *err = file_error (wth->fh);
426             }
427           return -1;
428         }
429     }
430
431   return -1;
432 }
433
434 /*
435  * Read packets in random-access fashion
436  */
437 static gboolean
438 iseries_seek_read (wtap * wth, gint64 seek_off,
439                    union wtap_pseudo_header *pseudo_header, guint8 * pd,
440                    int len, int *err, gchar ** err_info)
441 {
442   int pkt_len;
443
444   /* seek to packet location */
445   if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
446     return FALSE;
447
448   /*
449    * Parse the packet and extract the various fields
450    */
451   pkt_len = iseries_parse_packet (wth, wth->random_fh, pseudo_header, pd,
452                                   err, err_info);
453
454   if (pkt_len != len)
455     {
456       if (pkt_len != -1)
457         {
458           *err = WTAP_ERR_BAD_RECORD;
459           *err_info =
460             g_strdup_printf
461             ("iseries: requested length %d doesn't match record length %d",
462              len, pkt_len);
463         }
464       return FALSE;
465     }
466   return TRUE;
467 }
468
469 /* Parses a packet. */
470 static int
471 iseries_parse_packet (wtap * wth, FILE_T fh,
472                       union wtap_pseudo_header *pseudo_header, guint8 * pd,
473                       int *err, gchar ** err_info)
474 {
475   gint64 cur_off;
476   gboolean isValid, isCurrentPacket, IPread, TCPread, isDATA;
477   int num_items_scanned, line, pktline, buflen;
478   guint32 pkt_len;
479   int cap_len, pktnum, month, day, year, hr, min, sec, csec;
480   char direction[2], destmac[13], srcmac[13], type[5], ipheader[41],
481     tcpheader[81];
482   char hex1[17], hex2[17], hex3[17], hex4[17];
483   char data[ISERIES_LINE_LENGTH * 2];
484   guint8 *buf, *asciibuf, *tcpdatabuf, *workbuf;
485   struct tm tm;
486
487   /*
488    * Check for packet headers in first 3 lines this should handle page breaks
489    * situations and the header lines output at each page throw and ensure we
490    * read both the captured and packet lengths.
491    */
492   isValid = FALSE;
493   for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++)
494     {
495       cur_off = file_tell (fh);
496       if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
497         {
498           *err = file_error (fh);
499           if (*err == 0)
500             {
501               *err = WTAP_ERR_SHORT_READ;
502             }
503           return -1;
504         }
505       /* Convert UNICODE data to ASCII */
506       if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
507         {
508           iseries_UNICODE_to_ASCII (data, ISERIES_LINE_LENGTH);
509         }
510       /* look for packet header */
511       num_items_scanned =
512         sscanf (data,
513                 "%6d   %1s   %6d  %d:%d:%d.%d               %12s  %12s  ETHV2   Type: %s",
514                 &pktnum, direction, &cap_len, &hr, &min, &sec, &csec, destmac,
515                 srcmac, type);
516       if (num_items_scanned == 10)
517         {
518           /* OK! We found the packet header line */
519           isValid = TRUE;
520           /*
521            * XXX - The Capture length returned by the iSeries trace doesn't seem to include the src/dest MAC
522            * addresses or the packet type. So we add them here.
523            */
524           cap_len += 14;
525           break;
526         }
527     }
528
529   /*
530    * If no packet header found we exit at this point and inform the user.
531    */
532   if (!isValid)
533     {
534       *err = WTAP_ERR_BAD_RECORD;
535       *err_info = g_strdup ("iseries: packet header isn't valid");
536       return -1;
537     }
538
539   /*
540    * If we have Wiretap Header then populate it here
541    *
542    * XXX - Timer resolution on the iSeries is hardware dependant, the value for csec may be
543    * different on other platforms though all the traces I've seen seem to show resolution
544    * to Milliseconds (i.e HH:MM:SS.nnnnn) or Nanoseconds (i.e HH:MM:SS.nnnnnn)
545    */
546   if (wth->capture.iseries->sdate)
547     {
548       num_items_scanned =
549         sscanf (wth->capture.iseries->sdate, "%d/%d/%d", &month, &day, &year);
550       tm.tm_year = 100 + year;
551       tm.tm_mon = month - 1;
552       tm.tm_mday = day;
553       tm.tm_hour = hr;
554       tm.tm_min = min;
555       tm.tm_sec = sec;
556       tm.tm_isdst = -1;
557       wth->phdr.ts.secs = mktime (&tm);
558       /* Handle Millisecond precision for timer */
559       if (csec > 99999)
560         {
561           wth->phdr.ts.nsecs = csec * 1000;
562         }
563       /* Handle Nanosecond precision for timer */
564       else
565         {
566           wth->phdr.ts.nsecs = csec * 10000;
567         }
568       wth->phdr.caplen = cap_len;
569       wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
570       pseudo_header->eth.fcs_len = -1;
571     }
572
573   /*
574    * Start Reading packet contents
575    */
576   isCurrentPacket = TRUE;
577   IPread = FALSE;
578   TCPread = FALSE;
579   isDATA = FALSE;
580   /*
581    * Allocate 2 work buffers to handle concatentation of the hex data block
582    */
583   tcpdatabuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
584   g_snprintf (tcpdatabuf, 1, "%s", "");
585   workbuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
586   g_snprintf (workbuf, 1, "%s", "");
587   /* loop through packet lines and breakout when the next packet header is read */
588   pktline = 0;
589   while (isCurrentPacket)
590     {
591       pktline++;
592       /* Read the next line */
593       if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
594         {
595           if (file_eof (fh))
596             {
597               break;
598             }
599           else
600             {
601               *err = file_error (fh);
602               if (*err == 0)
603                 {
604                   *err = WTAP_ERR_SHORT_READ;
605                 }
606               return -1;
607             }
608         }
609
610       /* Convert UNICODE data to ASCII and determine line length */
611       if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
612         {
613           buflen = iseries_UNICODE_to_ASCII (data, ISERIES_LINE_LENGTH);
614         }
615       else
616         {
617           /* Else bytes to rewind is just length of ASCII string */
618           buflen = strlen (data);
619         }
620
621       /* If this is a IP header hex string then set flag */
622       num_items_scanned = sscanf (data + 22, "IP Header  : %40s", ipheader);
623       if (num_items_scanned == 1)
624         {
625           IPread = TRUE;
626         }
627
628       /* If this is TCP header hex string then set flag */
629       num_items_scanned = sscanf (data + 22, "TCP Header : %80s", tcpheader);
630       if (num_items_scanned == 1)
631         {
632           TCPread = TRUE;
633         }
634
635       /*
636        * If there is data in the packet handle it here.
637        *
638        * The data header line will have the "Data . . " identifier, subsequent lines don't
639        */
640       num_items_scanned =
641         sscanf (data + 27, "%16[A-Z0-9] %16[A-Z0-9] %16[A-Z0-9] %16[A-Z0-9]",
642                 hex1, hex2, hex3, hex4);
643       if (num_items_scanned > 0)
644         {
645           isDATA = TRUE;
646           /*
647            * Scan the data line for data blocks, depending on the number of blocks scanned
648            * add them along with current tcpdata buffer to the work buffer and then copy
649            * work buffer to tcpdata buffer to continue building up tcpdata buffer to contain
650            * a single hex string.
651            */
652           switch (num_items_scanned)
653             {
654             case 1:
655               g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s", tcpdatabuf,
656                           hex1);
657               break;
658             case 2:
659               g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s",
660                           tcpdatabuf, hex1, hex2);
661               break;
662             case 3:
663               g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s",
664                           tcpdatabuf, hex1, hex2, hex3);
665               break;
666             default:
667               g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s",
668                           tcpdatabuf, hex1, hex2, hex3, hex4);
669             }
670           memcpy (tcpdatabuf, workbuf, ISERIES_PKT_ALLOC_SIZE);
671         }
672
673       /*
674        * If we see the identifier for the next packet then rewind and set
675        * isCurrentPacket FALSE
676        */
677       if ((strncmp (data + 80, ISERIES_PKT_MAGIC_STR, ISERIES_PKT_MAGIC_LEN)
678            == 0) && pktline > 1)
679         {
680           isCurrentPacket = FALSE;
681           cur_off = file_tell (fh);
682           if (cur_off == -1)
683             {
684               /* Error. */
685               *err = file_error (fh);
686               return -1;
687             }
688           if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
689             {
690               return -1;
691             }
692         }
693     }
694
695   /*
696    * For a formated trace ensure we have read at least the IP and TCP headers otherwise
697    * exit and pass error message to user.
698    */
699   if (wth->capture.iseries->tcp_formatted)
700     {
701       if (!IPread)
702         {
703           *err = WTAP_ERR_BAD_RECORD;
704           *err_info = g_strdup ("iseries: IP header isn't valid");
705           return -1;
706         }
707       if (!TCPread)
708         {
709           *err = WTAP_ERR_BAD_RECORD;
710           *err_info = g_strdup ("iseries: TCP header isn't valid");
711           return -1;
712         }
713     }
714
715   /*
716    * Create a buffer to hold all the ASCII Hex data and populate with all the
717    * extracted data.
718    */
719   asciibuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
720   if (isDATA)
721     {
722       /* packet contained data */
723       if (wth->capture.iseries->tcp_formatted)
724         {
725           /* build string for formatted fields */
726           g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s%s",
727                       destmac, srcmac, type, ipheader, tcpheader, tcpdatabuf);
728         }
729       else
730         {
731           /* build string for unformatted data fields */
732           g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s", destmac,
733                       srcmac, type, tcpdatabuf);
734         }
735     }
736   else
737     {
738       /* No data in the packet */
739       g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s", destmac,
740                   srcmac, type, ipheader, tcpheader);
741     }
742
743   /*
744    * Extract the packet length from the actual IP header; this may
745    * differ from the capture length reported by the formatted trace.
746    * Note: if the entire Ethernet packet is present, but the IP
747    * packet is less than 46 bytes long, there will be padding, and
748    * the length in the IP header won't include the padding; if
749    * the packet length is less than the captured length, set the
750    * packet length to the captured length.
751    */
752   num_items_scanned = sscanf (asciibuf + 32, "%4x", &pkt_len);
753   wth->phdr.len = pkt_len + 14;
754   if (wth->phdr.caplen > wth->phdr.len)
755     wth->phdr.len = wth->phdr.caplen;
756
757   /* Make sure we have enough room for the packet, only create buffer if none supplied */
758   if (pd == NULL)
759     {
760       buffer_assure_space (wth->frame_buffer, ISERIES_MAX_PACKET_LEN);
761       buf = buffer_start_ptr (wth->frame_buffer);
762       /* Convert ascii data to binary and return in the frame buffer */
763       iseries_parse_hex_string (asciibuf, buf, strlen (asciibuf));
764     }
765   else
766     {
767       /* Convert ascii data to binary and return in the frame buffer */
768       iseries_parse_hex_string (asciibuf, pd, strlen (asciibuf));
769     }
770
771   /* free buffers allocs and return */
772   *err = 0;
773   free (asciibuf);
774   free (tcpdatabuf);
775   free (workbuf);
776   return wth->phdr.len;
777 }
778
779 /*
780  * Simple routine to convert an UNICODE buffer to ASCII
781  *
782  * XXX - This may be possible with iconv or similar
783  */
784 static int
785 iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
786 {
787   guint i;
788   guint8 *bufptr;
789   bufptr = buf;
790
791   for (i = 0; i < bytes; i++)
792     {
793       switch (buf[i])
794         {
795         case 0xFE:
796         case 0xFF:
797         case 0x00:
798           break;
799         default:
800           *bufptr = buf[i];
801           bufptr++;
802         }
803       if (buf[i] == 0x0A)
804         return i;
805     }
806   return i;
807 }
808
809 /*
810  * Simple routine to convert an ASCII hex string to binary data
811  * Requires ASCII hex data and buffer to populate with binary data
812  */
813 static gboolean
814 iseries_parse_hex_string (guint8 * ascii, guint8 * buf, int len)
815 {
816   int i, byte;
817   char hexvalue[3] = { 0, 0, 0 };
818
819   byte = 0;
820   for (i = 0; i < len; i++)
821     {
822       hexvalue[0] = ascii[i];
823       i++;
824       hexvalue[1] = ascii[i];
825       buf[byte] = (guint8) strtoul (hexvalue, NULL, 16);
826       byte++;
827     }
828   return TRUE;
829 }