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