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