6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
29 #include "file_wrappers.h"
33 /* Magic number in Aethra PC108 files. */
36 static const guchar aethra_magic[MAGIC_SIZE] = {
37 'V', '0', '2', '0', '8'
40 /* Aethra file header. */
42 guchar magic[MAGIC_SIZE];
44 guchar sw_vers[60]; /* software version string, not null-terminated */
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 */
53 guint8 start_day[2]; /* day of capture start date */
55 guchar com_info[16]; /* COM port and speed, null-padded(?) */
57 guchar xxx_vers[41]; /* unknown version string (longer, null-padded?) */
60 /* Aethra record header. Yes, the alignment is weird.
61 All multi-byte fields are little-endian. */
62 struct aethrarec_hdr {
63 guint8 rec_size[2]; /* record length, not counting the length itself */
64 guint8 rec_type; /* record type */
65 guint8 timestamp[4]; /* milliseconds since start of capture */
66 guint8 flags; /* low-order bit: 0 = N->U, 1 = U->N */
72 * XXX - is a record type of 0 used for anything other than "end of
73 * capture"? In at least one capture there's a record with a rec_type
74 * of 0, a timestamp of 0, and a flags value of 4, as well as a trailing
75 * record which is probably a "Stop Monitor" record with a rec_type of 0,
76 * a non-zero timestamp (not checked to see whether it gives the same
77 * time stamp as PC108 displays for the Stop Monitor record), and a
80 #define AETHRA_STOP_MONITOR 0 /* end of capture */
81 #define AETHRA_PACKET 1 /* packet */
86 * XXX - what does this mean for AETHRA_STOP_MONITOR records?
88 #define AETHRA_U_TO_N 0x01
94 static gboolean aethra_read(wtap *wth, int *err, gchar **err_info,
96 static gboolean aethra_seek_read(wtap *wth, gint64 seek_off,
97 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
98 int *err, gchar **err_info);
99 static gboolean aethra_read_rec_header(FILE_T fh, struct aethrarec_hdr *hdr,
100 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
101 static gboolean aethra_read_rec_data(FILE_T fh, guint8 *pd, int length,
102 int *err, gchar **err_info);
104 int aethra_open(wtap *wth, int *err, gchar **err_info)
107 struct aethra_hdr hdr;
111 /* Read in the string that should be at the start of a "aethra" file */
112 errno = WTAP_ERR_CANT_READ;
113 bytes_read = file_read(hdr.magic, sizeof hdr.magic, wth->fh);
114 if (bytes_read != sizeof hdr.magic) {
115 *err = file_error(wth->fh, err_info);
120 wth->data_offset += sizeof hdr.magic;
122 if (memcmp(hdr.magic, aethra_magic, sizeof aethra_magic) != 0)
125 /* Read the rest of the header. */
126 errno = WTAP_ERR_CANT_READ;
127 bytes_read = file_read((char *)&hdr + sizeof hdr.magic,
128 sizeof hdr - sizeof hdr.magic, wth->fh);
129 if (bytes_read != sizeof hdr - sizeof hdr.magic) {
130 *err = file_error(wth->fh, err_info);
135 wth->data_offset += sizeof hdr - sizeof hdr.magic;
136 wth->file_type = WTAP_FILE_AETHRA;
137 aethra = (aethra_t *)g_malloc(sizeof(aethra_t));
138 wth->priv = (void *)aethra;
139 wth->subtype_read = aethra_read;
140 wth->subtype_seek_read = aethra_seek_read;
143 * Convert the time stamp to a "time_t".
145 tm.tm_year = pletohs(&hdr.start_year) - 1900;
146 tm.tm_mon = pletohs(&hdr.start_month) - 1;
147 tm.tm_mday = pletohs(&hdr.start_day);
148 tm.tm_hour = hdr.start_hour;
149 tm.tm_min = hdr.start_min;
150 tm.tm_sec = hdr.start_sec;
152 aethra->start = mktime(&tm);
155 * We've only seen ISDN files, so, for now, we treat all
158 wth->file_encap = WTAP_ENCAP_ISDN;
159 wth->snapshot_length = 0; /* not available in header */
160 wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
164 /* Read the next packet */
165 static gboolean aethra_read(wtap *wth, int *err, gchar **err_info,
168 aethra_t *aethra = (aethra_t *)wth->priv;
169 struct aethrarec_hdr hdr;
175 * Keep reading until we see an AETHRA_PACKET record or get
179 *data_offset = wth->data_offset;
181 /* Read record header. */
182 if (!aethra_read_rec_header(wth->fh, &hdr, &wth->pseudo_header,
186 rec_size = pletohs(hdr.rec_size);
187 if (rec_size < (sizeof hdr - sizeof hdr.rec_size)) {
188 /* The record is shorter than a record header. */
189 *err = WTAP_ERR_BAD_RECORD;
190 *err_info = g_strdup_printf("aethra: File has %u-byte record, less than minimum of %u",
191 rec_size, (unsigned int)(sizeof hdr - sizeof hdr.rec_size));
194 wth->data_offset += sizeof hdr;
197 * XXX - if this is big, we might waste memory by
198 * growing the buffer to handle it.
200 packet_size = rec_size - (sizeof hdr - sizeof hdr.rec_size);
201 if (packet_size != 0) {
202 buffer_assure_space(wth->frame_buffer, packet_size);
203 if (!aethra_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
204 packet_size, err, err_info))
205 return FALSE; /* Read error */
206 wth->data_offset += packet_size;
208 } while (hdr.rec_type != AETHRA_PACKET);
210 msecs = pletohl(hdr.timestamp);
211 wth->phdr.ts.secs = aethra->start + (msecs / 1000);
212 wth->phdr.ts.nsecs = (msecs % 1000) * 1000000;
213 wth->phdr.caplen = packet_size;
214 wth->phdr.len = packet_size;
220 aethra_seek_read(wtap *wth, gint64 seek_off,
221 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
222 int *err, gchar **err_info)
224 struct aethrarec_hdr hdr;
226 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
229 if (!aethra_read_rec_header(wth->random_fh, &hdr, pseudo_header, err, err_info))
233 * Read the packet data.
235 if (!aethra_read_rec_data(wth->random_fh, pd, length, err, err_info))
236 return FALSE; /* failed */
242 aethra_read_rec_header(FILE_T fh, struct aethrarec_hdr *hdr,
243 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
247 /* Read record header. */
248 errno = WTAP_ERR_CANT_READ;
249 bytes_read = file_read(hdr, sizeof *hdr, fh);
250 if (bytes_read != sizeof *hdr) {
251 *err = file_error(fh, err_info);
252 if (*err == 0 && bytes_read != 0)
253 *err = WTAP_ERR_SHORT_READ;
257 pseudo_header->isdn.uton = hdr->flags & AETHRA_U_TO_N;
258 pseudo_header->isdn.channel = 0; /* XXX - D channel */
264 aethra_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
269 errno = WTAP_ERR_CANT_READ;
270 bytes_read = file_read(pd, length, fh);
272 if (bytes_read != length) {
273 *err = file_error(fh, err_info);
275 *err = WTAP_ERR_SHORT_READ;