Add remark about including packet.h before tap.h
[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://www.windowsecurity.com/whitepapers/Description_of_the_LANalysers_output_file.html
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 typedef struct {
121         time_t  start;
122 } lanalyzer_t;
123
124 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
125     gint64 *data_offset);
126 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
127     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
128     int *err, gchar **err_info);
129 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
130
131 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
132 {
133         int bytes_read;
134         char LE_record_type[2];
135         char LE_record_length[2];
136         char summary[210];
137         guint16 board_type, mxslc;
138         guint16 record_type, record_length;
139         guint8 cr_day, cr_month;
140         guint16 cr_year;
141         struct tm tm;
142         lanalyzer_t *lanalyzer;
143
144         errno = WTAP_ERR_CANT_READ;
145         bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
146         bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
147         if (bytes_read != 4) {
148                 *err = file_error(wth->fh);
149                 if (*err != 0)
150                         return -1;
151                 return 0;
152         }
153         wth->data_offset += 4;
154         record_type = pletohs(LE_record_type);
155         record_length = pletohs(LE_record_length); /* make sure to do this for while() loop */
156
157         if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
158                 return 0;
159         }
160
161         /* If we made it this far, then the file is a LANAlyzer file.
162          * Let's get some info from it. Note that we get wth->snapshot_length
163          * from a record later in the file. */
164         wth->file_type = WTAP_FILE_LANALYZER;
165         lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));;
166         wth->priv = (void *)lanalyzer;
167         wth->subtype_read = lanalyzer_read;
168         wth->subtype_seek_read = lanalyzer_seek_read;
169         wth->snapshot_length = 0;
170         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
171
172         /* Read records until we find the start of packets */
173         while (1) {
174                 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
175                         g_free(wth->priv);
176                         return -1;
177                 }
178                 wth->data_offset += record_length;
179                 errno = WTAP_ERR_CANT_READ;
180                 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
181                 bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
182                 if (bytes_read != 4) {
183                         *err = file_error(wth->fh);
184                         if (*err != 0) {
185                                 g_free(wth->priv);
186                                 return -1;
187                         }
188                         g_free(wth->priv);
189                         return 0;
190                 }
191                 wth->data_offset += 4;
192
193                 record_type = pletohs(LE_record_type);
194                 record_length = pletohs(LE_record_length);
195
196                 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
197                 switch (record_type) {
198                         /* Trace Summary Record */
199                         case RT_Summary:
200                                 errno = WTAP_ERR_CANT_READ;
201                                 bytes_read = file_read(summary, 1, sizeof summary,
202                                     wth->fh);
203                                 if (bytes_read != sizeof summary) {
204                                         *err = file_error(wth->fh);
205                                         if (*err != 0) {
206                                                 g_free(wth->priv);
207                                                 return -1;
208                                         }
209                                         g_free(wth->priv);
210                                         return 0;
211                                 }
212                                 wth->data_offset += sizeof summary;
213
214                                 /* Assume that the date of the creation of the trace file
215                                  * is the same date of the trace. Lanalyzer doesn't
216                                  * store the creation date/time of the trace, but only of
217                                  * the file. Unless you traced at 11:55 PM and saved at 00:05
218                                  * AM, the assumption that trace.date == file.date is true.
219                                  */
220                                 cr_day = summary[0];
221                                 cr_month = summary[1];
222                                 cr_year = pletohs(&summary[2]);
223                                 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
224                                                 cr_year, cr_year);*/
225
226                                 /* Get capture start time. I learned how to do
227                                  * this from Guy's code in ngsniffer.c
228                                  */
229                                 tm.tm_year = cr_year - 1900;
230                                 tm.tm_mon = cr_month - 1;
231                                 tm.tm_mday = cr_day;
232                                 tm.tm_hour = 0;
233                                 tm.tm_min = 0;
234                                 tm.tm_sec = 0;
235                                 tm.tm_isdst = -1;
236                                 lanalyzer->start = mktime(&tm);
237                                 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
238                                                 tm.tm_mon, tm.tm_year);*/
239                                 mxslc = pletohs(&summary[30]);
240                                 wth->snapshot_length = mxslc;
241
242                                 record_length = 0; /* to fake the next iteration of while() */
243                                 board_type = pletohs(&summary[188]);
244                                 switch (board_type) {
245                                         case BOARD_325:
246                                                 wth->file_encap = WTAP_ENCAP_ETHERNET;
247                                                 break;
248                                         case BOARD_325TR:
249                                                 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
250                                                 break;
251                                         default:
252                                                 g_free(wth->priv);
253                                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
254                                                 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
255                                                     board_type);
256                                                 return -1;
257                                 }
258                                 break;
259
260                         /* Trace Packet Data Record */
261                         case RT_PacketData:
262                                 /* Go back header number ob ytes so that lanalyzer_read
263                                  * can read this header */
264                                 if (file_seek(wth->fh, -bytes_read, SEEK_CUR, err) == -1) {
265                                         g_free(wth->priv);
266                                         return -1;
267                                 }
268                                 wth->data_offset -= bytes_read;
269                                 return 1;
270
271                         default:
272                                 ; /* no action */
273                 }
274         }
275 }
276
277 #define DESCRIPTOR_LEN  32
278
279 /* Read the next packet */
280 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
281     gint64 *data_offset)
282 {
283         int             packet_size = 0;
284         int             bytes_read;
285         char            LE_record_type[2];
286         char            LE_record_length[2];
287         guint16         record_type, record_length;
288         gchar           descriptor[DESCRIPTOR_LEN];
289         guint16         time_low, time_med, time_high, true_size;
290         guint64         t;
291         time_t          tsecs;
292         lanalyzer_t     *lanalyzer;
293
294         /* read the record type and length. */
295         errno = WTAP_ERR_CANT_READ;
296         bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
297         if (bytes_read != 2) {
298                 *err = file_error(wth->fh);
299                 if (*err == 0 && bytes_read != 0) {
300                         *err = WTAP_ERR_SHORT_READ;
301                 }
302                 return FALSE;
303         }
304         wth->data_offset += 2;
305         bytes_read = file_read(LE_record_length, 1, 2, wth->fh);
306         if (bytes_read != 2) {
307                 *err = file_error(wth->fh);
308                 if (*err == 0)
309                         *err = WTAP_ERR_SHORT_READ;
310                 return FALSE;
311         }
312         wth->data_offset += 2;
313
314         record_type = pletohs(LE_record_type);
315         record_length = pletohs(LE_record_length);
316
317         /* Only Trace Packet Data Records should occur now that we're in
318          * the middle of reading packets.  If any other record type exists
319          * after a Trace Packet Data Record, mark it as an error. */
320         if (record_type != RT_PacketData) {
321                 *err = WTAP_ERR_BAD_RECORD;
322                 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
323                     record_type);
324                 return FALSE;
325         }
326         else {
327                 packet_size = record_length - DESCRIPTOR_LEN;
328         }
329
330         /* Read the descriptor data */
331         errno = WTAP_ERR_CANT_READ;
332         bytes_read = file_read(descriptor, 1, DESCRIPTOR_LEN, wth->fh);
333         if (bytes_read != DESCRIPTOR_LEN) {
334                 *err = file_error(wth->fh);
335                 if (*err == 0)
336                         *err = WTAP_ERR_SHORT_READ;
337                 return FALSE;
338         }
339         wth->data_offset += DESCRIPTOR_LEN;
340
341         /* Read the packet data */
342         buffer_assure_space(wth->frame_buffer, packet_size);
343         *data_offset = wth->data_offset;
344         errno = WTAP_ERR_CANT_READ;
345         bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
346                 packet_size, wth->fh);
347
348         if (bytes_read != packet_size) {
349                 *err = file_error(wth->fh);
350                 if (*err == 0)
351                         *err = WTAP_ERR_SHORT_READ;
352                 return FALSE;
353         }
354         wth->data_offset += packet_size;
355
356         true_size = pletohs(&descriptor[4]);
357         packet_size = pletohs(&descriptor[6]);
358
359         /*
360          * OK, is the frame data size greater than than what's left of the
361          * record?
362          */
363         if (packet_size > record_length - DESCRIPTOR_LEN) {
364                 /*
365                  * Yes - treat this as an error.
366                  */
367                 *err = WTAP_ERR_BAD_RECORD;
368                 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
369                 return FALSE;
370         }
371
372         time_low = pletohs(&descriptor[8]);
373         time_med = pletohs(&descriptor[10]);
374         time_high = pletohs(&descriptor[12]);
375         t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
376             (((guint64)time_high) << 32);
377         tsecs = (time_t) (t/2000000);
378         lanalyzer = (lanalyzer_t *)wth->priv;
379         wth->phdr.ts.secs = tsecs + lanalyzer->start;
380         wth->phdr.ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
381
382         if (true_size - 4 >= packet_size) {
383                 /*
384                  * It appears that the "true size" includes the FCS;
385                  * make it reflect the non-FCS size (the "packet size"
386                  * appears never to include the FCS, even if no slicing
387                  * is done).
388                  */
389                 true_size -= 4;
390         }
391         wth->phdr.len = true_size;
392         wth->phdr.caplen = packet_size;
393
394         switch (wth->file_encap) {
395
396         case WTAP_ENCAP_ETHERNET:
397                 /* We assume there's no FCS in this frame. */
398                 wth->pseudo_header.eth.fcs_len = 0;
399                 break;
400         }
401
402         return TRUE;
403 }
404
405 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
406     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
407     int *err, gchar **err_info _U_)
408 {
409         int bytes_read;
410
411         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
412                 return FALSE;
413
414         /*
415          * Read the packet data.
416          */
417         bytes_read = file_read(pd, sizeof(guint8), length, wth->random_fh);
418         if (bytes_read != length) {
419                 *err = file_error(wth->random_fh);
420                 if (*err == 0)
421                         *err = WTAP_ERR_SHORT_READ;
422                 return FALSE;
423         }
424
425         switch (wth->file_encap) {
426
427         case WTAP_ENCAP_ETHERNET:
428                 /* We assume there's no FCS in this frame. */
429                 pseudo_header->eth.fcs_len = 0;
430                 break;
431         }
432
433         return TRUE;
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->priv);
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->priv          = 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->priv);
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 }