timestamp display precision:
[metze/wireshark/wip.git] / wiretap / lanalyzer.c
1 /* lanalyzer.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 <stdlib.h>
27 #include <errno.h>
28 #include "wtap-int.h"
29 #include "file_wrappers.h"
30 #include "buffer.h"
31 #include "lanalyzer.h"
32
33 /* The LANalyzer format is documented (at least in part) in Novell document
34    TID022037, which can be found at, among other places:
35
36         http://secinf.net/info/nw/lan/trace.txt
37  */
38
39 /* LANalyzer board types (which indicate the type of network on which
40    the capture was done). */
41 #define BOARD_325               226     /* LANalyzer 325 (Ethernet) */
42 #define BOARD_325TR             227     /* LANalyzer 325TR (Token-ring) */
43
44
45 static const guint8 LA_HeaderRegularFake[] = {
46 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
47 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
48 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
49 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
50 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
51       };
52
53 static const guint8 LA_RxChannelNameFake[] = {
54 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
55 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
56 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
57 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
58 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
59 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
60 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
61 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
62 0x00,0x00,0x00,0x00
63       };
64
65 static const guint8 LA_TxChannelNameFake[] = {
66                     0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
67 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
68 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
69 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
70       };
71
72 static const guint8 LA_RxTemplateNameFake[] = {
73                                                                        0x35,0x10,
74 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
75 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
76 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
77 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
78 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
79 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 0x00,0x00
84       };
85
86 static const guint8 LA_TxTemplateNameFake[] = {
87           0x36,0x10,0x36,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
88 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
91       };
92
93 static const guint8 LA_DisplayOptionsFake[] = {
94                                                              0x0a,0x10,0x0a,0x01,
95 0x00,0x00,0x01,0x00,0x01,0x02,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00
112       };
113
114 static const guint8 LA_CyclicInformationFake[] = {
115                                                    0x09,0x10,0x1a,0x00,0x00,0x00,
116 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
118       };
119
120 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
121     long *data_offset);
122 static gboolean lanalyzer_seek_read(wtap *wth, long seek_off,
123     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
124     int *err, gchar **err_info);
125 static void     lanalyzer_close(wtap *wth);
126 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
127
128 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
129 {
130         int bytes_read;
131         char LE_record_type[2];
132         char LE_record_length[2];
133         char summary[210];
134         guint16 board_type, mxslc;
135         guint16 record_type, record_length;
136         guint8 cr_day, cr_month;
137         guint16 cr_year;
138         struct tm tm;
139
140         errno = WTAP_ERR_CANT_READ;
141         bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
142         bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
143         if (bytes_read != 4) {
144                 *err = file_error(wth->fh);
145                 if (*err != 0)
146                         return -1;
147                 return 0;
148         }
149         wth->data_offset += 4;
150         record_type = pletohs(LE_record_type);
151         record_length = pletohs(LE_record_length); /* make sure to do this for while() loop */
152
153         if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
154                 return 0;
155         }
156
157         /* If we made it this far, then the file is a LANAlyzer file.
158          * Let's get some info from it. Note that we get wth->snapshot_length
159          * from a record later in the file. */
160         wth->file_type = WTAP_FILE_LANALYZER;
161         wth->capture.lanalyzer = g_malloc(sizeof(lanalyzer_t));
162         wth->subtype_read = lanalyzer_read;
163         wth->subtype_seek_read = lanalyzer_seek_read;
164         wth->subtype_close = lanalyzer_close;
165         wth->snapshot_length = 0;
166         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
167
168         /* Read records until we find the start of packets */
169         while (1) {
170                 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
171                         g_free(wth->capture.lanalyzer);
172                         return -1;
173                 }
174                 wth->data_offset += record_length;
175                 errno = WTAP_ERR_CANT_READ;
176                 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
177                 bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
178                 if (bytes_read != 4) {
179                         *err = file_error(wth->fh);
180                         if (*err != 0) {
181                                 g_free(wth->capture.lanalyzer);
182                                 return -1;
183                         }
184                         g_free(wth->capture.lanalyzer);
185                         return 0;
186                 }
187                 wth->data_offset += 4;
188
189                 record_type = pletohs(LE_record_type);
190                 record_length = pletohs(LE_record_length);
191
192                 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
193                 switch (record_type) {
194                         /* Trace Summary Record */
195                         case RT_Summary:
196                                 errno = WTAP_ERR_CANT_READ;
197                                 bytes_read = file_read(summary, 1, sizeof summary,
198                                     wth->fh);
199                                 if (bytes_read != sizeof summary) {
200                                         *err = file_error(wth->fh);
201                                         if (*err != 0) {
202                                                 g_free(wth->capture.lanalyzer);
203                                                 return -1;
204                                         }
205                                         g_free(wth->capture.lanalyzer);
206                                         return 0;
207                                 }
208                                 wth->data_offset += sizeof summary;
209
210                                 /* Assume that the date of the creation of the trace file
211                                  * is the same date of the trace. Lanalyzer doesn't
212                                  * store the creation date/time of the trace, but only of
213                                  * the file. Unless you traced at 11:55 PM and saved at 00:05
214                                  * AM, the assumption that trace.date == file.date is true.
215                                  */
216                                 cr_day = summary[0];
217                                 cr_month = summary[1];
218                                 cr_year = pletohs(&summary[2]);
219                                 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
220                                                 cr_year, cr_year);*/
221
222                                 /* Get capture start time. I learned how to do
223                                  * this from Guy's code in ngsniffer.c
224                                  */
225                                 tm.tm_year = cr_year - 1900;
226                                 tm.tm_mon = cr_month - 1;
227                                 tm.tm_mday = cr_day;
228                                 tm.tm_hour = 0;
229                                 tm.tm_min = 0;
230                                 tm.tm_sec = 0;
231                                 tm.tm_isdst = -1;
232                                 wth->capture.lanalyzer->start = mktime(&tm);
233                                 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
234                                                 tm.tm_mon, tm.tm_year);*/
235                                 mxslc = pletohs(&summary[30]);
236                                 wth->snapshot_length = mxslc;
237
238                                 record_length = 0; /* to fake the next iteration of while() */
239                                 board_type = pletohs(&summary[188]);
240                                 switch (board_type) {
241                                         case BOARD_325:
242                                                 wth->file_encap = WTAP_ENCAP_ETHERNET;
243                                                 break;
244                                         case BOARD_325TR:
245                                                 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
246                                                 break;
247                                         default:
248                                                 g_free(wth->capture.lanalyzer);
249                                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
250                                                 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
251                                                     board_type);
252                                                 return -1;
253                                 }
254                                 break;
255
256                         /* Trace Packet Data Record */
257                         case RT_PacketData:
258                                 /* Go back header number ob ytes so that lanalyzer_read
259                                  * can read this header */
260                                 if (file_seek(wth->fh, -bytes_read, SEEK_CUR, err) == -1) {
261                                         g_free(wth->capture.lanalyzer);
262                                         return -1;
263                                 }
264                                 wth->data_offset -= bytes_read;
265                                 return 1;
266
267                         default:
268                                 ; /* no action */
269                 }
270         }
271 }
272
273 #define DESCRIPTOR_LEN  32
274
275 /* Read the next packet */
276 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
277     long *data_offset)
278 {
279         int             packet_size = 0;
280         int             bytes_read;
281         char            LE_record_type[2];
282         char            LE_record_length[2];
283         guint16         record_type, record_length;
284         gchar           descriptor[DESCRIPTOR_LEN];
285         guint16         time_low, time_med, time_high, true_size;
286         double          t;
287
288         /* read the record type and length. */
289         errno = WTAP_ERR_CANT_READ;
290         bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
291         if (bytes_read != 2) {
292                 *err = file_error(wth->fh);
293                 if (*err == 0 && bytes_read != 0) {
294                         *err = WTAP_ERR_SHORT_READ;
295                 }
296                 return FALSE;
297         }
298         wth->data_offset += 2;
299         bytes_read = file_read(LE_record_length, 1, 2, wth->fh);
300         if (bytes_read != 2) {
301                 *err = file_error(wth->fh);
302                 if (*err == 0)
303                         *err = WTAP_ERR_SHORT_READ;
304                 return FALSE;
305         }
306         wth->data_offset += 2;
307
308         record_type = pletohs(LE_record_type);
309         record_length = pletohs(LE_record_length);
310
311         /* Only Trace Packet Data Records should occur now that we're in
312          * the middle of reading packets.  If any other record type exists
313          * after a Trace Packet Data Record, mark it as an error. */
314         if (record_type != RT_PacketData) {
315                 *err = WTAP_ERR_BAD_RECORD;
316                 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
317                     record_type);
318                 return FALSE;
319         }
320         else {
321                 packet_size = record_length - DESCRIPTOR_LEN;
322         }
323
324         /* Read the descriptor data */
325         errno = WTAP_ERR_CANT_READ;
326         bytes_read = file_read(descriptor, 1, DESCRIPTOR_LEN, wth->fh);
327         if (bytes_read != DESCRIPTOR_LEN) {
328                 *err = file_error(wth->fh);
329                 if (*err == 0)
330                         *err = WTAP_ERR_SHORT_READ;
331                 return FALSE;
332         }
333         wth->data_offset += DESCRIPTOR_LEN;
334
335         /* Read the packet data */
336         buffer_assure_space(wth->frame_buffer, packet_size);
337         *data_offset = wth->data_offset;
338         errno = WTAP_ERR_CANT_READ;
339         bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
340                 packet_size, wth->fh);
341
342         if (bytes_read != packet_size) {
343                 *err = file_error(wth->fh);
344                 if (*err == 0)
345                         *err = WTAP_ERR_SHORT_READ;
346                 return FALSE;
347         }
348         wth->data_offset += packet_size;
349
350         true_size = pletohs(&descriptor[4]);
351         packet_size = pletohs(&descriptor[6]);
352         time_low = pletohs(&descriptor[8]);
353         time_med = pletohs(&descriptor[10]);
354         time_high = pletohs(&descriptor[12]);
355
356         /*
357          * OK, is the frame data size greater than than what's left of the
358          * record?
359          */
360         if (packet_size > record_length - DESCRIPTOR_LEN) {
361                 /*
362                  * Yes - treat this as an error.
363                  */
364                 *err = WTAP_ERR_BAD_RECORD;
365                 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
366                 return FALSE;
367         }
368
369         t = (double)time_low+(double)(time_med)*65536.0 +
370                 (double)time_high*4294967296.0;
371         t = t/1000000.0 * 0.5; /* t = # of secs */
372         t += wth->capture.lanalyzer->start;
373
374         wth->phdr.ts.secs = (long)t;
375         wth->phdr.ts.nsecs = (unsigned long)((t-(double)(wth->phdr.ts.secs))
376                         *1.0e9);
377
378         if (true_size - 4 >= packet_size) {
379                 /*
380                  * It appears that the "true size" includes the FCS;
381                  * make it reflect the non-FCS size (the "packet size"
382                  * appears never to include the FCS, even if no slicing
383                  * is done).
384                  */
385                 true_size -= 4;
386         }
387         wth->phdr.len = true_size;
388         wth->phdr.caplen = packet_size;
389
390         switch (wth->file_encap) {
391
392         case WTAP_ENCAP_ETHERNET:
393                 /* We assume there's no FCS in this frame. */
394                 wth->pseudo_header.eth.fcs_len = 0;
395                 break;
396         }
397
398         return TRUE;
399 }
400
401 static gboolean lanalyzer_seek_read(wtap *wth, long seek_off,
402     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
403     int *err, gchar **err_info _U_)
404 {
405         int bytes_read;
406
407         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
408                 return FALSE;
409
410         /*
411          * Read the packet data.
412          */
413         bytes_read = file_read(pd, sizeof(guint8), length, wth->random_fh);
414         if (bytes_read != length) {
415                 *err = file_error(wth->random_fh);
416                 if (*err == 0)
417                         *err = WTAP_ERR_SHORT_READ;
418                 return FALSE;
419         }
420
421         switch (wth->file_encap) {
422
423         case WTAP_ENCAP_ETHERNET:
424                 /* We assume there's no FCS in this frame. */
425                 pseudo_header->eth.fcs_len = 0;
426                 break;
427         }
428
429         return TRUE;
430 }
431
432 static void
433 lanalyzer_close(wtap *wth)
434 {
435         g_free(wth->capture.lanalyzer);
436 }
437
438 /*---------------------------------------------------
439  * Returns 0 or error
440  * Write one block with error control
441  *---------------------------------------------------*/
442 static int swrite(const void* what, guint size, FILE *hd)
443 {
444         size_t nwritten;
445
446         nwritten = fwrite(what, 1, size, hd);
447         if (nwritten != size) {
448                 if (nwritten == 0 && ferror(hd))
449                         return errno;
450                 else
451                         return WTAP_ERR_SHORT_WRITE;
452             }
453         return 0; /* ok */
454 }
455
456 /*---------------------------------------------------
457  * Returns 0 or error
458  * Write one block with error control
459  *---------------------------------------------------*/
460 static int s0write(guint cnt, FILE *hd)
461 {
462         static guint8 z64[64];
463         size_t nwritten;
464         size_t snack;
465
466         while (cnt) {
467             snack = cnt > 64 ? 64 : cnt;
468             nwritten = fwrite(z64, 1, snack, hd);
469             if (nwritten != snack) {
470                       if (nwritten == 0 && ferror(hd))
471                               return errno;
472                       else
473                               return WTAP_ERR_SHORT_WRITE;
474                   }
475             cnt -= snack;
476             }
477         return 0; /* ok */
478 }
479
480 /*---------------------------------------------------
481  * Returns 0 or error
482  * Write one block with error control
483  *---------------------------------------------------*/
484 static int s8write(const guint8 s8, FILE *hd)
485 {
486         size_t nwritten;
487
488         nwritten = fwrite(&s8, 1, 1, hd);
489         if (nwritten != 1) {
490                 if (nwritten == 0 && ferror(hd))
491                         return errno;
492                 else
493                         return WTAP_ERR_SHORT_WRITE;
494             }
495         return 0; /* ok */
496 }
497 /*---------------------------------------------------
498  * Returns 0 or error
499  * Write one block with error control
500  *---------------------------------------------------*/
501 static int s16write(const guint16 s16, FILE *hd)
502 {
503         size_t nwritten;
504
505         nwritten = fwrite(&s16, 1, 2, hd);
506         if (nwritten != 2) {
507                 if (nwritten == 0 && ferror(hd))
508                         return errno;
509                 else
510                         return WTAP_ERR_SHORT_WRITE;
511             }
512         return 0; /* ok */
513 }
514 /*---------------------------------------------------
515  * Returns 0 or error
516  * Write one block with error control
517  *---------------------------------------------------*/
518 static int s32write(const guint32 s32, FILE *hd)
519 {
520         size_t nwritten;
521
522         nwritten = fwrite(&s32, 1, 4, hd);
523         if (nwritten != 4) {
524                 if (nwritten == 0 && ferror(hd))
525                         return errno;
526                 else
527                         return WTAP_ERR_SHORT_WRITE;
528             }
529         return 0; /* ok */
530 }
531 /*---------------------------------------------------
532  *
533  * calculates C.c = A.a - B.b
534  *---------------------------------------------------*/
535 static void my_timersub(const struct timeval *a,
536                         const struct timeval *b,
537                               struct timeval *c)
538 {
539       gint32 usec = a->tv_usec;
540
541       c->tv_sec = a->tv_sec - b->tv_sec;
542       if (b->tv_usec > usec) {
543            c->tv_sec--;
544            usec += 1000000;
545            }
546       c->tv_usec = usec - b->tv_usec;
547 }
548 /*---------------------------------------------------
549  * Write a record for a packet to a dump file.
550  * Returns TRUE on success, FALSE on failure.
551  *---------------------------------------------------*/
552 static gboolean lanalyzer_dump(wtap_dumper *wdh,
553         const struct wtap_pkthdr *phdr,
554         const union wtap_pseudo_header *pseudo_header _U_,
555         const guchar *pd, int *err)
556 {
557       double x;
558       int    i;
559       int    len;
560           struct timeval tv;
561
562       LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->dump.opaque);
563       struct timeval td;
564       int    thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
565
566       if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
567             /* printf(" LA_ProFileLimit reached\n");     */
568             *err = EFBIG;
569             return FALSE; /* and don't forget the header */
570             }
571
572       len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
573
574       *err = s16write(htoles(0x1005), wdh->fh);
575       if (*err)
576             return FALSE;
577       *err = s16write(htoles(len), wdh->fh);
578       if (*err)
579             return FALSE;
580
581           tv.tv_sec  = phdr->ts.secs;
582           tv.tv_usec = phdr->ts.nsecs / 1000;
583
584       if (!itmp->init) {
585             /* collect some information for the
586              * finally written header
587              */
588                     /* XXX - this conversion could probably improved, if the start uses ns */
589             itmp->start   = tv;
590             itmp->pkts    = 0;
591             itmp->init    = TRUE;
592             itmp->encap   = wdh->encap;
593             itmp->lastlen = 0;
594             }
595
596       my_timersub(&(tv),&(itmp->start),&td);
597
598       x   = (double) td.tv_usec;
599       x  += (double) td.tv_sec * 1000000;
600       x  *= 2;
601
602       *err = s16write(htoles(0x0001), wdh->fh);           /* pr.rx_channels */
603       if (*err)
604             return FALSE;
605       *err = s16write(htoles(0x0008), wdh->fh);           /* pr.rx_errors   */
606       if (*err)
607             return FALSE;
608       *err = s16write(htoles(phdr->len + 4), wdh->fh);    /* pr.rx_frm_len  */
609       if (*err)
610             return FALSE;
611       *err = s16write(htoles(phdr->caplen), wdh->fh);     /* pr.rx_frm_sln  */
612       if (*err)
613             return FALSE;
614
615       for (i = 0; i < 3; i++) {
616             *err = s16write(htoles((guint16) x), wdh->fh);/* pr.rx_time[i]  */
617             if (*err)
618                   return FALSE;
619             x /= 0xffff;
620             }
621
622       *err = s32write(htolel(++itmp->pkts), wdh->fh);      /* pr.pktno      */
623       if (*err)
624             return FALSE;
625       *err = s16write(htoles(itmp->lastlen), wdh->fh);     /* pr.prlen      */
626       if (*err)
627             return FALSE;
628       itmp->lastlen = len;
629
630       *err = s0write(12, wdh->fh);
631       if (*err)
632                 return FALSE;
633
634       *err = swrite(pd , phdr->caplen , wdh->fh);
635       if (*err)
636                 return FALSE;
637
638       wdh->bytes_dumped += thisSize;
639
640       return TRUE;
641 }
642
643 /*---------------------------------------------------
644  * Returns 0 if we could write the specified encapsulation type,
645  * an error indication otherwise.
646  *---------------------------------------------------*/
647 int lanalyzer_dump_can_write_encap(int encap)
648 {
649       /* Per-packet encapsulations aren't supported. */
650       if (encap == WTAP_ENCAP_PER_PACKET)
651                   return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
652
653       if ( encap != WTAP_ENCAP_ETHERNET
654         && encap != WTAP_ENCAP_TOKEN_RING )
655                   return WTAP_ERR_UNSUPPORTED_ENCAP;
656       /*
657        * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
658        */
659       return 0;
660 }
661
662 /*---------------------------------------------------
663  * Returns TRUE on success, FALSE on failure; sets "*err" to an
664  * error code on failure
665  *---------------------------------------------------*/
666 gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
667 {
668       int   jump;
669       void  *tmp;
670
671       /* This is a LANalyzer file.  We can't fill in some fields in the
672          header until all the packets have been written, so we can't
673          write to a pipe. */
674       if (cant_seek) {
675               *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
676               return FALSE;
677             }
678
679       tmp = g_malloc(sizeof(LA_TmpInfo));
680       if (!tmp) {
681               *err = errno;
682               return FALSE;
683             }
684
685       ((LA_TmpInfo*)tmp)->init = FALSE;
686       wdh->dump.opaque         = tmp;
687       wdh->subtype_write       = lanalyzer_dump;
688       wdh->subtype_close       = lanalyzer_dump_close;
689
690       /* Some of the fields in the file header aren't known yet so
691        just skip over it for now.  It will be created after all
692        of the packets have been written. */
693
694       jump = sizeof (LA_HeaderRegularFake)
695            + sizeof (LA_RxChannelNameFake)
696            + sizeof (LA_TxChannelNameFake)
697            + sizeof (LA_RxTemplateNameFake)
698            + sizeof (LA_TxTemplateNameFake)
699            + sizeof (LA_DisplayOptionsFake)
700            + LA_SummaryRecordSize
701            + LA_SubfileSummaryRecordSize
702            + sizeof (LA_CyclicInformationFake)
703            + LA_IndexRecordSize;
704
705       if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
706               *err = errno;
707               return FALSE;
708             }
709       wdh->bytes_dumped = jump;
710       return TRUE;
711 }
712
713 /*---------------------------------------------------
714  *
715  *---------------------------------------------------*/
716 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
717 {
718       LA_TmpInfo *itmp   = (LA_TmpInfo*)(wdh->dump.opaque);
719       struct tm  *fT     = localtime(&(itmp->start.tv_sec));
720       guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
721                               ? BOARD_325TR     /* LANalyzer Board Type */
722                               : BOARD_325;      /* LANalyzer Board Type */
723
724       fseek(wdh->fh, 0, SEEK_SET);
725
726       *err = swrite(&LA_HeaderRegularFake,  sizeof LA_HeaderRegularFake, wdh->fh);
727       if (*err)
728                 return FALSE;
729       *err = swrite(&LA_RxChannelNameFake , sizeof LA_RxChannelNameFake , wdh->fh);
730       if (*err)
731                 return FALSE;
732       *err = swrite(&LA_TxChannelNameFake , sizeof LA_TxChannelNameFake , wdh->fh);
733       if (*err)
734                 return FALSE;
735       *err = swrite(&LA_RxTemplateNameFake, sizeof LA_RxTemplateNameFake, wdh->fh);
736       if (*err)
737                 return FALSE;
738       *err = swrite(&LA_TxTemplateNameFake, sizeof LA_TxTemplateNameFake, wdh->fh);
739       if (*err)
740                 return FALSE;
741       *err = swrite(&LA_DisplayOptionsFake, sizeof LA_DisplayOptionsFake, wdh->fh);
742       if (*err)
743                 return FALSE;
744       /*-----------------------------------------------------------------*/
745       *err = s16write(htoles(RT_Summary), wdh->fh);        /* rid */
746       if (*err)
747             return FALSE;
748       *err = s16write(htoles(SummarySize), wdh->fh);       /* rlen */
749       if (*err)
750             return FALSE;
751       *err = s8write((guint8) fT->tm_mday, wdh->fh);       /* s.datcre.day */
752       if (*err)
753             return FALSE;
754       *err = s8write((guint8) (fT->tm_mon+1), wdh->fh);    /* s.datcre.mon */
755       if (*err)
756             return FALSE;
757       *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datcre.year */
758       if (*err)
759             return FALSE;
760       *err = s8write((guint8) fT->tm_mday, wdh->fh);       /* s.datclo.day */
761       if (*err)
762             return FALSE;
763       *err = s8write((guint8) (fT->tm_mon+1), wdh->fh);    /* s.datclo.mon */
764       if (*err)
765             return FALSE;
766       *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datclo.year */
767       if (*err)
768             return FALSE;
769       *err = s8write((guint8) fT->tm_sec, wdh->fh);        /* s.timeopn.second */
770       if (*err)
771             return FALSE;
772       *err = s8write((guint8) fT->tm_min, wdh->fh);        /* s.timeopn.minute */
773       if (*err)
774             return FALSE;
775       *err = s8write((guint8) fT->tm_hour, wdh->fh);       /* s.timeopn.hour */
776       if (*err)
777             return FALSE;
778       *err = s8write((guint8) fT->tm_mday, wdh->fh);       /* s.timeopn.mday */
779       if (*err)
780             return FALSE;
781       *err = s0write(2, wdh->fh);
782       if (*err)
783                 return FALSE;
784       *err = s8write((guint8) fT->tm_sec, wdh->fh);        /* s.timeclo.second */
785       if (*err)
786             return FALSE;
787       *err = s8write((guint8) fT->tm_min, wdh->fh);        /* s.timeclo.minute */
788       if (*err)
789             return FALSE;
790       *err = s8write((guint8) fT->tm_hour, wdh->fh);       /* s.timeclo.hour */
791       if (*err)
792             return FALSE;
793       *err = s8write((guint8) fT->tm_mday, wdh->fh);       /* s.timeclo.mday */
794       if (*err)
795             return FALSE;
796       *err = s0write(2, wdh->fh);
797       if (*err)
798                 return FALSE;
799       *err = s0write(6, wdh->fh);                          /* EAddr  == 0      */
800       if (*err)
801                 return FALSE;
802       *err = s16write(htoles(1), wdh->fh);                 /* s.mxseqno */
803       if (*err)
804             return FALSE;
805       *err = s16write(htoles(0), wdh->fh);                 /* s.slcoffo */
806       if (*err)
807             return FALSE;
808       *err = s16write(htoles(1514), wdh->fh);              /* s.mxslc */
809       if (*err)
810             return FALSE;
811       *err = s32write(htolel(itmp->pkts), wdh->fh);        /* s.totpktt */
812       if (*err)
813             return FALSE;
814       *err = s0write(12, wdh->fh);                         /* statrg == 0; ? -1*/
815       if (*err)                                            /* stptrg == 0; ? -1*/
816                 return FALSE;                                  /* s.mxpkta[0]=0    */
817       *err = s32write(htolel(itmp->pkts), wdh->fh);        /* sr.s.mxpkta[1]  */
818       if (*err)
819             return FALSE;
820       *err = s0write(34*4, wdh->fh);                       /* s.mxpkta[2-33]=0  */
821       if (*err)
822                 return FALSE;
823       *err = s16write(htoles(board_type), wdh->fh);
824       if (*err)
825             return FALSE;
826       *err = s0write(20, wdh->fh);                         /* board_version == 0 */
827       if (*err)
828             return FALSE;
829       /*-----------------------------------------------------------------*/
830       *err = s16write(htoles(RT_SubfileSummary), wdh->fh);    /* ssr.rid */
831       if (*err)
832             return FALSE;
833       *err = s16write(htoles(LA_SubfileSummaryRecordSize-4), wdh->fh);    /* ssr.rlen */
834       if (*err)
835             return FALSE;
836       *err = s16write(htoles(1), wdh->fh);                    /* ssr.seqno */
837       if (*err)
838             return FALSE;
839       *err = s32write(htolel(itmp->pkts), wdh->fh);           /* ssr.totpkts */
840       if (*err)
841             return FALSE;
842       /*-----------------------------------------------------------------*/
843       *err = swrite(&LA_CyclicInformationFake, sizeof LA_CyclicInformationFake, wdh->fh);
844       if (*err)
845                 return FALSE;
846       /*-----------------------------------------------------------------*/
847       *err = s16write(htoles(RT_Index), wdh->fh);             /* rid */
848       if (*err)
849             return FALSE;
850       *err = s16write(htoles(LA_IndexRecordSize -4), wdh->fh);/* rlen */
851       if (*err)
852             return FALSE;
853       *err = s16write(htoles(LA_IndexSize), wdh->fh);         /* idxsp */
854       if (*err)
855             return FALSE;
856       *err = s0write(LA_IndexRecordSize - 6, wdh->fh);
857       if (*err)
858             return FALSE;
859
860       return TRUE;
861 }
862
863 /*---------------------------------------------------
864  * Finish writing to a dump file.
865  * Returns TRUE on success, FALSE on failure.
866  *---------------------------------------------------*/
867 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
868 {
869       lanalyzer_dump_header(wdh,err);
870       return *err ? FALSE : TRUE;
871 }