Put the magic number into the aethra_hdr structure, to avoid compiler
[obnox/wireshark/wip.git] / wiretap / aethra.c
1 /* aethra.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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 #include <errno.h>
27 #include <string.h>
28 #include "wtap-int.h"
29 #include "file_wrappers.h"
30 #include "buffer.h"
31 #include "aethra.h"
32
33 /* Magic number in Aethra PC108 files. */
34 #define MAGIC_SIZE      5
35
36 static const guchar aethra_magic[MAGIC_SIZE] = {
37         'V', '0', '2', '0', '8'
38 };
39
40 /* Aethra file header. */
41 struct aethra_hdr {
42         guchar  magic[MAGIC_SIZE];
43         guint8  unknown1[39];
44         guchar  sw_vers[60];    /* software version string, not null-terminated */
45         guint8  unknown2[118];
46         guint8  start_sec;      /* seconds of capture start time */
47         guint8  start_min;      /* minutes of capture start time */
48         guint8  start_hour;     /* hour of capture start time */
49         guint8  unknown3[5007];
50         guint8  start_year[2];  /* year of capture start date */
51         guint8  start_month[2]; /* month of capture start date */
52         guint8  unknown4[2];
53         guint8  start_day[2];   /* day of capture start date */
54         guint8  unknown5[8];
55         guchar  com_info[16];   /* COM port and speed, null-padded(?) */
56         guint8  unknown6[107];
57         guchar  xxx_vers[29];   /* unknown version string (longer, null-padded?) */
58         guint8  unknown7[20];
59 };
60
61 /* Aethra record header.  Yes, the alignment is weird.
62    All multi-byte fields are little-endian. */
63 struct aethrarec_hdr {
64         guint8 rec_size[2];     /* record length, not counting the length itself */
65         guint8 rec_type;        /* record type */
66         guint8 timestamp[4];    /* milliseconds since start of capture */
67         guint8 flags;           /* low-order bit: 0 = N->U, 1 = U->N */
68 };
69
70 /*
71  * Record types.
72  */
73 #define AETHRA_STOP_MONITOR     0       /* end of capture */
74 #define AETHRA_PACKET           1       /* packet */
75
76 /*
77  * Flags.
78  */
79 #define AETHRA_U_TO_N           0x01
80
81 typedef struct {
82         time_t  start;
83 } aethra_t;
84
85 static gboolean aethra_read(wtap *wth, int *err, gchar **err_info,
86     gint64 *data_offset);
87 static gboolean aethra_seek_read(wtap *wth, gint64 seek_off,
88     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
89     int *err, gchar **err_info);
90 static gboolean aethra_read_rec_header(FILE_T fh, struct aethrarec_hdr *hdr,
91     union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
92 static gboolean aethra_read_rec_data(FILE_T fh, guint8 *pd, int length,
93     int *err, gchar **err_info);
94
95 int aethra_open(wtap *wth, int *err, gchar **err_info)
96 {
97         int bytes_read;
98         struct aethra_hdr hdr;
99         struct tm tm;
100         aethra_t *aethra;
101
102         /* Read in the string that should be at the start of a "aethra" file */
103         errno = WTAP_ERR_CANT_READ;
104         bytes_read = file_read(hdr.magic, sizeof hdr.magic, wth->fh);
105         if (bytes_read != sizeof hdr.magic) {
106                 *err = file_error(wth->fh, err_info);
107                 if (*err != 0)
108                         return -1;
109                 return 0;
110         }
111         wth->data_offset += sizeof hdr.magic;
112
113         if (memcmp(hdr.magic, aethra_magic, sizeof aethra_magic) != 0)
114                 return 0;
115
116         /* Read the rest of the header. */
117         errno = WTAP_ERR_CANT_READ;
118         bytes_read = file_read((char *)&hdr + sizeof hdr.magic,
119             sizeof hdr - sizeof hdr.magic, wth->fh);
120         if (bytes_read != sizeof hdr - sizeof hdr.magic) {
121                 *err = file_error(wth->fh, err_info);
122                 if (*err != 0)
123                         return -1;
124                 return 0;
125         }
126         wth->data_offset += sizeof hdr - sizeof hdr.magic;
127         wth->file_type = WTAP_FILE_AETHRA;
128         aethra = (aethra_t *)g_malloc(sizeof(aethra_t));
129         wth->priv = (void *)aethra;
130         wth->subtype_read = aethra_read;
131         wth->subtype_seek_read = aethra_seek_read;
132
133         /*
134          * Convert the time stamp to a "time_t".
135          */
136         tm.tm_year = pletohs(&hdr.start_year) - 1900;
137         tm.tm_mon = pletohs(&hdr.start_month) - 1;
138         tm.tm_mday = pletohs(&hdr.start_day);
139         tm.tm_hour = hdr.start_hour;
140         tm.tm_min = hdr.start_min;
141         tm.tm_sec = hdr.start_sec;
142         tm.tm_isdst = -1;
143         aethra->start = mktime(&tm);
144
145         /*
146          * We've only seen ISDN files, so, for now, we treat all
147          * files as ISDN.
148          */
149         wth->file_encap = WTAP_ENCAP_ISDN;
150         wth->snapshot_length = 0;       /* not available in header */
151         wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
152         return 1;
153 }
154
155 /* Read the next packet */
156 static gboolean aethra_read(wtap *wth, int *err, gchar **err_info,
157     gint64 *data_offset)
158 {
159         aethra_t *aethra = (aethra_t *)wth->priv;
160         struct aethrarec_hdr hdr;
161         guint32 rec_size;
162         guint32 packet_size;
163         guint32 msecs;
164
165         /*
166          * Keep reading until we see an AETHRA_PACKET record or get
167          * an end-of-file.
168          */
169         do {
170                 *data_offset = wth->data_offset;
171
172                 /* Read record header. */
173                 if (!aethra_read_rec_header(wth->fh, &hdr, &wth->pseudo_header,
174                     err, err_info))
175                         return FALSE;
176
177                 rec_size = pletohs(hdr.rec_size);
178                 if (rec_size < (sizeof hdr - sizeof hdr.rec_size)) {
179                         /* The record is shorter than a record header. */
180                         *err = WTAP_ERR_BAD_RECORD;
181                         *err_info = g_strdup_printf("aethra: File has %u-byte record, less than minimum of %u",
182                             rec_size, (unsigned int)(sizeof hdr - sizeof hdr.rec_size));
183                         return FALSE;
184                 }
185                 wth->data_offset += sizeof hdr;
186
187                 /*
188                  * XXX - if this is big, we might waste memory by
189                  * growing the buffer to handle it.
190                  */
191                 packet_size = rec_size - (sizeof hdr - sizeof hdr.rec_size);
192                 if (packet_size != 0) {
193                         buffer_assure_space(wth->frame_buffer, packet_size);
194                         if (!aethra_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
195                             packet_size, err, err_info))
196                                 return FALSE;   /* Read error */
197                         wth->data_offset += packet_size;
198                 }
199         } while (hdr.rec_type != AETHRA_PACKET);
200
201         msecs = pletohl(hdr.timestamp);
202         wth->phdr.ts.secs = aethra->start + (msecs / 1000);
203         wth->phdr.ts.nsecs = (msecs % 1000) * 1000000;
204         wth->phdr.caplen = packet_size;
205         wth->phdr.len = packet_size;
206
207         return TRUE;
208 }
209
210 static gboolean
211 aethra_seek_read(wtap *wth, gint64 seek_off,
212     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
213     int *err, gchar **err_info)
214 {
215         struct aethrarec_hdr hdr;
216
217         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
218                 return FALSE;
219
220         if (!aethra_read_rec_header(wth->random_fh, &hdr, pseudo_header, err, err_info))
221                 return FALSE;
222
223         /*
224          * Read the packet data.
225          */
226         if (!aethra_read_rec_data(wth->random_fh, pd, length, err, err_info))
227                 return FALSE;   /* failed */
228
229         return TRUE;
230 }
231
232 static gboolean
233 aethra_read_rec_header(FILE_T fh, struct aethrarec_hdr *hdr,
234     union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
235 {
236         int     bytes_read;
237
238         /* Read record header. */
239         errno = WTAP_ERR_CANT_READ;
240         bytes_read = file_read(hdr, sizeof hdr, fh);
241         if (bytes_read != sizeof *hdr) {
242                 *err = file_error(fh, err_info);
243                 if (*err == 0 && bytes_read != 0)
244                         *err = WTAP_ERR_SHORT_READ;
245                 return FALSE;
246         }
247
248         pseudo_header->isdn.uton = hdr->flags & AETHRA_U_TO_N;
249         pseudo_header->isdn.channel = 0;        /* XXX - D channel */
250
251         return TRUE;
252 }
253
254 static gboolean
255 aethra_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
256     gchar **err_info)
257 {
258         int     bytes_read;
259
260         errno = WTAP_ERR_CANT_READ;
261         bytes_read = file_read(pd, length, fh);
262
263         if (bytes_read != length) {
264                 *err = file_error(fh, err_info);
265                 if (*err == 0)
266                         *err = WTAP_ERR_SHORT_READ;
267                 return FALSE;
268         }
269         return TRUE;
270 }