Add #include <string.h>, to get prototypes for mem* and str* functions.
[metze/wireshark/wip.git] / wiretap / i4btrace.c
1 /* i4btrace.c
2  *
3  * $Id: i4btrace.c,v 1.12 2000/11/17 21:00:40 gram 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, int *data_offset);
36 static int i4btrace_seek_read(wtap *wth, int seek_off,
37     union wtap_pseudo_header *pseudo_header, u_char *pd, int length);
38 static int i4b_read_rec_header(FILE_T fh, i4b_trace_hdr_t *hdr, int *err);
39 static void i4b_byte_swap_header(wtap *wth, i4b_trace_hdr_t *hdr);
40 static int i4b_read_rec_data(FILE_T fh, u_char *pd, int length, int *err);
41 static void i4b_set_pseudo_header(wtap *wth, i4b_trace_hdr_t *hdr,
42     union wtap_pseudo_header *pseudo_header);
43
44 /*
45  * Test some fields in the header to see if they make sense.
46  */
47 #define I4B_HDR_IS_OK(hdr) \
48         (!((unsigned)hdr.length < 3 || (unsigned)hdr.unit > 4 || \
49             (unsigned)hdr.type > 4 || (unsigned)hdr.dir > 2 || \
50             (unsigned)hdr.trunc > 2048))
51
52 int i4btrace_open(wtap *wth, int *err)
53 {
54         int bytes_read;
55         i4b_trace_hdr_t hdr;
56         gboolean byte_swapped = FALSE;
57
58         /* I4B trace files have no magic in the header... Sigh */
59         file_seek(wth->fh, 0, SEEK_SET);
60         errno = WTAP_ERR_CANT_READ;
61         bytes_read = file_read(&hdr, 1, sizeof(hdr), wth->fh);
62         if (bytes_read != sizeof(hdr)) {
63                 *err = file_error(wth->fh);
64                 if (*err != 0)
65                         return -1;
66                 return 0;
67         }
68
69         /* Silly heuristic... */
70         if (!I4B_HDR_IS_OK(hdr)) {
71                 /*
72                  * OK, try byte-swapping the header fields.
73                  */
74                 hdr.length = BSWAP32(hdr.length);
75                 hdr.unit = BSWAP32(hdr.unit);
76                 hdr.type = BSWAP32(hdr.type);
77                 hdr.dir = BSWAP32(hdr.dir);
78                 hdr.trunc = BSWAP32(hdr.trunc);
79                 if (!I4B_HDR_IS_OK(hdr)) {
80                         /*
81                          * It doesn't look valid in either byte order.
82                          */
83                         return 0;
84                 }
85
86                 /*
87                  * It looks valid byte-swapped, so assume it's a
88                  * trace written in the opposite byte order.
89                  */
90                 byte_swapped = TRUE;
91         }
92
93         file_seek(wth->fh, 0, SEEK_SET);
94         wth->data_offset = 0;
95
96         /* Get capture start time */
97
98         wth->file_type = WTAP_FILE_I4BTRACE;
99         wth->capture.i4btrace = g_malloc(sizeof(i4btrace_t));
100         wth->subtype_read = i4btrace_read;
101         wth->subtype_seek_read = i4btrace_seek_read;
102         wth->snapshot_length = 2048;    /* actual length set per packet */
103
104         wth->capture.i4btrace->bchannel_prot[0] = -1;
105         wth->capture.i4btrace->bchannel_prot[1] = -1;
106         wth->capture.i4btrace->byte_swapped = byte_swapped;
107
108         wth->file_encap = WTAP_ENCAP_PER_PACKET;
109
110         return 1;
111 }
112
113 #define V120SABME       "\010\001\177"
114
115 /* Read the next packet */
116 static gboolean i4btrace_read(wtap *wth, int *err, int *data_offset)
117 {
118         int     ret;
119         i4b_trace_hdr_t hdr;
120         guint16 length;
121         void *bufp;
122         int channel;
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         length = hdr.length - sizeof(hdr);
134         if (length == 0)
135                 return FALSE;
136
137         wth->phdr.len = length;
138         wth->phdr.caplen = length;
139
140         wth->phdr.ts.tv_sec = hdr.time.tv_sec;
141         wth->phdr.ts.tv_usec = hdr.time.tv_usec;
142
143         /*
144          * Read the packet data.
145          */
146         buffer_assure_space(wth->frame_buffer, length);
147         bufp = buffer_start_ptr(wth->frame_buffer);
148         if (i4b_read_rec_data(wth->fh, bufp, length, err) < 0)
149                 return FALSE;   /* Read error */
150         wth->data_offset += length;
151
152         switch (hdr.type) {
153
154         case TRC_CH_I:
155                 /*
156                  * XXX - what is it?  It's probably not WTAP_ENCAP_NULL,
157                  * as that means it has a 4-byte AF_ type as the
158                  * encapsulation header.
159                  */
160                 wth->phdr.pkt_encap = WTAP_ENCAP_NULL;
161                 break;
162
163         case TRC_CH_D:
164                 /*
165                  * D channel, so it's LAPD.
166                  */
167                 wth->phdr.pkt_encap = WTAP_ENCAP_LAPD;
168                 break;
169
170         case TRC_CH_B1:
171         case TRC_CH_B2:
172                 /*
173                  * B channel, so it could be any of a number of things.
174                  */
175                 channel = hdr.type - TRC_CH_B1;
176
177                 if (wth->capture.i4btrace->bchannel_prot[channel] == -1) {
178                         /*
179                          * We don't know yet whether the datastream is
180                          * V.120 or not; this heuristic tries to figure
181                          * that out.
182                          *
183                          * We cannot glean this from the Q.931 SETUP message,
184                          * because no commercial V.120 implementation I've
185                          * seen actually sets the V.120 protocol discriminator
186                          * (that, or I'm misreading the spec badly).
187                          *
188                          * TODO: reset the flag to -1 (unknown) after a close
189                          * on the B channel is detected.
190                          */
191                         if (memcmp(bufp, V120SABME, 3) == 0)
192                             wth->capture.i4btrace->bchannel_prot[channel] = 1;
193                         else
194                             wth->capture.i4btrace->bchannel_prot[channel] = 0;
195                 }
196                 if (wth->capture.i4btrace->bchannel_prot[channel] == 1) {
197                         /*
198                          * V.120.
199                          */
200                         wth->phdr.pkt_encap = WTAP_ENCAP_V120;
201                 } else {
202                         /*
203                          * Not V.120.
204                          *
205                          * XXX - what is it?  It's probably not
206                          * WTAP_ENCAP_NULL, as that means it has a
207                          * 4-byte AF_ type as the encapsulation header.
208                          * If it's PPP, we should use WTAP_ENCAP_PPP here.
209                          */
210                         wth->phdr.pkt_encap = WTAP_ENCAP_NULL;
211                 }
212                 break;
213         }
214
215         i4b_set_pseudo_header(wth, &hdr, &wth->pseudo_header);
216
217         return TRUE;
218 }
219
220 static int
221 i4btrace_seek_read(wtap *wth, int seek_off,
222     union wtap_pseudo_header *pseudo_header, u_char *pd, int length)
223 {
224         int     ret;
225         int     err;            /* XXX - return this */
226         i4b_trace_hdr_t hdr;
227
228         file_seek(wth->random_fh, seek_off, SEEK_SET);
229
230         /* Read record header. */
231         ret = i4b_read_rec_header(wth->random_fh, &hdr, &err);
232         if (ret <= 0) {
233                 /* Read error or EOF */
234                 return ret;
235         }
236         i4b_byte_swap_header(wth, &hdr);
237
238         i4b_set_pseudo_header(wth, &hdr, pseudo_header);
239
240         /*
241          * Read the packet data.
242          */
243         return i4b_read_rec_data(wth->random_fh, pd, length, &err);
244 }
245
246 static int
247 i4b_read_rec_header(FILE_T fh, i4b_trace_hdr_t *hdr, int *err)
248 {
249         int     bytes_read;
250
251         errno = WTAP_ERR_CANT_READ;
252         bytes_read = file_read(hdr, 1, sizeof *hdr, fh);
253         if (bytes_read != sizeof *hdr) {
254                 *err = file_error(fh);
255                 if (*err != 0)
256                         return -1;
257                 if (bytes_read != 0) {
258                         *err = WTAP_ERR_SHORT_READ;
259                         return -1;
260                 }
261                 return 0;
262         }
263         return 1;
264 }
265
266 static void
267 i4b_byte_swap_header(wtap *wth, i4b_trace_hdr_t *hdr)
268 {
269         if (wth->capture.i4btrace->byte_swapped) {
270                 /*
271                  * Byte-swap the header.
272                  */
273                 hdr->length = BSWAP32(hdr->length);
274                 hdr->unit = BSWAP32(hdr->unit);
275                 hdr->type = BSWAP32(hdr->type);
276                 hdr->dir = BSWAP32(hdr->dir);
277                 hdr->trunc = BSWAP32(hdr->trunc);
278                 hdr->count = BSWAP32(hdr->count);
279                 hdr->time.tv_sec = BSWAP32(hdr->time.tv_sec);
280                 hdr->time.tv_usec = BSWAP32(hdr->time.tv_usec);
281         }
282 }
283
284 static int
285 i4b_read_rec_data(FILE_T fh, u_char *pd, int length, int *err)
286 {
287         int     bytes_read;
288
289         errno = WTAP_ERR_CANT_READ;
290         bytes_read = file_read(pd, 1, length, fh);
291
292         if (bytes_read != length) {
293                 *err = file_error(fh);
294                 if (*err == 0)
295                         *err = WTAP_ERR_SHORT_READ;
296                 return -1;
297         }
298         return 0;
299 }
300
301 static void
302 i4b_set_pseudo_header(wtap *wth, i4b_trace_hdr_t *hdr,
303     union wtap_pseudo_header *pseudo_header)
304 {
305         int channel;
306
307         switch (hdr->type) {
308
309         case TRC_CH_D:
310                 /*
311                  * D channel, so it's LAPD; set "p2p.sent".
312                  */
313                 pseudo_header->p2p.sent = (hdr->dir == FROM_TE) ? TRUE : FALSE;
314                 break;
315
316         case TRC_CH_B1:
317         case TRC_CH_B2:
318                 /*
319                  * B channel, so it could be any of a number of things;
320                  * if it's V.120, set "x25.flags".
321                  */
322                 channel = hdr->type - TRC_CH_B1;
323
324                 if (wth->capture.i4btrace->bchannel_prot[channel] == 1) {
325                         /*
326                          * V.120.
327                          */
328                         pseudo_header->x25.flags =
329                             (hdr->dir == FROM_TE) ? 0x00 : 0x80;
330                 }
331                 break;
332         }
333 }