]> git.samba.org - obnox/wireshark/wip.git/blob - wiretap/netmon.c
From Aaron Woo (via Jeff Weston): Optimized Link State Routing Protocol
[obnox/wireshark/wip.git] / wiretap / netmon.c
1 /* netmon.c
2  *
3  * $Id: netmon.c,v 1.67 2003/12/23 00:15:02 ulfl 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 <errno.h>
27 #include <string.h>
28 #include "wtap-int.h"
29 #include "file_wrappers.h"
30 #include "buffer.h"
31 #include "atm.h"
32 #include "netmon.h"
33
34 /* The file at
35  *
36  *      ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
37  *
38  * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
39  * for the header of a Microsoft Network Monitor capture file.
40  */
41
42 /* Capture file header, *including* magic number, is padded to 128 bytes. */
43 #define CAPTUREFILE_HEADER_SIZE 128
44
45 /* Magic number in Network Monitor 1.x files. */
46 static const char netmon_1_x_magic[] = {
47         'R', 'T', 'S', 'S'
48 };
49
50 /* Magic number in Network Monitor 2.x files. */
51 static const char netmon_2_x_magic[] = {
52         'G', 'M', 'B', 'U'
53 };
54
55 /* Network Monitor file header (minus magic number). */
56 struct netmon_hdr {
57         guint8  ver_minor;      /* minor version number */
58         guint8  ver_major;      /* major version number */
59         guint16 network;        /* network type */
60         guint16 ts_year;        /* year of capture start */
61         guint16 ts_month;       /* month of capture start (January = 1) */
62         guint16 ts_dow;         /* day of week of capture start (Sun = 0) */
63         guint16 ts_day;         /* day of month of capture start */
64         guint16 ts_hour;        /* hour of capture start */
65         guint16 ts_min;         /* minute of capture start */
66         guint16 ts_sec;         /* second of capture start */
67         guint16 ts_msec;        /* millisecond of capture start */
68         guint32 frametableoffset;       /* frame index table offset */
69         guint32 frametablelength;       /* frame index table size */
70         guint32 userdataoffset;         /* user data offset */
71         guint32 userdatalength;         /* user data size */
72         guint32 commentdataoffset;      /* comment data offset */
73         guint32 commentdatalength;      /* comment data size */
74         guint32 statisticsoffset;       /* offset to statistics structure */
75         guint32 statisticslength;       /* length of statistics structure */
76         guint32 networkinfooffset;      /* offset to network info structure */
77         guint32 networkinfolength;      /* length of network info structure */
78 };
79
80 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
81  * looking at capture files. */
82 struct netmonrec_1_x_hdr {
83         guint32 ts_delta;       /* time stamp - msecs since start of capture */
84         guint16 orig_len;       /* actual length of packet */
85         guint16 incl_len;       /* number of octets captured in file */
86 };
87
88 /* Network Monitor 2.x record header; not defined in STRUCT.H, but deduced by
89  * looking at capture files. */
90 struct netmonrec_2_x_hdr {
91         guint32 ts_delta_lo;    /* time stamp - usecs since start of capture */
92         guint32 ts_delta_hi;    /* time stamp - usecs since start of capture */
93         guint32 orig_len;       /* actual length of packet */
94         guint32 incl_len;       /* number of octets captured in file */
95 };
96
97 /*
98  * The link-layer header on ATM packets.
99  */
100 struct netmon_atm_hdr {
101         guint8  dest[6];        /* "Destination address" - what is it? */
102         guint8  src[6];         /* "Source address" - what is it? */
103         guint16 vpi;            /* VPI */
104         guint16 vci;            /* VCI */
105 };
106
107 static gboolean netmon_read(wtap *wth, int *err, long *data_offset);
108 static gboolean netmon_seek_read(wtap *wth, long seek_off,
109     union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err);
110 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
111     union wtap_pseudo_header *pseudo_header, int *err);
112 static gboolean netmon_read_rec_data(FILE_T fh, guchar *pd, int length,
113     int *err);
114 static void netmon_sequential_close(wtap *wth);
115 static void netmon_close(wtap *wth);
116 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
117     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
118 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
119
120 int netmon_open(wtap *wth, int *err)
121 {
122         int bytes_read;
123         char magic[sizeof netmon_1_x_magic];
124         struct netmon_hdr hdr;
125         int file_type;
126         static const int netmon_encap[] = {
127                 WTAP_ENCAP_UNKNOWN,
128                 WTAP_ENCAP_ETHERNET,
129                 WTAP_ENCAP_TOKEN_RING,
130                 WTAP_ENCAP_FDDI_BITSWAPPED,
131                 WTAP_ENCAP_ATM_PDUS,    /* NDIS WAN - this is what's used for ATM */
132                 WTAP_ENCAP_UNKNOWN,     /* NDIS LocalTalk */
133                 WTAP_ENCAP_UNKNOWN,     /* NDIS "DIX" - should not occur */
134                 WTAP_ENCAP_UNKNOWN,     /* NDIS ARCNET raw */
135                 WTAP_ENCAP_UNKNOWN,     /* NDIS ARCNET 878.2 */
136                 WTAP_ENCAP_UNKNOWN,     /* NDIS ATM (no, this is NOT used for ATM) */
137                 WTAP_ENCAP_UNKNOWN,     /* NDIS Wireless WAN */
138                 WTAP_ENCAP_UNKNOWN      /* NDIS IrDA */
139         };
140         #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
141         struct tm tm;
142         int frame_table_offset;
143         guint32 frame_table_length;
144         guint32 frame_table_size;
145         guint32 *frame_table;
146 #ifdef WORDS_BIGENDIAN
147         unsigned int i;
148 #endif
149
150         /* Read in the string that should be at the start of a Network
151          * Monitor file */
152         errno = WTAP_ERR_CANT_READ;
153         bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
154         if (bytes_read != sizeof magic) {
155                 *err = file_error(wth->fh);
156                 if (*err != 0)
157                         return -1;
158                 return 0;
159         }
160
161         if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
162          && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
163                 return 0;
164         }
165
166         /* Read the rest of the header. */
167         errno = WTAP_ERR_CANT_READ;
168         bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
169         if (bytes_read != sizeof hdr) {
170                 *err = file_error(wth->fh);
171                 if (*err != 0)
172                         return -1;
173                 return 0;
174         }
175
176         switch (hdr.ver_major) {
177
178         case 1:
179                 file_type = WTAP_FILE_NETMON_1_x;
180                 break;
181
182         case 2:
183                 file_type = WTAP_FILE_NETMON_2_x;
184                 break;
185
186         default:
187                 g_message("netmon: major version %u unsupported", hdr.ver_major);
188                 *err = WTAP_ERR_UNSUPPORTED;
189                 return -1;
190         }
191
192         hdr.network = pletohs(&hdr.network);
193         if (hdr.network >= NUM_NETMON_ENCAPS
194             || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
195                 g_message("netmon: network type %u unknown or unsupported",
196                     hdr.network);
197                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
198                 return -1;
199         }
200
201         /* This is a netmon file */
202         wth->file_type = file_type;
203         wth->capture.netmon = g_malloc(sizeof(netmon_t));
204         wth->subtype_read = netmon_read;
205         wth->subtype_seek_read = netmon_seek_read;
206         wth->subtype_sequential_close = netmon_sequential_close;
207         wth->subtype_close = netmon_close;
208         wth->file_encap = netmon_encap[hdr.network];
209         wth->snapshot_length = 0;       /* not available in header */
210         /*
211          * Convert the time stamp to a "time_t" and a number of
212          * milliseconds.
213          */
214         tm.tm_year = pletohs(&hdr.ts_year) - 1900;
215         tm.tm_mon = pletohs(&hdr.ts_month) - 1;
216         tm.tm_mday = pletohs(&hdr.ts_day);
217         tm.tm_hour = pletohs(&hdr.ts_hour);
218         tm.tm_min = pletohs(&hdr.ts_min);
219         tm.tm_sec = pletohs(&hdr.ts_sec);
220         tm.tm_isdst = -1;
221         wth->capture.netmon->start_secs = mktime(&tm);
222         /*
223          * XXX - what if "secs" is -1?  Unlikely, but if the capture was
224          * done in a time zone that switches between standard and summer
225          * time sometime other than when we do, and thus the time was one
226          * that doesn't exist here because a switch from standard to summer
227          * time zips over it, it could happen.
228          *
229          * On the other hand, if the capture was done in a different time
230          * zone, this won't work right anyway; unfortunately, the time
231          * zone isn't stored in the capture file (why the hell didn't
232          * they stuff a FILETIME, which is the number of 100-nanosecond
233          * intervals since 1601-01-01 00:00:00 "UTC", there, instead
234          * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
235          */
236         wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
237
238         wth->capture.netmon->version_major = hdr.ver_major;
239
240         /*
241          * Get the offset of the frame index table.
242          */
243         frame_table_offset = pletohl(&hdr.frametableoffset);
244
245         /*
246          * It appears that some NetMon 2.x files don't have the
247          * first packet starting exactly 128 bytes into the file.
248          *
249          * Furthermore, it also appears that there are "holes" in
250          * the file, i.e. frame N+1 doesn't always follow immediately
251          * after frame N.
252          *
253          * Therefore, we must read the frame table, and use the offsets
254          * in it as the offsets of the frames.
255          */
256         frame_table_length = pletohl(&hdr.frametablelength);
257         frame_table_size = frame_table_length / sizeof (guint32);
258         if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
259                 g_message("netmon: frame table length is %u, which is not a multiple of the size of an entry",
260                     frame_table_length);
261                 *err = WTAP_ERR_UNSUPPORTED;
262                 return -1;
263         }
264         if (frame_table_size == 0) {
265                 g_message("netmon: frame table length is %u, which means it's less than one entry in size",
266                     frame_table_length);
267                 *err = WTAP_ERR_UNSUPPORTED;
268                 return -1;
269         }
270         if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
271                 g_free(wth->capture.netmon);
272                 return -1;
273         }
274         frame_table = g_malloc(frame_table_length);
275         errno = WTAP_ERR_CANT_READ;
276         bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
277         if ((guint32)bytes_read != frame_table_length) {
278                 *err = file_error(wth->fh);
279                 if (*err == 0)
280                         *err = WTAP_ERR_SHORT_READ;
281                 return -1;
282         }
283         wth->capture.netmon->frame_table_size = frame_table_size;
284         wth->capture.netmon->frame_table = frame_table;
285
286 #ifdef WORDS_BIGENDIAN
287         /*
288          * OK, now byte-swap the frame table.
289          */
290         for (i = 0; i < frame_table_size; i++)
291                 frame_table[i] = pletohl(&frame_table[i]);
292 #endif
293
294         /* Set up to start reading at the first frame. */
295         wth->capture.netmon->current_frame = 0;
296
297         return 1;
298 }
299
300 /* Read the next packet */
301 static gboolean netmon_read(wtap *wth, int *err, long *data_offset)
302 {
303         netmon_t *netmon = wth->capture.netmon;
304         guint32 packet_size = 0;
305         guint32 orig_size = 0;
306         int     bytes_read;
307         union {
308                 struct netmonrec_1_x_hdr hdr_1_x;
309                 struct netmonrec_2_x_hdr hdr_2_x;
310         }       hdr;
311         int     hdr_size = 0;
312         int     rec_offset;
313         guint8  *data_ptr;
314         time_t  secs;
315         guint32 usecs;
316         double  t;
317
318         /* Have we reached the end of the packet data? */
319         if (netmon->current_frame >= netmon->frame_table_size) {
320                 /* Yes.  We won't need the frame table any more;
321                    free it. */
322                 g_free(wth->capture.netmon->frame_table);
323                 wth->capture.netmon->frame_table = NULL;
324                 *err = 0;       /* it's just an EOF, not an error */
325                 return FALSE;
326         }
327
328         /* Seek to the beginning of the current record, if we're
329            not there already (seeking to the current position
330            may still cause a seek and a read of the underlying file,
331            so we don't want to do it unconditionally). */
332         rec_offset = netmon->frame_table[netmon->current_frame];
333         if (wth->data_offset != rec_offset) {
334                 wth->data_offset = rec_offset;
335                 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
336                         return FALSE;
337         }
338         netmon->current_frame++;
339
340         /* Read record header. */
341         switch (netmon->version_major) {
342
343         case 1:
344                 hdr_size = sizeof (struct netmonrec_1_x_hdr);
345                 break;
346
347         case 2:
348                 hdr_size = sizeof (struct netmonrec_2_x_hdr);
349                 break;
350         }
351         errno = WTAP_ERR_CANT_READ;
352
353         bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
354         if (bytes_read != hdr_size) {
355                 *err = file_error(wth->fh);
356                 if (*err == 0 && bytes_read != 0) {
357                         *err = WTAP_ERR_SHORT_READ;
358                 }
359                 return FALSE;
360         }
361         wth->data_offset += hdr_size;
362
363         switch (netmon->version_major) {
364
365         case 1:
366                 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
367                 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
368                 break;
369
370         case 2:
371                 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
372                 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
373                 break;
374         }
375         if (packet_size > WTAP_MAX_PACKET_SIZE) {
376                 /*
377                  * Probably a corrupt capture file; don't blow up trying
378                  * to allocate space for an immensely-large packet.
379                  */
380                 g_message("netmon: File has %u-byte packet, bigger than maximum of %u",
381                     packet_size, WTAP_MAX_PACKET_SIZE);
382                 *err = WTAP_ERR_BAD_RECORD;
383                 return FALSE;
384         }
385
386         *data_offset = wth->data_offset;
387
388         /*
389          * If this is an ATM packet, the first
390          * "sizeof (struct netmon_atm_hdr)" bytes have destination and
391          * source addresses (6 bytes - MAC addresses of some sort?)
392          * and the VPI and VCI; read them and generate the pseudo-header
393          * from them.
394          */
395         switch (wth->file_encap) {
396
397         case WTAP_ENCAP_ATM_PDUS:
398                 if (packet_size < sizeof (struct netmon_atm_hdr)) {
399                         /*
400                          * Uh-oh, the packet isn't big enough to even
401                          * have a pseudo-header.
402                          */
403                         g_message("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header\n",
404                             packet_size);
405                         *err = WTAP_ERR_BAD_RECORD;
406                         return FALSE;
407                 }
408                 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
409                     err))
410                         return FALSE;   /* Read error */
411
412                 /*
413                  * Don't count the pseudo-header as part of the packet.
414                  */
415                 orig_size -= sizeof (struct netmon_atm_hdr);
416                 packet_size -= sizeof (struct netmon_atm_hdr);
417                 wth->data_offset += sizeof (struct netmon_atm_hdr);
418                 break;
419
420         case WTAP_ENCAP_ETHERNET:
421                 /*
422                  * We assume there's no FCS in this frame.
423                  */
424                 wth->pseudo_header.eth.fcs_len = 0;
425                 break;
426         }
427
428         buffer_assure_space(wth->frame_buffer, packet_size);
429         data_ptr = buffer_start_ptr(wth->frame_buffer);
430         if (!netmon_read_rec_data(wth->fh, data_ptr, packet_size, err))
431                 return FALSE;   /* Read error */
432         wth->data_offset += packet_size;
433
434         t = (double)netmon->start_usecs;
435         switch (netmon->version_major) {
436
437         case 1:
438                 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
439                 break;
440
441         case 2:
442                 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
443                     + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
444                 break;
445         }
446         secs = (time_t)(t/1000000);
447         usecs = (guint32)(t - (double)secs*1000000);
448         wth->phdr.ts.tv_sec = netmon->start_secs + secs;
449         wth->phdr.ts.tv_usec = usecs;
450         wth->phdr.caplen = packet_size;
451         wth->phdr.len = orig_size;
452         wth->phdr.pkt_encap = wth->file_encap;
453
454         /*
455          * Attempt to guess from the packet data, the VPI, and the VCI
456          * information about the type of traffic.
457          */
458         if (wth->file_encap == WTAP_ENCAP_ATM_PDUS) {
459                 atm_guess_traffic_type(data_ptr, packet_size,
460                     &wth->pseudo_header);
461         }
462
463         return TRUE;
464 }
465
466 static gboolean
467 netmon_seek_read(wtap *wth, long seek_off,
468     union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err)
469 {
470         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
471                 return FALSE;
472
473         switch (wth->file_encap) {
474
475         case WTAP_ENCAP_ATM_PDUS:
476                 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
477                     err)) {
478                         /* Read error */
479                         return FALSE;
480                 }
481                 break;
482
483         case WTAP_ENCAP_ETHERNET:
484                 /*
485                  * We assume there's no FCS in this frame.
486                  */
487                 pseudo_header->eth.fcs_len = 0;
488                 break;
489         }
490
491         /*
492          * Read the packet data.
493          */
494         if (!netmon_read_rec_data(wth->random_fh, pd, length, err))
495                 return FALSE;
496
497         /*
498          * Attempt to guess from the packet data, the VPI, and the VCI
499          * information about the type of traffic.
500          */
501         if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
502                 atm_guess_traffic_type(pd, length, pseudo_header);
503
504         return TRUE;
505 }
506
507 static gboolean
508 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
509     int *err)
510 {
511         struct netmon_atm_hdr atm_phdr;
512         int     bytes_read;
513         guint16 vpi, vci;
514
515         errno = WTAP_ERR_CANT_READ;
516         bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
517         if (bytes_read != sizeof (struct netmon_atm_hdr)) {
518                 *err = file_error(fh);
519                 if (*err == 0)
520                         *err = WTAP_ERR_SHORT_READ;
521                 return FALSE;
522         }
523
524         vpi = g_ntohs(atm_phdr.vpi);
525         vci = g_ntohs(atm_phdr.vci);
526
527         pseudo_header->atm.vpi = vpi;
528         pseudo_header->atm.vci = vci;
529
530         /* We don't have this information */
531         pseudo_header->atm.flags = 0;
532         pseudo_header->atm.channel = 0;
533         pseudo_header->atm.cells = 0;
534         pseudo_header->atm.aal5t_u2u = 0;
535         pseudo_header->atm.aal5t_len = 0;
536         pseudo_header->atm.aal5t_chksum = 0;
537
538         return TRUE;
539 }
540
541 static gboolean
542 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
543 {
544         int     bytes_read;
545
546         errno = WTAP_ERR_CANT_READ;
547         bytes_read = file_read(pd, 1, length, fh);
548
549         if (bytes_read != length) {
550                 *err = file_error(fh);
551                 if (*err == 0)
552                         *err = WTAP_ERR_SHORT_READ;
553                 return FALSE;
554         }
555         return TRUE;
556 }
557
558 /* Throw away the frame table used by the sequential I/O stream. */
559 static void
560 netmon_sequential_close(wtap *wth)
561 {
562         if (wth->capture.netmon->frame_table != NULL) {
563                 g_free(wth->capture.netmon->frame_table);
564                 wth->capture.netmon->frame_table = NULL;
565         }
566 }
567
568 /* Close stuff used by the random I/O stream, if any, and free up any
569    private data structures.  (If there's a "sequential_close" routine
570    for a capture file type, it'll be called before the "close" routine
571    is called, so we don't have to free the frame table here.) */
572 static void
573 netmon_close(wtap *wth)
574 {
575         g_free(wth->capture.netmon);
576 }
577
578 static const int wtap_encap[] = {
579         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
580         1,              /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
581         2,              /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
582         -1,             /* WTAP_ENCAP_SLIP -> unsupported */
583         -1,             /* WTAP_ENCAP_PPP -> unsupported */
584         3,              /* WTAP_ENCAP_FDDI -> NDIS FDDI */
585         3,              /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
586         -1,             /* WTAP_ENCAP_RAW_IP -> unsupported */
587         -1,             /* WTAP_ENCAP_ARCNET -> unsupported */
588         -1,             /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
589         -1,             /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
590         -1,             /* WTAP_ENCAP_LAPB -> unsupported*/
591         4,              /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
592         -1              /* WTAP_ENCAP_NULL -> unsupported */
593 };
594 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
595
596 /* Returns 0 if we could write the specified encapsulation type,
597    an error indication otherwise. */
598 int netmon_dump_can_write_encap(int encap)
599 {
600         /* Per-packet encapsulations aren't supported. */
601         if (encap == WTAP_ENCAP_PER_PACKET)
602                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
603
604         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
605                 return WTAP_ERR_UNSUPPORTED_ENCAP;
606
607         return 0;
608 }
609
610 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
611    failure */
612 gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
613 {
614         /* This is a NetMon file.  We can't fill in some fields in the
615            header until all the packets have been written, so we can't
616            write to a pipe. */
617         if (cant_seek) {
618                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
619                 return FALSE;
620         }
621
622         /* We can't fill in all the fields in the file header, as we
623            haven't yet written any packets.  As we'll have to rewrite
624            the header when we've written out all the packets, we just
625            skip over the header for now. */
626         if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
627                 *err = errno;
628                 return FALSE;
629         }
630
631         wdh->subtype_write = netmon_dump;
632         wdh->subtype_close = netmon_dump_close;
633
634         wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
635         wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
636         wdh->dump.netmon->got_first_record_time = FALSE;
637         wdh->dump.netmon->frame_table = NULL;
638         wdh->dump.netmon->frame_table_index = 0;
639         wdh->dump.netmon->frame_table_size = 0;
640
641         return TRUE;
642 }
643
644 /* Write a record for a packet to a dump file.
645    Returns TRUE on success, FALSE on failure. */
646 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
647     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
648 {
649         netmon_dump_t *netmon = wdh->dump.netmon;
650         struct netmonrec_1_x_hdr rec_1_x_hdr;
651         struct netmonrec_2_x_hdr rec_2_x_hdr;
652         char *hdrp;
653         size_t hdr_size;
654         size_t nwritten;
655         double t;
656         guint32 time_low, time_high;
657         struct netmon_atm_hdr atm_hdr;
658         int atm_hdrsize;
659
660         /* NetMon files have a capture start time in the file header,
661            and have times relative to that in the packet headers;
662            pick the time of the first packet as the capture start
663            time. */
664         if (!netmon->got_first_record_time) {
665                 netmon->first_record_time = phdr->ts;
666                 netmon->got_first_record_time = TRUE;
667         }
668
669         if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
670                 atm_hdrsize = sizeof (struct netmon_atm_hdr);
671         else
672                 atm_hdrsize = 0;
673         switch (wdh->file_type) {
674
675         case WTAP_FILE_NETMON_1_x:
676                 rec_1_x_hdr.ts_delta = htolel(
677                     (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000
678                   + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec + 500)/1000);
679                 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
680                 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
681                 hdrp = (char *)&rec_1_x_hdr;
682                 hdr_size = sizeof rec_1_x_hdr;
683                 break;
684
685         case WTAP_FILE_NETMON_2_x:
686                 /*
687                  * Unfortunately, not all the platforms on which we run
688                  * support 64-bit integral types, even though most do
689                  * (even on 32-bit processors), so we do it in floating
690                  * point.
691                  */
692                 t = (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000000.0
693                   + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec);
694                 time_high = (guint32) (t/4294967296.0);
695                 time_low  = (guint32) (t - (time_high*4294967296.0));
696                 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
697                 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
698                 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
699                 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
700                 hdrp = (char *)&rec_2_x_hdr;
701                 hdr_size = sizeof rec_2_x_hdr;
702                 break;
703
704         default:
705                 /* We should never get here - our open routine
706                    should only get called for the types above. */
707                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
708                 return FALSE;
709         }
710
711         nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
712         if (nwritten != hdr_size) {
713                 if (nwritten == 0 && ferror(wdh->fh))
714                         *err = errno;
715                 else
716                         *err = WTAP_ERR_SHORT_WRITE;
717                 return FALSE;
718         }
719
720         if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
721                 /*
722                  * Write the ATM header.
723                  * We supply all-zero destination and source addresses.
724                  */
725                 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
726                 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
727                 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
728                 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
729                 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
730                 if (nwritten != sizeof atm_hdr) {
731                         if (nwritten == 0 && ferror(wdh->fh))
732                                 *err = errno;
733                         else
734                                 *err = WTAP_ERR_SHORT_WRITE;
735                         return FALSE;
736                 }
737         }
738
739         nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
740         if (nwritten != phdr->caplen) {
741                 if (nwritten == 0 && ferror(wdh->fh))
742                         *err = errno;
743                 else
744                         *err = WTAP_ERR_SHORT_WRITE;
745                 return FALSE;
746         }
747
748         /*
749          * Stash the file offset of this frame.
750          */
751         if (netmon->frame_table_size == 0) {
752                 /*
753                  * Haven't yet allocated the buffer for the frame table.
754                  */
755                 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
756                 netmon->frame_table_size = 1024;
757         } else {
758                 /*
759                  * We've allocated it; are we at the end?
760                  */
761                 if (netmon->frame_table_index >= netmon->frame_table_size) {
762                         /*
763                          * Yes - double the size of the frame table.
764                          */
765                         netmon->frame_table_size *= 2;
766                         netmon->frame_table = g_realloc(netmon->frame_table,
767                             netmon->frame_table_size * sizeof *netmon->frame_table);
768                 }
769         }
770         netmon->frame_table[netmon->frame_table_index] =
771             htolel(netmon->frame_table_offset);
772         netmon->frame_table_index++;
773         netmon->frame_table_offset += hdr_size + phdr->caplen + atm_hdrsize;
774
775         return TRUE;
776 }
777
778 /* Finish writing to a dump file.
779    Returns TRUE on success, FALSE on failure. */
780 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
781 {
782         netmon_dump_t *netmon = wdh->dump.netmon;
783         size_t n_to_write;
784         size_t nwritten;
785         struct netmon_hdr file_hdr;
786         const char *magicp;
787         size_t magic_size;
788         struct tm *tm;
789
790         /* Write out the frame table.  "netmon->frame_table_index" is
791            the number of entries we've put into it. */
792         n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
793         nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
794         if (nwritten != n_to_write) {
795                 if (err != NULL) {
796                         if (nwritten == 0 && ferror(wdh->fh))
797                                 *err = errno;
798                         else
799                                 *err = WTAP_ERR_SHORT_WRITE;
800                 }
801                 return FALSE;
802         }
803
804         /* Now go fix up the file header. */
805         fseek(wdh->fh, 0, SEEK_SET);
806         memset(&file_hdr, '\0', sizeof file_hdr);
807         switch (wdh->file_type) {
808
809         case WTAP_FILE_NETMON_1_x:
810                 magicp = netmon_1_x_magic;
811                 magic_size = sizeof netmon_1_x_magic;
812                 /* current NetMon version, for 1.x, is 1.1 */
813                 file_hdr.ver_major = 1;
814                 file_hdr.ver_minor = 1;
815                 break;
816
817         case WTAP_FILE_NETMON_2_x:
818                 magicp = netmon_2_x_magic;
819                 magic_size = sizeof netmon_2_x_magic;
820                 /* current NetMon version, for 2.x, is 2.0 */
821                 file_hdr.ver_major = 2;
822                 file_hdr.ver_minor = 0;
823                 break;
824
825         default:
826                 /* We should never get here - our open routine
827                    should only get called for the types above. */
828                 if (err != NULL)
829                         *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
830                 return FALSE;
831         }
832         nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
833         if (nwritten != magic_size) {
834                 if (err != NULL) {
835                         if (nwritten == 0 && ferror(wdh->fh))
836                                 *err = errno;
837                         else
838                                 *err = WTAP_ERR_SHORT_WRITE;
839                 }
840                 return FALSE;
841         }
842
843         file_hdr.network = htoles(wtap_encap[wdh->encap]);
844         tm = localtime(&netmon->first_record_time.tv_sec);
845         if (tm != NULL) {
846                 file_hdr.ts_year  = htoles(1900 + tm->tm_year);
847                 file_hdr.ts_month = htoles(tm->tm_mon + 1);
848                 file_hdr.ts_dow   = htoles(tm->tm_wday);
849                 file_hdr.ts_day   = htoles(tm->tm_mday);
850                 file_hdr.ts_hour  = htoles(tm->tm_hour);
851                 file_hdr.ts_min   = htoles(tm->tm_min);
852                 file_hdr.ts_sec   = htoles(tm->tm_sec);
853         } else {
854                 file_hdr.ts_year  = htoles(1900 + 0);
855                 file_hdr.ts_month = htoles(0 + 1);
856                 file_hdr.ts_dow   = htoles(0);
857                 file_hdr.ts_day   = htoles(0);
858                 file_hdr.ts_hour  = htoles(0);
859                 file_hdr.ts_min   = htoles(0);
860                 file_hdr.ts_sec   = htoles(0);
861         }
862         file_hdr.ts_msec  = htoles(netmon->first_record_time.tv_usec/1000);
863                 /* XXX - what about rounding? */
864         file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
865         file_hdr.frametablelength =
866             htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
867         nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
868         if (nwritten != sizeof file_hdr) {
869                 if (err != NULL) {
870                         if (nwritten == 0 && ferror(wdh->fh))
871                                 *err = errno;
872                         else
873                                 *err = WTAP_ERR_SHORT_WRITE;
874                 }
875                 return FALSE;
876         }
877
878         return TRUE;
879 }