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