From Joerg Mayer:
[metze/wireshark/wip.git] / wiretap / ngsniffer.c
1 /* ngsniffer.c
2  *
3  * $Id: ngsniffer.c,v 1.84 2002/07/29 06:09:59 guy Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  * 
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.
12  * 
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.
17  * 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 /* The code in ngsniffer.c that decodes the time fields for each packet in the
24  * Sniffer trace originally came from code from TCPVIEW:
25  *
26  * TCPVIEW
27  *
28  * Author:      Martin Hunt
29  *              Networks and Distributed Computing
30  *              Computing & Communications
31  *              University of Washington
32  *              Administration Building, AG-44
33  *              Seattle, WA  98195
34  *              Internet: martinh@cac.washington.edu
35  *
36  *
37  * Copyright 1992 by the University of Washington
38  *
39  * Permission to use, copy, modify, and distribute this software and its
40  * documentation for any purpose and without fee is hereby granted, provided
41  * that the above copyright notice appears in all copies and that both the
42  * above copyright notice and this permission notice appear in supporting
43  * documentation, and that the name of the University of Washington not be
44  * used in advertising or publicity pertaining to distribution of the software
45  * without specific, written prior permission.  This software is made
46  * available "as is", and
47  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
48  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
49  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
50  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
51  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
52  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
53  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
54  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55  *
56  */
57 #ifdef HAVE_CONFIG_H
58 #include "config.h"
59 #endif
60
61 #include <stdlib.h>
62 #include <errno.h>
63 #include <string.h>
64 #include "wtap-int.h"
65 #include "file_wrappers.h"
66 #include "buffer.h"
67 #include "ngsniffer.h"
68
69 /* Magic number in Sniffer files. */
70 static const char ngsniffer_magic[] = {
71         'T', 'R', 'S', 'N', 'I', 'F', 'F', ' ', 'd', 'a', 't', 'a',
72         ' ', ' ', ' ', ' ', 0x1a
73 };
74
75 /*
76  * Sniffer record types.
77  */
78 #define REC_VERS        1       /* Version record (f_vers) */
79 #define REC_FRAME2      4       /* Frame data (f_frame2) */
80 #define REC_FRAME4      8       /* Frame data (f_frame4) */
81 #define REC_FRAME6      12      /* Frame data (f_frame6) (see below) */
82 #define REC_EOF         3       /* End-of-file record (no data follows) */
83 /*
84  * and now for some unknown header types
85  */
86 #define REC_HEADER1     6       /* Header containing serial numbers? */
87 #define REC_HEADER2     7       /* Header containing ??? */
88 #define REC_V2DESC      8       /* In version 2 sniffer traces contains
89                                  * infos about this capturing session.
90                                  * Collides with REC_FRAME4 */
91 #define REC_HEADER3     13      /* Retransmission counts? */
92 #define REC_HEADER4     14      /* ? */
93 #define REC_HEADER5     15      /* ? */
94 #define REC_HEADER6     16      /* More broadcast/retransmission counts? */
95 #define REC_HEADER7     17      /* ? */
96
97
98 /*
99  * Sniffer version record format.
100  */
101 struct vers_rec {
102         gint16  maj_vers;       /* major version number */
103         gint16  min_vers;       /* minor version number */
104         gint16  time;           /* DOS-format time */
105         gint16  date;           /* DOS-format date */
106         gint8   type;           /* what type of records follow */
107         guint8  network;        /* network type */
108         gint8   format;         /* format version */
109         guint8  timeunit;       /* timestamp units */
110         gint8   cmprs_vers;     /* compression version */
111         gint8   cmprs_level;    /* compression level */
112         gint16  rsvd[2];        /* reserved */
113 };
114
115 /*
116  * Sniffer type 2 data record format - followed by frame data.
117  */
118 struct frame2_rec {
119         guint16 time_low;       /* low part of time stamp */
120         guint16 time_med;       /* middle part of time stamp */
121         guint16 time_high;      /* high part of time stamp */
122         gint16  size;           /* number of bytes of data */
123         guint8  fs;             /* frame error status bits */
124         guint8  flags;          /* buffer flags */
125         gint16  true_size;      /* size of original frame, in bytes */
126         gint16  rsvd;           /* reserved */
127 };
128
129 /*
130  * Sniffer type 4 data record format - followed by frame data.
131  *
132  * XXX - the manual says that the "flags" field holds "buffer flags;
133  * BF_xxxx", but doesn't say what the BF_xxxx flags are.
134  *
135  * XXX - the manual also says there's an 8-byte "ATMTimeStamp" driver
136  * time stamp at the end of "ATMSaveInfo", but, from an ATM Sniffer capture
137  * file I've looked at, that appears not to be the case.
138  */
139
140 /*
141  * Fields from the AAL5 trailer for the frame, if it's an AAL5 frame
142  * rather than a cell.
143  */
144 typedef struct _ATM_AAL5Trailer {
145         guint16 aal5t_u2u;      /* user-to-user indicator */
146         guint16 aal5t_len;      /* length of the packet */
147         guint32 aal5t_chksum; /* checksum for AAL5 packet */
148 } ATM_AAL5Trailer;
149
150 typedef struct _ATMTimeStamp {
151         guint32 msw;    /* most significant word */
152         guint32 lsw;    /* least significant word */
153 } ATMTimeStamp;
154
155 typedef struct _ATMSaveInfo {
156         guint32 StatusWord;     /* status word from driver */
157         ATM_AAL5Trailer Trailer; /* AAL5 trailer */
158         guint8  AppTrafType;    /* traffic type */
159         guint8  AppHLType;      /* protocol type */
160         guint16 AppReserved;    /* reserved */
161         guint16 Vpi;            /* virtual path identifier */
162         guint16 Vci;            /* virtual circuit identifier */
163         guint16 channel;        /* link: 0 for DCE, 1 for DTE */
164         guint16 cells;          /* number of cells */
165         guint32 AppVal1;        /* type-dependent */
166         guint32 AppVal2;        /* type-dependent */
167 } ATMSaveInfo;
168
169 /*
170  * Bits in StatusWord.
171  */
172 #define SW_ERRMASK              0x0F    /* Error mask: */
173 #define SW_RX_FIFO_UNDERRUN     0x01    /* Receive FIFO underrun */
174 #define SW_RX_FIFO_OVERRUN      0x02    /* Receive FIFO overrun */
175 #define SW_RX_PKT_TOO_LONG      0x03    /* Received packet > max size */
176 #define SW_CRC_ERROR            0x04    /* CRC error */
177 #define SW_USER_ABORTED_RX      0x05    /* User aborted receive */
178 #define SW_BUF_LEN_TOO_LONG     0x06    /* buffer len > max buf */
179 #define SW_INTERNAL_T1_ERROR    0x07    /* Internal T1 error */
180 #define SW_RX_CHANNEL_DEACTIV8  0x08    /* Rx channel deactivate */
181
182 #define SW_ERROR                0x80    /* Error indicator */
183 #define SW_CONGESTION           0x40    /* Congestion indicator */
184 #define SW_CLP                  0x20    /* Cell loss priority indicator */
185 #define SW_RAW_CELL             0x100   /* RAW cell indicator */
186 #define SW_OAM_CELL             0x200   /* OAM cell indicator */
187
188 /*
189  * Bits in AppTrafType.
190  *
191  * For AAL types other than AAL5, the packet data is presumably for a
192  * single cell, not a reassembled frame, as the ATM Sniffer manual says
193  * it dosn't reassemble cells other than AAL5 cells.
194  */
195 #define ATT_AALTYPE             0x0F    /* AAL type: */
196 #define ATT_AAL_UNKNOWN         0x00    /* Unknown AAL */
197 #define ATT_AAL1                0x01    /* AAL1 */
198 #define ATT_AAL3_4              0x02    /* AAL3/4 */
199 #define ATT_AAL5                0x03    /* AAL5 */
200 #define ATT_AAL_USER            0x04    /* User AAL */
201 #define ATT_AAL_SIGNALLING      0x05    /* Signaling AAL */
202 #define ATT_OAMCELL             0x06    /* OAM cell */
203
204 #define ATT_HLTYPE              0xF0    /* Higher-layer type: */
205 #define ATT_HL_UNKNOWN          0x00    /* unknown */
206 #define ATT_HL_LLCMX            0x10    /* LLC multiplexed (probably RFC 1483) */
207 #define ATT_HL_VCMX             0x20    /* VC multiplexed (probably RFC 1483) */
208 #define ATT_HL_LANE             0x30    /* LAN Emulation */
209 #define ATT_HL_ILMI             0x40    /* ILMI */
210 #define ATT_HL_FRMR             0x50    /* Frame Relay */
211 #define ATT_HL_SPANS            0x60    /* FORE SPANS */
212 #define ATT_HL_IPSILON          0x70    /* Ipsilon */
213
214 /*
215  * Values for AppHLType; the interpretation depends on the ATT_HLTYPE
216  * bits in AppTrafType.
217  */
218 #define AHLT_UNKNOWN            0x0
219 #define AHLT_VCMX_802_3_FCS     0x1     /* VCMX: 802.3 FCS */
220 #define AHLT_LANE_LE_CTRL       0x1     /* LANE: LE Ctrl */
221 #define AHLT_IPSILON_FT0        0x1     /* Ipsilon: Flow Type 0 */
222 #define AHLT_VCMX_802_4_FCS     0x2     /* VCMX: 802.4 FCS */
223 #define AHLT_LANE_802_3         0x2     /* LANE: 802.3 */
224 #define AHLT_IPSILON_FT1        0x2     /* Ipsilon: Flow Type 1 */
225 #define AHLT_VCMX_802_5_FCS     0x3     /* VCMX: 802.5 FCS */
226 #define AHLT_LANE_802_5         0x3     /* LANE: 802.5 */
227 #define AHLT_IPSILON_FT2        0x3     /* Ipsilon: Flow Type 2 */
228 #define AHLT_VCMX_FDDI_FCS      0x4     /* VCMX: FDDI FCS */
229 #define AHLT_LANE_802_3_MC      0x4     /* LANE: 802.3 multicast */
230 #define AHLT_VCMX_802_6_FCS     0x5     /* VCMX: 802.6 FCS */
231 #define AHLT_LANE_802_5_MC      0x5     /* LANE: 802.5 multicast */
232 #define AHLT_VCMX_802_3         0x7     /* VCMX: 802.3 */
233 #define AHLT_VCMX_802_4         0x8     /* VCMX: 802.4 */
234 #define AHLT_VCMX_802_5         0x9     /* VCMX: 802.5 */
235 #define AHLT_VCMX_FDDI          0xa     /* VCMX: FDDI */
236 #define AHLT_VCMX_802_6         0xb     /* VCMX: 802.6 */
237 #define AHLT_VCMX_FRAGMENTS     0xc     /* VCMX: Fragments */
238 #define AHLT_VCMX_BPDU          0xe     /* VCMX: BPDU */
239
240 struct frame4_rec {
241         guint16 time_low;       /* low part of time stamp */
242         guint16 time_med;       /* middle part of time stamp */
243         gint8   time_high;      /* high part of time stamp */
244         gint8   time_day;       /* time in days since start of capture */
245         gint16  size;           /* number of bytes of data */
246         gint8   fs;             /* frame error status bits */
247         gint8   flags;          /* buffer flags */
248         gint16  true_size;      /* size of original frame, in bytes */
249         gint16  rsvd3;          /* reserved */
250         gint16  atm_pad;        /* pad to 4-byte boundary */
251         ATMSaveInfo atm_info;   /* ATM-specific stuff */
252 };
253
254 /*
255  * XXX - I have a version 5.50 file with a bunch of token ring
256  * records listed as type "12".  The record format below was
257  * derived from frame4_rec and a bit of experimentation.
258  * - Gerald
259  */
260 struct frame6_rec {
261         guint16 time_low;       /* low part of time stamp */
262         guint16 time_med;       /* middle part of time stamp */
263         gint8   time_high;      /* high part of time stamp */
264         gint8   time_day;       /* time in days since start of capture */
265         gint16  size;           /* number of bytes of data */
266         gint8   fs;             /* frame error status bits */
267         gint8   flags;          /* buffer flags */
268         gint16  true_size;      /* size of original frame, in bytes */
269         guint8  chemical_x[22]; /* ? */
270 };
271
272 /*
273  * Network type values in type 7 records.
274  */
275 #define NET_SDLC        0
276 #define NET_HDLC        1
277 #define NET_FRAME_RELAY 2
278 #define NET_ROUTER      3       /* what's this? */
279 #define NET_PPP         4
280 #define NET_SMDS        5
281
282 /* values for V.timeunit */
283 #define NUM_NGSNIFF_TIMEUNITS 7
284 static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
285
286 static int skip_header_records(wtap *wth, int *err, gint16 version);
287 static gboolean ngsniffer_read(wtap *wth, int *err, long *data_offset);
288 static gboolean ngsniffer_seek_read(wtap *wth, long seek_off,
289     union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
290     int *err);
291 static int ngsniffer_read_rec_header(wtap *wth, gboolean is_random,
292     guint16 *typep, guint16 *lengthp, int *err);
293 static gboolean ngsniffer_read_frame2(wtap *wth, gboolean is_random,
294     struct frame2_rec *frame2, int *err);
295 static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
296     struct frame2_rec *frame2);
297 static gboolean ngsniffer_read_frame4(wtap *wth, gboolean is_random,
298     struct frame4_rec *frame4, int *err);
299 static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
300     struct frame4_rec *frame4);
301 static gboolean ngsniffer_read_frame6(wtap *wth, gboolean is_random,
302     struct frame6_rec *frame6, int *err);
303 static void set_pseudo_header_frame6(union wtap_pseudo_header *pseudo_header,
304     struct frame6_rec *frame6);
305 static gboolean ngsniffer_read_rec_data(wtap *wth, gboolean is_random,
306     guchar *pd, int length, int *err);
307 static void fix_pseudo_header(wtap *wth,
308     union wtap_pseudo_header *pseudo_header);
309 static void ngsniffer_sequential_close(wtap *wth);
310 static void ngsniffer_close(wtap *wth);
311 static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
312         const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
313 static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err);
314 static int SnifferDecompress( unsigned char * inbuf, size_t inlen,
315         unsigned char * outbuf, size_t outlen, int *err );
316 static int ng_file_read(void *buffer, size_t elementsize, size_t numelements,
317     wtap *wth, gboolean is_random, int *err);
318 static int read_blob(FILE_T infile, ngsniffer_comp_stream_t *comp_stream,
319     int *err);
320 static long ng_file_seek_seq(wtap *wth, long offset, int whence, int *err);
321 static long ng_file_seek_rand(wtap *wth, long offset, int whence, int *err);
322
323 int ngsniffer_open(wtap *wth, int *err)
324 {
325         int bytes_read;
326         char magic[sizeof ngsniffer_magic];
327         char record_type[2];
328         char record_length[4]; /* only the first 2 bytes are length,
329                                   the last 2 are "reserved" and are thrown away */
330         guint16 type, length;
331         struct vers_rec version;
332         guint16 start_date;
333         guint16 start_time;
334         static const int sniffer_encap[] = {
335                 WTAP_ENCAP_TOKEN_RING,
336                 WTAP_ENCAP_ETHERNET,
337                 WTAP_ENCAP_ARCNET,
338                 WTAP_ENCAP_UNKNOWN,     /* StarLAN */
339                 WTAP_ENCAP_UNKNOWN,     /* PC Network broadband */
340                 WTAP_ENCAP_UNKNOWN,     /* LocalTalk */
341                 WTAP_ENCAP_UNKNOWN,     /* Znet */
342                 WTAP_ENCAP_UNKNOWN,     /* Internetwork analyzer (synchronous) */
343                 WTAP_ENCAP_UNKNOWN,     /* Internetwork analyzer (asynchronous) */
344                 WTAP_ENCAP_FDDI_BITSWAPPED,
345                 WTAP_ENCAP_ATM_SNIFFER
346         };
347         #define NUM_NGSNIFF_ENCAPS (sizeof sniffer_encap / sizeof sniffer_encap[0])
348         struct tm tm;
349
350         /* Read in the string that should be at the start of a Sniffer file */
351         errno = WTAP_ERR_CANT_READ;
352         bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
353         if (bytes_read != sizeof magic) {
354                 *err = file_error(wth->fh);
355                 if (*err != 0)
356                         return -1;
357                 return 0;
358         }
359         wth->data_offset += sizeof magic;
360
361         if (memcmp(magic, ngsniffer_magic, sizeof ngsniffer_magic)) {
362                 return 0;
363         }
364
365         /*
366          * Read the first record, which the manual says is a version
367          * record.
368          */
369         errno = WTAP_ERR_CANT_READ;
370         bytes_read = file_read(record_type, 1, 2, wth->fh);
371         bytes_read += file_read(record_length, 1, 4, wth->fh);
372         if (bytes_read != 6) {
373                 *err = file_error(wth->fh);
374                 if (*err != 0)
375                         return -1;
376                 return 0;
377         }
378         wth->data_offset += 6;
379
380         type = pletohs(record_type);
381         length = pletohs(record_length);
382
383         if (type != REC_VERS) {
384                 g_message("ngsniffer: Sniffer file doesn't start with a version record");
385                 *err = WTAP_ERR_BAD_RECORD;
386                 return -1;
387         }
388
389         errno = WTAP_ERR_CANT_READ;
390         bytes_read = file_read(&version, 1, sizeof version, wth->fh);
391         if (bytes_read != sizeof version) {
392                 *err = file_error(wth->fh);
393                 if (*err != 0)
394                         return -1;
395                 return 0;
396         }
397         wth->data_offset += sizeof version;
398
399         /* Check the data link type.
400            If "version.network" is 7, that's "Internetwork analyzer";
401            Sniffers appear to write out LAPB, LAPD and PPP captures
402            (and perhaps other types of captures) in that fashion,
403            and, so far, the only way we know of distinguishing them
404            is to look at the first byte of the packet - if it's 0xFF,
405            it's PPP, otherwise if it's odd, it's LAPB else it's LAPD.
406            Therefore, we treat it as WTAP_ENCAP_UNKNOWN for now, but
407            don't treat that as an error.
408
409            In one PPP capture, the two 16-bit words of the "rsvd" field
410            were 1 and 3, respectively, and in one X.25 capture, they
411            were both 0.  That's too small a sample from which to
412            conclude anything, however.... */
413         if (version.network >= NUM_NGSNIFF_ENCAPS
414             || (sniffer_encap[version.network] == WTAP_ENCAP_UNKNOWN
415                && version.network != 7)) {
416                 g_message("ngsniffer: network type %u unknown or unsupported",
417                     version.network);
418                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
419                 return -1;
420         }
421
422         /* Check the time unit */
423         if (version.timeunit >= NUM_NGSNIFF_TIMEUNITS) {
424                 g_message("ngsniffer: Unknown timeunit %u", version.timeunit);
425                 *err = WTAP_ERR_UNSUPPORTED;
426                 return -1;
427         }
428
429         /* compressed or uncompressed Sniffer file? */
430         if (version.format != 1) {
431                 wth->file_type = WTAP_FILE_NGSNIFFER_COMPRESSED;
432
433         } else {
434                 wth->file_type = WTAP_FILE_NGSNIFFER_UNCOMPRESSED;
435         }
436
437         /* Set encap type before reading header records because the
438          * header record may change encap type.
439          */
440         wth->file_encap = sniffer_encap[version.network];
441
442         /*
443          * We don't know how to handle the remaining header record types,
444          * so we just skip them - except for REC_HEADER2 records, which
445          * we look at, for "Internetwork analyzer" captures, to attempt to
446          * determine what the link-layer encapsulation is.
447          */
448         if (skip_header_records(wth, err, version.maj_vers) < 0)
449                 return -1;
450
451         /*
452          * Now, if we have a random stream open, position it to the same
453          * location, which should be the beginning of the real data, and
454          * should be the beginning of the compressed data.
455          *
456          * XXX - will we see any records other than REC_FRAME2, REC_FRAME4,
457          * or REC_EOF after this?  If not, we can get rid of the loop in
458          * "ngsniffer_read()".
459          */
460         if (wth->random_fh != NULL) {
461                 if (file_seek(wth->random_fh, wth->data_offset, SEEK_SET, err) == -1)
462                         return -1;
463         }
464
465         /* This is a ngsniffer file */
466         wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
467
468         /* We haven't allocated any uncompression buffers yet. */
469         wth->capture.ngsniffer->seq.buf = NULL;
470         wth->capture.ngsniffer->rand.buf = NULL;
471
472         /* Set the current file offset; the offset in the compressed file
473            and in the uncompressed data stream currently the same. */
474         wth->capture.ngsniffer->seq.uncomp_offset = wth->data_offset;
475         wth->capture.ngsniffer->seq.comp_offset = wth->data_offset;
476         wth->capture.ngsniffer->rand.uncomp_offset = wth->data_offset;
477         wth->capture.ngsniffer->rand.comp_offset = wth->data_offset;
478
479         /* We don't yet have any list of compressed blobs. */
480         wth->capture.ngsniffer->first_blob = NULL;
481         wth->capture.ngsniffer->last_blob = NULL;
482         wth->capture.ngsniffer->current_blob = NULL;
483
484         wth->subtype_read = ngsniffer_read;
485         wth->subtype_seek_read = ngsniffer_seek_read;
486         wth->subtype_sequential_close = ngsniffer_sequential_close;
487         wth->subtype_close = ngsniffer_close;
488         wth->snapshot_length = 0;       /* not available in header, only in frame */
489         wth->capture.ngsniffer->timeunit = Usec[version.timeunit];
490         wth->capture.ngsniffer->is_atm =
491             (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER);
492
493         /* Get capture start time */
494         start_time = pletohs(&version.time);
495         start_date = pletohs(&version.date);
496         tm.tm_year = ((start_date&0xfe00)>>9) + 1980 - 1900;
497         tm.tm_mon = ((start_date&0x1e0)>>5) - 1;
498         tm.tm_mday = (start_date&0x1f);
499         /* The time does not appear to act as an offset; only the date
500         tm.tm_hour = (start_time&0xf800)>>11;
501         tm.tm_min = (start_time&0x7e0)>>5;
502         tm.tm_sec = (start_time&0x1f)<<1;*/
503         tm.tm_hour = 0;
504         tm.tm_min = 0;
505         tm.tm_sec = 0;
506         tm.tm_isdst = -1;
507         wth->capture.ngsniffer->start = mktime(&tm);
508         /*
509          * XXX - what if "secs" is -1?  Unlikely,
510          * but if the capture was done in a time
511          * zone that switches between standard and
512          * summer time sometime other than when we
513          * do, and thus the time was one that doesn't
514          * exist here because a switch from standard
515          * to summer time zips over it, it could
516          * happen.
517          *
518          * On the other hand, if the capture was done
519          * in a different time zone, this won't work
520          * right anyway; unfortunately, the time zone
521          * isn't stored in the capture file.
522          */
523
524         return 1;
525 }
526
527 static int
528 skip_header_records(wtap *wth, int *err, gint16 version)
529 {
530         int bytes_read;
531         char record_type[2];
532         char record_length[4]; /* only the first 2 bytes are length,
533                                   the last 2 are "reserved" and are thrown away */
534         guint16 type, length;
535         int bytes_to_read;
536         unsigned char buffer[32];
537
538         for (;;) {
539                 errno = WTAP_ERR_CANT_READ;
540                 bytes_read = file_read(record_type, 1, 2, wth->fh);
541                 if (bytes_read != 2) {
542                         *err = file_error(wth->fh);
543                         if (*err != 0)
544                                 return -1;
545                         if (bytes_read != 0) {
546                                 *err = WTAP_ERR_SHORT_READ;
547                                 return -1;
548                         }
549                         return 0;       /* EOF */
550                 }
551
552                 type = pletohs(record_type);
553                 if ((type != REC_HEADER1) && (type != REC_HEADER2)
554                         && (type != REC_HEADER3) && (type != REC_HEADER4)
555                         && (type != REC_HEADER5) && (type != REC_HEADER6)
556                         && (type != REC_HEADER7)
557                         && ((type != REC_V2DESC) || (version > 2)) ) {
558                         /*
559                          * Well, this is either some unknown header type
560                          * (we ignore this case), an uncompressed data
561                          * frame or the length of a compressed blob
562                          * which implies data. Seek backwards over the
563                          * two bytes we read, and return.
564                          */
565                         if (file_seek(wth->fh, -2, SEEK_CUR, err) == -1)
566                                 return -1;
567                         return 0;
568                 }
569
570                 errno = WTAP_ERR_CANT_READ;
571                 bytes_read = file_read(record_length, 1, 4, wth->fh);
572                 if (bytes_read != 4) {
573                         *err = file_error(wth->fh);
574                         if (*err == 0)
575                                 *err = WTAP_ERR_SHORT_READ;
576                         return -1;
577                 }
578                 wth->data_offset += 6;
579
580                 length = pletohs(record_length);
581
582                 /*
583                  * Is this a REC_HEADER2 record, and do we not yet know
584                  * the encapsulation type (i.e., is this is an
585                  * "Internetwork analyzer" capture?
586                  *
587                  * If so, the 5th byte of the record appears to specify
588                  * the particular type of network we're on.
589                  */
590                 if (type == REC_HEADER2 &&
591                     wth->file_encap == WTAP_ENCAP_UNKNOWN) {
592                         /*
593                          * Yes, get the first 32 bytes of the record
594                          * data.
595                          */
596                         bytes_to_read = MIN(length, sizeof buffer);
597                         bytes_read = file_read(buffer, 1, bytes_to_read,
598                                 wth->fh);
599                         if (bytes_read != bytes_to_read) {
600                                 *err = file_error(wth->fh);
601                                 if (*err == 0) {
602                                         *err = WTAP_ERR_SHORT_READ;
603                                         return -1;
604                                 }
605                         }
606                         /*
607                          * Skip the rest of the record.
608                          */
609                         if (length > sizeof buffer) {
610                                 if (file_seek(wth->fh, length - sizeof buffer,
611                                     SEEK_CUR, err) == -1)
612                                         return -1;
613                         }
614
615                         /*
616                          * XXX - what about LAPB and LAPD?  At least one
617                          * X.25 capture has a type of NET_HDLC, but one 
618                          * might also consider LAPD to be an HDLC
619                          * variant; if it also has a type of NET_HDLC,
620                          * we'd have to look at some other data to
621                          * distinguish them.
622                          *
623                          * I have no LAPD captures, so I can't check
624                          * various fields of this record (and I'd
625                          * need multiple captures of both LAPB/X.25
626                          * and LAPD/ISDN to be reasonable certain
627                          * where the magic key is).
628                          *
629                          * So, for now, we don't set the encapsulation
630                          * for NET_HDLC.
631                          */
632                         switch (buffer[4]) {
633
634                         case NET_FRAME_RELAY:
635                                 wth->file_encap = WTAP_ENCAP_FRELAY;
636                                 break;
637
638                         case NET_PPP:
639                                 wth->file_encap = WTAP_ENCAP_PPP;
640                                 break;
641                         }
642
643                 } else {
644                         /* Nope, just skip over the data. */
645                         if (file_seek(wth->fh, length, SEEK_CUR, err) == -1)
646                                 return -1;
647                 }
648                 wth->data_offset += length;
649         }
650 }
651
652 /* Read the next packet */
653 static gboolean ngsniffer_read(wtap *wth, int *err, long *data_offset)
654 {
655         int     ret;
656         guint16 type, length;
657         struct frame2_rec frame2;
658         struct frame4_rec frame4;
659         struct frame6_rec frame6;
660         double  t;
661         guint16 time_low, time_med, time_high, true_size, size;
662         guchar  *pd;
663
664         for (;;) {
665                 /*
666                  * Read the record header.
667                  */
668                 *data_offset = wth->data_offset;
669                 ret = ngsniffer_read_rec_header(wth, FALSE, &type, &length,
670                     err);
671                 if (ret <= 0) {
672                         /* Read error or EOF */
673                         return FALSE;
674                 }
675                 wth->data_offset += 6;
676
677                 switch (type) {
678
679                 case REC_FRAME2:
680                         if (wth->capture.ngsniffer->is_atm) {
681                                 /*
682                                  * We shouldn't get a frame2 record in
683                                  * an ATM capture.
684                                  */
685                                 g_message("ngsniffer: REC_FRAME2 record in an ATM Sniffer file");
686                                 *err = WTAP_ERR_BAD_RECORD;
687                                 return FALSE;
688                         }
689
690                         /* Read the f_frame2_struct */
691                         if (!ngsniffer_read_frame2(wth, FALSE, &frame2, err)) {
692                                 /* Read error */
693                                 return FALSE;
694                         }
695                         wth->data_offset += sizeof frame2;
696                         time_low = pletohs(&frame2.time_low);
697                         time_med = pletohs(&frame2.time_med);
698                         time_high = pletohs(&frame2.time_high);
699                         size = pletohs(&frame2.size);
700                         true_size = pletohs(&frame2.true_size);
701
702                         length -= sizeof frame2;        /* we already read that much */
703
704                         t = (double)time_low+(double)(time_med)*65536.0 +
705                             (double)time_high*4294967296.0;
706
707                         set_pseudo_header_frame2(&wth->pseudo_header, &frame2);
708                         goto found;
709
710                 case REC_FRAME4:
711                         if (!wth->capture.ngsniffer->is_atm) {
712                                 /*
713                                  * We shouldn't get a frame2 record in
714                                  * a non-ATM capture.
715                                  */
716                                 g_message("ngsniffer: REC_FRAME4 record in a non-ATM Sniffer file");
717                                 *err = WTAP_ERR_BAD_RECORD;
718                                 return FALSE;
719                         }
720
721                         /* Read the f_frame4_struct */
722                         if (!ngsniffer_read_frame4(wth, FALSE, &frame4, err)) {
723                                 /* Read error */
724                                 return FALSE;
725                         }
726                         wth->data_offset += sizeof frame4;
727                         time_low = pletohs(&frame4.time_low);
728                         time_med = pletohs(&frame4.time_med);
729                         time_high = frame4.time_high;
730                         size = pletohs(&frame4.size);
731                         true_size = pletohs(&frame4.true_size);
732
733                         length -= sizeof frame4;        /* we already read that much */
734
735                         /*
736                          * XXX - use the "time_day" field?  Is that for captures
737                          * that take a *really* long time?
738                          */
739                         t = (double)time_low+(double)(time_med)*65536.0 +
740                             (double)time_high*4294967296.0;
741
742                         set_pseudo_header_frame4(&wth->pseudo_header, &frame4);
743                         goto found;
744
745                 case REC_FRAME6:
746                         /* XXX - Is this test valid? */
747                         if (wth->capture.ngsniffer->is_atm) {
748                                 g_message("ngsniffer: REC_FRAME6 record in an ATM Sniffer file");
749                                 *err = WTAP_ERR_BAD_RECORD;
750                                 return FALSE;
751                         }
752
753                         /* Read the f_frame6_struct */
754                         if (!ngsniffer_read_frame6(wth, FALSE, &frame6, err)) {
755                                 /* Read error */
756                                 return FALSE;
757                         }
758                         wth->data_offset += sizeof frame6;
759                         time_low = pletohs(&frame6.time_low);
760                         time_med = pletohs(&frame6.time_med);
761                         time_high = frame6.time_high;
762                         size = pletohs(&frame6.size);
763                         true_size = pletohs(&frame6.true_size);
764
765                         length -= sizeof frame6;        /* we already read that much */
766
767                         /*
768                          * XXX - use the "time_day" field?  Is that for captures
769                          * that take a *really* long time?
770                          */
771                         t = (double)time_low+(double)(time_med)*65536.0 +
772                             (double)time_high*4294967296.0;
773
774                         set_pseudo_header_frame6(&wth->pseudo_header, &frame6);
775                         goto found;
776
777                 case REC_EOF:
778                         /*
779                          * End of file.  Return an EOF indication.
780                          */
781                         *err = 0;       /* EOF, not error */
782                         return FALSE;
783
784                 default:
785                         break;  /* unknown type, skip it */
786                 }
787
788                 /*
789                  * Well, we don't know what it is, or we know what
790                  * it is but can't handle it.  Skip past the data
791                  * portion, and keep looping.
792                  */
793                 if (ng_file_seek_seq(wth, length, SEEK_CUR, err) == -1)
794                         return FALSE;
795                 wth->data_offset += length;
796         }
797
798 found:
799         /*
800          * OK, is the frame data size greater than than what's left of the
801          * record?
802          */
803         if (size > length) {
804                 /*
805                  * Yes - treat this as an error.
806                  */
807                 g_message("ngsniffer: Record length is less than packet size");
808                 *err = WTAP_ERR_BAD_RECORD;
809                 return FALSE;
810         }
811
812         wth->phdr.len = true_size ? true_size : size;
813         wth->phdr.caplen = size;
814
815         /*
816          * Read the packet data.
817          */
818         buffer_assure_space(wth->frame_buffer, length);
819         pd = buffer_start_ptr(wth->frame_buffer);
820         if (!ngsniffer_read_rec_data(wth, FALSE, pd, length, err))
821                 return FALSE;   /* Read error */
822         wth->data_offset += length;
823
824         if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
825                 /*
826                  * OK, this is from an "Internetwork analyzer", and
827                  * we either didn't see a type 7 record or it had
828                  * a network type such as NET_HDLC that doesn't
829                  * tell us which *particular* HDLC derivative this
830                  * is; let's look at the first byte of the packet,
831                  * and figure out whether it's LAPB, LAPD, PPP, or
832                  * Frame Relay.
833                  */
834                 if (pd[0] == 0xFF) {
835                         /*
836                          * PPP.
837                          */
838                         wth->file_encap = WTAP_ENCAP_PPP;
839                 } else if (pd[0] == 0x34 || pd[0] == 0x28) {
840                         /*
841                          * Frame Relay.
842                          */
843                         wth->file_encap = WTAP_ENCAP_FRELAY;
844                 } else if (pd[0] & 1) {
845                         /*
846                          * LAPB.
847                          */
848                         wth->file_encap = WTAP_ENCAP_LAPB;
849                 } else {
850                         /*
851                          * LAPD.
852                          */
853                         wth->file_encap = WTAP_ENCAP_LAPD;
854                 }
855         }
856
857         /*
858          * Fix up the pseudo-header; we may have set "x25.flags",
859          * but, for some traffic, we should set "p2p.sent" instead.
860          */
861         fix_pseudo_header(wth, &wth->pseudo_header);
862
863         t = t/1000000.0 * wth->capture.ngsniffer->timeunit; /* t = # of secs */
864         t += wth->capture.ngsniffer->start;
865         wth->phdr.ts.tv_sec = (long)t;
866         wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
867                         *1.0e6);
868         wth->phdr.pkt_encap = wth->file_encap;
869         return TRUE;
870 }
871
872 static gboolean ngsniffer_seek_read(wtap *wth, long seek_off,
873     union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
874     int *err)
875 {
876         int     ret;
877         guint16 type, length;
878         struct frame2_rec frame2;
879         struct frame4_rec frame4;
880         struct frame6_rec frame6;
881
882         if (ng_file_seek_rand(wth, seek_off, SEEK_SET, err) == -1)
883                 return FALSE;
884
885         ret = ngsniffer_read_rec_header(wth, TRUE, &type, &length, err);
886         if (ret <= 0) {
887                 /* Read error or EOF */
888                 if (ret == 0) {
889                         /* EOF means "short read" in random-access mode */
890                         *err = WTAP_ERR_SHORT_READ;
891                 }
892                 return FALSE;
893         }
894
895         switch (type) {
896
897         case REC_FRAME2:
898                 /* Read the f_frame2_struct */
899                 if (!ngsniffer_read_frame2(wth, TRUE, &frame2, err)) {
900                         /* Read error */
901                         return FALSE;
902                 }
903
904                 length -= sizeof frame2;        /* we already read that much */
905
906                 set_pseudo_header_frame2(pseudo_header, &frame2);
907                 break;
908
909         case REC_FRAME4:
910                 /* Read the f_frame4_struct */
911                 if (!ngsniffer_read_frame4(wth, TRUE, &frame4, err)) {
912                         /* Read error */
913                         return FALSE;
914                 }
915
916                 length -= sizeof frame4;        /* we already read that much */
917
918                 set_pseudo_header_frame4(pseudo_header, &frame4);
919                 break;
920
921         case REC_FRAME6:
922                 /* Read the f_frame6_struct */
923                 if (!ngsniffer_read_frame6(wth, TRUE, &frame6, err)) {
924                         /* Read error */
925                         return FALSE;
926                 }
927
928                 length -= sizeof frame6;        /* we already read that much */
929
930                 set_pseudo_header_frame6(pseudo_header, &frame6);
931                 break;
932
933         default:
934                 /*
935                  * "Can't happen".
936                  */
937                 g_assert_not_reached();
938                 return FALSE;
939         }
940
941         /*
942          * Fix up the pseudo-header; we may have set "x25.flags",
943          * but, for some traffic, we should set "p2p.sent" instead.
944          */
945         fix_pseudo_header(wth, pseudo_header);
946
947         /*
948          * Got the pseudo-header (if any), now get the data.
949          */
950         return ngsniffer_read_rec_data(wth, TRUE, pd, packet_size, err);
951 }
952
953 static int ngsniffer_read_rec_header(wtap *wth, gboolean is_random,
954     guint16 *typep, guint16 *lengthp, int *err)
955 {
956         int     bytes_read;
957         char    record_type[2];
958         char    record_length[4]; /* only 1st 2 bytes are length */
959
960         /*
961          * Read the record header.
962          */
963         bytes_read = ng_file_read(record_type, 1, 2, wth, is_random, err);
964         if (bytes_read != 2) {
965                 if (*err != 0)
966                         return -1;
967                 if (bytes_read != 0) {
968                         *err = WTAP_ERR_SHORT_READ;
969                         return -1;
970                 }
971                 return 0;
972         }
973         bytes_read = ng_file_read(record_length, 1, 4, wth, is_random, err);
974         if (bytes_read != 4) {
975                 if (*err == 0)
976                         *err = WTAP_ERR_SHORT_READ;
977                 return -1;
978         }
979
980         *typep = pletohs(record_type);
981         *lengthp = pletohs(record_length);
982         return 1;       /* success */
983 }
984
985 static gboolean ngsniffer_read_frame2(wtap *wth, gboolean is_random,
986     struct frame2_rec *frame2, int *err)
987 {
988         int bytes_read;
989
990         /* Read the f_frame2_struct */
991         bytes_read = ng_file_read(frame2, 1, sizeof *frame2, wth, is_random,
992             err);
993         if (bytes_read != sizeof *frame2) {
994                 if (*err == 0)
995                         *err = WTAP_ERR_SHORT_READ;
996                 return FALSE;
997         }
998         return TRUE;
999 }
1000
1001 static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
1002     struct frame2_rec *frame2)
1003 {
1004         /*
1005          * In one PPP "Internetwork analyzer" capture,
1006          * the only bit seen in "fs" is the 0x80 bit,
1007          * which probably indicates the packet's
1008          * direction; all other bits were zero.
1009          * All bits in "frame2.flags" were zero.
1010          *
1011          * In one X.25 "Interenetwork analyzer" capture,
1012          * the only bit seen in "fs" is the 0x80 bit,
1013          * which probably indicates the packet's
1014          * direction; all other bits were zero.
1015          * "frame2.flags" was always 0x18.
1016          *
1017          * In one Ethernet capture, "fs" was always 0,
1018          * and "flags" was either 0 or 0x18, with no
1019          * obvious correlation with anything.
1020          *
1021          * In one Token Ring capture, "fs" was either 0
1022          * or 0xcc, and "flags" was either 0 or 0x18,
1023          * with no obvious correlation with anything.
1024          */
1025         pseudo_header->x25.flags = (frame2->fs & 0x80) ? 0x00 : FROM_DCE;
1026 }
1027
1028 static gboolean ngsniffer_read_frame4(wtap *wth, gboolean is_random,
1029     struct frame4_rec *frame4, int *err)
1030 {
1031         int bytes_read;
1032
1033         /* Read the f_frame4_struct */
1034         bytes_read = ng_file_read(frame4, 1, sizeof *frame4, wth, is_random,
1035             err);
1036         if (bytes_read != sizeof *frame4) {
1037                 if (*err == 0)
1038                         *err = WTAP_ERR_SHORT_READ;
1039                 return FALSE;
1040         }
1041         return TRUE;
1042 }
1043
1044 static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
1045     struct frame4_rec *frame4)
1046 {
1047         guint8 aal_type, hl_type;
1048         guint16 vpi, vci;
1049
1050         aal_type = frame4->atm_info.AppTrafType & ATT_AALTYPE;
1051         hl_type = frame4->atm_info.AppTrafType & ATT_HLTYPE;
1052         vpi = pletohs(&frame4->atm_info.Vpi);
1053         vci = pletohs(&frame4->atm_info.Vci);
1054
1055         switch (aal_type) {
1056
1057         case ATT_AAL_UNKNOWN:
1058                 /*
1059                  * Map ATT_AAL_UNKNOWN on VPI 0, VCI 5 to ATT_AAL_SIGNALLING,
1060                  * as that's the VPCI used for signalling.
1061                  *
1062                  * XXX - is this necessary, or will frames to 0/5 always
1063                  * have ATT_AAL_SIGNALLING?
1064                  */
1065                 if (vpi == 0 && vci == 5)
1066                         pseudo_header->atm.aal = AAL_SIGNALLING;
1067                 else
1068                         pseudo_header->atm.aal = AAL_UNKNOWN;
1069                 pseudo_header->atm.type = TRAF_UNKNOWN;
1070                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1071                 break;
1072
1073         case ATT_AAL1:
1074                 pseudo_header->atm.aal = AAL_1;
1075                 pseudo_header->atm.type = TRAF_UNKNOWN;
1076                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1077                 break;
1078
1079         case ATT_AAL3_4:
1080                 pseudo_header->atm.aal = AAL_3_4;
1081                 pseudo_header->atm.type = TRAF_UNKNOWN;
1082                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1083                 break;
1084
1085         case ATT_AAL5:
1086                 pseudo_header->atm.aal = AAL_5;
1087                 switch (hl_type) {
1088
1089                 case ATT_HL_UNKNOWN:
1090                         pseudo_header->atm.type = TRAF_UNKNOWN;
1091                         pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1092                         break;
1093
1094                 case ATT_HL_LLCMX:
1095                         pseudo_header->atm.type = TRAF_LLCMX;
1096                         pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1097                         break;
1098
1099                 case ATT_HL_VCMX:
1100                         pseudo_header->atm.type = TRAF_VCMX;
1101                         switch (frame4->atm_info.AppHLType) {
1102
1103                         case AHLT_UNKNOWN:
1104                                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1105                                 break;
1106
1107                         case AHLT_VCMX_802_3_FCS:
1108                                 pseudo_header->atm.subtype =
1109                                     TRAF_ST_VCMX_802_3_FCS;
1110                                 break;
1111
1112                         case AHLT_VCMX_802_4_FCS:
1113                                 pseudo_header->atm.subtype =
1114                                     TRAF_ST_VCMX_802_4_FCS;
1115                                 break;
1116
1117                         case AHLT_VCMX_802_5_FCS:
1118                                 pseudo_header->atm.subtype =
1119                                     TRAF_ST_VCMX_802_5_FCS;
1120                                 break;
1121
1122                         case AHLT_VCMX_FDDI_FCS:
1123                                 pseudo_header->atm.subtype =
1124                                     TRAF_ST_VCMX_FDDI_FCS;
1125                                 break;
1126
1127                         case AHLT_VCMX_802_6_FCS:
1128                                 pseudo_header->atm.subtype =
1129                                     TRAF_ST_VCMX_802_6_FCS;
1130                                 break;
1131
1132                         case AHLT_VCMX_802_3:
1133                                 pseudo_header->atm.subtype = TRAF_ST_VCMX_802_3;
1134                                 break;
1135
1136                         case AHLT_VCMX_802_4:
1137                                 pseudo_header->atm.subtype = TRAF_ST_VCMX_802_4;
1138                                 break;
1139
1140                         case AHLT_VCMX_802_5:
1141                                 pseudo_header->atm.subtype = TRAF_ST_VCMX_802_5;
1142                                 break;
1143
1144                         case AHLT_VCMX_FDDI:
1145                                 pseudo_header->atm.subtype = TRAF_ST_VCMX_FDDI;
1146                                 break;
1147
1148                         case AHLT_VCMX_802_6:
1149                                 pseudo_header->atm.subtype = TRAF_ST_VCMX_802_6;
1150                                 break;
1151
1152                         case AHLT_VCMX_FRAGMENTS:
1153                                 pseudo_header->atm.subtype =
1154                                     TRAF_ST_VCMX_FRAGMENTS;
1155                                 break;
1156
1157                         case AHLT_VCMX_BPDU:
1158                                 pseudo_header->atm.subtype = TRAF_ST_VCMX_BPDU;
1159                                 break;
1160
1161                         default:
1162                                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1163                                 break;
1164                         }
1165                         break;
1166
1167                 case ATT_HL_LANE:
1168                         pseudo_header->atm.type = TRAF_LANE;
1169                         switch (frame4->atm_info.AppHLType) {
1170
1171                         case AHLT_UNKNOWN:
1172                                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1173                                 break;
1174
1175                         case AHLT_LANE_LE_CTRL:
1176                                 pseudo_header->atm.subtype =
1177                                     TRAF_ST_LANE_LE_CTRL;
1178                                 break;
1179
1180                         case AHLT_LANE_802_3:
1181                                 pseudo_header->atm.subtype = TRAF_ST_LANE_802_3;
1182                                 break;
1183
1184                         case AHLT_LANE_802_5:
1185                                 pseudo_header->atm.subtype = TRAF_ST_LANE_802_5;
1186                                 break;
1187
1188                         case AHLT_LANE_802_3_MC:
1189                                 pseudo_header->atm.subtype =
1190                                     TRAF_ST_LANE_802_3_MC;
1191                                 break;
1192
1193                         case AHLT_LANE_802_5_MC:
1194                                 pseudo_header->atm.subtype =
1195                                     TRAF_ST_LANE_802_5_MC;
1196                                 break;
1197
1198                         default:
1199                                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1200                                 break;
1201                         }
1202                         break;
1203
1204                 case ATT_HL_ILMI:
1205                         pseudo_header->atm.type = TRAF_ILMI;
1206                         pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1207                         break;
1208
1209                 case ATT_HL_FRMR:
1210                         pseudo_header->atm.type = TRAF_FR;
1211                         pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1212                         break;
1213
1214                 case ATT_HL_SPANS:
1215                         pseudo_header->atm.type = TRAF_SPANS;
1216                         pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1217                         break;
1218
1219                 case ATT_HL_IPSILON:
1220                         pseudo_header->atm.type = TRAF_IPSILON;
1221                         switch (frame4->atm_info.AppHLType) {
1222
1223                         case AHLT_UNKNOWN:
1224                                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1225                                 break;
1226
1227                         case AHLT_IPSILON_FT0:
1228                                 pseudo_header->atm.subtype =
1229                                     TRAF_ST_IPSILON_FT0;
1230                                 break;
1231
1232                         case AHLT_IPSILON_FT1:
1233                                 pseudo_header->atm.subtype =
1234                                     TRAF_ST_IPSILON_FT1;
1235                                 break;
1236
1237                         case AHLT_IPSILON_FT2:
1238                                 pseudo_header->atm.subtype =
1239                                     TRAF_ST_IPSILON_FT2;
1240                                 break;
1241
1242                         default:
1243                                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1244                                 break;
1245                         }
1246                         break;
1247
1248                 default:
1249                         pseudo_header->atm.type = TRAF_UNKNOWN;
1250                         pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1251                         break;
1252                 }
1253                 break;
1254
1255         case ATT_AAL_USER:
1256                 pseudo_header->atm.aal = AAL_USER;
1257                 pseudo_header->atm.type = TRAF_UNKNOWN;
1258                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1259                 break;
1260
1261         case ATT_AAL_SIGNALLING:
1262                 pseudo_header->atm.aal = AAL_SIGNALLING;
1263                 pseudo_header->atm.type = TRAF_UNKNOWN;
1264                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1265                 break;
1266
1267         case ATT_OAMCELL:
1268                 pseudo_header->atm.aal = AAL_OAMCELL;
1269                 pseudo_header->atm.type = TRAF_UNKNOWN;
1270                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1271                 break;
1272
1273         default:
1274                 pseudo_header->atm.aal = AAL_UNKNOWN;
1275                 pseudo_header->atm.type = TRAF_UNKNOWN;
1276                 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
1277                 break;
1278         }
1279         pseudo_header->atm.vpi = vpi;
1280         pseudo_header->atm.vci = vci;
1281         pseudo_header->atm.channel = pletohs(&frame4->atm_info.channel);
1282         pseudo_header->atm.cells = pletohs(&frame4->atm_info.cells);
1283         pseudo_header->atm.aal5t_u2u = pletohs(&frame4->atm_info.Trailer.aal5t_u2u);
1284         pseudo_header->atm.aal5t_len = pletohs(&frame4->atm_info.Trailer.aal5t_len);
1285         pseudo_header->atm.aal5t_chksum = pletohl(&frame4->atm_info.Trailer.aal5t_chksum);
1286 }
1287
1288 static gboolean ngsniffer_read_frame6(wtap *wth, gboolean is_random,
1289     struct frame6_rec *frame6, int *err)
1290 {
1291         int bytes_read;
1292
1293         /* Read the f_frame6_struct */
1294         bytes_read = ng_file_read(frame6, 1, sizeof *frame6, wth, is_random,
1295             err);
1296         if (bytes_read != sizeof *frame6) {
1297                 if (*err == 0)
1298                         *err = WTAP_ERR_SHORT_READ;
1299                 return FALSE;
1300         }
1301         return TRUE;
1302 }
1303
1304 static void set_pseudo_header_frame6(
1305         union wtap_pseudo_header *pseudo_header _U_,
1306         struct frame6_rec *frame6 _U_)
1307 {
1308         /* XXX - Once the frame format is divined, something will most likely go here */
1309 }
1310
1311 static gboolean ngsniffer_read_rec_data(wtap *wth, gboolean is_random,
1312     guchar *pd, int length, int *err)
1313 {
1314         int     bytes_read;
1315
1316         bytes_read = ng_file_read(pd, 1, length, wth, is_random, err);
1317
1318         if (bytes_read != length) {
1319                 if (*err == 0)
1320                         *err = WTAP_ERR_SHORT_READ;
1321                 return FALSE;
1322         }
1323         return TRUE;
1324 }
1325
1326 static void fix_pseudo_header(wtap *wth,
1327     union wtap_pseudo_header *pseudo_header)
1328 {
1329         switch (wth->file_encap) {
1330
1331         case WTAP_ENCAP_LAPD:
1332                 if (pseudo_header->x25.flags == 0x00)
1333                         pseudo_header->p2p.sent = TRUE;
1334                 else
1335                         pseudo_header->p2p.sent = FALSE;
1336                 break;
1337         }
1338 }
1339
1340 /* Throw away the buffers used by the sequential I/O stream, but not
1341    those used by the random I/O stream. */
1342 static void ngsniffer_sequential_close(wtap *wth)
1343 {
1344         if (wth->capture.ngsniffer->seq.buf != NULL) {
1345                 g_free(wth->capture.ngsniffer->seq.buf);
1346                 wth->capture.ngsniffer->seq.buf = NULL;
1347         }
1348 }
1349
1350 static void free_blob(gpointer data, gpointer user_data _U_)
1351 {
1352         g_free(data);
1353 }
1354
1355 /* Close stuff used by the random I/O stream, if any, and free up any
1356    private data structures.  (If there's a "sequential_close" routine
1357    for a capture file type, it'll be called before the "close" routine
1358    is called, so we don't have to free the sequential buffer here.) */
1359 static void ngsniffer_close(wtap *wth)
1360 {
1361         if (wth->capture.ngsniffer->rand.buf != NULL)
1362                 g_free(wth->capture.ngsniffer->rand.buf);
1363         if (wth->capture.ngsniffer->first_blob != NULL) {
1364                 g_list_foreach(wth->capture.ngsniffer->first_blob, free_blob, NULL);
1365                 g_list_free(wth->capture.ngsniffer->first_blob);
1366         }
1367         g_free(wth->capture.ngsniffer);
1368 }
1369
1370 static const int wtap_encap[] = {
1371     -1,         /* WTAP_ENCAP_UNKNOWN -> unsupported */
1372     1,          /* WTAP_ENCAP_ETHERNET */
1373     0,          /* WTAP_ENCAP_TOKEN_RING */
1374     -1,         /* WTAP_ENCAP_SLIP -> unsupported */
1375     7,          /* WTAP_ENCAP_PPP -> Internetwork analyzer (synchronous) FIXME ! */
1376     9,          /* WTAP_ENCAP_FDDI */
1377     9,          /* WTAP_ENCAP_FDDI_BITSWAPPED */
1378     -1,         /* WTAP_ENCAP_RAW_IP -> unsupported */
1379     2,          /* WTAP_ENCAP_ARCNET */
1380     -1,         /* WTAP_ENCAP_ATM_RFC1483 */
1381     -1,         /* WTAP_ENCAP_LINUX_ATM_CLIP */
1382     7,          /* WTAP_ENCAP_LAPB -> Internetwork analyzer (synchronous) */
1383     -1,         /* WTAP_ENCAP_ATM_SNIFFER */
1384     -1          /* WTAP_ENCAP_NULL -> unsupported */
1385 };
1386 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
1387
1388 /* Returns 0 if we could write the specified encapsulation type,
1389    an error indication otherwise. */
1390 int ngsniffer_dump_can_write_encap(int encap)
1391 {
1392     /* Per-packet encapsulations aren't supported. */
1393     if (encap == WTAP_ENCAP_PER_PACKET)
1394         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
1395
1396     if (encap < 0 || (unsigned)encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
1397         return WTAP_ERR_UNSUPPORTED_ENCAP;
1398
1399     return 0;
1400 }
1401
1402 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
1403    failure */
1404 gboolean ngsniffer_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
1405 {
1406     size_t nwritten;
1407     char buf[6] = {REC_VERS, 0x00, 0x12, 0x00, 0x00, 0x00}; /* version record */
1408
1409     /* This is a sniffer file */
1410     wdh->subtype_write = ngsniffer_dump;
1411     wdh->subtype_close = ngsniffer_dump_close;
1412
1413     wdh->dump.ngsniffer = g_malloc(sizeof(ngsniffer_dump_t));
1414     wdh->dump.ngsniffer->first_frame = TRUE;
1415     wdh->dump.ngsniffer->start = 0;
1416
1417     /* Write the file header. */
1418     nwritten = fwrite(ngsniffer_magic, 1, sizeof ngsniffer_magic, wdh->fh);
1419     if (nwritten != sizeof ngsniffer_magic) {
1420         if (nwritten == 0 && ferror(wdh->fh))
1421             *err = errno;
1422         else
1423             *err = WTAP_ERR_SHORT_WRITE;
1424         return FALSE;
1425     }
1426     nwritten = fwrite(buf, 1, 6, wdh->fh);
1427     if (nwritten != 6) {
1428         if (nwritten == 0 && ferror(wdh->fh))
1429             *err = errno;
1430         else
1431             *err = WTAP_ERR_SHORT_WRITE;
1432         return FALSE;
1433     }
1434
1435     return TRUE;
1436 }
1437
1438 /* Write a record for a packet to a dump file.
1439    Returns TRUE on success, FALSE on failure. */
1440 static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1441     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
1442 {
1443     ngsniffer_dump_t *priv = wdh->dump.ngsniffer;
1444     struct frame2_rec rec_hdr;
1445     size_t nwritten;
1446     char buf[6];
1447     double t;
1448     guint16 t_low, t_med, t_high;
1449     struct vers_rec version;
1450     gint16 maj_vers, min_vers;
1451     guint16 start_date;
1452     struct tm *tm;
1453
1454     /* Sniffer files have a capture start date in the file header, and
1455        have times relative to the beginning of that day in the packet
1456        headers; pick the date of the first packet as the capture start
1457        date. */
1458     if (priv->first_frame) {
1459         priv->first_frame=FALSE;
1460         tm = localtime(&phdr->ts.tv_sec);
1461         if (tm != NULL) {
1462           start_date = (tm->tm_year - (1980 - 1900)) << 9;
1463           start_date |= (tm->tm_mon + 1) << 5;
1464           start_date |= tm->tm_mday;
1465           /* record the start date, not the start time */
1466           priv->start = phdr->ts.tv_sec - (3600*tm->tm_hour + 60*tm->tm_min + tm->tm_sec);
1467         } else {
1468           start_date = 0;
1469           priv->start = 0;
1470         }
1471
1472         /* "sniffer" version ? */
1473         maj_vers = 4;
1474         min_vers = 0;
1475         version.maj_vers = htoles(maj_vers);
1476         version.min_vers = htoles(min_vers);
1477         version.time = 0;
1478         version.date = htoles(start_date);
1479         version.type = 4;
1480         version.network = wtap_encap[wdh->encap];
1481         version.format = 1;
1482         version.timeunit = 1; /* 0.838096 */
1483         version.cmprs_vers = 0;
1484         version.cmprs_level = 0;
1485         version.rsvd[0] = 0;
1486         version.rsvd[1] = 0;
1487         nwritten = fwrite(&version, 1, sizeof version, wdh->fh);
1488         if (nwritten != sizeof version) {
1489             if (nwritten == 0 && ferror(wdh->fh))
1490                 *err = errno;
1491             else
1492                 *err = WTAP_ERR_SHORT_WRITE;
1493             return FALSE;
1494         }
1495     }
1496
1497     buf[0] = REC_FRAME2;
1498     buf[1] = 0x00;
1499     buf[2] = (char)((phdr->caplen + sizeof(struct frame2_rec))%256);
1500     buf[3] = (char)((phdr->caplen + sizeof(struct frame2_rec))/256);
1501     buf[4] = 0x00;
1502     buf[5] = 0x00;
1503     nwritten = fwrite(buf, 1, 6, wdh->fh);
1504     if (nwritten != 6) {
1505         if (nwritten == 0 && ferror(wdh->fh))
1506             *err = errno;
1507         else
1508             *err = WTAP_ERR_SHORT_WRITE;
1509         return FALSE;
1510     }
1511     t = (double)phdr->ts.tv_sec + (double)phdr->ts.tv_usec/1.0e6; /* # of secs */
1512     t = (t - priv->start)*1.0e6 / Usec[1]; /* timeunit = 1 */
1513     t_low = (guint16)(t-(double)((guint32)(t/65536.0))*65536.0);
1514     t_med = (guint16)((guint32)(t/65536.0) % 65536);
1515     t_high = (guint16)(t/4294967296.0);
1516     rec_hdr.time_low = htoles(t_low);
1517     rec_hdr.time_med = htoles(t_med);
1518     rec_hdr.time_high = htoles(t_high);
1519     rec_hdr.size = htoles(phdr->caplen);
1520     if (wdh->encap == WTAP_ENCAP_LAPB || wdh->encap == WTAP_ENCAP_PPP)
1521         rec_hdr.fs = (pseudo_header->x25.flags & FROM_DCE) ? 0x00 : 0x80;
1522     else
1523         rec_hdr.fs = 0;
1524     rec_hdr.flags = 0;
1525     rec_hdr.true_size = phdr->len != phdr->caplen ? htoles(phdr->len) : 0;
1526     rec_hdr.rsvd = 0;
1527     nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, wdh->fh);
1528     if (nwritten != sizeof rec_hdr) {
1529         if (nwritten == 0 && ferror(wdh->fh))
1530             *err = errno;
1531         else
1532             *err = WTAP_ERR_SHORT_WRITE;
1533         return FALSE;
1534     }
1535     nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
1536     if (nwritten != phdr->caplen) {
1537         if (nwritten == 0 && ferror(wdh->fh))
1538             *err = errno;
1539         else
1540             *err = WTAP_ERR_SHORT_WRITE;
1541         return FALSE;
1542     }
1543     return TRUE;
1544 }
1545
1546 /* Finish writing to a dump file.
1547    Returns TRUE on success, FALSE on failure. */
1548 static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err)
1549 {
1550     /* EOF record */
1551     char buf[6] = {REC_EOF, 0x00, 0x00, 0x00, 0x00, 0x00};
1552     size_t nwritten;
1553
1554     nwritten = fwrite(buf, 1, 6, wdh->fh);
1555     if (nwritten != 6) {
1556         if (err != NULL) {
1557             if (nwritten == 0 && ferror(wdh->fh))
1558                 *err = errno;
1559             else
1560                 *err = WTAP_ERR_SHORT_WRITE;
1561         }
1562         return FALSE;
1563     }
1564     return TRUE;
1565 }
1566
1567 /*
1568    SnifferDecompress() decompresses a blob of compressed data from a
1569          Sniffer(R) capture file.
1570
1571    This function is Copyright (c) 1999-2999 Tim Farley
1572
1573    Parameters
1574       inbuf - buffer of compressed bytes from file, not including
1575          the preceding length word
1576       inlen - length of inbuf in bytes
1577       outbuf - decompressed contents, could contain a partial Sniffer
1578          record at the end.
1579       outlen - length of outbuf.
1580
1581    Return value is the number of bytes in outbuf on return.
1582 */
1583 static int
1584 SnifferDecompress( unsigned char * inbuf, size_t inlen, 
1585                        unsigned char * outbuf, size_t outlen, int *err )
1586 {
1587    unsigned char * pin = inbuf;
1588    unsigned char * pout = outbuf;
1589    unsigned char * pin_end = pin + inlen;
1590    unsigned char * pout_end = pout + outlen;
1591    unsigned int bit_mask;  /* one bit is set in this, to mask with bit_value */
1592    unsigned int bit_value = 0; /* cache the last 16 coding bits we retrieved */
1593    unsigned int code_type; /* encoding type, from high 4 bits of byte */
1594    unsigned int code_low;  /* other 4 bits from encoding byte */
1595    int length;             /* length of RLE sequence or repeated string */
1596    int offset;             /* offset of string to repeat */
1597
1598    bit_mask  = 0;  /* don't have any bits yet */
1599    while (1)
1600    {
1601       /* Shift down the bit mask we use to see whats encoded */
1602       bit_mask = bit_mask >> 1;
1603
1604       /* If there are no bits left, time to get another 16 bits */
1605       if ( 0 == bit_mask )
1606       {
1607          bit_mask  = 0x8000;  /* start with the high bit */
1608          bit_value = pletohs(pin);   /* get the next 16 bits */
1609          pin += 2;          /* skip over what we just grabbed */
1610          if ( pin >= pin_end )
1611          {
1612             *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1613             return ( -1 );
1614          }
1615       }
1616
1617       /* Use the bits in bit_value to see what's encoded and what is raw data */
1618       if ( !(bit_mask & bit_value) )
1619       {
1620          /* bit not set - raw byte we just copy */
1621          *(pout++) = *(pin++);
1622       }
1623       else
1624       {
1625          /* bit set - next item is encoded.  Peel off high nybble
1626             of next byte to see the encoding type.  Set aside low
1627             nybble while we are at it */
1628          code_type = (unsigned int) ((*pin) >> 4 ) & 0xF;
1629          code_low  = (unsigned int) ((*pin) & 0xF );
1630          pin++;   /* increment over the code byte we just retrieved */
1631          if ( pin >= pin_end )
1632          {
1633             *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1634             return ( -1 );
1635          }
1636
1637          /* Based on the code type, decode the compressed string */
1638          switch ( code_type )
1639          {
1640             case 0  :   /* RLE short runs */
1641                 /*
1642                     Run length is the low nybble of the first code byte.
1643                     Byte to repeat immediately follows.
1644                     Total code size: 2 bytes.
1645                 */    
1646                 length = code_low + 3;
1647                 /* If length would put us past end of output, avoid overflow */
1648                 if ( pout + length > pout_end )
1649                 {
1650                     *err = WTAP_ERR_UNC_OVERFLOW;
1651                     return ( -1 );
1652                 }
1653
1654                 /* generate the repeated series of bytes */
1655                 memset( pout, *pin++, length );
1656                 pout += length;
1657                 break;
1658             case 1  :   /* RLE long runs */
1659                 /*
1660                     Low 4 bits of run length is the low nybble of the 
1661                     first code byte, upper 8 bits of run length is in 
1662                     the next byte.
1663                     Byte to repeat immediately follows.
1664                     Total code size: 3 bytes.
1665                 */    
1666                 length = code_low + ((unsigned int)(*pin++) << 4) + 19;
1667                 /* If we are already at end of input, there is no byte
1668                    to repeat */
1669                 if ( pin >= pin_end )
1670                 {
1671                     *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1672                     return ( -1 );
1673                 }
1674                 /* If length would put us past end of output, avoid overflow */
1675                 if ( pout + length > pout_end )
1676                 {
1677                     *err = WTAP_ERR_UNC_OVERFLOW;
1678                     return ( -1 );
1679                 }
1680
1681                 /* generate the repeated series of bytes */
1682                 memset( pout, *pin++, length );
1683                 pout += length;
1684                 break;
1685             case 2  :   /* LZ77 long strings */
1686                 /*
1687                     Low 4 bits of offset to string is the low nybble of the 
1688                     first code byte, upper 8 bits of offset is in 
1689                     the next byte.
1690                     Length of string immediately follows.
1691                     Total code size: 3 bytes.
1692                 */    
1693                 offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
1694                 /* If we are already at end of input, there is no byte
1695                    to repeat */
1696                 if ( pin >= pin_end )
1697                 {
1698                     *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1699                     return ( -1 );
1700                 }
1701                 /* Check if offset would put us back past begin of buffer */
1702                 if ( pout - offset < outbuf )
1703                 {
1704                     *err = WTAP_ERR_UNC_BAD_OFFSET;
1705                     return ( -1 );
1706                 }
1707
1708                 /* get length from next byte, make sure it won't overrun buf */
1709                 length = (unsigned int)(*pin++) + 16;
1710                 if ( pout + length > pout_end )
1711                 {
1712                     *err = WTAP_ERR_UNC_OVERFLOW;
1713                     return ( -1 );
1714                 }
1715
1716                 /* Copy the string from previous text to output position,
1717                    advance output pointer */
1718                 memcpy( pout, pout - offset, length );
1719                 pout += length;
1720                 break;
1721             default :   /* (3 to 15): LZ77 short strings */
1722                 /*
1723                     Low 4 bits of offset to string is the low nybble of the 
1724                     first code byte, upper 8 bits of offset is in 
1725                     the next byte.
1726                     Length of string to repeat is overloaded into code_type.
1727                     Total code size: 2 bytes.
1728                 */    
1729                 offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
1730                 /* Check if offset would put us back past begin of buffer */
1731                 if ( pout - offset < outbuf )
1732                 {
1733                     *err = WTAP_ERR_UNC_BAD_OFFSET;
1734                     return ( -1 );
1735                 }
1736
1737                 /* get length from code_type, make sure it won't overrun buf */
1738                 length = code_type;
1739                 if ( pout + length > pout_end )
1740                 {
1741                     *err = WTAP_ERR_UNC_OVERFLOW;
1742                     return ( -1 );
1743                 }
1744
1745                 /* Copy the string from previous text to output position,
1746                    advance output pointer */
1747                 memcpy( pout, pout - offset, length );
1748                 pout += length;
1749                 break;
1750          }
1751       }
1752
1753       /* If we've consumed all the input, we are done */
1754       if ( pin >= pin_end )
1755          break;
1756    }
1757
1758    return ( pout - outbuf );  /* return length of expanded text */
1759 }
1760
1761 /*
1762  * XXX - is there any guarantee that this is big enough to hold the
1763  * uncompressed data from any blob?
1764  */
1765 #define OUTBUF_SIZE     65536
1766
1767 /* Information about a compressed blob; we save the offset in the
1768    underlying compressed file, and the offset in the uncompressed data
1769    stream, of the blob. */
1770 typedef struct {
1771         long    blob_comp_offset;
1772         long    blob_uncomp_offset;
1773 } blob_info_t;
1774
1775 static int
1776 ng_file_read(void *buffer, size_t elementsize, size_t numelements, wtap *wth,
1777     gboolean is_random, int *err)
1778 {
1779     FILE_T infile;
1780     ngsniffer_comp_stream_t *comp_stream;
1781     int copybytes = elementsize * numelements; /* bytes left to be copied */
1782     int copied_bytes = 0; /* bytes already copied */
1783     unsigned char *outbuffer = buffer; /* where to write next decompressed data */
1784     blob_info_t *blob;
1785     int bytes_to_copy;
1786     int bytes_left;
1787
1788     if (is_random) {
1789         infile = wth->random_fh;
1790         comp_stream = &wth->capture.ngsniffer->rand;
1791     } else {
1792         infile = wth->fh;
1793         comp_stream = &wth->capture.ngsniffer->seq;
1794     }
1795
1796     if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED) {
1797         errno = WTAP_ERR_CANT_READ;
1798         copied_bytes = file_read(buffer, 1, copybytes, infile);
1799         if (copied_bytes != copybytes)
1800             *err = file_error(infile);
1801         return copied_bytes;
1802     }
1803
1804     /* Allocate the stream buffer if it hasn't already been allocated. */
1805     if (comp_stream->buf == NULL) {
1806         comp_stream->buf = g_malloc(OUTBUF_SIZE);
1807
1808         if (is_random) {
1809             /* This is the first read of the random file, so we're at
1810                the beginning of the sequence of blobs in the file
1811                (as we've not done any random reads yet to move the
1812                current position in the random stream); set the
1813                current blob to be the first blob. */
1814             wth->capture.ngsniffer->current_blob =
1815                 wth->capture.ngsniffer->first_blob;
1816         } else {
1817             /* This is the first sequential read; if we also have a
1818                random stream open, allocate the first element for the
1819                list of blobs, and make it the last element as well. */
1820             if (wth->random_fh != NULL) {
1821                 g_assert(wth->capture.ngsniffer->first_blob == NULL);
1822                 blob = g_malloc(sizeof (blob_info_t));
1823                 blob->blob_comp_offset = comp_stream->comp_offset;
1824                 blob->blob_uncomp_offset = comp_stream->uncomp_offset;
1825                 wth->capture.ngsniffer->first_blob =
1826                         g_list_append(wth->capture.ngsniffer->first_blob, blob);
1827                 wth->capture.ngsniffer->last_blob =
1828                         wth->capture.ngsniffer->first_blob;
1829             }
1830         }
1831
1832         /* Now read the first blob into the buffer. */
1833         if (read_blob(infile, comp_stream, err) < 0)
1834             return -1;
1835     }
1836     while (copybytes > 0) {
1837         bytes_left = comp_stream->nbytes - comp_stream->nextout;
1838         if (bytes_left == 0) {
1839             /* There's no decompressed stuff left to copy from the current
1840                blob; get the next blob. */
1841
1842             if (is_random) {
1843                 /* Move to the next blob in the list. */
1844                 wth->capture.ngsniffer->current_blob =
1845                         g_list_next(wth->capture.ngsniffer->current_blob);
1846                 blob = wth->capture.ngsniffer->current_blob->data;
1847             } else {
1848                 /* If we also have a random stream open, add a new element,
1849                    for this blob, to the list of blobs; we know the list is
1850                    non-empty, as we initialized it on the first sequential
1851                    read, so we just add the new element at the end, and
1852                    adjust the pointer to the last element to refer to it. */
1853                 if (wth->random_fh != NULL) {
1854                     blob = g_malloc(sizeof (blob_info_t));
1855                     blob->blob_comp_offset = comp_stream->comp_offset;
1856                     blob->blob_uncomp_offset = comp_stream->uncomp_offset;
1857                     wth->capture.ngsniffer->last_blob =
1858                         g_list_append(wth->capture.ngsniffer->last_blob, blob);
1859                 }
1860             }
1861
1862             if (read_blob(infile, comp_stream, err) < 0)
1863                 return -1;
1864             bytes_left = comp_stream->nbytes - comp_stream->nextout;
1865         }
1866             
1867         bytes_to_copy = copybytes;
1868         if (bytes_to_copy > bytes_left)
1869             bytes_to_copy = bytes_left;
1870         memcpy(outbuffer, &comp_stream->buf[comp_stream->nextout],
1871                 bytes_to_copy);
1872         copybytes -= bytes_to_copy;
1873         copied_bytes += bytes_to_copy;
1874         outbuffer += bytes_to_copy;
1875         comp_stream->nextout += bytes_to_copy;
1876         comp_stream->uncomp_offset += bytes_to_copy;
1877     }
1878     return copied_bytes;
1879 }
1880
1881 /* Read a blob from a compressed stream.
1882    Return -1 and set "*err" on error, otherwise return 0. */
1883 static int
1884 read_blob(FILE_T infile, ngsniffer_comp_stream_t *comp_stream, int *err)
1885 {
1886     size_t in_len;
1887     size_t read_len;
1888     unsigned short blob_len;
1889     gint16 blob_len_host;
1890     gboolean uncompressed;
1891     unsigned char file_inbuf[65536];
1892     int out_len;
1893
1894     /* Read one 16-bit word which is length of next compressed blob */
1895     errno = WTAP_ERR_CANT_READ;
1896     read_len = file_read(&blob_len, 1, 2, infile);
1897     if (2 != read_len) {
1898         *err = file_error(infile);
1899         return -1;
1900     }
1901     comp_stream->comp_offset += 2;
1902     blob_len_host = pletohs(&blob_len);
1903
1904     /* Compressed or uncompressed? */
1905     if (blob_len_host < 0) {
1906         /* Uncompressed blob; blob length is absolute value of the number. */
1907         in_len = -blob_len_host;
1908         uncompressed = TRUE;
1909     } else {
1910         in_len = blob_len_host;
1911         uncompressed = FALSE;
1912     }
1913
1914     /* Read the blob */
1915     errno = WTAP_ERR_CANT_READ;
1916     read_len = file_read(file_inbuf, 1, in_len, infile);
1917     if (in_len != read_len) {
1918         *err = file_error(infile);
1919         return -1;
1920     }
1921     comp_stream->comp_offset += in_len;
1922
1923     if (uncompressed) {
1924         memcpy(comp_stream->buf, file_inbuf, in_len);
1925         out_len = in_len;
1926     } else {
1927         /* Decompress the blob */
1928         out_len = SnifferDecompress(file_inbuf, in_len,
1929                                 comp_stream->buf, OUTBUF_SIZE, err);
1930         if (out_len < 0)
1931             return -1;
1932     }
1933     comp_stream->nextout = 0;
1934     comp_stream->nbytes = out_len;
1935     return 0;
1936 }
1937
1938 /* Seek in the sequential data stream; we can only seek forward, and we
1939    do it on compressed files by skipping forward. */
1940 static long
1941 ng_file_seek_seq(wtap *wth, long offset, int whence, int *err)
1942 {
1943     long delta;
1944     char buf[65536];
1945     long amount_to_read;
1946
1947     if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED)
1948         return file_seek(wth->fh, offset, whence, err);
1949
1950     switch (whence) {
1951
1952     case SEEK_SET:
1953         break;          /* "offset" is the target offset */
1954
1955     case SEEK_CUR:
1956         offset += wth->capture.ngsniffer->seq.uncomp_offset;
1957         break;          /* "offset" is relative to the current offset */
1958
1959     case SEEK_END:
1960         g_assert_not_reached(); /* "offset" is relative to the end of the file... */
1961         break;          /* ...but we don't know where that is. */
1962     }
1963
1964     delta = offset - wth->capture.ngsniffer->seq.uncomp_offset;
1965     g_assert(delta >= 0);
1966
1967     /* Ok, now read and discard "delta" bytes. */
1968     while (delta != 0) {
1969         amount_to_read = delta;
1970         if ((unsigned long)amount_to_read > sizeof buf)
1971             amount_to_read = sizeof buf;
1972         if (ng_file_read(buf, 1, amount_to_read, wth, FALSE, err) < 0)
1973             return -1;  /* error */
1974         delta -= amount_to_read;
1975     }
1976     return offset;
1977 }
1978
1979 /* Seek in the random data stream.
1980
1981    On compressed files, we see whether we're seeking to a position within
1982    the blob we currently have in memory and, if not, we find in the list
1983    of blobs the last blob that starts at or before the position to which
1984    we're seeking, and read that blob in.  We can then move to the appropriate
1985    position within the blob we have in memory (whether it's the blob we
1986    already had in memory or, if necessary, the one we read in). */
1987 static long
1988 ng_file_seek_rand(wtap *wth, long offset, int whence, int *err)
1989 {
1990     ngsniffer_t *ngsniffer;
1991     long delta;
1992     GList *new, *next;
1993     blob_info_t *next_blob, *new_blob;
1994
1995     if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED)
1996         return file_seek(wth->random_fh, offset, whence, err);
1997
1998     ngsniffer = wth->capture.ngsniffer;
1999
2000     switch (whence) {
2001
2002     case SEEK_SET:
2003         break;          /* "offset" is the target offset */
2004
2005     case SEEK_CUR:
2006         offset += ngsniffer->rand.uncomp_offset;
2007         break;          /* "offset" is relative to the current offset */
2008
2009     case SEEK_END:
2010         g_assert_not_reached(); /* "offset" is relative to the end of the file... */
2011         break;          /* ...but we don't know where that is. */
2012     }
2013
2014     delta = offset - ngsniffer->rand.uncomp_offset;
2015
2016     /* Is the place to which we're seeking within the current buffer, or
2017        will we have to read a different blob into the buffer? */
2018     new = NULL;
2019     if (delta > 0) {
2020         /* We're going forwards.
2021            Is the place to which we're seeking within the current buffer? */
2022         if ((size_t)(ngsniffer->rand.nextout + delta) >= ngsniffer->rand.nbytes) {
2023             /* No.  Search for a blob that contains the target offset in
2024                the uncompressed byte stream, starting with the blob
2025                following the current blob. */
2026             new = g_list_next(ngsniffer->current_blob);
2027             for (;;) {
2028                 next = g_list_next(new);
2029                 if (next == NULL) {
2030                     /* No more blobs; the current one is it. */
2031                     break;
2032                 }
2033
2034                 next_blob = next->data;
2035                 /* Does the next blob start after the target offset?
2036                    If so, the current blob is the one we want. */
2037                 if (next_blob->blob_uncomp_offset > offset)
2038                     break;
2039
2040                 new = next;
2041             }
2042         }
2043     } else if (delta < 0) {
2044         /* We're going backwards.
2045            Is the place to which we're seeking within the current buffer? */
2046         if (ngsniffer->rand.nextout + delta < 0) {
2047             /* No.  Search for a blob that contains the target offset in
2048                the uncompressed byte stream, starting with the blob
2049                preceding the current blob. */
2050             new = g_list_previous(ngsniffer->current_blob);
2051             for (;;) {
2052                 /* Does this blob start at or before the target offset?
2053                    If so, the current blob is the one we want. */
2054                 new_blob = new->data;
2055                 if (new_blob->blob_uncomp_offset <= offset)
2056                     break;
2057
2058                 /* It doesn't - skip to the previous blob. */
2059                 new = g_list_previous(new);
2060             }
2061         }
2062     }
2063
2064     if (new != NULL) {
2065         /* The place to which we're seeking isn't in the current buffer;
2066            move to a new blob. */
2067         new_blob = new->data;
2068
2069         /* Seek in the compressed file to the offset in the compressed file
2070            of the beginning of that blob. */
2071         if (file_seek(wth->random_fh, new_blob->blob_comp_offset, SEEK_SET, err) == -1)
2072             return -1;
2073
2074         /* Make the blob we found the current one. */
2075         ngsniffer->current_blob = new;
2076
2077         /* Now set the current offsets to the offsets of the beginning
2078            of the blob. */
2079         ngsniffer->rand.uncomp_offset = new_blob->blob_uncomp_offset;
2080         ngsniffer->rand.comp_offset = new_blob->blob_comp_offset;
2081
2082         /* Now fill the buffer. */
2083         if (read_blob(wth->random_fh, &ngsniffer->rand, err) < 0)
2084             return -1;
2085
2086         /* Set "delta" to the amount to move within this blob; it had
2087            better be >= 0, and < the amount of uncompressed data in
2088            the blob, as otherwise it'd mean we need to seek before
2089            the beginning or after the end of this blob. */
2090         delta = offset - ngsniffer->rand.uncomp_offset;
2091         g_assert(delta >= 0 && (unsigned long)delta < ngsniffer->rand.nbytes);
2092     }
2093
2094     /* OK, the place to which we're seeking is in the buffer; adjust
2095        "ngsniffer->rand.nextout" to point to the place to which
2096        we're seeking, and adjust "ngsniffer->rand.uncomp_offset" to be
2097        the destination offset. */
2098     ngsniffer->rand.nextout += delta;
2099     ngsniffer->rand.uncomp_offset += delta;
2100
2101     return offset;
2102 }