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