Use the "rx_frm_len" field from the trace packet data record header,
[obnox/wireshark/wip.git] / wiretap / lanalyzer.c
1 /* lanalyzer.c
2  *
3  * $Id: lanalyzer.c,v 1.38 2003/06/30 00:41:33 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         packet_size = pletohs(&descriptor[6]);
348         time_low = pletohs(&descriptor[8]);
349         time_med = pletohs(&descriptor[10]);
350         time_high = pletohs(&descriptor[12]);
351
352         /*
353          * OK, is the frame data size greater than than what's left of the
354          * record?
355          */
356         if (packet_size > record_length - DESCRIPTOR_LEN) {
357                 /*
358                  * Yes - treat this as an error.
359                  */
360                 g_message("lanalyzer: Record length is less than packet size");
361                 *err = WTAP_ERR_BAD_RECORD;
362                 return FALSE;
363         }
364
365         t = (double)time_low+(double)(time_med)*65536.0 +
366                 (double)time_high*4294967296.0;
367         t = t/1000000.0 * 0.5; /* t = # of secs */
368         t += wth->capture.lanalyzer->start;
369
370         wth->phdr.ts.tv_sec = (long)t;
371         wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
372                         *1.0e6);
373
374         if (true_size - 4 >= packet_size) {
375                 /*
376                  * It appears that the "true size" includes the FCS;
377                  * make it reflect the non-FCS size (the "packet size"
378                  * appears never to include the FCS, even if no slicing
379                  * is done).
380                  */
381                 true_size -= 4;
382         }
383         wth->phdr.len = true_size;
384         wth->phdr.caplen = packet_size;
385         wth->phdr.pkt_encap = wth->file_encap;
386
387         return TRUE;
388 }
389
390 static void
391 lanalyzer_close(wtap *wth)
392 {
393         g_free(wth->capture.lanalyzer);
394 }
395
396 /*---------------------------------------------------
397  * Returns 0 or error
398  * Write one block with error control
399  *---------------------------------------------------*/
400 static int swrite(const void* what, guint size, FILE *hd)
401 {
402         size_t nwritten;
403
404         nwritten = fwrite(what, 1, size, hd);
405         if (nwritten != size) {
406                 if (nwritten == 0 && ferror(hd))
407                         return errno;
408                 else
409                         return WTAP_ERR_SHORT_WRITE;
410             }
411         return 0; /* ok */
412 }
413
414 /*---------------------------------------------------
415  * Returns 0 or error
416  * Write one block with error control
417  *---------------------------------------------------*/
418 static int s0write(guint cnt, FILE *hd)
419 {
420         static gint8 z64[64];
421         size_t nwritten;
422         size_t snack;
423
424         while (cnt) {
425             snack = cnt > 64 ? 64 : cnt;
426             nwritten = fwrite(z64, 1, snack, hd);
427             if (nwritten != snack) {
428                       if (nwritten == 0 && ferror(hd))
429                               return errno;
430                       else
431                               return WTAP_ERR_SHORT_WRITE;
432                   }
433             cnt -= snack;
434             }
435         return 0; /* ok */
436 }
437
438 /*---------------------------------------------------
439  * Returns 0 or error
440  * Write one block with error control
441  *---------------------------------------------------*/
442 static int s8write(const guint8 s8, FILE *hd)
443 {
444         size_t nwritten;
445
446         nwritten = fwrite(&s8, 1, 1, hd);
447         if (nwritten != 1) {
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  * Returns 0 or error
457  * Write one block with error control
458  *---------------------------------------------------*/
459 static int s16write(const guint16 s16, FILE *hd)
460 {
461         size_t nwritten;
462
463         nwritten = fwrite(&s16, 1, 2, hd);
464         if (nwritten != 2) {
465                 if (nwritten == 0 && ferror(hd))
466                         return errno;
467                 else
468                         return WTAP_ERR_SHORT_WRITE;
469             }
470         return 0; /* ok */
471 }
472 /*---------------------------------------------------
473  * Returns 0 or error
474  * Write one block with error control
475  *---------------------------------------------------*/
476 static int s32write(const guint32 s32, FILE *hd)
477 {
478         size_t nwritten;
479
480         nwritten = fwrite(&s32, 1, 4, hd);
481         if (nwritten != 4) {
482                 if (nwritten == 0 && ferror(hd))
483                         return errno;
484                 else
485                         return WTAP_ERR_SHORT_WRITE;
486             }
487         return 0; /* ok */
488 }
489 /*---------------------------------------------------
490  *
491  * calculates C.c = A.a - B.b
492  *---------------------------------------------------*/
493 static void my_timersub(const struct timeval *a,
494                         const struct timeval *b,
495                               struct timeval *c)
496 {
497       gint32 usec = a->tv_usec;
498
499       c->tv_sec = a->tv_sec - b->tv_sec;
500       if (b->tv_usec > usec) {
501            c->tv_sec--;
502            usec += 1000000;
503            }
504       c->tv_usec = usec - b->tv_usec;
505 }
506 /*---------------------------------------------------
507  * Write a record for a packet to a dump file.
508  * Returns TRUE on success, FALSE on failure.
509  *---------------------------------------------------*/
510 static gboolean lanalyzer_dump(wtap_dumper *wdh,
511         const struct wtap_pkthdr *phdr,
512         const union wtap_pseudo_header *pseudo_header _U_,
513         const guchar *pd, int *err)
514 {
515       double x;
516       int    i;
517       int    len;
518
519       LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->dump.opaque);
520       struct timeval td;
521       int    thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
522
523       if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
524             /* printf(" LA_ProFileLimit reached\n");     */
525             *err = EFBIG;
526             return FALSE; /* and don't forget the header */
527             }
528
529       len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
530
531       *err = s16write(htoles(0x1005), wdh->fh);
532       if (*err)
533             return FALSE;
534       *err = s16write(htoles(len), wdh->fh);
535       if (*err)
536             return FALSE;
537
538
539       if (!itmp->init) {
540             /* collect some information for the
541              * finally written header
542              */
543             itmp->start   = phdr->ts;
544             itmp->pkts    = 0;
545             itmp->init    = TRUE;
546             itmp->encap   = wdh->encap;
547             itmp->lastlen = 0;
548             }
549
550       my_timersub(&(phdr->ts),&(itmp->start),&td);
551
552       x   = (double) td.tv_usec;
553       x  += (double) td.tv_sec * 1000000;
554       x  *= 2;
555
556       *err = s16write(htoles(0x0001), wdh->fh);           /* pr.rx_channels */
557       if (*err)
558             return FALSE;
559       *err = s16write(htoles(0x0008), wdh->fh);           /* pr.rx_errors   */
560       if (*err)
561             return FALSE;
562       *err = s16write(htoles(phdr->len + 4), wdh->fh);    /* pr.rx_frm_len  */
563       if (*err)
564             return FALSE;
565       *err = s16write(htoles(phdr->caplen), wdh->fh);     /* pr.rx_frm_sln  */
566       if (*err)
567             return FALSE;
568
569       for (i = 0; i < 3; i++) {
570             *err = s16write(htoles((guint16) x), wdh->fh);/* pr.rx_time[i]  */
571             if (*err)
572                   return FALSE;
573             x /= 0xffff;
574             }
575
576       *err = s32write(htolel(++itmp->pkts), wdh->fh);      /* pr.pktno      */
577       if (*err)
578             return FALSE;
579       *err = s16write(htoles(itmp->lastlen), wdh->fh);     /* pr.prlen      */
580       if (*err)
581             return FALSE;
582       itmp->lastlen = len;
583
584       *err = s0write(12, wdh->fh);
585       if (*err)
586                 return FALSE;
587
588       *err = swrite(pd , phdr->caplen , wdh->fh);
589       if (*err)
590                 return FALSE;
591
592       wdh->bytes_dumped += thisSize;
593
594       return TRUE;
595 }
596
597 /*---------------------------------------------------
598  * Returns 0 if we could write the specified encapsulation type,
599  * an error indication otherwise.
600  *---------------------------------------------------*/
601 int lanalyzer_dump_can_write_encap(int encap)
602 {
603       /* Per-packet encapsulations aren't supported. */
604       if (encap == WTAP_ENCAP_PER_PACKET)
605                   return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
606
607       if ( encap != WTAP_ENCAP_ETHERNET
608         && encap != WTAP_ENCAP_TOKEN_RING )
609                   return WTAP_ERR_UNSUPPORTED_ENCAP;
610       /*
611        * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
612        */
613       return 0;
614 }
615
616 /*---------------------------------------------------
617  * Returns TRUE on success, FALSE on failure; sets "*err" to an
618  * error code on failure
619  *---------------------------------------------------*/
620 gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
621 {
622       int   jump;
623       void  *tmp;
624
625       /* This is a LANalyzer file.  We can't fill in some fields in the
626          header until all the packets have been written, so we can't
627          write to a pipe. */
628       if (cant_seek) {
629               *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
630               return FALSE;
631             }
632
633       tmp = g_malloc(sizeof(LA_TmpInfo));
634       if (!tmp) {
635               *err = errno;
636               return FALSE;
637             }
638
639       ((LA_TmpInfo*)tmp)->init = FALSE;
640       wdh->dump.opaque         = tmp;
641       wdh->subtype_write       = lanalyzer_dump;
642       wdh->subtype_close       = lanalyzer_dump_close;
643
644       /* Some of the fields in the file header aren't known yet so
645        just skip over it for now.  It will be created after all
646        of the packets have been written. */
647
648       jump = sizeof (LA_HeaderRegularFake)
649            + sizeof (LA_RxChannelNameFake)
650            + sizeof (LA_TxChannelNameFake)
651            + sizeof (LA_RxTemplateNameFake)
652            + sizeof (LA_TxTemplateNameFake)
653            + sizeof (LA_DisplayOptionsFake)
654            + LA_SummaryRecordSize
655            + LA_SubfileSummaryRecordSize
656            + sizeof (LA_CyclicInformationFake)
657            + LA_IndexRecordSize;
658
659       if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
660               *err = errno;
661               return FALSE;
662             }
663       wdh->bytes_dumped = jump;
664       return TRUE;
665 }
666
667 /*---------------------------------------------------
668  *
669  *---------------------------------------------------*/
670 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
671 {
672       LA_TmpInfo *itmp   = (LA_TmpInfo*)(wdh->dump.opaque);
673       struct tm  *fT     = localtime(&(itmp->start.tv_sec));
674       guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
675                               ? BOARD_325TR     /* LANalyzer Board Type */
676                               : BOARD_325;      /* LANalyzer Board Type */
677
678       fseek(wdh->fh, 0, SEEK_SET);
679
680       *err = swrite(&LA_HeaderRegularFake,  sizeof LA_HeaderRegularFake, wdh->fh);
681       if (*err)
682                 return FALSE;
683       *err = swrite(&LA_RxChannelNameFake , sizeof LA_RxChannelNameFake , wdh->fh);
684       if (*err)
685                 return FALSE;
686       *err = swrite(&LA_TxChannelNameFake , sizeof LA_TxChannelNameFake , wdh->fh);
687       if (*err)
688                 return FALSE;
689       *err = swrite(&LA_RxTemplateNameFake, sizeof LA_RxTemplateNameFake, wdh->fh);
690       if (*err)
691                 return FALSE;
692       *err = swrite(&LA_TxTemplateNameFake, sizeof LA_TxTemplateNameFake, wdh->fh);
693       if (*err)
694                 return FALSE;
695       *err = swrite(&LA_DisplayOptionsFake, sizeof LA_DisplayOptionsFake, wdh->fh);
696       if (*err)
697                 return FALSE;
698       /*-----------------------------------------------------------------*/
699       *err = s16write(htoles(RT_Summary), wdh->fh);        /* rid */
700       if (*err)
701             return FALSE;
702       *err = s16write(htoles(SummarySize), wdh->fh);       /* rlen */
703       if (*err)
704             return FALSE;
705       *err = s8write(fT->tm_mday, wdh->fh);                /* s.datcre.day */
706       if (*err)
707             return FALSE;
708       *err = s8write(fT->tm_mon+1, wdh->fh);               /* s.datcre.mon */
709       if (*err)
710             return FALSE;
711       *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datcre.year */
712       if (*err)
713             return FALSE;
714       *err = s8write(fT->tm_mday, wdh->fh);                /* s.datclo.day */
715       if (*err)
716             return FALSE;
717       *err = s8write(fT->tm_mon+1, wdh->fh);               /* s.datclo.mon */
718       if (*err)
719             return FALSE;
720       *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datclo.year */
721       if (*err)
722             return FALSE;
723       *err = s8write(fT->tm_sec, wdh->fh);                 /* s.timeopn.second */
724       if (*err)
725             return FALSE;
726       *err = s8write(fT->tm_min, wdh->fh);                 /* s.timeopn.minute */
727       if (*err)
728             return FALSE;
729       *err = s8write(fT->tm_hour, wdh->fh);                /* s.timeopn.hour */
730       if (*err)
731             return FALSE;
732       *err = s8write(fT->tm_mday, wdh->fh);                /* s.timeopn.mday */
733       if (*err)
734             return FALSE;
735       *err = s0write(2, wdh->fh);
736       if (*err)
737                 return FALSE;
738       *err = s8write(fT->tm_sec, wdh->fh);                 /* s.timeclo.second */
739       if (*err)
740             return FALSE;
741       *err = s8write(fT->tm_min, wdh->fh);                 /* s.timeclo.minute */
742       if (*err)
743             return FALSE;
744       *err = s8write(fT->tm_hour, wdh->fh);                /* s.timeclo.hour */
745       if (*err)
746             return FALSE;
747       *err = s8write(fT->tm_mday, wdh->fh);                /* s.timeclo.mday */
748       if (*err)
749             return FALSE;
750       *err = s0write(2, wdh->fh);
751       if (*err)
752                 return FALSE;
753       *err = s0write(6, wdh->fh);                          /* EAddr  == 0      */
754       if (*err)
755                 return FALSE;
756       *err = s16write(htoles(1), wdh->fh);                 /* s.mxseqno */
757       if (*err)
758             return FALSE;
759       *err = s16write(htoles(0), wdh->fh);                 /* s.slcoffo */
760       if (*err)
761             return FALSE;
762       *err = s16write(htoles(1514), wdh->fh);              /* s.mxslc */
763       if (*err)
764             return FALSE;
765       *err = s32write(htolel(itmp->pkts), wdh->fh);        /* s.totpktt */
766       if (*err)
767             return FALSE;
768       *err = s0write(12, wdh->fh);                         /* statrg == 0; ? -1*/
769       if (*err)                                            /* stptrg == 0; ? -1*/
770                 return FALSE;                                  /* s.mxpkta[0]=0    */
771       *err = s32write(htolel(itmp->pkts), wdh->fh);        /* sr.s.mxpkta[1]  */
772       if (*err)
773             return FALSE;
774       *err = s0write(34*4, wdh->fh);                       /* s.mxpkta[2-33]=0  */
775       if (*err)
776                 return FALSE;
777       *err = s16write(htoles(board_type), wdh->fh);
778       if (*err)
779             return FALSE;
780       *err = s0write(20, wdh->fh);                         /* board_version == 0 */
781       if (*err)
782             return FALSE;
783       /*-----------------------------------------------------------------*/
784       *err = s16write(htoles(RT_SubfileSummary), wdh->fh);    /* ssr.rid */
785       if (*err)
786             return FALSE;
787       *err = s16write(htoles(LA_SubfileSummaryRecordSize-4), wdh->fh);    /* ssr.rlen */
788       if (*err)
789             return FALSE;
790       *err = s16write(htoles(1), wdh->fh);                    /* ssr.seqno */
791       if (*err)
792             return FALSE;
793       *err = s32write(htolel(itmp->pkts), wdh->fh);           /* ssr.totpkts */
794       if (*err)
795             return FALSE;
796       /*-----------------------------------------------------------------*/
797       *err = swrite(&LA_CyclicInformationFake, sizeof LA_CyclicInformationFake, wdh->fh);
798       if (*err)
799                 return FALSE;
800       /*-----------------------------------------------------------------*/
801       *err = s16write(htoles(RT_Index), wdh->fh);             /* rid */
802       if (*err)
803             return FALSE;
804       *err = s16write(htoles(LA_IndexRecordSize -4), wdh->fh);/* rlen */
805       if (*err)
806             return FALSE;
807       *err = s16write(htoles(LA_IndexSize), wdh->fh);         /* idxsp */
808       if (*err)
809             return FALSE;
810       *err = s0write(LA_IndexRecordSize - 6, wdh->fh);
811       if (*err)
812             return FALSE;
813
814       return TRUE;
815 }
816
817 /*---------------------------------------------------
818  * Finish writing to a dump file.
819  * Returns TRUE on success, FALSE on failure.
820  *---------------------------------------------------*/
821 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
822 {
823       if (wdh->dump.opaque) {
824             lanalyzer_dump_header(wdh,err);
825             g_free(wdh->dump.opaque);
826             wdh->dump.opaque = 0;
827             }
828       return *err ? FALSE : TRUE;
829 }