1 /* visual.c
2 * File read and write routines for Visual Networks cap files.
3 * Copyright (c) 2001, Tom Nisbet tnisbet@visualnetworks.com
4 *
5 * Wiretap Library
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "config.h"
12 #include <errno.h>
13 #include <string.h>
14 #include "wtap-int.h"
15 #include "file_wrappers.h"
16 #include "visual.h"
17
18 /*
19 * A Visual Networks traffic capture file contains three sections. The
20 * first is a 192 octet file header. This is followed by the captured
21 * packet header, and for ATM captures, there is an additional atm packet header.
22 * The data follows the packet header. The last section is the packet index block.
23 * The index block contains one 4 octet pointer for each captured packet.
24 * The first packet index is (4 * num_pkts) octets from the end of the file
25 * and the last index is in the last four octets of the file.
26 *
27 * All integer and time values are stored in little-endian format, except for
28 * the ATM Packet Header, which is stored in network byte order.
29 *
30 * [ File Header ]
31 *
32 *
33 * [ Packet Header 1 ] [(opt) ATM Packet Header] [ Data ]
34 * ...
35 * [ Packet Header n ] [(opt) ATM Packet Header] [ Data ]
36 *
37 *
38 * [ Index Block 1 ] ... [ Index Block n ]
39 */
40
41 /* Capture file header, INCLUDING the magic number, is 192 bytes. */
42 #define CAPTUREFILE_HEADER_SIZE 192
43
44 /* Magic number for Visual Networks traffic capture files. */
45 static const char visual_magic[] = {
46 5, 'V', 'N', 'F'
47 };
48
49
50 /* Visual File Header (minus magic number). */
51 /* This structure is used to extract information */
52 struct visual_file_hdr
53 {
54 guint32 num_pkts; /* Number of packets in the file */
55 guint32 start_time; /* Capture start time in PC format */
56 guint16 media_type; /* IANA ifType of packet source */
57 guint16 max_length; /* Max allowable stored packet length */
58 guint16 file_flags; /* File type flags */
59 /* Bit 0 indicates indexes present */
60 guint16 file_version; /* Version number of this file format */
61 guint32 media_speed; /* ifSpeed of packet source in bits/sec. */
62 guint16 media_param; /* Media-specific extra parameter. */
63 char RESERVED_[102]; /* MUST BE ALL ZEROS FOR FUTURE COMPATIBILITY */
64 char description[64]; /* File description (null terminated) */
65 };
66
67
68 /* Packet status bits */
69 #define PS_LONG 0x01
70 #define PS_SHORT 0x02
71 #define PS_ERRORED 0x04
72 #define PS_1ST_AFTER_DROP 0x08
73 #define PS_APPROX_ORDER 0x10
74 #define PS_SENT 0x40
75 #define PS_ABORTED 0x80
76
77 /* Visual Packet Header */
78 /* This structure is used to extract information */
79 struct visual_pkt_hdr
80 {
81 guint32 ts_delta; /* Time stamp - msecs since start of capture */
82 guint16 orig_len; /* Actual length of packet */
83 guint16 incl_len; /* Number of octets captured in file */
84 guint32 status; /* Packet status flags (media specific) */
85 guint8 encap_hint; /* Encapsulation type hint */
86 guint8 encap_skip; /* Number of bytes to skip before decoding */
87 char RESERVED_[6]; /* RESERVED - must be zero */
88 };
89
90 /* Optional Visual ATM Packet Header */
91 /* This structure is used to extract information */
92 struct visual_atm_hdr
93 {
94 guint16 vpi; /* 4 bits of zeros; 12 bits of ATM VPI */
95 guint16 vci; /* ATM VCI */
96 guint8 info; /* 4 bits version; 3 bits unused-zero; 1 bit direction */
97 guint8 category; /* indicates type of traffic. 4 bits of status + 4 bits of type */
98 guint16 cell_count; /* number of cells that make up this pdu */
99 guint32 data_length; /* PDU data length for AAL-5 PDUs, all others - cellcount * 48 */
100 guint32 ts_secs; /* seonds value of sysUpTime when the last cell of this PDU was captured */
101 guint32 ts_nsec; /* nanoseonds value of sysUpTime when the last cell of this PDU was captured */
102
103 };
104
105 /* visual_atm_hdr info bit definitions */
106 #define FROM_NETWORK 0x01
107 #define ATM_VER_MASK 0xf0 /* Not currently displayed */
108
109 /* visual_atm_hdr category definitions */
110 /* High nibble - not currently displayed */
111 #define VN_INCOMPLETE 0x40
112 #define VN_BAD_CRC 0x80
113 #define VN_CAT_STAT_MASK 0xf0
114 /* Low nibble */
115 #define VN_UNKNOWN 0x00
116 #define VN_AAL1 0x01
117 #define VN_AAL2 0x02
118 #define VN_AAL34 0x03
119 #define VN_O191 0x04
120 #define VN_AAL5 0x05
121 #define VN_OAM 0x0a
122 #define VN_RM 0x0b
123 #define VN_IDLE 0x0c
124 #define VN_CAT_TYPE_MASK 0x0f
125
126
127 /* Additional information for reading Visual files */
128 struct visual_read_info
129 {
130 guint32 num_pkts; /* Number of pkts in the file */
131 guint32 current_pkt; /* Next packet to be read */
132 time_t start_time; /* Capture start time in seconds */
133 };
134
135
136 /* Additional information for writing Visual files */
137 struct visual_write_info
138 {
139 time_t start_time; /* Capture start time in seconds */
140 int index_table_index; /* Index of the next index entry */
141 int index_table_size; /* Allocated size of the index table */
142 guint32 * index_table; /* File offsets for the packets */
143 guint32 next_offset; /* Offset of next packet */
144 };
145
146
147 /* Local functions to handle file reads and writes */
148 static gboolean visual_read(wtap *wth, wtap_rec *rec, Buffer *buf,
149 int *err, gchar **err_info, gint64 *data_offset);
150 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
151 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
152 static gboolean visual_read_packet(wtap *wth, FILE_T fh,
153 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
154 static gboolean visual_dump(wtap_dumper *wdh, const wtap_rec *rec,
155 const guint8 *pd, int *err, gchar **err_info);
156 static gboolean visual_dump_finish(wtap_dumper *wdh, int *err,
157 gchar **err_info);
158 static void visual_dump_free(wtap_dumper *wdh);
159
160 static int visual_file_type_subtype = -1;
161
162 void register_visual(void);
163
164
165 /* Open a file for reading */
visual_open(wtap * wth,int * err,gchar ** err_info)166 wtap_open_return_val visual_open(wtap *wth, int *err, gchar **err_info)
167 {
168 char magic[sizeof visual_magic];
169 struct visual_file_hdr vfile_hdr;
170 struct visual_read_info * visual;
171 int encap;
172
173 /* Check the magic string at the start of the file */
174 if (!wtap_read_bytes(wth->fh, magic, sizeof magic, err, err_info))
175 {
176 if (*err != WTAP_ERR_SHORT_READ)
177 return WTAP_OPEN_ERROR;
178 return WTAP_OPEN_NOT_MINE;
179 }
180 if (memcmp(magic, visual_magic, sizeof visual_magic) != 0)
181 {
182 return WTAP_OPEN_NOT_MINE;
183 }
184
185 /* Read the rest of the file header. */
186 if (!wtap_read_bytes(wth->fh, &vfile_hdr, sizeof vfile_hdr, err, err_info))
187 {
188 return WTAP_OPEN_ERROR;
189 }
190
191 /* Verify the file version is known */
192 vfile_hdr.file_version = pletoh16(&vfile_hdr.file_version);
193 if (vfile_hdr.file_version != 1)
194 {
195 *err = WTAP_ERR_UNSUPPORTED;
196 *err_info = g_strdup_printf("visual: file version %u unsupported", vfile_hdr.file_version);
197 return WTAP_OPEN_ERROR;
198 }
199
200 /* Translate the encapsulation type; these values are SNMP ifType
201 values, as found in https://www.iana.org/assignments/smi-numbers.
202
203 Note that a file with media type 22 ("propPointToPointSerial") may
204 contain Cisco HDLC or PPP over HDLC. This will get sorted out after
205 the first packet is read.
206
207 XXX - should we use WTAP_ENCAP_PER_PACKET for that? */
208 switch (pletoh16(&vfile_hdr.media_type))
209 {
210 case 6: /* ethernet-csmacd */
211 encap = WTAP_ENCAP_ETHERNET;
212 break;
213
214 case 9: /* IEEE802.5 */
215 encap = WTAP_ENCAP_TOKEN_RING;
216 break;
217
218 case 16: /* lapb */
219 encap = WTAP_ENCAP_LAPB;
220 break;
221
222 case 22: /* propPointToPointSerial */
223 case 118: /* HDLC */
224 encap = WTAP_ENCAP_CHDLC_WITH_PHDR;
225 break;
226
227 case 32: /* frame-relay */
228 encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
229 break;
230
231 case 37: /* ATM */
232 encap = WTAP_ENCAP_ATM_PDUS;
233 break;
234
235 default:
236 *err = WTAP_ERR_UNSUPPORTED;
237 *err_info = g_strdup_printf("visual: network type %u unknown or unsupported",
238 vfile_hdr.media_type);
239 return WTAP_OPEN_ERROR;
240 }
241
242 /* Fill in the wiretap struct with data from the file header */
243 wth->file_type_subtype = visual_file_type_subtype;
244 wth->file_encap = encap;
245 wth->snapshot_length = pletoh16(&vfile_hdr.max_length);
246
247 /* Set up the pointers to the handlers for this file type */
248 wth->subtype_read = visual_read;
249 wth->subtype_seek_read = visual_seek_read;
250 wth->file_tsprec = WTAP_TSPREC_MSEC;
251
252 /* Add Visual-specific information to the wiretap struct for later use. */
253 visual = g_new(struct visual_read_info, 1);
254 wth->priv = (void *)visual;
255 visual->num_pkts = pletoh32(&vfile_hdr.num_pkts);
256 visual->start_time = pletoh32(&vfile_hdr.start_time);
257 visual->current_pkt = 1;
258
259 /*
260 * Add an IDB; we don't know how many interfaces were
261 * involved, so we just say one interface, about which
262 * we only know the link-layer type, snapshot length,
263 * and time stamp resolution.
264 */
265 wtap_add_generated_idb(wth);
266
267 return WTAP_OPEN_MINE;
268 }
269
270
271 /* Read the next available packet from the file. This is called
272 in a loop to sequentially read the entire file one time. After
273 the file has been read once, any Future access to the packets is
274 done through seek_read. */
visual_read(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)275 static gboolean visual_read(wtap *wth, wtap_rec *rec, Buffer *buf,
276 int *err, gchar **err_info, gint64 *data_offset)
277 {
278 struct visual_read_info *visual = (struct visual_read_info *)wth->priv;
279
280 /* Check for the end of the packet data. Note that a check for file EOF
281 will not work because there are index values stored after the last
282 packet's data. */
283 if (visual->current_pkt > visual->num_pkts)
284 {
285 *err = 0; /* it's just an EOF, not an error */
286 return FALSE;
287 }
288 visual->current_pkt++;
289
290 *data_offset = file_tell(wth->fh);
291
292 return visual_read_packet(wth, wth->fh, rec, buf, err, err_info);
293 }
294
295 /* Read packet header and data for random access. */
visual_seek_read(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)296 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
297 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
298 {
299 /* Seek to the packet header */
300 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
301 return FALSE;
302
303 /* Read the packet. */
304 if (!visual_read_packet(wth, wth->random_fh, rec, buf, err, err_info)) {
305 if (*err == 0)
306 *err = WTAP_ERR_SHORT_READ;
307 return FALSE;
308 }
309 return TRUE;
310 }
311
312 static gboolean
visual_read_packet(wtap * wth,FILE_T fh,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)313 visual_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
314 Buffer *buf, int *err, gchar **err_info)
315 {
316 struct visual_read_info *visual = (struct visual_read_info *)wth->priv;
317 struct visual_pkt_hdr vpkt_hdr;
318 guint32 packet_size;
319 struct visual_atm_hdr vatm_hdr;
320 guint32 relmsecs;
321 guint32 packet_status;
322 guint8 *pd;
323
324 /* Read the packet header. */
325 if (!wtap_read_bytes_or_eof(fh, &vpkt_hdr, (unsigned int)sizeof vpkt_hdr, err, err_info))
326 {
327 return FALSE;
328 }
329
330 /* Get the included length of data. This includes extra headers + payload */
331 packet_size = pletoh16(&vpkt_hdr.incl_len);
332
333 rec->rec_type = REC_TYPE_PACKET;
334 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
335 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
336
337 /* Set the packet time and length. */
338 relmsecs = pletoh32(&vpkt_hdr.ts_delta);
339 rec->ts.secs = visual->start_time + relmsecs/1000;
340 rec->ts.nsecs = (relmsecs % 1000)*1000000;
341
342 rec->rec_header.packet_header.len = pletoh16(&vpkt_hdr.orig_len);
343
344 packet_status = pletoh32(&vpkt_hdr.status);
345
346 /* Do encapsulation-specific processing.
347
348 Most Visual capture types include the FCS in the original length
349 value, but don't include the FCS as part of the payload or captured
350 length. This is different from the model used in most other capture
351 file formats, including pcap and pcapng in cases where the FCS isn't
352 captured (which are the typical cases), and causes the RTP audio
353 payload save to fail since then captured len != orig len.
354
355 We adjust the original length to remove the FCS bytes we counted based
356 on the file encapsualtion type. The only downside to this fix is
357 throughput calculations will be slightly lower as it won't include
358 the FCS bytes. However, as noted, that problem also exists with
359 other capture formats.
360
361 We also set status flags. The only status currently supported for
362 all encapsulations is direction. This either goes in the p2p or the
363 X.25 pseudo header. It would probably be better to move this up
364 into the phdr. */
365 switch (wth->file_encap)
366 {
367 case WTAP_ENCAP_ETHERNET:
368 /* Ethernet has a 4-byte FCS. */
369 if (rec->rec_header.packet_header.len < 4)
370 {
371 *err = WTAP_ERR_BAD_FILE;
372 *err_info = g_strdup_printf("visual: Ethernet packet has %u-byte original packet, less than the FCS length",
373 rec->rec_header.packet_header.len);
374 return FALSE;
375 }
376 rec->rec_header.packet_header.len -= 4;
377
378 /* XXX - the above implies that there's never an FCS; should this
379 set the FCS length to 0? */
380 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1;
381 break;
382
383 case WTAP_ENCAP_CHDLC_WITH_PHDR:
384 /* This has a 2-byte FCS. */
385 if (rec->rec_header.packet_header.len < 2)
386 {
387 *err = WTAP_ERR_BAD_FILE;
388 *err_info = g_strdup_printf("visual: Cisco HDLC packet has %u-byte original packet, less than the FCS length",
389 rec->rec_header.packet_header.len);
390 return FALSE;
391 }
392 rec->rec_header.packet_header.len -= 2;
393
394 rec->rec_header.packet_header.pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
395 break;
396
397 case WTAP_ENCAP_PPP_WITH_PHDR:
398 /* No FCS.
399 XXX - true? Note that PPP can negotiate no FCS, a 2-byte FCS,
400 or a 4-byte FCS. */
401 rec->rec_header.packet_header.pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
402 break;
403
404 case WTAP_ENCAP_FRELAY_WITH_PHDR:
405 /* This has a 2-byte FCS. */
406 if (rec->rec_header.packet_header.len < 2)
407 {
408 *err = WTAP_ERR_BAD_FILE;
409 *err_info = g_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
410 rec->rec_header.packet_header.len);
411 return FALSE;
412 }
413 rec->rec_header.packet_header.len -= 2;
414
415 rec->rec_header.packet_header.pseudo_header.dte_dce.flags =
416 (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
417 break;
418
419 case WTAP_ENCAP_LAPB:
420 /* This has a 2-byte FCS. */
421 if (rec->rec_header.packet_header.len < 2)
422 {
423 *err = WTAP_ERR_BAD_FILE;
424 *err_info = g_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
425 rec->rec_header.packet_header.len);
426 return FALSE;
427 }
428 rec->rec_header.packet_header.len -= 2;
429
430 rec->rec_header.packet_header.pseudo_header.dte_dce.flags =
431 (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
432 break;
433
434 case WTAP_ENCAP_ATM_PDUS:
435 /* ATM original length doesn't include any FCS. Do nothing to
436 the packet length.
437
438 ATM packets have an additional packet header; read and
439 process it. */
440 if (!wtap_read_bytes(fh, &vatm_hdr, (unsigned int)sizeof vatm_hdr, err, err_info))
441 {
442 return FALSE;
443 }
444
445 /* Remove ATM header from length of included bytes in capture, as
446 this header was appended by the processor doing the packet
447 reassembly, and was not transmitted across the wire */
448 packet_size -= (guint32)sizeof vatm_hdr;
449
450 /* Set defaults */
451 rec->rec_header.packet_header.pseudo_header.atm.type = TRAF_UNKNOWN;
452 rec->rec_header.packet_header.pseudo_header.atm.subtype = TRAF_ST_UNKNOWN;
453 rec->rec_header.packet_header.pseudo_header.atm.aal5t_len = 0;
454
455 /* Next two items not supported. Defaulting to zero */
456 rec->rec_header.packet_header.pseudo_header.atm.aal5t_u2u = 0;
457 rec->rec_header.packet_header.pseudo_header.atm.aal5t_chksum = 0;
458
459 /* Flags appear only to convey that packet is a raw cell. Set to 0 */
460 rec->rec_header.packet_header.pseudo_header.atm.flags = 0;
461
462 /* Not supported. Defaulting to zero */
463 rec->rec_header.packet_header.pseudo_header.atm.aal2_cid = 0;
464
465 switch(vatm_hdr.category & VN_CAT_TYPE_MASK )
466 {
467 case VN_AAL1:
468 rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_1;
469 break;
470
471 case VN_AAL2:
472 rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_2;
473 break;
474
475 case VN_AAL34:
476 rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_3_4;
477 break;
478
479 case VN_AAL5:
480 rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_5;
481 rec->rec_header.packet_header.pseudo_header.atm.type = TRAF_LLCMX;
482 rec->rec_header.packet_header.pseudo_header.atm.aal5t_len = pntoh32(&vatm_hdr.data_length);
483 break;
484
485 case VN_OAM:
486 /* Marking next 3 as OAM versus unknown */
487 case VN_O191:
488 case VN_IDLE:
489 case VN_RM:
490 rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_OAMCELL;
491 break;
492
493 case VN_UNKNOWN:
494 default:
495 rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_UNKNOWN;
496 break;
497 }
498 rec->rec_header.packet_header.pseudo_header.atm.vpi = pntoh16(&vatm_hdr.vpi) & 0x0FFF;
499 rec->rec_header.packet_header.pseudo_header.atm.vci = pntoh16(&vatm_hdr.vci);
500 rec->rec_header.packet_header.pseudo_header.atm.cells = pntoh16(&vatm_hdr.cell_count);
501
502 /* Using bit value of 1 (DCE -> DTE) to indicate From Network */
503 rec->rec_header.packet_header.pseudo_header.atm.channel = vatm_hdr.info & FROM_NETWORK;
504 break;
505
506 /* Not sure about token ring. Just leaving alone for now. */
507 case WTAP_ENCAP_TOKEN_RING:
508 default:
509 break;
510 }
511
512 rec->rec_header.packet_header.caplen = packet_size;
513
514 /* Check for too-large packet. */
515 if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD)
516 {
517 /* Probably a corrupt capture file; don't blow up trying
518 to allocate space for an immensely-large packet. */
519 *err = WTAP_ERR_BAD_FILE;
520 *err_info = g_strdup_printf("visual: File has %u-byte packet, bigger than maximum of %u",
521 packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
522 return FALSE;
523 }
524
525 /* Read the packet data */
526 if (!wtap_read_packet_bytes(fh, buf, packet_size, err, err_info))
527 return FALSE;
528
529 if (wth->file_encap == WTAP_ENCAP_CHDLC_WITH_PHDR)
530 {
531 /* Fill in the encapsulation. Visual files have a media type in the
532 file header and an encapsulation type in each packet header. Files
533 with a media type of HDLC can be either Cisco EtherType or PPP.
534
535 The encapsulation hint values we've seen are:
536
537 2 - seen in an Ethernet capture
538 13 - seen in a PPP capture; possibly also seen in Cisco HDLC
539 captures
540 14 - seen in a PPP capture; probably seen only for PPP.
541
542 According to bug 2005, the collection probe can be configured
543 for PPP, in which case the encapsulation hint is 14, or can
544 be configured for auto-detect, in which case the encapsulation
545 hint is 13, and the encapsulation must be guessed from the
546 packet contents. Auto-detect is the default. */
547 pd = ws_buffer_start_ptr(buf);
548
549 /* If PPP is specified in the encap hint, then use that */
550 if (vpkt_hdr.encap_hint == 14)
551 {
552 /* But first we need to examine the first three octets to
553 try to determine the proper encapsulation, see RFC 2364. */
554 if (packet_size >= 3 &&
555 (0xfe == pd[0]) && (0xfe == pd[1]) && (0x03 == pd[2]))
556 {
557 /* It is actually LLC encapsulated PPP */
558 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ATM_RFC1483;
559 }
560 else
561 {
562 /* It is actually PPP */
563 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
564 }
565 }
566 else
567 {
568 /* Otherwise, we need to examine the first two octets to
569 try to determine the encapsulation. */
570 if (packet_size >= 2 && (0xff == pd[0]) && (0x03 == pd[1]))
571 {
572 /* It is actually PPP */
573 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
574 }
575 }
576 }
577
578 return TRUE;
579 }
580
581 /* Check for media types that may be written in Visual file format.
582 Returns 0 if the specified encapsulation type is supported,
583 an error indication otherwise. */
visual_dump_can_write_encap(int encap)584 static int visual_dump_can_write_encap(int encap)
585 {
586 /* Per-packet encapsulations aren't supported. */
587 if (encap == WTAP_ENCAP_PER_PACKET)
588 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
589
590 /* Check for supported encapsulation types */
591 switch (encap)
592 {
593 case WTAP_ENCAP_ETHERNET:
594 case WTAP_ENCAP_TOKEN_RING:
595 case WTAP_ENCAP_LAPB:
596 case WTAP_ENCAP_CHDLC_WITH_PHDR:
597 case WTAP_ENCAP_FRELAY_WITH_PHDR:
598 case WTAP_ENCAP_PPP:
599 case WTAP_ENCAP_PPP_WITH_PHDR:
600 return 0;
601 }
602
603 return WTAP_ERR_UNWRITABLE_ENCAP;
604 }
605
606
607 /* Open a file for writing.
608 Returns TRUE on success, FALSE on failure; sets "*err" to an
609 error code on failure */
visual_dump_open(wtap_dumper * wdh,int * err,gchar ** err_info _U_)610 static gboolean visual_dump_open(wtap_dumper *wdh, int *err, gchar **err_info _U_)
611 {
612 struct visual_write_info *visual;
613
614 /* Set the write routines for a visual file. */
615 wdh->subtype_write = visual_dump;
616 wdh->subtype_finish = visual_dump_finish;
617
618 /* Create a struct to hold file information for the duration
619 of the write */
620 visual = g_new(struct visual_write_info, 1);
621 wdh->priv = (void *)visual;
622 visual->index_table_index = 0;
623 visual->index_table_size = 1024;
624 visual->index_table = 0;
625 visual->next_offset = CAPTUREFILE_HEADER_SIZE;
626
627 /* All of the fields in the file header aren't known yet so
628 just skip over it for now. It will be created after all
629 of the packets have been written. */
630 if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
631 return FALSE;
632
633 return TRUE;
634 }
635
636
637 /* Write a packet to a Visual dump file.
638 Returns TRUE on success, FALSE on failure. */
visual_dump(wtap_dumper * wdh,const wtap_rec * rec,const guint8 * pd,int * err,gchar ** err_info _U_)639 static gboolean visual_dump(wtap_dumper *wdh, const wtap_rec *rec,
640 const guint8 *pd, int *err, gchar **err_info _U_)
641 {
642 const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
643 struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
644 struct visual_pkt_hdr vpkt_hdr = {0};
645 size_t hdr_size = sizeof vpkt_hdr;
646 guint delta_msec;
647 guint32 packet_status;
648
649 /* We can only write packet records. */
650 if (rec->rec_type != REC_TYPE_PACKET) {
651 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
652 return FALSE;
653 }
654
655 /*
656 * Make sure this packet doesn't have a link-layer type that
657 * differs from the one for the file.
658 */
659 if (wdh->encap != rec->rec_header.packet_header.pkt_encap) {
660 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
661 return FALSE;
662 }
663
664 /* Don't write anything we're not willing to read. */
665 if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
666 *err = WTAP_ERR_PACKET_TOO_LARGE;
667 return FALSE;
668 }
669
670 /* If the visual structure was never allocated then nothing useful
671 can be done. */
672 if (visual == 0)
673 return FALSE;
674
675 /* Visual UpTime capture files have a capture start time in the
676 file header. Each packet has a capture time (in msec) relative
677 to the file start time. Use the time of the first packet as the
678 file start time. */
679 if (visual->index_table_index == 0)
680 {
681 /* This is the first packet. Save its start time as the file time. */
682 visual->start_time = rec->ts.secs;
683
684 /* Initialize the index table */
685 visual->index_table = (guint32 *)g_malloc(1024 * sizeof *visual->index_table);
686 visual->index_table_size = 1024;
687 }
688
689 /* Calculate milliseconds since capture start. */
690 delta_msec = rec->ts.nsecs / 1000000;
691 delta_msec += (guint32)((rec->ts.secs - visual->start_time) * 1000);
692 vpkt_hdr.ts_delta = GUINT32_TO_LE(delta_msec);
693
694 /* Fill in the length fields. */
695 vpkt_hdr.orig_len = GUINT16_TO_LE(rec->rec_header.packet_header.len);
696 vpkt_hdr.incl_len = GUINT16_TO_LE(rec->rec_header.packet_header.caplen);
697
698 /* Fill in the encapsulation hint for the file's media type. */
699 switch (wdh->encap)
700 {
701 case WTAP_ENCAP_ETHERNET: /* Ethernet */
702 vpkt_hdr.encap_hint = 2;
703 break;
704 case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
705 vpkt_hdr.encap_hint = 3;
706 break;
707 case WTAP_ENCAP_PPP: /* PPP */
708 case WTAP_ENCAP_PPP_WITH_PHDR:
709 vpkt_hdr.encap_hint = 14;
710 break;
711 case WTAP_ENCAP_CHDLC_WITH_PHDR: /* HDLC Router */
712 vpkt_hdr.encap_hint = 13;
713 break;
714 case WTAP_ENCAP_FRELAY_WITH_PHDR: /* Frame Relay Auto-detect */
715 vpkt_hdr.encap_hint = 12;
716 break;
717 case WTAP_ENCAP_LAPB: /* Unknown */
718 default:
719 vpkt_hdr.encap_hint = 1;
720 break;
721 }
722
723 /* Set status flags. The only status currently supported for all
724 encapsulations is direction. This either goes in the p2p or the
725 X.25 pseudo header. It would probably be better to move this up
726 into the phdr. */
727 packet_status = 0;
728 switch (wdh->encap)
729 {
730 case WTAP_ENCAP_CHDLC_WITH_PHDR:
731 packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
732 break;
733
734 case WTAP_ENCAP_FRELAY_WITH_PHDR:
735 case WTAP_ENCAP_LAPB:
736 packet_status |=
737 ((pseudo_header->dte_dce.flags & FROM_DCE) ? 0x00 : PS_SENT);
738 break;
739 }
740 vpkt_hdr.status = GUINT32_TO_LE(packet_status);
741
742 /* Write the packet header. */
743 if (!wtap_dump_file_write(wdh, &vpkt_hdr, hdr_size, err))
744 return FALSE;
745
746 /* Write the packet data */
747 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
748 return FALSE;
749
750 /* Store the frame offset in the index table. */
751 if (visual->index_table_index >= visual->index_table_size)
752 {
753 /* End of table reached. Reallocate with a larger size */
754 visual->index_table_size *= 2;
755 visual->index_table = (guint32 *)g_realloc(visual->index_table,
756 visual->index_table_size * sizeof *visual->index_table);
757 }
758 visual->index_table[visual->index_table_index] = GUINT32_TO_LE(visual->next_offset);
759
760 /* Update the table index and offset for the next frame. */
761 visual->index_table_index++;
762 visual->next_offset += (guint32) hdr_size + rec->rec_header.packet_header.caplen;
763
764 return TRUE;
765 }
766
767
768 /* Finish writing to a dump file.
769 Returns TRUE on success, FALSE on failure. */
visual_dump_finish(wtap_dumper * wdh,int * err,gchar ** err_info _U_)770 static gboolean visual_dump_finish(wtap_dumper *wdh, int *err,
771 gchar **err_info _U_)
772 {
773 struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
774 size_t n_to_write;
775 struct visual_file_hdr vfile_hdr = {0};
776 const char *magicp;
777 size_t magic_size;
778
779 /* If the visual structure was never allocated then nothing useful
780 can be done. */
781 if (visual == 0)
782 return FALSE;
783
784 /* Write out the frame table at the end of the file. */
785 if (visual->index_table)
786 {
787 /* Write the index table to the file. */
788 n_to_write = visual->index_table_index * sizeof *visual->index_table;
789 if (!wtap_dump_file_write(wdh, visual->index_table, n_to_write, err))
790 {
791 visual_dump_free(wdh);
792 return FALSE;
793 }
794 }
795
796 /* Write the magic number at the start of the file. */
797 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
798 return FALSE;
799 magicp = visual_magic;
800 magic_size = sizeof visual_magic;
801 if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
802 {
803 visual_dump_free(wdh);
804 return FALSE;
805 }
806
807 vfile_hdr.num_pkts = GUINT32_TO_LE(visual->index_table_index);
808 vfile_hdr.start_time = GUINT32_TO_LE(visual->start_time);
809 vfile_hdr.max_length = GUINT16_TO_LE(65535);
810 vfile_hdr.file_flags = GUINT16_TO_LE(1); /* indexes are present */
811 vfile_hdr.file_version = GUINT16_TO_LE(1);
812 (void) g_strlcpy(vfile_hdr.description, "Wireshark file", 64);
813
814 /* Translate the encapsulation type */
815 switch (wdh->encap)
816 {
817 case WTAP_ENCAP_ETHERNET:
818 vfile_hdr.media_type = GUINT16_TO_LE(6);
819 break;
820
821 case WTAP_ENCAP_TOKEN_RING:
822 vfile_hdr.media_type = GUINT16_TO_LE(9);
823 break;
824
825 case WTAP_ENCAP_LAPB:
826 vfile_hdr.media_type = GUINT16_TO_LE(16);
827 break;
828
829 case WTAP_ENCAP_PPP: /* PPP is differentiated from CHDLC in PktHdr */
830 case WTAP_ENCAP_PPP_WITH_PHDR:
831 case WTAP_ENCAP_CHDLC_WITH_PHDR:
832 vfile_hdr.media_type = GUINT16_TO_LE(22);
833 break;
834
835 case WTAP_ENCAP_FRELAY_WITH_PHDR:
836 vfile_hdr.media_type = GUINT16_TO_LE(32);
837 break;
838 }
839
840 /* Write the file header following the magic bytes. */
841 if (!wtap_dump_file_write(wdh, &vfile_hdr, sizeof vfile_hdr, err))
842 {
843 visual_dump_free(wdh);
844 return FALSE;
845 }
846
847 /* Deallocate the file write data */
848 visual_dump_free(wdh);
849 return TRUE;
850 }
851
852
853 /* Free the memory allocated by a visual file writer. */
visual_dump_free(wtap_dumper * wdh)854 static void visual_dump_free(wtap_dumper *wdh)
855 {
856 struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
857
858 if (visual)
859 {
860 /* Free the index table memory. */
861 g_free(visual->index_table);
862 }
863 }
864
865 static const struct supported_block_type visual_blocks_supported[] = {
866 /*
867 * We support packet blocks, with no comments or other options.
868 */
869 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
870 };
871
872 static const struct file_type_subtype_info visual_info = {
873 "Visual Networks traffic capture", "visual", NULL, NULL,
874 TRUE, BLOCKS_SUPPORTED(visual_blocks_supported),
875 visual_dump_can_write_encap, visual_dump_open, NULL
876 };
877
register_visual(void)878 void register_visual(void)
879 {
880 visual_file_type_subtype = wtap_register_file_type_subtype(&visual_info);
881
882 /*
883 * Register name for backwards compatibility with the
884 * wtap_filetypes table in Lua.
885 */
886 wtap_register_backwards_compatibility_lua_name("VISUAL_NETWORKS",
887 visual_file_type_subtype);
888 }
889
890 /*
891 * Editor modelines - https://www.wireshark.org/tools/modelines.html
892 *
893 * Local variables:
894 * c-basic-offset: 4
895 * tab-width: 8
896 * indent-tabs-mode: nil
897 * End:
898 *
899 * vi: set shiftwidth=4 tabstop=8 expandtab:
900 * :indentSize=4:tabSize=8:noTabs=true:
901 */
902