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