4f7f241b429295dbb0315aff246363e33f715110
[metze/wireshark/wip.git] / wiretap / i4btrace.c
1 /* i4btrace.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1999 by Bert Driehuis <driehuis@playbeing.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include <wsutil/buffer.h>
29 #include "i4b_trace.h"
30 #include "i4btrace.h"
31
32 typedef struct {
33         gboolean byte_swapped;
34 } i4btrace_t;
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     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
40 static int i4b_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
41     Buffer *buf, int *err, gchar **err_info);
42
43 /*
44  * Test some fields in the header to see if they make sense.
45  */
46 #define I4B_HDR_IS_OK(hdr) \
47         (!((unsigned int)hdr.length < 3 || (unsigned int)hdr.length > 16384 || \
48             (unsigned int)hdr.unit > 4 || (unsigned int)hdr.type > 4 || \
49             (unsigned int)hdr.dir > 2 || (unsigned int)hdr.trunc > 2048))
50
51 int i4btrace_open(wtap *wth, int *err, gchar **err_info)
52 {
53         i4b_trace_hdr_t hdr;
54         gboolean byte_swapped = FALSE;
55         i4btrace_t *i4btrace;
56
57         /* I4B trace files have no magic in the header... Sigh */
58         errno = WTAP_ERR_CANT_READ;
59         if (!wtap_read_bytes(wth->fh, &hdr, sizeof(hdr), err, err_info)) {
60                 if (*err != WTAP_ERR_SHORT_READ)
61                         return -1;
62                 return 0;
63         }
64
65         /* Silly heuristic... */
66         if (!I4B_HDR_IS_OK(hdr)) {
67                 /*
68                  * OK, try byte-swapping the header fields.
69                  */
70                 hdr.length = GUINT32_SWAP_LE_BE(hdr.length);
71                 hdr.unit = GUINT32_SWAP_LE_BE(hdr.unit);
72                 hdr.type = GUINT32_SWAP_LE_BE(hdr.type);
73                 hdr.dir = GUINT32_SWAP_LE_BE(hdr.dir);
74                 hdr.trunc = GUINT32_SWAP_LE_BE(hdr.trunc);
75                 if (!I4B_HDR_IS_OK(hdr)) {
76                         /*
77                          * It doesn't look valid in either byte order.
78                          */
79                         return 0;
80                 }
81
82                 /*
83                  * It looks valid byte-swapped, so assume it's a
84                  * trace written in the opposite byte order.
85                  */
86                 byte_swapped = TRUE;
87         }
88
89         if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
90                 return -1;
91
92         /* Get capture start time */
93
94         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_I4BTRACE;
95         i4btrace = (i4btrace_t *)g_malloc(sizeof(i4btrace_t));
96         wth->priv = (void *)i4btrace;
97         wth->subtype_read = i4btrace_read;
98         wth->subtype_seek_read = i4btrace_seek_read;
99         wth->snapshot_length = 0;       /* not known */
100
101         i4btrace->byte_swapped = byte_swapped;
102
103         wth->file_encap = WTAP_ENCAP_ISDN;
104         wth->file_tsprec = WTAP_TSPREC_USEC;
105
106         return 1;
107 }
108
109 /* Read the next packet */
110 static gboolean i4btrace_read(wtap *wth, int *err, gchar **err_info,
111     gint64 *data_offset)
112 {
113         *data_offset = file_tell(wth->fh);
114
115         return i4b_read_rec(wth, wth->fh, &wth->phdr, wth->frame_buffer,
116             err, err_info);
117 }
118
119 static gboolean
120 i4btrace_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
121     Buffer *buf, int *err, gchar **err_info)
122 {
123         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
124                 return FALSE;
125
126         if (!i4b_read_rec(wth, wth->random_fh, phdr, buf, err, err_info)) {
127                 /* Read error or EOF */
128                 if (*err == 0) {
129                         /* EOF means "short read" in random-access mode */
130                         *err = WTAP_ERR_SHORT_READ;
131                 }
132                 return FALSE;
133         }
134         return TRUE;
135 }
136
137 static gboolean
138 i4b_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
139     int *err, gchar **err_info)
140 {
141         i4btrace_t *i4btrace = (i4btrace_t *)wth->priv;
142         i4b_trace_hdr_t hdr;
143         guint32 length;
144
145         errno = WTAP_ERR_CANT_READ;
146         if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
147                 return FALSE;
148
149         if (i4btrace->byte_swapped) {
150                 /*
151                  * Byte-swap the header.
152                  */
153                 hdr.length = GUINT32_SWAP_LE_BE(hdr.length);
154                 hdr.unit = GUINT32_SWAP_LE_BE(hdr.unit);
155                 hdr.type = GUINT32_SWAP_LE_BE(hdr.type);
156                 hdr.dir = GUINT32_SWAP_LE_BE(hdr.dir);
157                 hdr.trunc = GUINT32_SWAP_LE_BE(hdr.trunc);
158                 hdr.count = GUINT32_SWAP_LE_BE(hdr.count);
159                 hdr.ts_sec = GUINT32_SWAP_LE_BE(hdr.ts_sec);
160                 hdr.ts_usec = GUINT32_SWAP_LE_BE(hdr.ts_usec);
161         }
162
163         if (hdr.length < sizeof(hdr)) {
164                 *err = WTAP_ERR_BAD_FILE;       /* record length < header! */
165                 *err_info = g_strdup_printf("i4btrace: record length %u < header length %lu",
166                     hdr.length, (unsigned long)sizeof(hdr));
167                 return FALSE;
168         }
169         length = hdr.length - (guint32)sizeof(hdr);
170         if (length > WTAP_MAX_PACKET_SIZE) {
171                 /*
172                  * Probably a corrupt capture file; don't blow up trying
173                  * to allocate space for an immensely-large packet.
174                  */
175                 *err = WTAP_ERR_BAD_FILE;
176                 *err_info = g_strdup_printf("i4btrace: File has %u-byte packet, bigger than maximum of %u",
177                     length, WTAP_MAX_PACKET_SIZE);
178                 return FALSE;
179         }
180
181         phdr->rec_type = REC_TYPE_PACKET;
182         phdr->presence_flags = WTAP_HAS_TS;
183
184         phdr->len = length;
185         phdr->caplen = length;
186
187         phdr->ts.secs = hdr.ts_sec;
188         phdr->ts.nsecs = hdr.ts_usec * 1000;
189
190         switch (hdr.type) {
191
192         case TRC_CH_I:
193                 /*
194                  * XXX - what is it?  It's probably not WTAP_ENCAP_NULL,
195                  * as that means it has a 4-byte AF_ type as the
196                  * encapsulation header.
197                  */
198                 phdr->pkt_encap = WTAP_ENCAP_NULL;
199                 break;
200
201         case TRC_CH_D:
202                 /*
203                  * D channel, so it's LAPD; set "p2p.sent".
204                  */
205                 phdr->pkt_encap = WTAP_ENCAP_ISDN;
206                 phdr->pseudo_header.isdn.channel = 0;
207                 break;
208
209         case TRC_CH_B1:
210                 /*
211                  * B channel 1.
212                  */
213                 phdr->pkt_encap = WTAP_ENCAP_ISDN;
214                 phdr->pseudo_header.isdn.channel = 1;
215                 break;
216
217         case TRC_CH_B2:
218                 /*
219                  * B channel 2.
220                  */
221                 phdr->pkt_encap = WTAP_ENCAP_ISDN;
222                 phdr->pseudo_header.isdn.channel = 2;
223                 break;
224         }
225
226         phdr->pseudo_header.isdn.uton = (hdr.dir == FROM_TE);
227
228         /*
229          * Read the packet data.
230          */
231         return wtap_read_packet_bytes(fh, buf, length, err, err_info);
232 }