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