Add a new WTAP_ERR_DECOMPRESS error, and use that for errors discovered
[obnox/wireshark/wip.git] / wiretap / i4btrace.c
1 /* i4btrace.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1999 by Bert Driehuis <driehuis@playbeing.org>
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include "wtap-int.h"
31 #include "file_wrappers.h"
32 #include "buffer.h"
33 #include "i4b_trace.h"
34 #include "i4btrace.h"
35
36 typedef struct {
37         gboolean byte_swapped;
38 } i4btrace_t;
39
40 static gboolean i4btrace_read(wtap *wth, int *err, gchar **err_info,
41     gint64 *data_offset);
42 static gboolean i4btrace_seek_read(wtap *wth, gint64 seek_off,
43     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
44     int *err, gchar **err_info);
45 static int i4b_read_rec_header(FILE_T fh, i4b_trace_hdr_t *hdr, int *err,
46     gchar **err_info);
47 static void i4b_byte_swap_header(wtap *wth, i4b_trace_hdr_t *hdr);
48 static gboolean i4b_read_rec_data(FILE_T fh, guchar *pd, int length, int *err,
49     gchar **err_info);
50 static void i4b_set_pseudo_header(i4b_trace_hdr_t *hdr,
51     union wtap_pseudo_header *pseudo_header);
52
53 /*
54  * Test some fields in the header to see if they make sense.
55  */
56 #define I4B_HDR_IS_OK(hdr) \
57         (!((unsigned)hdr.length < 3 || (unsigned)hdr.length > 16384 || \
58             (unsigned)hdr.unit > 4 || (unsigned)hdr.type > 4 || \
59             (unsigned)hdr.dir > 2 || (unsigned)hdr.trunc > 2048))
60
61 int i4btrace_open(wtap *wth, int *err, gchar **err_info)
62 {
63         int bytes_read;
64         i4b_trace_hdr_t hdr;
65         gboolean byte_swapped = FALSE;
66         i4btrace_t *i4btrace;
67
68         /* I4B trace files have no magic in the header... Sigh */
69         errno = WTAP_ERR_CANT_READ;
70         bytes_read = file_read(&hdr, sizeof(hdr), wth->fh);
71         if (bytes_read != sizeof(hdr)) {
72                 *err = file_error(wth->fh, err_info);
73                 if (*err != 0)
74                         return -1;
75                 return 0;
76         }
77
78         /* Silly heuristic... */
79         if (!I4B_HDR_IS_OK(hdr)) {
80                 /*
81                  * OK, try byte-swapping the header fields.
82                  */
83                 hdr.length = BSWAP32(hdr.length);
84                 hdr.unit = BSWAP32(hdr.unit);
85                 hdr.type = BSWAP32(hdr.type);
86                 hdr.dir = BSWAP32(hdr.dir);
87                 hdr.trunc = BSWAP32(hdr.trunc);
88                 if (!I4B_HDR_IS_OK(hdr)) {
89                         /*
90                          * It doesn't look valid in either byte order.
91                          */
92                         return 0;
93                 }
94
95                 /*
96                  * It looks valid byte-swapped, so assume it's a
97                  * trace written in the opposite byte order.
98                  */
99                 byte_swapped = TRUE;
100         }
101
102         if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
103                 return -1;
104         wth->data_offset = 0;
105
106         /* Get capture start time */
107
108         wth->file_type = WTAP_FILE_I4BTRACE;
109         i4btrace = (i4btrace_t *)g_malloc(sizeof(i4btrace_t));
110         wth->priv = (void *)i4btrace;
111         wth->subtype_read = i4btrace_read;
112         wth->subtype_seek_read = i4btrace_seek_read;
113         wth->snapshot_length = 0;       /* not known */
114
115         i4btrace->byte_swapped = byte_swapped;
116
117         wth->file_encap = WTAP_ENCAP_ISDN;
118         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
119
120         return 1;
121 }
122
123 /* Read the next packet */
124 static gboolean i4btrace_read(wtap *wth, int *err, gchar **err_info,
125     gint64 *data_offset)
126 {
127         int     ret;
128         i4b_trace_hdr_t hdr;
129         guint32 length;
130         void *bufp;
131
132         /* Read record header. */
133         *data_offset = wth->data_offset;
134         ret = i4b_read_rec_header(wth->fh, &hdr, err, err_info);
135         if (ret <= 0) {
136                 /* Read error or EOF */
137                 return FALSE;
138         }
139         wth->data_offset += sizeof hdr;
140         i4b_byte_swap_header(wth, &hdr);
141         if (hdr.length < sizeof(hdr)) {
142                 *err = WTAP_ERR_BAD_RECORD;     /* record length < header! */
143                 *err_info = g_strdup_printf("i4btrace: record length %u < header length %lu",
144                     hdr.length, (unsigned long)sizeof(hdr));
145                 return FALSE;
146         }
147         length = hdr.length - (guint32)sizeof(hdr);
148
149         wth->phdr.len = length;
150         wth->phdr.caplen = length;
151
152         wth->phdr.ts.secs = hdr.ts_sec;
153         wth->phdr.ts.nsecs = hdr.ts_usec * 1000;
154
155         /*
156          * Read the packet data.
157          */
158         buffer_assure_space(wth->frame_buffer, length);
159         bufp = buffer_start_ptr(wth->frame_buffer);
160         if (!i4b_read_rec_data(wth->fh, bufp, length, err, err_info))
161                 return FALSE;   /* Read error */
162         wth->data_offset += length;
163
164         switch (hdr.type) {
165
166         case TRC_CH_I:
167                 /*
168                  * XXX - what is it?  It's probably not WTAP_ENCAP_NULL,
169                  * as that means it has a 4-byte AF_ type as the
170                  * encapsulation header.
171                  */
172                 wth->phdr.pkt_encap = WTAP_ENCAP_NULL;
173                 break;
174
175         case TRC_CH_D:
176         case TRC_CH_B1:
177         case TRC_CH_B2:
178                 /*
179                  * D or B channel.
180                  */
181                 wth->phdr.pkt_encap = WTAP_ENCAP_ISDN;
182                 break;
183         }
184
185         i4b_set_pseudo_header(&hdr, &wth->pseudo_header);
186
187         return TRUE;
188 }
189
190 static gboolean
191 i4btrace_seek_read(wtap *wth, gint64 seek_off,
192     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
193     int *err, gchar **err_info)
194 {
195         int     ret;
196         i4b_trace_hdr_t hdr;
197
198         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
199                 return FALSE;
200
201         /* Read record header. */
202         ret = i4b_read_rec_header(wth->random_fh, &hdr, err, err_info);
203         if (ret <= 0) {
204                 /* Read error or EOF */
205                 if (ret == 0) {
206                         /* EOF means "short read" in random-access mode */
207                         *err = WTAP_ERR_SHORT_READ;
208                 }
209                 return FALSE;
210         }
211         i4b_byte_swap_header(wth, &hdr);
212
213         i4b_set_pseudo_header(&hdr, pseudo_header);
214
215         /*
216          * Read the packet data.
217          */
218         return i4b_read_rec_data(wth->random_fh, pd, length, err, err_info);
219 }
220
221 static int
222 i4b_read_rec_header(FILE_T fh, i4b_trace_hdr_t *hdr, int *err, gchar **err_info)
223 {
224         int     bytes_read;
225
226         errno = WTAP_ERR_CANT_READ;
227         bytes_read = file_read(hdr, sizeof *hdr, fh);
228         if (bytes_read != sizeof *hdr) {
229                 *err = file_error(fh, err_info);
230                 if (*err != 0)
231                         return -1;
232                 if (bytes_read != 0) {
233                         *err = WTAP_ERR_SHORT_READ;
234                         return -1;
235                 }
236                 return 0;
237         }
238         return 1;
239 }
240
241 static void
242 i4b_byte_swap_header(wtap *wth, i4b_trace_hdr_t *hdr)
243 {
244         i4btrace_t *i4btrace = (i4btrace_t *)wth->priv;
245
246         if (i4btrace->byte_swapped) {
247                 /*
248                  * Byte-swap the header.
249                  */
250                 hdr->length = BSWAP32(hdr->length);
251                 hdr->unit = BSWAP32(hdr->unit);
252                 hdr->type = BSWAP32(hdr->type);
253                 hdr->dir = BSWAP32(hdr->dir);
254                 hdr->trunc = BSWAP32(hdr->trunc);
255                 hdr->count = BSWAP32(hdr->count);
256                 hdr->ts_sec = BSWAP32(hdr->ts_sec);
257                 hdr->ts_usec = BSWAP32(hdr->ts_usec);
258         }
259 }
260
261 static gboolean
262 i4b_read_rec_data(FILE_T fh, guchar *pd, int length, int *err, gchar **err_info)
263 {
264         int     bytes_read;
265
266         errno = WTAP_ERR_CANT_READ;
267         bytes_read = file_read(pd, length, fh);
268
269         if (bytes_read != length) {
270                 *err = file_error(fh, err_info);
271                 if (*err == 0)
272                         *err = WTAP_ERR_SHORT_READ;
273                 return FALSE;
274         }
275         return TRUE;
276 }
277
278 static void
279 i4b_set_pseudo_header(i4b_trace_hdr_t *hdr,
280     union wtap_pseudo_header *pseudo_header)
281 {
282         pseudo_header->isdn.uton = (hdr->dir == FROM_TE);
283         switch (hdr->type) {
284
285         case TRC_CH_D:
286                 /*
287                  * D channel, so it's LAPD; set "p2p.sent".
288                  */
289                 pseudo_header->isdn.channel = 0;
290                 break;
291
292         case TRC_CH_B1:
293                 /*
294                  * B channel 1.
295                  */
296                 pseudo_header->isdn.channel = 1;
297                 break;
298
299         case TRC_CH_B2:
300                 /*
301                  * B channel 2.
302                  */
303                 pseudo_header->isdn.channel = 2;
304                 break;
305         }
306 }