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