smb-direct fragmentation
[metze/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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include <errno.h>
25 #include <string.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "buffer.h"
29 #include "aethra.h"
30
31 /* Magic number in Aethra PC108 files. */
32 #define MAGIC_SIZE      5
33
34 static const guchar aethra_magic[MAGIC_SIZE] = {
35         'V', '0', '2', '0', '8'
36 };
37
38 /* Aethra file header. */
39 struct aethra_hdr {
40         guchar  magic[MAGIC_SIZE];
41         guint8  unknown1[39];
42         guchar  sw_vers[60];    /* software version string, not null-terminated */
43         guint8  unknown2[118];
44         guint8  start_sec;      /* seconds of capture start time */
45         guint8  start_min;      /* minutes of capture start time */
46         guint8  start_hour;     /* hour of capture start time */
47         guint8  unknown3[5007];
48         guint8  start_year[2];  /* year of capture start date */
49         guint8  start_month[2]; /* month of capture start date */
50         guint8  unknown4[2];
51         guint8  start_day[2];   /* day of capture start date */
52         guint8  unknown5[8];
53         guchar  com_info[16];   /* COM port and speed, null-padded(?) */
54         guint8  unknown6[107];
55         guchar  xxx_vers[41];   /* unknown version string (longer, null-padded?) */
56 };
57
58 /* Aethra record header.  Yes, the alignment is weird.
59    All multi-byte fields are little-endian. */
60 struct aethrarec_hdr {
61         guint8 rec_size[2];     /* record length, not counting the length itself */
62         guint8 rec_type;        /* record type */
63         guint8 timestamp[4];    /* milliseconds since start of capture */
64         guint8 flags;           /* low-order bit: 0 = N->U, 1 = U->N */
65 };
66
67 /*
68  * Record types.
69  *
70  * As the indications from the device and signalling messages appear not
71  * to have the 8th bit set, and at least some B-channel records do, we
72  * assume, for now, that the 8th bit indicates bearer information.
73  *
74  * 0x9F is the record type seen for B31 channel records; that might be
75  * 0x80|31, so, for now, we assume that if the 8th bit is set, the B
76  * channel number is in the low 7 bits.
77  */
78 #define AETHRA_BEARER           0x80    /* bearer information */
79
80 #define AETHRA_DEVICE           0x00    /* indication from the monitoring device */
81 #define AETHRA_ISDN_LINK        0x01    /* information from the ISDN link */
82
83 /*
84  * In AETHRA_DEVICE records, the flags field has what appears to
85  * be a record subtype.
86  */
87 #define AETHRA_DEVICE_STOP_MONITOR      0x00    /* Stop Monitor */
88 #define AETHRA_DEVICE_START_MONITOR     0x04    /* Start Monitor */
89 #define AETHRA_DEVICE_ACTIVATION        0x05    /* Activation */
90 #define AETHRA_DEVICE_START_CAPTURE     0x5F    /* Start Capture */
91
92 /*
93  * In AETHRA_ISDN_LINK and bearer channel records, the flags field has
94  * a direction flag and possibly some other bits.
95  *
96  * In AETHRA_ISDN_LINK records, at least some of the other bits are
97  * a subtype.
98  *
99  * In bearer channel records, there are records with data and
100  * "Constant Value" records with a single byte.  Data has a
101  * flags value of 0x14 ORed with the direction flag, and Constant Value
102  * records have a flags value of 0x16 ORed with the direction flag.
103  * There are also records of an unknown type with 0x02, probably
104  * ORed with the direction flag.
105  */
106 #define AETHRA_U_TO_N                           0x01    /* set for TE->NT */
107
108 #define AETHRA_ISDN_LINK_SUBTYPE                0xFE
109 #define AETHRA_ISDN_LINK_LAPD                   0x00    /* LAPD frame */
110 #define AETHRA_ISDN_LINK_SA_BITS                0x2E    /* 2048K PRI Sa bits (G.704 section 2.3.2) */
111 #define AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED     0x30    /* All Alarms Cleared */
112
113 typedef struct {
114         time_t  start;
115 } aethra_t;
116
117 static gboolean aethra_read(wtap *wth, int *err, gchar **err_info,
118     gint64 *data_offset);
119 static gboolean aethra_seek_read(wtap *wth, gint64 seek_off,
120     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
121 static gboolean aethra_read_rec_header(wtap *wth, FILE_T fh, struct aethrarec_hdr *hdr,
122     struct wtap_pkthdr *phdr, int *err, gchar **err_info);
123
124 int aethra_open(wtap *wth, int *err, gchar **err_info)
125 {
126         int bytes_read;
127         struct aethra_hdr hdr;
128         struct tm tm;
129         aethra_t *aethra;
130
131         /* Read in the string that should be at the start of a "aethra" file */
132         errno = WTAP_ERR_CANT_READ;
133         bytes_read = file_read(hdr.magic, sizeof hdr.magic, wth->fh);
134         if (bytes_read != sizeof hdr.magic) {
135                 *err = file_error(wth->fh, err_info);
136                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
137                         return -1;
138                 return 0;
139         }
140
141         if (memcmp(hdr.magic, aethra_magic, sizeof aethra_magic) != 0)
142                 return 0;
143
144         /* Read the rest of the header. */
145         errno = WTAP_ERR_CANT_READ;
146         bytes_read = file_read((char *)&hdr + sizeof hdr.magic,
147             sizeof hdr - sizeof hdr.magic, wth->fh);
148         if (bytes_read != sizeof hdr - sizeof hdr.magic) {
149                 *err = file_error(wth->fh, err_info);
150                 if (*err == 0)
151                         *err = WTAP_ERR_SHORT_READ;
152                 return -1;
153         }
154         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_AETHRA;
155         aethra = (aethra_t *)g_malloc(sizeof(aethra_t));
156         wth->priv = (void *)aethra;
157         wth->subtype_read = aethra_read;
158         wth->subtype_seek_read = aethra_seek_read;
159
160         /*
161          * Convert the time stamp to a "time_t".
162          */
163         tm.tm_year = pletoh16(&hdr.start_year) - 1900;
164         tm.tm_mon = pletoh16(&hdr.start_month) - 1;
165         tm.tm_mday = pletoh16(&hdr.start_day);
166         tm.tm_hour = hdr.start_hour;
167         tm.tm_min = hdr.start_min;
168         tm.tm_sec = hdr.start_sec;
169         tm.tm_isdst = -1;
170         aethra->start = mktime(&tm);
171
172         /*
173          * We've only seen ISDN files, so, for now, we treat all
174          * files as ISDN.
175          */
176         wth->file_encap = WTAP_ENCAP_ISDN;
177         wth->snapshot_length = 0;       /* not available in header */
178         wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
179         return 1;
180 }
181
182 #if 0
183 static guint packet = 0;
184 #endif
185
186 /* Read the next packet */
187 static gboolean aethra_read(wtap *wth, int *err, gchar **err_info,
188     gint64 *data_offset)
189 {
190         struct aethrarec_hdr hdr;
191
192         /*
193          * Keep reading until we see an AETHRA_ISDN_LINK with a subtype
194          * of AETHRA_ISDN_LINK_LAPD record or get an end-of-file.
195          */
196         for (;;) {
197                 *data_offset = file_tell(wth->fh);
198
199                 /* Read record header. */
200                 if (!aethra_read_rec_header(wth, wth->fh, &hdr, &wth->phdr, err, err_info))
201                         return FALSE;
202
203                 /*
204                  * XXX - if this is big, we might waste memory by
205                  * growing the buffer to handle it.
206                  */
207                 if (wth->phdr.caplen != 0) {
208                         if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer,
209                             wth->phdr.caplen, err, err_info))
210                                 return FALSE;   /* Read error */
211                 }
212 #if 0
213 packet++;
214 #endif
215                 switch (hdr.rec_type) {
216
217                 case AETHRA_ISDN_LINK:
218 #if 0
219 fprintf(stderr, "Packet %u: type 0x%02x (AETHRA_ISDN_LINK)\n",
220 packet, hdr.rec_type);
221 #endif
222                         switch (hdr.flags & AETHRA_ISDN_LINK_SUBTYPE) {
223
224                         case AETHRA_ISDN_LINK_LAPD:
225                                 /*
226                                  * The data is a LAPD frame.
227                                  */
228 #if 0
229 fprintf(stderr, "    subtype 0x%02x (AETHRA_ISDN_LINK_LAPD)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE);
230 #endif
231                                 goto found;
232
233                         case AETHRA_ISDN_LINK_SA_BITS:
234                                 /*
235                                  * These records have one data byte, which
236                                  * has the Sa bits in the lower 5 bits.
237                                  *
238                                  * XXX - what about stuff other than 2048K
239                                  * PRI lines?
240                                  */
241 #if 0
242 fprintf(stderr, "    subtype 0x%02x (AETHRA_ISDN_LINK_SA_BITS)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE);
243 #endif
244                                 break;
245
246                         case AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED:
247                                 /*
248                                  * No data, just an "all alarms cleared"
249                                  * indication.
250                                  */
251 #if 0
252 fprintf(stderr, "    subtype 0x%02x (AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE);
253 #endif
254                                 break;
255
256                         default:
257 #if 0
258 fprintf(stderr, "    subtype 0x%02x, packet_size %u, direction 0x%02x\n",
259 hdr.flags & AETHRA_ISDN_LINK_SUBTYPE, wth->phdr.caplen, hdr.flags & AETHRA_U_TO_N);
260 #endif
261                                 break;
262                         }
263                         break;
264
265                 default:
266 #if 0
267 fprintf(stderr, "Packet %u: type 0x%02x, packet_size %u, flags 0x%02x\n",
268 packet, hdr.rec_type, wth->phdr.caplen, hdr.flags);
269 #endif
270                         break;
271                 }
272         }
273
274 found:
275         return TRUE;
276 }
277
278 static gboolean
279 aethra_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
280     Buffer *buf, int *err, gchar **err_info)
281 {
282         struct aethrarec_hdr hdr;
283
284         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
285                 return FALSE;
286
287         if (!aethra_read_rec_header(wth, wth->random_fh, &hdr, phdr, err,
288             err_info)) {
289                 if (*err == 0)
290                         *err = WTAP_ERR_SHORT_READ;
291                 return FALSE;
292         }
293
294         /*
295          * Read the packet data.
296          */
297         if (!wtap_read_packet_bytes(wth->random_fh, buf, phdr->caplen, err, err_info))
298                 return FALSE;   /* failed */
299
300         return TRUE;
301 }
302
303 static gboolean
304 aethra_read_rec_header(wtap *wth, FILE_T fh, struct aethrarec_hdr *hdr,
305     struct wtap_pkthdr *phdr, int *err, gchar **err_info)
306 {
307         aethra_t *aethra = (aethra_t *)wth->priv;
308         int     bytes_read;
309         guint32 rec_size;
310         guint32 packet_size;
311         guint32 msecs;
312
313         /* Read record header. */
314         errno = WTAP_ERR_CANT_READ;
315         bytes_read = file_read(hdr, sizeof *hdr, fh);
316         if (bytes_read != sizeof *hdr) {
317                 *err = file_error(fh, err_info);
318                 if (*err == 0 && bytes_read != 0)
319                         *err = WTAP_ERR_SHORT_READ;
320                 return FALSE;
321         }
322
323         rec_size = pletoh16(hdr->rec_size);
324         if (rec_size < (sizeof *hdr - sizeof hdr->rec_size)) {
325                 /* The record is shorter than a record header. */
326                 *err = WTAP_ERR_BAD_FILE;
327                 *err_info = g_strdup_printf("aethra: File has %u-byte record, less than minimum of %u",
328                     rec_size,
329                     (unsigned int)(sizeof *hdr - sizeof hdr->rec_size));
330                 return FALSE;
331         }
332
333         packet_size = rec_size - (guint32)(sizeof *hdr - sizeof hdr->rec_size);
334
335         msecs = pletoh32(hdr->timestamp);
336         phdr->presence_flags = WTAP_HAS_TS;
337         phdr->ts.secs = aethra->start + (msecs / 1000);
338         phdr->ts.nsecs = (msecs % 1000) * 1000000;
339         phdr->caplen = packet_size;
340         phdr->len = packet_size;
341         phdr->pseudo_header.isdn.uton = (hdr->flags & AETHRA_U_TO_N);
342         phdr->pseudo_header.isdn.channel = 0;   /* XXX - D channel */
343
344         return TRUE;
345 }