wireshark/wiretap/netscaler.c

2511 lines
96 KiB
C
Raw Normal View History

/* netscaler.c
*
* Wiretap Library
* Copyright (c) 2006 by Ravi Kondamuru <Ravi.Kondamuru@citrix.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <errno.h>
#include <string.h>
#include "wtap-int.h"
#include "file_wrappers.h"
#include "netscaler.h"
#include <wsutil/ws_assert.h>
/* Defines imported from netscaler code: nsperfrc.h */
#define NSPR_SIGSTR_V10 "NetScaler Performance Data"
#define NSPR_SIGSTR_V20 "NetScaler V20 Performance Data"
#define NSPR_SIGSTR NSPR_SIGSTR_V20
#define NSPR_SIGSTR_V30 "Netscaler V30 Performance Data"
#define NSPR_SIGSTR_V35 "Netscaler V35 Performance Data"
/* Defined but not used */
#define NSPR_SIGSTR_V21 "NetScaler V21 Performance Data"
#define NSPR_SIGSTR_V22 "NetScaler V22 Performance Data"
/*
* NetScaler trace files are divided into 8K pages, with each page
* containing one or more records. The last page of the file
* might be less than 8K bytes.
*
* Records are not split across page boundaries; if a record doesn't
* fit in what remains in a page, the page is padded with null bytes
* and the next record is put at the beginning of the next page.
* A record type value of 0 means "unused space", so if there are
* enough null bytes to constitute a record type value, it will
* look as if there's an "unused space" record (which has no fields
* other than the type and zero or more additional padding bytes).
*/
#define NSPR_PAGESIZE 8192
#define NSPR_PAGESIZE_TRACE (2*NSPR_PAGESIZE)
/* The different record types
** NOTE: The Record Type is two byte fields and unused space is recognized by
** either bytes being zero, therefore no record should any byte value as
** zero.
**
** New Performance Record Type is only one byte.
*/
#define NSPR_UNUSEDSPACE_V10 0x0000 /* rest of the page is unused */
#define NSPR_UNUSEDSPACE_V20 0x00 /* rest of the page is unused */
#define NSPR_SIGNATURE_V10 0x0101 /* signature */
#define NSPR_SIGNATURE_V20 0x01 /* signature */
#define NSPR_SIGNATURE_V30 NSPR_SIGNATURE_V20
#define NSPR_SIGNATURE_V35 NSPR_SIGNATURE_V20
#define NSPR_ABSTIME_V10 0x0107 /* data capture time in secs from 1970*/
#define NSPR_ABSTIME_V20 0x07 /* data capture time in secs from 1970*/
#define NSPR_RELTIME_V10 0x0108 /* relative time in ms from last time */
#define NSPR_RELTIME_V20 0x08 /* relative time in ms from last time */
#define NSPR_RELTIMEHR_V10 0x0109 /* high resolution relative time */
#define NSPR_RELTIMEHR_V20 0x09 /* high resolution relative time */
#define NSPR_SYSTARTIME_V10 0x010A /* system start time */
#define NSPR_SYSTARTIME_V20 0x0A /* system start time */
#define NSPR_RELTIME2B_V10 0x010B /* relative time in ms from last time */
#define NSPR_RELTIME2B_V20 0x0B /* relative time in ms from last time */
/* The high resolution relative time format.
2020-10-10 23:42:05 +00:00
** The MS 2 bits of the high resolution time is defined as follows:
** 00 : time value is in seconds
** 01 : time value is in milliseconds
** 10 : time value is in microseconds
** 11 : time value is in nanoseconds
*/
#define NSPR_HRTIME_MASKTM 0x3FFFFFFF /* mask to get time value */
#define NSPR_HRTIME_MASKFMT 0xC0000000 /* time value format mask */
#define NSPR_HRTIME_SEC 0x00000000 /* time value in second */
#define NSPR_HRTIME_MSEC 0x40000000 /* time value in mili second */
#define NSPR_HRTIME_USEC 0x80000000 /* time value in micro second */
#define NSPR_HRTIME_NSEC 0xC0000000 /* time value in nano second */
typedef struct nspr_header_v10
{
guint8 ph_RecordType[2]; /* Record Type */
guint8 ph_RecordSize[2]; /* Record Size including header */
} nspr_header_v10_t;
#define nspr_header_v10_s ((guint32)sizeof(nspr_header_v10_t))
/* This is V20 short header (2 bytes long) to be included where needed */
#define NSPR_HEADER_V20(prefix) \
guint8 prefix##_RecordType; /* Record Type */ \
guint8 prefix##_RecordSize /* Record Size including header */ \
/* end of declaration */
/* This is new long header (3 bytes long) to be included where needed */
#define NSPR_HEADER3B_V20(prefix) \
guint8 prefix##_RecordType; /* Record Type */ \
guint8 prefix##_RecordSizeLow; /* Record Size including header */ \
guint8 prefix##_RecordSizeHigh /* Record Size including header */ \
/* end of declaration */
#define NSPR_HEADER3B_V21 NSPR_HEADER3B_V20
#define NSPR_HEADER3B_V22 NSPR_HEADER3B_V20
#define NSPR_HEADER3B_V30 NSPR_HEADER3B_V20
typedef struct nspr_hd_v20
{
NSPR_HEADER3B_V20(phd); /* long performance header */
} nspr_hd_v20_t;
#define nspr_hd_v20_s ((guint32)sizeof(nspr_hd_v20_t))
/*
** How to know if header size is short or long?
** The short header size can be 0-127 bytes long. If MS Bit of ph_RecordSize
** is set then record size has 2 bytes
*/
#define NSPR_V20RECORDSIZE_2BYTES 0x80U
/* Performance Data Header with device number */
typedef struct nspr_headerdev_v10
{
guint8 ph_RecordType[2]; /* Record Type */
guint8 ph_RecordSize[2]; /* Record Size including header */
guint8 ph_DevNo[4]; /* Network Device (NIC/CONN) number */
} nspr_headerdev_v10_t;
#define nspr_headerdev_v10_s ((guint32)sizeof(nspr_headerdev_v10_t))
typedef struct nspr_hd_v10
{
nspr_header_v10_t phd; /* performance header */
} nspr_hd_v10_t;
#define nspr_hd_v10_s ((guint32)sizeof(nspr_hd_v10_t))
typedef struct nspr_hdev_v10
{
nspr_headerdev_v10_t phd; /* performance header */
} nspr_hdev_v10_t;
#define nspr_hdev_v10_s ((guint32)sizeof(nspr_hdev_v10_t))
/* if structure has defined phd as first field, it can use following names */
#define nsprRecordType phd.ph_RecordType
#define nsprRecordSize phd.ph_RecordSize
#define nsprReserved phd.ph_Reserved
#define nsprRecordTypeOrg phd.ph_Reserved
#define nsprDevNo phd.ph_DevNo
/* NSPR_SIGNATURE_V10 structure */
#define NSPR_SIGSIZE_V10 56 /* signature value size in bytes */
typedef struct nspr_signature_v10
{
nspr_header_v10_t phd; /* performance header */
guint8 sig_EndianType; /* Endian Type for the data */
guint8 sig_Reserved0;
guint8 sig_Reserved1[2];
gchar sig_Signature[NSPR_SIGSIZE_V10]; /* Signature value */
} nspr_signature_v10_t;
#define nspr_signature_v10_s ((guint32)sizeof(nspr_signature_v10_t))
/* NSPR_SIGNATURE_V20 structure */
#define NSPR_SIGSIZE_V20 sizeof(NSPR_SIGSTR_V20) /* signature value size in bytes */
typedef struct nspr_signature_v20
{
NSPR_HEADER_V20(sig); /* short performance header */
guint8 sig_EndianType; /* Endian Type for the data */
gchar sig_Signature[NSPR_SIGSIZE_V20]; /* Signature value */
} nspr_signature_v20_t;
#define nspr_signature_v20_s ((guint32)sizeof(nspr_signature_v20_t))
/* NSPR_SIGNATURE_V30 structure */
#define NSPR_SIGSIZE_V30 sizeof(NSPR_SIGSTR_V30) /* signature value size in bytes */
typedef struct nspr_signature_v30
{
NSPR_HEADER_V20(sig); /* short performance header */
guint8 sig_EndianType; /* Endian Type for the data */
gchar sig_Signature[NSPR_SIGSIZE_V30]; /* Signature value */
} nspr_signature_v30_t;
#define nspr_signature_v30_s ((guint32)sizeof(nspr_signature_v30_t))
#define NSPR_SIGSIZE_V35 sizeof(NSPR_SIGSTR_V35) /* signature value size in bytes */
typedef struct nspr_signature_v35
{
NSPR_HEADER_V20(sig); /* short performance header */
guint8 sig_EndianType; /* Endian Type for the data */
gchar sig_Signature[NSPR_SIGSIZE_V35]; /* Signature value */
} nspr_signature_v35_t;
#define nspr_signature_v35_s ((guint32)sizeof(nspr_signature_v35_t))
/* NSPR_ABSTIME_V10 and NSPR_SYSTARTIME_V10 structure */
typedef struct nspr_abstime_v10
{
nspr_header_v10_t phd; /* performance header */
guint8 abs_RelTime[4]; /* relative time is ms from last time */
guint8 abs_Time[4]; /* absolute time in seconds from 1970 */
} nspr_abstime_v10_t;
#define nspr_abstime_v10_s ((guint32)sizeof(nspr_abstime_v10_t))
/* NSPR_ABSTIME_V20 and NSPR_SYSTARTIME_V20 structure */
typedef struct nspr_abstime_v20
{
NSPR_HEADER_V20(abs); /* short performance header */
guint8 abs_RelTime[2]; /* relative time is ms from last time */
guint8 abs_Time[4]; /* absolute time in seconds from 1970 */
} nspr_abstime_v20_t;
#define nspr_abstime_v20_s ((guint32)sizeof(nspr_abstime_v20_t))
/* full packet trace structure */
typedef struct nspr_pktracefull_v10
{
nspr_headerdev_v10_t phd; /* performance header */
guint8 fp_RelTimeHr[4]; /* High resolution relative time */
} nspr_pktracefull_v10_t;
#define nspr_pktracefull_v10_s ((guint32)(sizeof(nspr_pktracefull_v10_t)))
/* new full packet trace structure v20 */
typedef struct nspr_pktracefull_v20
{
NSPR_HEADER3B_V20(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_RelTimeHr[4]; /* High resolution relative time */
} nspr_pktracefull_v20_t;
#define nspr_pktracefull_v20_s ((guint32)(sizeof(nspr_pktracefull_v20_t)))
/* new full packet trace structure v21 */
typedef struct nspr_pktracefull_v21
{
NSPR_HEADER3B_V21(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_RelTimeHr[4]; /* High resolution relative time */
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
} nspr_pktracefull_v21_t;
#define nspr_pktracefull_v21_s ((guint32)(sizeof(nspr_pktracefull_v21_t)))
/* new full packet trace structure v22 */
typedef struct nspr_pktracefull_v22
{
NSPR_HEADER3B_V22(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_RelTimeHr[4]; /* High resolution relative time */
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_VlanTag[2]; /* vlan tag */
} nspr_pktracefull_v22_t;
#define nspr_pktracefull_v22_s ((guint32)(sizeof(nspr_pktracefull_v22_t)))
typedef struct nspr_pktracefull_v23
{
NSPR_HEADER3B_V22(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_AbsTimeHr[8]; /* High resolution absolute time */
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_VlanTag[2]; /* vlan tag */
guint8 fp_Coreid[2]; /* coreid of the packet */
} nspr_pktracefull_v23_t;
#define nspr_pktracefull_v23_s ((guint32)(sizeof(nspr_pktracefull_v23_t)))
/* New full packet trace structure v24 for cluster tracing */
typedef struct nspr_pktracefull_v24
{
NSPR_HEADER3B_V22(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_AbsTimeHr[8]; /* High resolution absolute time in nanosec */
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_VlanTag[2]; /* vlan tag */
guint8 fp_Coreid[2]; /* coreid of the packet */
guint8 fp_srcNodeId[2]; /* source node # */
guint8 fp_destNodeId[2]; /* destination node # */
guint8 fp_clFlags; /* cluster flags */
} nspr_pktracefull_v24_t;
#define nspr_pktracefull_v24_s ((guint32)(sizeof(nspr_pktracefull_v24_t)))
/* New full packet trace structure v25 for vm info tracing */
typedef struct nspr_pktracefull_v25
{
NSPR_HEADER3B_V22(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_AbsTimeHr[8]; /* High resolution absolute time in nanosec */
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_VlanTag[2]; /* vlan tag */
guint8 fp_Coreid[2]; /* coreid of the packet */
guint8 fp_srcNodeId[2]; /* source node # */
guint8 fp_destNodeId[2]; /* destination node # */
guint8 fp_clFlags; /* cluster flags */
guint8 fp_src_vmname_len; /* vm src info */
guint8 fp_dst_vmname_len; /* vm src info */
} nspr_pktracefull_v25_t;
#define nspr_pktracefull_v25_s ((guint32)(sizeof(nspr_pktracefull_v25_t)))
/* New full packet trace structure v26 for vm info tracing */
typedef struct nspr_pktracefull_v26
{
NSPR_HEADER3B_V22(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_AbsTimeHr[8]; /* High resolution absolute time in nanosec */
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_VlanTag[2]; /* vlan tag */
guint8 fp_Coreid[2]; /* coreid of the packet */
guint8 fp_srcNodeId[2]; /* source node # */
guint8 fp_destNodeId[2]; /* destination node # */
guint8 fp_clFlags; /* cluster flags */
guint8 fp_src_vmname_len; /* vm src info */
guint8 fp_dst_vmname_len; /* vm src info */
guint8 fp_reserved;
guint8 fp_ns_activity[4];
guint8 fp_reserved_32[12]; /* Adding more field to reduce wireshark changes every time */
} nspr_pktracefull_v26_t;
#define nspr_pktracefull_v26_s ((guint32)(sizeof(nspr_pktracefull_v26_t)))
/* partial packet trace structure */
typedef struct nspr_pktracepart_v10
{
nspr_headerdev_v10_t phd; /* performance header */
guint8 pp_RelTimeHr[4]; /* High resolution relative time */
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
} nspr_pktracepart_v10_t;
#define nspr_pktracepart_v10_s ((guint32)(sizeof(nspr_pktracepart_v10_t)))
/* new partial packet trace structure */
typedef struct nspr_pktracepart_v20
{
NSPR_HEADER3B_V20(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_RelTimeHr[4]; /* High resolution relative time */
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
} nspr_pktracepart_v20_t;
#define nspr_pktracepart_v20_s ((guint32)(sizeof(nspr_pktracepart_v20_t)))
/* new partial packet trace structure */
typedef struct nspr_pktracepart_v21
{
NSPR_HEADER3B_V21(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_RelTimeHr[4]; /* High resolution relative time */
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
guint8 pp_PcbDevNo[4]; /* PCB devno */
guint8 pp_lPcbDevNo[4]; /* link PCB devno */
} nspr_pktracepart_v21_t;
#define nspr_pktracepart_v21_s ((guint32)(sizeof(nspr_pktracepart_v21_t)))
/* new partial packet trace structure v22 */
typedef struct nspr_pktracepart_v22
{
NSPR_HEADER3B_V22(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_RelTimeHr[4]; /* High resolution relative time */
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
guint8 pp_PcbDevNo[4]; /* PCB devno */
guint8 pp_lPcbDevNo[4]; /* link PCB devno */
guint8 pp_VlanTag[2]; /* Vlan Tag */
} nspr_pktracepart_v22_t;
#define nspr_pktracepart_v22_s ((guint32)(sizeof(nspr_pktracepart_v22_t)))
typedef struct nspr_pktracepart_v23
{
NSPR_HEADER3B_V22(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_AbsTimeHr[8]; /* High resolution absolute time */
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
guint8 pp_PcbDevNo[4]; /* PCB devno */
guint8 pp_lPcbDevNo[4]; /* link PCB devno */
guint8 pp_VlanTag[2]; /* vlan tag */
guint8 pp_Coreid[2]; /* Coreid of the packet */
} nspr_pktracepart_v23_t;
#define nspr_pktracepart_v23_s ((guint32)(sizeof(nspr_pktracepart_v23_t)))
/* New partial packet trace structure v24 for cluster tracing */
typedef struct nspr_pktracepart_v24
{
NSPR_HEADER3B_V22(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_AbsTimeHr[8]; /*High resolution absolute time in nanosec*/
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
guint8 pp_PcbDevNo[4]; /* PCB devno */
guint8 pp_lPcbDevNo[4]; /* link PCB devno */
guint8 pp_VlanTag[2]; /* vlan tag */
guint8 pp_Coreid[2]; /* Coreid of the packet */
guint8 pp_srcNodeId[2]; /* source node # */
guint8 pp_destNodeId[2]; /* destination node # */
guint8 pp_clFlags; /* cluster flags */
} nspr_pktracepart_v24_t;
#define nspr_pktracepart_v24_s ((guint32)(sizeof(nspr_pktracepart_v24_t)))
/* New partial packet trace structure v25 for vm info tracing */
typedef struct nspr_pktracepart_v25
{
NSPR_HEADER3B_V22(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_AbsTimeHr[8]; /*High resolution absolute time in nanosec*/
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
guint8 pp_PcbDevNo[4]; /* PCB devno */
guint8 pp_lPcbDevNo[4]; /* link PCB devno */
guint8 pp_VlanTag[2]; /* vlan tag */
guint8 pp_Coreid[2]; /* Coreid of the packet */
guint8 pp_srcNodeId[2]; /* source node # */
guint8 pp_destNodeId[2]; /* destination node # */
guint8 pp_clFlags; /* cluster flags */
guint8 pp_src_vmname_len; /* vm info */
guint8 pp_dst_vmname_len; /* vm info */
} nspr_pktracepart_v25_t;
#define nspr_pktracepart_v25_s ((guint32)(sizeof(nspr_pktracepart_v25_t)))
/* New full packet trace structure v30 for multipage spanning data */
typedef struct nspr_pktracefull_v30
{
NSPR_HEADER3B_V30(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_AbsTimeHr[8]; /*High resolution absolute time in nanosec*/
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_PktSizeOrg[2]; /* Original packet size */
guint8 fp_VlanTag[2]; /* vlan tag */
guint8 fp_Coreid[2]; /* coreid of the packet */
guint8 fp_srcNodeId[2]; /* cluster nodeid of the packet */
guint8 fp_destNodeId[2];
guint8 fp_clFlags;
guint8 fp_src_vmname_len;
guint8 fp_dst_vmname_len;
guint8 fp_reserved[3];
guint8 fp_ns_activity[4];
guint8 fp_reserved_32[12];
} nspr_pktracefull_v30_t;
#define nspr_pktracefull_v30_s ((guint32)(sizeof(nspr_pktracefull_v30_t)))
/* New full packet trace structure v35 for multipage spanning data */
typedef struct nspr_pktracefull_v35
{
NSPR_HEADER3B_V30(fp); /* long performance header */
guint8 fp_DevNo; /* Network Device (NIC) number */
guint8 fp_AbsTimeHr[8]; /*High resolution absolute time in nanosec*/
guint8 fp_PcbDevNo[4]; /* PCB devno */
guint8 fp_lPcbDevNo[4]; /* link PCB devno */
guint8 fp_PktSizeOrg[2]; /* Original packet size */
guint8 fp_VlanTag[2]; /* vlan tag */
guint8 fp_Coreid[2]; /* coreid of the packet */
guint8 fp_headerlen[2];
guint8 fp_errorcode;
guint8 fp_app;
guint8 fp_ns_activity[4];
guint8 fp_nextrectype;
} nspr_pktracefull_v35_t;
#define nspr_pktracefull_v35_s ((guint32)(sizeof(nspr_pktracefull_v35_t)))
/* New partial packet trace structure v26 for vm info tracing */
typedef struct nspr_pktracepart_v26
{
NSPR_HEADER3B_V22(pp); /* long performance header */
guint8 pp_DevNo; /* Network Device (NIC) number */
guint8 pp_AbsTimeHr[8]; /*High resolution absolute time in nanosec*/
guint8 pp_PktSizeOrg[2]; /* Original packet size */
guint8 pp_PktOffset[2]; /* starting offset in packet */
guint8 pp_PcbDevNo[4]; /* PCB devno */
guint8 pp_lPcbDevNo[4]; /* link PCB devno */
guint8 pp_VlanTag[2]; /* vlan tag */
guint8 pp_Coreid[2]; /* Coreid of the packet */
guint8 pp_srcNodeId[2]; /* source node # */
guint8 pp_destNodeId[2]; /* destination node # */
guint8 pp_clFlags; /* cluster flags */
guint8 pp_src_vmname_len; /* vm info */
guint8 pp_dst_vmname_len; /* vm info */
guint8 pp_reserved;
guint8 pp_ns_activity[4];
guint8 pp_reserved_32[12]; /* Adding more field to reduce wireshark changes every time */
} nspr_pktracepart_v26_t;
#define nspr_pktracepart_v26_s ((guint32)(sizeof(nspr_pktracepart_v26_t)))
#define __TNDO(rec,enumprefix,structname,hdrname)\
static const guint8 enumprefix##_##hdrname##_offset = (guint8)sizeof(nspr_##structname##_t);
#define __TNO(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
static const guint8 enumprefix##_##hdrname##_offset = (guint8)GPOINTER_TO_INT(offsetof(nspr_##structname##_t,structprefix##_##structfieldname));
#define __TNL(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
static const guint8 enumprefix##_##hdrname##_len = (guint8)sizeof(((nspr_##structname##_t*)0)->structprefix##_##structfieldname);
#define __TNV1O(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
static const guint8 enumprefix##_##hdrname##_offset = (guint8)GPOINTER_TO_INT(offsetof(nspr_##structname##_t,structfieldname));
#define __TNV1L(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
static const guint8 enumprefix##_##hdrname##_len = (guint8)sizeof(((nspr_##structname##_t*)0)->structfieldname);
#define TRACE_V10_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
__TNV1O(rec,enumprefix,structprefix,structname,dir,phd.ph_RecordType)\
__TNV1L(rec,enumprefix,structprefix,structname,dir,phd.ph_RecordType)\
__TNV1O(rec,enumprefix,structprefix,structname,nicno,phd.ph_DevNo)\
__TNV1L(rec,enumprefix,structprefix,structname,nicno,phd.ph_DevNo)\
__TNDO(rec,enumprefix,structname,eth)
#define TRACE_V20_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
__TNO(rec,enumprefix,structprefix,structname,dir,RecordType)\
__TNL(rec,enumprefix,structprefix,structname,dir,RecordType)\
__TNO(rec,enumprefix,structprefix,structname,nicno,DevNo)\
__TNL(rec,enumprefix,structprefix,structname,nicno,DevNo)\
__TNDO(rec,enumprefix,structname,eth)
#define TRACE_V21_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
TRACE_V20_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNO(rec,enumprefix,structprefix,structname,pcb,PcbDevNo)\
__TNO(rec,enumprefix,structprefix,structname,l_pcb,lPcbDevNo)
#define TRACE_V22_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
TRACE_V21_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNO(rec,enumprefix,structprefix,structname,vlantag,VlanTag)
#define TRACE_V23_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
TRACE_V22_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNO(rec,enumprefix,structprefix,structname,coreid,Coreid)
#define TRACE_V24_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
TRACE_V23_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNO(rec,enumprefix,structprefix,structname,srcnodeid,srcNodeId)\
__TNO(rec,enumprefix,structprefix,structname,destnodeid,destNodeId)\
__TNO(rec,enumprefix,structprefix,structname,clflags,clFlags)
#define TRACE_V25_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
TRACE_V24_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNO(rec,enumprefix,structprefix,structname,src_vmname_len,src_vmname_len)\
__TNO(rec,enumprefix,structprefix,structname,dst_vmname_len,dst_vmname_len)\
__TNDO(rec,enumprefix,structname,data)
#define TRACE_V26_REC_LEN_OFF(rec,enumprefix,structprefix,structname) \
TRACE_V25_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNO(rec,enumprefix,structprefix,structname,ns_activity,ns_activity)\
#define TRACE_V30_REC_LEN_OFF(rec, enumprefix, structprefix, structname) \
TRACE_V26_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
#define TRACE_V35_REC_LEN_OFF(rec, enumprefix, structprefix, structname) \
TRACE_V23_REC_LEN_OFF(rec,enumprefix,structprefix,structname)\
__TNDO(rec,enumprefix,structname,data)\
__TNO(rec,enumprefix,structprefix,structname,ns_activity,ns_activity)
TRACE_V10_REC_LEN_OFF(NULL,v10_part,pp,pktracepart_v10)
TRACE_V10_REC_LEN_OFF(NULL,v10_full,fp,pktracefull_v10)
TRACE_V20_REC_LEN_OFF(NULL,v20_part,pp,pktracepart_v20)
TRACE_V20_REC_LEN_OFF(NULL,v20_full,fp,pktracefull_v20)
TRACE_V21_REC_LEN_OFF(NULL,v21_part,pp,pktracepart_v21)
TRACE_V21_REC_LEN_OFF(NULL,v21_full,fp,pktracefull_v21)
TRACE_V22_REC_LEN_OFF(NULL,v22_part,pp,pktracepart_v22)
TRACE_V22_REC_LEN_OFF(NULL,v22_full,fp,pktracefull_v22)
TRACE_V23_REC_LEN_OFF(NULL,v23_part,pp,pktracepart_v23)
TRACE_V23_REC_LEN_OFF(NULL,v23_full,fp,pktracefull_v23)
TRACE_V24_REC_LEN_OFF(NULL,v24_part,pp,pktracepart_v24)
TRACE_V24_REC_LEN_OFF(NULL,v24_full,fp,pktracefull_v24)
TRACE_V25_REC_LEN_OFF(NULL,v25_part,pp,pktracepart_v25)
TRACE_V25_REC_LEN_OFF(NULL,v25_full,fp,pktracefull_v25)
TRACE_V26_REC_LEN_OFF(NULL,v26_part,pp,pktracepart_v26)
TRACE_V26_REC_LEN_OFF(NULL,v26_full,fp,pktracefull_v26)
TRACE_V30_REC_LEN_OFF(NULL,v30_full,fp,pktracefull_v30)
TRACE_V35_REC_LEN_OFF(NULL,v35_full,fp,pktracefull_v35)
#undef __TNV1O
#undef __TNV1L
#undef __TNO
#undef __TNDO
#undef __TNL
#define ns_setabstime(nstrace, AbsoluteTime, RelativeTimems) \
do { \
(nstrace)->nspm_curtime = AbsoluteTime; \
(nstrace)->nspm_curtimemsec += RelativeTimems; \
(nstrace)->nspm_curtimelastmsec = nstrace->nspm_curtimemsec; \
} while(0)
#define ns_setrelativetime(nstrace, RelativeTimems) \
do { \
guint32 rsec; \
(nstrace)->nspm_curtimemsec += RelativeTimems; \
rsec = (guint32)((nstrace)->nspm_curtimemsec - (nstrace)->nspm_curtimelastmsec)/1000; \
(nstrace)->nspm_curtime += rsec; \
(nstrace)->nspm_curtimelastmsec += rsec * 1000; \
} while (0)
typedef struct {
gchar *pnstrace_buf;
gint64 xxx_offset;
guint32 nstrace_buf_offset;
guint32 nstrace_buflen;
/* Performance Monitor Time variables */
guint32 nspm_curtime; /* current time since 1970 */
guint64 nspm_curtimemsec; /* current time in milliseconds */
guint64 nspm_curtimelastmsec; /* nspm_curtime last update time in milliseconds */
guint64 nsg_creltime;
guint64 file_size;
} nstrace_t;
/*
* File versions.
*/
#define NSPM_SIGNATURE_1_0 0
#define NSPM_SIGNATURE_2_0 1
#define NSPM_SIGNATURE_3_0 2
#define NSPM_SIGNATURE_3_5 3
#define NSPM_SIGNATURE_NOMATCH -1
static int nspm_signature_version(gchar*, gint32);
static gboolean nstrace_read_v10(wtap *wth, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info,
gint64 *data_offset);
static gboolean nstrace_read_v20(wtap *wth, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info,
gint64 *data_offset);
static gboolean nstrace_read_v30(wtap *wth, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info,
gint64 *data_offset);
static gboolean nstrace_seek_read_v10(wtap *wth, gint64 seek_off,
wtap_rec *rec,
Buffer *buf,
int *err, gchar **err_info);
static gboolean nstrace_seek_read_v20(wtap *wth, gint64 seek_off,
wtap_rec *rec,
Buffer *buf,
int *err, gchar **err_info);
static gboolean nstrace_seek_read_v30(wtap *wth, gint64 seek_off,
wtap_rec *rec,
Buffer *buf,
int *err, gchar **err_info);
static void nstrace_close(wtap *wth);
static gboolean nstrace_set_start_time_v10(wtap *wth, int *err,
gchar **err_info);
static gboolean nstrace_set_start_time_v20(wtap *wth, int *err,
gchar **err_info);
static gboolean nstrace_set_start_time(wtap *wth, int version, int *err,
gchar **err_info);
static guint64 ns_hrtime2nsec(guint32 tm);
static gboolean nstrace_dump(wtap_dumper *wdh, const wtap_rec *rec,
const guint8 *pd, int *err, gchar **err_info);
static int nstrace_1_0_file_type_subtype = -1;
static int nstrace_2_0_file_type_subtype = -1;
static int nstrace_3_0_file_type_subtype = -1;
static int nstrace_3_5_file_type_subtype = -1;
void register_nstrace(void);
/*
* Minimum of the page size and the amount of data left in the file;
* the last page of a file can be short.
*/
#define GET_READ_PAGE_SIZE(remaining_file_size) ((gint32)((remaining_file_size>NSPR_PAGESIZE)?NSPR_PAGESIZE:remaining_file_size))
#define GET_READ_PAGE_SIZEV3(remaining_file_size) ((gint32)((remaining_file_size>NSPR_PAGESIZE_TRACE)?NSPR_PAGESIZE_TRACE:remaining_file_size))
/*
* Check whether we have enough room to retrieve the data in the caller.
* If not, we have a malformed file.
*/
static gboolean nstrace_ensure_buflen(nstrace_t* nstrace, guint offset, guint len, int *err, gchar** err_info)
{
if (offset > nstrace->nstrace_buflen || nstrace->nstrace_buflen - offset < len) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: malformed file");
return FALSE;
}
return TRUE;
}
static guint64 ns_hrtime2nsec(guint32 tm)
{
guint32 val = tm & NSPR_HRTIME_MASKTM;
switch(tm & NSPR_HRTIME_MASKFMT)
{
case NSPR_HRTIME_SEC: return (guint64)val*1000000000;
case NSPR_HRTIME_MSEC: return (guint64)val*1000000;
case NSPR_HRTIME_USEC: return (guint64)val*1000;
case NSPR_HRTIME_NSEC: return val;
}
return tm;
}
static gboolean
nstrace_read_buf(FILE_T fh, void *buf, guint32 buflen, int *err,
gchar **err_info)
{
int bytes_read;
bytes_read = file_read(buf, buflen, fh);
if (bytes_read < 0) {
*err = file_error(fh, err_info);
return FALSE;
}
if ((guint32)bytes_read != buflen) {
/*
* XXX - for which files can the last page be short?
*/
*err = 0;
return FALSE;
}
return TRUE;
}
/*
** Netscaler trace format open routines
*/
wtap_open_return_val nstrace_open(wtap *wth, int *err, gchar **err_info)
{
int file_version;
gchar *nstrace_buf;
gint64 file_size;
gint32 page_size;
int bytes_read;
nstrace_t *nstrace;
if ((file_size = wtap_file_size(wth, err)) == -1)
return WTAP_OPEN_ERROR;
if (file_size == 0)
return WTAP_OPEN_NOT_MINE;
/* The size is 64 bits; we assume it fits in 63 bits, so it's positive */
nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE);
page_size = GET_READ_PAGE_SIZE(file_size);
/* Read the first page, so we can look for a signature */
bytes_read = file_read(nstrace_buf, page_size, wth->fh);
if (bytes_read < 0 || bytes_read != page_size) {
*err = file_error(wth->fh, err_info);
g_free(nstrace_buf);
if (*err == 0 && bytes_read > 0)
return WTAP_OPEN_NOT_MINE;
return WTAP_OPEN_ERROR;
}
/*
* Scan it for a signature block.
*/
file_version = nspm_signature_version(nstrace_buf, page_size);
switch (file_version) {
case NSPM_SIGNATURE_1_0:
wth->file_type_subtype = nstrace_1_0_file_type_subtype;
wth->file_encap = WTAP_ENCAP_NSTRACE_1_0;
break;
case NSPM_SIGNATURE_2_0:
wth->file_type_subtype = nstrace_2_0_file_type_subtype;
wth->file_encap = WTAP_ENCAP_NSTRACE_2_0;
break;
case NSPM_SIGNATURE_3_0:
wth->file_type_subtype = nstrace_3_0_file_type_subtype;
wth->file_encap = WTAP_ENCAP_NSTRACE_3_0;
g_free(nstrace_buf);
nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE_TRACE);
page_size = GET_READ_PAGE_SIZEV3(file_size);
break;
case NSPM_SIGNATURE_3_5:
wth->file_type_subtype = nstrace_3_5_file_type_subtype;
wth->file_encap = WTAP_ENCAP_NSTRACE_3_5;
g_free(nstrace_buf);
nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE_TRACE);
page_size = GET_READ_PAGE_SIZEV3(file_size);
break;
default:
/* No known signature found, assume it's not NetScaler */
g_free(nstrace_buf);
return WTAP_OPEN_NOT_MINE;
}
/* Seek back to the beginning of the file after reading the first byte. */
if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1)
{
g_free(nstrace_buf);
return WTAP_OPEN_ERROR;
}
/* XXX - didn't the read above already handle this? */
if (!wtap_read_bytes(wth->fh, nstrace_buf, page_size, err, err_info))
{
g_free(nstrace_buf);
if (*err != WTAP_ERR_SHORT_READ)
return WTAP_OPEN_ERROR;
return WTAP_OPEN_NOT_MINE;
}
switch (file_version)
{
case NSPM_SIGNATURE_1_0:
wth->subtype_read = nstrace_read_v10;
wth->subtype_seek_read = nstrace_seek_read_v10;
break;
case NSPM_SIGNATURE_2_0:
wth->subtype_read = nstrace_read_v20;
wth->subtype_seek_read = nstrace_seek_read_v20;
break;
case NSPM_SIGNATURE_3_0:
wth->subtype_read = nstrace_read_v30;
wth->subtype_seek_read = nstrace_seek_read_v30;
break;
case NSPM_SIGNATURE_3_5:
wth->subtype_read = nstrace_read_v30;
wth->subtype_seek_read = nstrace_seek_read_v30;
break;
}
wth->subtype_close = nstrace_close;
nstrace = g_new(nstrace_t, 1);
wth->priv = (void *)nstrace;
nstrace->pnstrace_buf = nstrace_buf;
nstrace->xxx_offset = 0;
nstrace->nstrace_buflen = page_size;
nstrace->nstrace_buf_offset = 0;
nstrace->nspm_curtime = 0;
nstrace->nspm_curtimemsec = 0;
nstrace->nspm_curtimelastmsec = 0;
nstrace->nsg_creltime = 0;
nstrace->file_size = file_size;
/* Set the start time by looking for the abstime record */
if ((nstrace_set_start_time(wth, file_version, err, err_info)) == FALSE)
{
/*
* No absolute time record seen, so we just reset the read
* pointer to the start of the file, so we start reading
* at the first record, rather than skipping records up
* to and including an absolute time record.
*/
if (*err != 0)
{
/* We got an error reading the records. */
return WTAP_OPEN_ERROR;
}
if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1)
{
return WTAP_OPEN_ERROR;
}
/* Read the first page of data */
if (!wtap_read_bytes(wth->fh, nstrace_buf, page_size, err, err_info))
{
return WTAP_OPEN_ERROR;
}
/* reset the buffer offset */
nstrace->nstrace_buf_offset = 0;
}
wth->file_tsprec = WTAP_TSPREC_NSEC;
*err = 0;
/*
* Add an IDB; we don't know how many interfaces were
* involved, so we just say one interface, about which
* we only know the link-layer type, snapshot length,
* and time stamp resolution.
*/
wtap_add_generated_idb(wth);
return WTAP_OPEN_MINE;
}
Fix the test for a NetScaler trace file. When testing the signature field against a given version's signature: we require that the signature field's size (size, not C null-terminated string length) be at least the size of the signature string (otherwise, it can't possibly match); we check to make sure that the first N bytes of the signature field, where N is the size of the version's signature string (not including any terminating '\0' in that string), match the version's signature string. I.e., we require that the version's signature string is a prefix of the signature string in the file. This does not require that the signature string in the file be null-terminated. It also doesn't allow the file's signature string to be a substring of the version's signature string, as that's *NOT* sufficient to identify the file as a NetScaler trace file, especially if we forcibly null-terminate the file's signature string and we trucate it to be zero-length, as, in that case, it's *always* a prefix of the version's signature string, and the file is incorrectly identified as a NetScaler trace file. (While we're at it, we make the nspm_signature_isvXXX() routines return true if it *is* and false if it *isn't*, rather than the reverse; having a routine with a name containing "is", and not "isnt", return true if it *isn't* is confusing.) Change-Id: I3694773a71b8b63d280e42f146698c82a0f0c332 Ping-Bug: 15601 Reviewed-on: https://code.wireshark.org/review/32403 Reviewed-by: Guy Harris <guy@alum.mit.edu>
2019-03-14 10:12:07 +00:00
/*
** Generates a function that checks whether the specified signature
** field, with the specified size, matches the signature string for
** the version specified as an argument to the macro.
**
** The function does so by checking whether the signature string for
** the version in question is a prefix of the signature field. The
** signature field appears to be a blob of text, with one or more
** lines, with lines separated by '\n', and the last line terminated
** with '\0'. The first lign is the signature field; it may end with
** '\n', meaning there's another line following it, or it may end
** with '\0', meaning it's the last line.
Fix the test for a NetScaler trace file. When testing the signature field against a given version's signature: we require that the signature field's size (size, not C null-terminated string length) be at least the size of the signature string (otherwise, it can't possibly match); we check to make sure that the first N bytes of the signature field, where N is the size of the version's signature string (not including any terminating '\0' in that string), match the version's signature string. I.e., we require that the version's signature string is a prefix of the signature string in the file. This does not require that the signature string in the file be null-terminated. It also doesn't allow the file's signature string to be a substring of the version's signature string, as that's *NOT* sufficient to identify the file as a NetScaler trace file, especially if we forcibly null-terminate the file's signature string and we trucate it to be zero-length, as, in that case, it's *always* a prefix of the version's signature string, and the file is incorrectly identified as a NetScaler trace file. (While we're at it, we make the nspm_signature_isvXXX() routines return true if it *is* and false if it *isn't*, rather than the reverse; having a routine with a name containing "is", and not "isnt", return true if it *isn't* is confusing.) Change-Id: I3694773a71b8b63d280e42f146698c82a0f0c332 Ping-Bug: 15601 Reviewed-on: https://code.wireshark.org/review/32403 Reviewed-by: Guy Harris <guy@alum.mit.edu>
2019-03-14 10:12:07 +00:00
**
** For that to be true, the field must have a size >= to the size (not
** counting the terminating'\0') of the version's signature string,
** and the first N bytes of the field, where N is the length of the
** version string of the version (again, not counting the terminating
** '\0'), are equal to the version's signature string.
**
** XXX - should this do an exact match rather than a prefix match,
** checking whether either a '\n' or '\0' follows the first line?
Fix the test for a NetScaler trace file. When testing the signature field against a given version's signature: we require that the signature field's size (size, not C null-terminated string length) be at least the size of the signature string (otherwise, it can't possibly match); we check to make sure that the first N bytes of the signature field, where N is the size of the version's signature string (not including any terminating '\0' in that string), match the version's signature string. I.e., we require that the version's signature string is a prefix of the signature string in the file. This does not require that the signature string in the file be null-terminated. It also doesn't allow the file's signature string to be a substring of the version's signature string, as that's *NOT* sufficient to identify the file as a NetScaler trace file, especially if we forcibly null-terminate the file's signature string and we trucate it to be zero-length, as, in that case, it's *always* a prefix of the version's signature string, and the file is incorrectly identified as a NetScaler trace file. (While we're at it, we make the nspm_signature_isvXXX() routines return true if it *is* and false if it *isn't*, rather than the reverse; having a routine with a name containing "is", and not "isnt", return true if it *isn't* is confusing.) Change-Id: I3694773a71b8b63d280e42f146698c82a0f0c332 Ping-Bug: 15601 Reviewed-on: https://code.wireshark.org/review/32403 Reviewed-by: Guy Harris <guy@alum.mit.edu>
2019-03-14 10:12:07 +00:00
*/
#define nspm_signature_func(ver) \
Fix the test for a NetScaler trace file. When testing the signature field against a given version's signature: we require that the signature field's size (size, not C null-terminated string length) be at least the size of the signature string (otherwise, it can't possibly match); we check to make sure that the first N bytes of the signature field, where N is the size of the version's signature string (not including any terminating '\0' in that string), match the version's signature string. I.e., we require that the version's signature string is a prefix of the signature string in the file. This does not require that the signature string in the file be null-terminated. It also doesn't allow the file's signature string to be a substring of the version's signature string, as that's *NOT* sufficient to identify the file as a NetScaler trace file, especially if we forcibly null-terminate the file's signature string and we trucate it to be zero-length, as, in that case, it's *always* a prefix of the version's signature string, and the file is incorrectly identified as a NetScaler trace file. (While we're at it, we make the nspm_signature_isvXXX() routines return true if it *is* and false if it *isn't*, rather than the reverse; having a routine with a name containing "is", and not "isnt", return true if it *isn't* is confusing.) Change-Id: I3694773a71b8b63d280e42f146698c82a0f0c332 Ping-Bug: 15601 Reviewed-on: https://code.wireshark.org/review/32403 Reviewed-by: Guy Harris <guy@alum.mit.edu>
2019-03-14 10:12:07 +00:00
static guint32 nspm_signature_isv##ver(gchar *sigp, size_t sigsize) {\
size_t versiglen = sizeof(NSPR_SIGSTR_V##ver)-1;\
return sigsize >= versiglen && strncmp(sigp,NSPR_SIGSTR_V##ver,versiglen) == 0;\
}
nspm_signature_func(10)
nspm_signature_func(20)
nspm_signature_func(30)
nspm_signature_func(35)
/*
** Scan a page for something that looks like a signature record and,
** if we find one, check the signature against the ones we support.
** If we find one we support, return the file type/subtype for that
** file version. If we don't find a signature record with a signature
2021-02-18 00:37:04 +00:00
** we support, return NSPM_SIGNATURE_NOMATCH.
**
** We don't know what version the file is, so we can't make
** assumptions about the format of the records.
**
** XXX - can we assume the signature block is the first block?
*/
static int
nspm_signature_version(gchar *nstrace_buf, gint32 len)
{
gchar *dp = nstrace_buf;
for ( ; len > (gint32)(MIN(nspr_signature_v10_s, nspr_signature_v20_s)); dp++, len--)
{
#define sigv10p ((nspr_signature_v10_t*)dp)
/*
* If this is a V10 signature record, then:
*
* 1) we have a full signature record's worth of data in what
* remains of the first page;
*
* 2) it appears to have a record type of NSPR_SIGNATURE_V10;
*
* 3) the length field specifies a length that fits in what
* remains of the first page;
*
* 4) it also specifies something as large as, or larger than,
* the declared size of a V10 signature record.
*
* (XXX - are all V10 signature records that size, or might they
* be smaller, with a shorter signature field?)
*/
if ((size_t)len >= nspr_signature_v10_s &&
(pletoh16(&sigv10p->nsprRecordType) == NSPR_SIGNATURE_V10) &&
(pletoh16(&sigv10p->nsprRecordSize) <= len) &&
(pletoh16(&sigv10p->nsprRecordSize) >= nspr_signature_v10_s))
{
if ((nspm_signature_isv10(sigv10p->sig_Signature, sizeof sigv10p->sig_Signature)))
return NSPM_SIGNATURE_1_0;
}
#undef sigv10p
#define sigv20p ((nspr_signature_v20_t*)dp)
/*
* If this is a V20-or-later signature record, then:
*
* 1) we have a full signature record's worth of data in what
* remains of the first page;
*
* 2) it appears to have a record type of NSPR_SIGNATURE_V20;
*
* 3) the length field specifies a length that fits in what
* remains of the first page;
*
* 4) it also specifies something as large as, or larger than,
* the declared size of a V20 signature record.
*/
if ((size_t)len >= nspr_signature_v20_s &&
(sigv20p->sig_RecordType == NSPR_SIGNATURE_V20) &&
(sigv20p->sig_RecordSize <= len) &&
(sigv20p->sig_RecordSize >= nspr_signature_v20_s))
{
if (nspm_signature_isv20(sigv20p->sig_Signature, sizeof sigv20p->sig_Signature)){
return NSPM_SIGNATURE_2_0;
} else if (nspm_signature_isv30(sigv20p->sig_Signature, sizeof sigv20p->sig_Signature)){
return NSPM_SIGNATURE_3_0;
} else if (nspm_signature_isv35(sigv20p->sig_Signature, sizeof sigv20p->sig_Signature)){
return NSPM_SIGNATURE_3_5;
}
}
#undef sigv20p
}
return NSPM_SIGNATURE_NOMATCH; /* no version found */
}
#define nspr_getv10recordtype(hdp) (pletoh16(&(hdp)->nsprRecordType))
#define nspr_getv10recordsize(hdp) (pletoh16(&(hdp)->nsprRecordSize))
#define nspr_getv20recordtype(hdp) ((hdp)->phd_RecordType)
#define nspr_getv20recordsize(hdp) \
(guint32)(((hdp)->phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES)? \
(((hdp)->phd_RecordSizeHigh * NSPR_V20RECORDSIZE_2BYTES)+ \
((hdp)->phd_RecordSizeLow & ~NSPR_V20RECORDSIZE_2BYTES)) : \
(hdp)->phd_RecordSizeLow)
#define nstrace_set_start_time_ver(ver) \
gboolean nstrace_set_start_time_v##ver(wtap *wth, int *err, gchar **err_info) \
{\
nstrace_t *nstrace = (nstrace_t *)wth->priv;\
gchar* nstrace_buf = nstrace->pnstrace_buf;\
guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;\
guint32 nstrace_buflen = nstrace->nstrace_buflen;\
guint32 record_size;\
do\
{\
while (nstrace_buf_offset < nstrace_buflen)\
{\
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_hd_v##ver##_t), err, err_info))\
return FALSE;\
nspr_hd_v##ver##_t *fp = (nspr_hd_v##ver##_t *) &nstrace_buf[nstrace_buf_offset];\
switch (nspr_getv##ver##recordtype(fp))\
{\
case NSPR_ABSTIME_V##ver:\
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_abstime_v##ver##_t), err, err_info))\
return FALSE;\
ns_setabstime(nstrace, pletoh32(&((nspr_abstime_v##ver##_t *) fp)->abs_Time), pletoh16(&((nspr_abstime_v##ver##_t *) fp)->abs_RelTime));\
nstrace->nstrace_buf_offset = nstrace_buf_offset + nspr_getv##ver##recordsize(fp);\
nstrace->nstrace_buflen = nstrace_buflen;\
return TRUE;\
case NSPR_UNUSEDSPACE_V10:\
nstrace_buf_offset = nstrace_buflen;\
break;\
default:\
record_size = nspr_getv##ver##recordsize(fp);\
if (record_size == 0) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: zero size record found");\
return FALSE;\
}\
nstrace_buf_offset += record_size;\
}\
}\
nstrace_buf_offset = 0;\
nstrace->xxx_offset += nstrace_buflen;\
nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));\
}while((nstrace_buflen > 0) && (nstrace_read_buf(wth->fh, nstrace_buf, nstrace_buflen, err, err_info)));\
return FALSE;\
}
nstrace_set_start_time_ver(10)
nstrace_set_start_time_ver(20)
#undef nspr_getv10recordtype
#undef nspr_getv20recordtype
/*
** Set the start time of the trace file. We look for the first ABSTIME record. We use that
** to set the start time. Apart from that we also make sure that we remember the position of
** the next record after the ABSTIME record. Inorder to report correct time values, all trace
** records before the ABSTIME record are ignored.
*/
static gboolean nstrace_set_start_time(wtap *wth, int file_version, int *err,
gchar **err_info)
{
if (file_version == NSPM_SIGNATURE_1_0)
return nstrace_set_start_time_v10(wth, err, err_info);
else if (file_version == NSPM_SIGNATURE_2_0)
return nstrace_set_start_time_v20(wth, err, err_info);
else if (file_version == NSPM_SIGNATURE_3_0)
return nstrace_set_start_time_v20(wth, err, err_info);
return FALSE;
}
#define __TNDO(rec,enumprefix,structname,hdrname)\
(rec)->rec_header.packet_header.pseudo_header.nstr.hdrname##_offset = enumprefix##_##hdrname##_offset;
#define __TNO(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
(rec)->rec_header.packet_header.pseudo_header.nstr.hdrname##_offset = enumprefix##_##hdrname##_offset;
#define __TNL(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
(rec)->rec_header.packet_header.pseudo_header.nstr.hdrname##_len = enumprefix##_##hdrname##_len;
#define __TNV1O(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
__TNO(rec,enumprefix,structprefix,structname,hdrname,structfieldname)
#define __TNV1L(rec,enumprefix,structprefix,structname,hdrname,structfieldname) \
__TNL(rec,enumprefix,structprefix,structname,hdrname,structfieldname)
/*
** Netscaler trace format read routines.
**
** The maximum value of the record data size is 65535, which is less than
** WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
*/
#define TIMEDEFV10(rec,fp,type) \
do {\
(rec)->presence_flags = WTAP_HAS_TS;\
nsg_creltime += ns_hrtime2nsec(pletoh32(&type->type##_RelTimeHr));\
(rec)->ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
(rec)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
}while(0)
#define PARTSIZEDEFV10(rec,pp,ver) \
do {\
(rec)->presence_flags |= WTAP_HAS_CAP_LEN;\
(rec)->rec_header.packet_header.len = pletoh16(&pp->pp_PktSizeOrg) + nspr_pktracepart_v##ver##_s;\
(rec)->rec_header.packet_header.caplen = pletoh16(&pp->nsprRecordSize);\
}while(0)
#define FULLSIZEDEFV10(rec,fp,ver) \
do {\
(rec)->rec_header.packet_header.len = pletoh16(&(fp)->nsprRecordSize);\
(rec)->rec_header.packet_header.caplen = (rec)->rec_header.packet_header.len;\
}while(0)
#define PACKET_DESCRIBE(rec,buf,FULLPART,fullpart,ver,type,HEADERVER) \
do {\
nspr_pktrace##fullpart##_v##ver##_t *type = (nspr_pktrace##fullpart##_v##ver##_t *) &nstrace_buf[nstrace_buf_offset];\
/* Make sure the record header is entirely contained in the page */\
if ((nstrace_buflen - nstrace_buf_offset) < sizeof *type) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record header crosses page boundary");\
return FALSE;\
}\
/* Check sanity of record size */\
if (pletoh16(&type->nsprRecordSize) < sizeof *type) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record size is less than record header size");\
return FALSE;\
}\
(rec)->rec_type = REC_TYPE_PACKET;\
(rec)->block = wtap_block_create(WTAP_BLOCK_PACKET);\
TIMEDEFV##ver((rec),fp,type);\
FULLPART##SIZEDEFV##ver((rec),type,ver);\
TRACE_V##ver##_REC_LEN_OFF((rec),v##ver##_##fullpart,type,pktrace##fullpart##_v##ver);\
/* Make sure the record is entirely contained in the page */\
if ((nstrace_buflen - nstrace_buf_offset) < (rec)->rec_header.packet_header.caplen) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record crosses page boundary");\
return FALSE;\
}\
ws_buffer_assure_space((buf), (rec)->rec_header.packet_header.caplen);\
memcpy(ws_buffer_start_ptr((buf)), type, (rec)->rec_header.packet_header.caplen);\
*data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
nstrace->nstrace_buf_offset = nstrace_buf_offset + (rec)->rec_header.packet_header.caplen;\
nstrace->nstrace_buflen = nstrace_buflen;\
nstrace->nsg_creltime = nsg_creltime;\
return TRUE;\
}while(0)
static gboolean nstrace_read_v10(wtap *wth, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info, gint64 *data_offset)
{
nstrace_t *nstrace = (nstrace_t *)wth->priv;
guint64 nsg_creltime = nstrace->nsg_creltime;
gchar *nstrace_buf = nstrace->pnstrace_buf;
guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
guint32 nstrace_buflen = nstrace->nstrace_buflen;
*err = 0;
*err_info = NULL;
do
{
while ((nstrace_buf_offset < nstrace_buflen) &&
((nstrace_buflen - nstrace_buf_offset) >= ((gint32)sizeof((( nspr_header_v10_t*)&nstrace_buf[nstrace_buf_offset])->ph_RecordType))))
{
#define GENERATE_CASE_FULL(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
PACKET_DESCRIBE(rec,buf,FULL,full,ver,fp,HEADERVER);
#define GENERATE_CASE_PART(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEPARTTX_V##ver:\
case NSPR_PDPKTRACEPARTTXB_V##ver:\
case NSPR_PDPKTRACEPARTRX_V##ver:\
PACKET_DESCRIBE(rec,buf,PART,part,ver,pp,HEADERVER);
switch (pletoh16(&(( nspr_header_v10_t*)&nstrace_buf[nstrace_buf_offset])->ph_RecordType))
{
GENERATE_CASE_FULL(rec,buf,10,100)
GENERATE_CASE_PART(rec,buf,10,100)
#undef GENERATE_CASE_FULL
#undef GENERATE_CASE_PART
case NSPR_ABSTIME_V10:
{
nspr_pktracefull_v10_t *fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
if (pletoh16(&fp->nsprRecordSize) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
return FALSE;
}
ns_setabstime(nstrace, pletoh32(((nspr_abstime_v10_t *) fp)->abs_Time), pletoh32(&((nspr_abstime_v10_t *) fp)->abs_RelTime));
nstrace_buf_offset += pletoh16(&fp->nsprRecordSize);
break;
}
case NSPR_RELTIME_V10:
{
nspr_pktracefull_v10_t *fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
if (pletoh16(&fp->nsprRecordSize) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
return FALSE;
}
ns_setrelativetime(nstrace, pletoh32(((nspr_abstime_v10_t *) fp)->abs_RelTime));
nstrace_buf_offset += pletoh16(&fp->nsprRecordSize);
break;
}
case NSPR_UNUSEDSPACE_V10:
nstrace_buf_offset = nstrace_buflen;
break;
default:
{
nspr_pktracefull_v10_t *fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
if (pletoh16(&fp->nsprRecordSize) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
return FALSE;
}
nstrace_buf_offset += pletoh16(&fp->nsprRecordSize);
break;
}
}
}
nstrace_buf_offset = 0;
nstrace->xxx_offset += nstrace_buflen;
nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));
}while((nstrace_buflen > 0) && (nstrace_read_buf(wth->fh, nstrace_buf, nstrace_buflen, err, err_info)));
return FALSE;
}
#undef PACKET_DESCRIBE
#define TIMEDEFV20(rec,fp,type) \
do {\
(rec)->presence_flags = WTAP_HAS_TS;\
nsg_creltime += ns_hrtime2nsec(pletoh32(fp->type##_RelTimeHr));\
(rec)->ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
(rec)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
}while(0)
#define TIMEDEFV23(rec,fp,type) \
do {\
(rec)->presence_flags = WTAP_HAS_TS;\
/* access _AbsTimeHr as a 64bit value */\
nsg_creltime = pletoh64(fp->type##_AbsTimeHr);\
(rec)->ts.secs = (guint32) (nsg_creltime / 1000000000);\
(rec)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
}while(0)
#define TIMEDEFV21(rec,fp,type) TIMEDEFV20(rec,fp,type)
#define TIMEDEFV22(rec,fp,type) TIMEDEFV20(rec,fp,type)
#define TIMEDEFV24(rec,fp,type) TIMEDEFV23(rec,fp,type)
#define TIMEDEFV25(rec,fp,type) TIMEDEFV24(rec,fp,type)
#define TIMEDEFV26(rec,fp,type) TIMEDEFV24(rec,fp,type)
/*
** The maximum value of the record data size is 65535, which is less than
** WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
*/
#define PARTSIZEDEFV20(rec,pp,ver) \
do {\
(rec)->presence_flags |= WTAP_HAS_CAP_LEN;\
(rec)->rec_header.packet_header.len = pletoh16(&pp->pp_PktSizeOrg) + nspr_pktracepart_v##ver##_s;\
(rec)->rec_header.packet_header.caplen = nspr_getv20recordsize((nspr_hd_v20_t *)pp);\
}while(0)
#define PARTSIZEDEFV21(rec,pp,ver) PARTSIZEDEFV20(rec,pp,ver)
#define PARTSIZEDEFV22(rec,pp,ver) PARTSIZEDEFV20(rec,pp,ver)
#define PARTSIZEDEFV23(rec,pp,ver) PARTSIZEDEFV20(rec,pp,ver)
#define PARTSIZEDEFV24(rec,pp,ver) PARTSIZEDEFV20(rec,pp,ver)
#define PARTSIZEDEFV25(rec,pp,ver) PARTSIZEDEFV20(rec,pp,ver)
#define PARTSIZEDEFV26(rec,pp,ver) PARTSIZEDEFV20(rec,pp,ver)
#define FULLSIZEDEFV20(rec,fp,ver)\
do {\
(rec)->rec_header.packet_header.len = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
(rec)->rec_header.packet_header.caplen = (rec)->rec_header.packet_header.len;\
}while(0)
#define FULLSIZEDEFV21(rec,fp,ver) FULLSIZEDEFV20(rec,fp,ver)
#define FULLSIZEDEFV22(rec,fp,ver) FULLSIZEDEFV20(rec,fp,ver)
#define FULLSIZEDEFV23(rec,fp,ver) FULLSIZEDEFV20(rec,fp,ver)
#define FULLSIZEDEFV24(rec,fp,ver) FULLSIZEDEFV20(rec,fp,ver)
#define FULLSIZEDEFV25(rec,fp,ver) FULLSIZEDEFV20(rec,fp,ver)
#define FULLSIZEDEFV26(rec,fp,ver) FULLSIZEDEFV20(rec,fp,ver)
#define PACKET_DESCRIBE(rec,buf,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
do {\
nspr_##structname##_t *fp= (nspr_##structname##_t*)&nstrace_buf[nstrace_buf_offset];\
/* Make sure the record header is entirely contained in the page */\
if ((nstrace_buflen - nstrace_buf_offset) < sizeof *fp) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record header crosses page boundary");\
return FALSE;\
}\
/* Check sanity of record size */\
if (nspr_getv20recordsize((nspr_hd_v20_t *)fp) < sizeof *fp) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record size is less than record header size");\
return FALSE;\
}\
(rec)->rec_type = REC_TYPE_PACKET;\
(rec)->block = wtap_block_create(WTAP_BLOCK_PACKET);\
TIMEDEFV##ver((rec),fp,type);\
FULLPART##SIZEDEFV##ver((rec),fp,ver);\
TRACE_V##ver##_REC_LEN_OFF((rec),enumprefix,type,structname);\
(rec)->rec_header.packet_header.pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
/* Make sure the record is entirely contained in the page */\
if ((nstrace_buflen - nstrace_buf_offset) < (rec)->rec_header.packet_header.caplen) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record crosses page boundary");\
return FALSE;\
}\
ws_buffer_assure_space((buf), (rec)->rec_header.packet_header.caplen);\
memcpy(ws_buffer_start_ptr((buf)), fp, (rec)->rec_header.packet_header.caplen);\
*data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
nstrace->nstrace_buf_offset = nstrace_buf_offset + nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
nstrace->nstrace_buflen = nstrace_buflen;\
nstrace->nsg_creltime = nsg_creltime;\
return TRUE;\
}while(0)
static gboolean nstrace_read_v20(wtap *wth, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info, gint64 *data_offset)
{
nstrace_t *nstrace = (nstrace_t *)wth->priv;
guint64 nsg_creltime = nstrace->nsg_creltime;
gchar *nstrace_buf = nstrace->pnstrace_buf;
guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
guint32 nstrace_buflen = nstrace->nstrace_buflen;
*err = 0;
*err_info = NULL;
do
{
while ((nstrace_buf_offset < nstrace_buflen) &&
((nstrace_buflen - nstrace_buf_offset) >= ((gint32)sizeof((( nspr_hd_v20_t*)&nstrace_buf[nstrace_buf_offset])->phd_RecordType))))
{
switch ((( nspr_hd_v20_t*)&nstrace_buf[nstrace_buf_offset])->phd_RecordType)
{
#define GENERATE_CASE_FULL(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
PACKET_DESCRIBE(rec,buf,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
#define GENERATE_CASE_FULL_V25(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
PACKET_DESCRIBE(rec,buf,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
#define GENERATE_CASE_PART(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEPARTTX_V##ver:\
case NSPR_PDPKTRACEPARTTXB_V##ver:\
case NSPR_PDPKTRACEPARTRX_V##ver:\
PACKET_DESCRIBE(rec,buf,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
#define GENERATE_CASE_PART_V25(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEPARTTX_V##ver:\
case NSPR_PDPKTRACEPARTTXB_V##ver:\
case NSPR_PDPKTRACEPARTRX_V##ver:\
case NSPR_PDPKTRACEPARTNEWRX_V##ver:\
PACKET_DESCRIBE(rec,buf,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
GENERATE_CASE_FULL(rec,buf,20,200);
GENERATE_CASE_PART(rec,buf,20,200);
GENERATE_CASE_FULL(rec,buf,21,201);
GENERATE_CASE_PART(rec,buf,21,201);
GENERATE_CASE_FULL(rec,buf,22,202);
GENERATE_CASE_PART(rec,buf,22,202);
GENERATE_CASE_FULL(rec,buf,23,203);
GENERATE_CASE_PART(rec,buf,23,203);
GENERATE_CASE_FULL_V25(rec,buf,24,204);
GENERATE_CASE_PART_V25(rec,buf,24,204);
GENERATE_CASE_FULL_V25(rec,buf,25,205);
GENERATE_CASE_PART_V25(rec,buf,25,205);
GENERATE_CASE_FULL_V25(rec,buf,26,206);
GENERATE_CASE_PART_V25(rec,buf,26,206);
#undef GENERATE_CASE_FULL
#undef GENERATE_CASE_FULL_V25
#undef GENERATE_CASE_PART
#undef GENERATE_CASE_PART_V25
case NSPR_ABSTIME_V20:
{
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_pktracefull_v20_t), err, err_info))
return FALSE;
nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
if (nspr_getv20recordsize((nspr_hd_v20_t *)fp20) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
return FALSE;
}
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_hd_v20_t), err, err_info))
return FALSE;
nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_abstime_v20_t), err, err_info))
return FALSE;
ns_setabstime(nstrace, pletoh32(&((nspr_abstime_v20_t *) fp20)->abs_Time), pletoh16(&((nspr_abstime_v20_t *) fp20)->abs_RelTime));
break;
}
case NSPR_RELTIME_V20:
{
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_pktracefull_v20_t), err, err_info))
return FALSE;
nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
if (nspr_getv20recordsize((nspr_hd_v20_t *)fp20) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
return FALSE;
}
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_abstime_v20_t), err, err_info))
return FALSE;
ns_setrelativetime(nstrace, pletoh16(&((nspr_abstime_v20_t *) fp20)->abs_RelTime));
nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
break;
}
case NSPR_UNUSEDSPACE_V20:
{
if (nstrace_buf_offset >= NSPR_PAGESIZE/2)
nstrace_buf_offset = nstrace_buflen;
else
nstrace_buf_offset = NSPR_PAGESIZE/2;
break;
}
default:
{
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_pktracefull_v20_t), err, err_info))
return FALSE;
nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
if (nspr_getv20recordsize((nspr_hd_v20_t *)fp20) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
return FALSE;
}
nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
break;
}
}
}
nstrace_buf_offset = 0;
nstrace->xxx_offset += nstrace_buflen;
nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));
}while((nstrace_buflen > 0) && (nstrace_read_buf(wth->fh, nstrace_buf, nstrace_buflen, err, err_info)));
return FALSE;
}
#undef PACKET_DESCRIBE
#define SETETHOFFSET_35(rec)\
(rec)->rec_header.packet_header.pseudo_header.nstr.eth_offset = pletoh16(&fp->fp_headerlen);\
#define SETETHOFFSET_30(rec) ;\
#define TIMEDEFV30(rec,fp,type) \
do {\
(rec)->presence_flags = WTAP_HAS_TS;\
/* access _AbsTimeHr as a 64bit value */\
nsg_creltime = pletoh64(fp->type##_AbsTimeHr);\
(rec)->ts.secs = (guint32) (nsg_creltime / 1000000000);\
(rec)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
}while(0)
#define TIMEDEFV35 TIMEDEFV30
/*
** The maximum value of the record data size is 65535, which is less than
** WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
*/
#define FULLSIZEDEFV30(rec,fp,ver)\
do {\
(rec)->presence_flags |= WTAP_HAS_CAP_LEN;\
(rec)->rec_header.packet_header.len = pletoh16(&fp->fp_PktSizeOrg) + nspr_pktracefull_v##ver##_s + fp->fp_src_vmname_len + fp->fp_dst_vmname_len;\
(rec)->rec_header.packet_header.caplen = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
}while(0)
#define FULLSIZEDEFV35(rec,fp,ver)\
do {\
(rec)->presence_flags |= WTAP_HAS_CAP_LEN;\
(rec)->rec_header.packet_header.len = pletoh16(&fp->fp_PktSizeOrg) + pletoh16(&fp->fp_headerlen);\
(rec)->rec_header.packet_header.caplen = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
}while(0)
#define PACKET_DESCRIBE(rec,buf,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
do {\
nspr_##structname##_t *fp = (nspr_##structname##_t *) &nstrace_buf[nstrace_buf_offset];\
/* Make sure the record header is entirely contained in the page */\
if ((nstrace->nstrace_buflen - nstrace_buf_offset) < sizeof *fp) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record header crosses page boundary");\
g_free(nstrace_tmpbuff);\
return FALSE;\
}\
(rec)->rec_type = REC_TYPE_PACKET;\
(rec)->block = wtap_block_create(WTAP_BLOCK_PACKET);\
TIMEDEFV##ver((rec),fp,type);\
FULLPART##SIZEDEFV##ver((rec),fp,ver);\
TRACE_V##ver##_REC_LEN_OFF((rec),enumprefix,type,structname);\
SETETHOFFSET_##ver(rec)\
(rec)->rec_header.packet_header.pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
/* Check sanity of record size */\
if ((rec)->rec_header.packet_header.caplen < sizeof *fp) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: record size is less than record header size");\
g_free(nstrace_tmpbuff);\
return FALSE;\
}\
ws_buffer_assure_space((buf), (rec)->rec_header.packet_header.caplen);\
*data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
/* Copy record header */\
while (nstrace_tmpbuff_off < nspr_##structname##_s) {\
if (nstrace_buf_offset >= nstrace_buflen) {\
*err = WTAP_ERR_BAD_FILE;\
*err_info = g_strdup("nstrace: malformed file");\
g_free(nstrace_tmpbuff);\
return FALSE;\
}\
nstrace_tmpbuff[nstrace_tmpbuff_off++] = nstrace_buf[nstrace_buf_offset++];\
}\
nst_dataSize = nspr_getv20recordsize(hdp);\
rec_size = nst_dataSize - nstrace_tmpbuff_off;\
nsg_nextPageOffset = ((nstrace_buf_offset + rec_size) >= (guint)nstrace->nstrace_buflen) ?\
((nstrace_buf_offset + rec_size) - (NSPR_PAGESIZE_TRACE - 1)) : 0;\
/* Copy record data */\
while (nsg_nextPageOffset) {\
/* Copy everything from this page */\
while (nstrace_buf_offset < nstrace->nstrace_buflen) {\
nstrace_tmpbuff[nstrace_tmpbuff_off++] = nstrace_buf[nstrace_buf_offset++];\
}\
nstrace->xxx_offset += nstrace_buflen;\
nstrace_buflen = NSPR_PAGESIZE_TRACE;\
/* Read the next page */\
bytes_read = file_read(nstrace_buf, NSPR_PAGESIZE_TRACE, wth->fh);\
if ( !file_eof(wth->fh) && bytes_read != NSPR_PAGESIZE_TRACE) {\
g_free(nstrace_tmpbuff);\
return FALSE;\
} else {\
nstrace_buf_offset = 0;\
}\
nstrace_buflen = bytes_read;\
rec_size = nst_dataSize - nstrace_tmpbuff_off;\
nsg_nextPageOffset = ((nstrace_buf_offset + rec_size) >= (guint)nstrace->nstrace_buflen) ?\
((nstrace_buf_offset + rec_size) - (NSPR_PAGESIZE_TRACE- 1)): 0;\
} \
/* Copy the rest of the record */\
while (nstrace_tmpbuff_off < nst_dataSize) {\
nstrace_tmpbuff[nstrace_tmpbuff_off++] = nstrace_buf[nstrace_buf_offset++];\
}\
memcpy(ws_buffer_start_ptr((buf)), nstrace_tmpbuff, (rec)->rec_header.packet_header.caplen);\
nstrace->nstrace_buf_offset = nstrace_buf_offset;\
nstrace->nstrace_buflen = nstrace_buflen;\
nstrace->nsg_creltime = nsg_creltime;\
g_free(nstrace_tmpbuff);\
return TRUE;\
} while(0)
static gboolean nstrace_read_v30(wtap *wth, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info, gint64 *data_offset)
{
nstrace_t *nstrace = (nstrace_t *)wth->priv;
guint64 nsg_creltime;
gchar *nstrace_buf = nstrace->pnstrace_buf;
guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
guint32 nstrace_buflen = nstrace->nstrace_buflen;
guint8* nstrace_tmpbuff;
guint32 nstrace_tmpbuff_off=0,nst_dataSize=0,rec_size=0,nsg_nextPageOffset=0;
nspr_hd_v20_t *hdp;
int bytes_read = 0;
*err = 0;
*err_info = NULL;
if(nstrace_buflen == 0){
return FALSE; /* Reached End Of File */
}
nstrace_tmpbuff = (guint8*)g_malloc(65536);
do
{
if (nstrace_buf_offset >= nstrace_buflen) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: malformed file");
g_free(nstrace_tmpbuff);
return FALSE;
}
if (!nstrace_buf[nstrace_buf_offset] && nstrace_buf_offset <= NSPR_PAGESIZE_TRACE){
nstrace_buf_offset = NSPR_PAGESIZE_TRACE;
}
if (file_eof(wth->fh) && bytes_read > 0 && bytes_read < NSPR_PAGESIZE_TRACE){
memset(&nstrace_buf[bytes_read], 0, NSPR_PAGESIZE_TRACE-bytes_read);
}
while ((nstrace_buf_offset < NSPR_PAGESIZE_TRACE) &&
nstrace_buf[nstrace_buf_offset])
{
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_hd_v20_t), err, err_info)) {
g_free(nstrace_tmpbuff);
return FALSE;
}
hdp = (nspr_hd_v20_t *) &nstrace_buf[nstrace_buf_offset];
if (nspr_getv20recordsize(hdp) == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("nstrace: zero size record found");
g_free(nstrace_tmpbuff);
return FALSE;
}
switch (hdp->phd_RecordType)
{
#define GENERATE_CASE_FULL_V30(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
PACKET_DESCRIBE(rec,buf,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
GENERATE_CASE_FULL_V30(rec,buf,30,300);
#undef GENERATE_CASE_FULL_V30
#define GENERATE_CASE_FULL_V35(rec,buf,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
PACKET_DESCRIBE(rec,buf,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
GENERATE_CASE_FULL_V35(rec,buf,35,350);
#undef GENERATE_CASE_FULL_V35
case NSPR_ABSTIME_V20:
{
nstrace_buf_offset += nspr_getv20recordsize(hdp);
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_abstime_v20_t), err, err_info)) {
g_free(nstrace_tmpbuff);
return FALSE;
}
ns_setabstime(nstrace, pletoh32(&((nspr_abstime_v20_t *) &nstrace_buf[nstrace_buf_offset])->abs_Time), pletoh16(&((nspr_abstime_v20_t *) &nstrace_buf[nstrace_buf_offset])->abs_RelTime));
break;
}
case NSPR_RELTIME_V20:
{
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_abstime_v20_t), err, err_info)) {
g_free(nstrace_tmpbuff);
return FALSE;
}
ns_setrelativetime(nstrace, pletoh16(&((nspr_abstime_v20_t *) &nstrace_buf[nstrace_buf_offset])->abs_RelTime));
nstrace_buf_offset += nspr_getv20recordsize(hdp);
break;
}
default:
{
if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_hd_v20_t), err, err_info)) {
g_free(nstrace_tmpbuff);
return FALSE;
}
nstrace_buf_offset += nspr_getv20recordsize(hdp);
break;
}
}
}
nstrace_buf_offset = 0;
nstrace->xxx_offset += nstrace_buflen;
nstrace_buflen = NSPR_PAGESIZE_TRACE;
} while((nstrace_buflen > 0) && (bytes_read = file_read(nstrace_buf, nstrace_buflen, wth->fh)) > 0 && (file_eof(wth->fh) || (guint32)bytes_read == nstrace_buflen));
if (bytes_read < 0)
*err = file_error(wth->fh, err_info);
else
*err = 0;
g_free(nstrace_tmpbuff);
return FALSE;
}
#undef PACKET_DESCRIBE
/*
* XXX - for these, we can't set the time stamp in the seek-read
* routine, because the time stamps are relative.
*/
#undef TIMEDEFV10
#define TIMEDEFV10(rec,fp,type) \
do {\
(rec)->presence_flags = 0;\
}while(0)
#define PACKET_DESCRIBE(rec,FULLPART,fullpart,ver,type,HEADERVER) \
do {\
nspr_pktrace##fullpart##_v##ver##_t *type = (nspr_pktrace##fullpart##_v##ver##_t *) pd;\
(rec)->rec_type = REC_TYPE_PACKET;\
(rec)->block = wtap_block_create(WTAP_BLOCK_PACKET);\
TIMEDEFV##ver((rec),fp,type);\
FULLPART##SIZEDEFV##ver((rec),type,ver);\
TRACE_V##ver##_REC_LEN_OFF(rec,v##ver##_##fullpart,type,pktrace##fullpart##_v##ver);\
(rec)->rec_header.packet_header.pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
}while(0)
static gboolean nstrace_seek_read_v10(wtap *wth, gint64 seek_off,
wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
{
nspr_hd_v10_t hdr;
guint record_length;
guint8 *pd;
unsigned int bytes_to_read;
*err = 0;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
/*
** Read the record header.
*/
if (!wtap_read_bytes(wth->random_fh, (void *)&hdr, sizeof hdr,
err, err_info))
return FALSE;
/*
** Get the record length.
*/
record_length = nspr_getv10recordsize(&hdr);
/*
** Copy the header to the buffer and read the rest of the record..
*/
ws_buffer_assure_space(buf, record_length);
pd = ws_buffer_start_ptr(buf);
memcpy(pd, (void *)&hdr, sizeof hdr);
if (record_length > sizeof hdr) {
bytes_to_read = (unsigned int)(record_length - sizeof hdr);
if (!wtap_read_bytes(wth->random_fh, pd + sizeof hdr, bytes_to_read,
err, err_info))
return FALSE;
}
/*
** Fill in what part of the struct wtap_rec we can.
*/
#define GENERATE_CASE_FULL(rec,type,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##type:\
case NSPR_PDPKTRACEFULLTXB_V##type:\
case NSPR_PDPKTRACEFULLRX_V##type:\
PACKET_DESCRIBE(rec,FULL,full,type,fp,HEADERVER);\
break;
#define GENERATE_CASE_PART(rec,type,HEADERVER) \
case NSPR_PDPKTRACEPARTTX_V##type:\
case NSPR_PDPKTRACEPARTTXB_V##type:\
case NSPR_PDPKTRACEPARTRX_V##type:\
PACKET_DESCRIBE(rec,PART,part,type,pp,HEADERVER);\
break;
switch (pletoh16(&(( nspr_header_v10_t*)pd)->ph_RecordType))
{
GENERATE_CASE_FULL(rec,10,100)
GENERATE_CASE_PART(rec,10,100)
}
#undef GENERATE_CASE_FULL
#undef GENERATE_CASE_PART
return TRUE;
}
#undef PACKET_DESCRIBE
/*
* XXX - for these, we can't set the time stamp in the seek-read
* routine, because the time stamps are relative.
*/
#undef TIMEDEFV20
#define TIMEDEFV20(rec,fp,type) \
do {\
(rec)->presence_flags = 0;\
}while(0)
#undef TIMEDEFV21
#undef TIMEDEFV22
#define TIMEDEFV21(rec,fp,type) TIMEDEFV20(rec,fp,type)
#define TIMEDEFV22(rec,fp,type) TIMEDEFV20(rec,fp,type)
#define PACKET_DESCRIBE(rec,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
do {\
nspr_##structname##_t *fp= (nspr_##structname##_t*)pd;\
(rec)->rec_type = REC_TYPE_PACKET;\
(rec)->block = wtap_block_create(WTAP_BLOCK_PACKET);\
TIMEDEFV##ver((rec),fp,type);\
FULLPART##SIZEDEFV##ver((rec),fp,ver);\
TRACE_V##ver##_REC_LEN_OFF((rec),enumprefix,type,structname);\
(rec)->rec_header.packet_header.pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
return TRUE;\
}while(0)
static gboolean nstrace_seek_read_v20(wtap *wth, gint64 seek_off,
wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
{
nspr_hd_v20_t hdr;
guint record_length;
guint hdrlen;
guint8 *pd;
unsigned int bytes_to_read;
guint64 nsg_creltime;
*err = 0;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
/*
** Read the first 2 bytes of the record header.
*/
if (!wtap_read_bytes(wth->random_fh, (void *)&hdr, 2, err, err_info))
return FALSE;
hdrlen = 2;
/*
** Is there a third byte? If so, read it.
*/
if (hdr.phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES) {
if (!wtap_read_bytes(wth->random_fh, (void *)&hdr.phd_RecordSizeHigh, 1,
err, err_info))
return FALSE;
hdrlen = 3;
}
/*
** Get the record length.
*/
record_length = nspr_getv20recordsize(&hdr);
/*
** Copy the header to the buffer and read the rest of the record..
*/
ws_buffer_assure_space(buf, record_length);
pd = ws_buffer_start_ptr(buf);
memcpy(pd, (void *)&hdr, hdrlen);
if (record_length > hdrlen) {
bytes_to_read = (unsigned int)(record_length - hdrlen);
if (!wtap_read_bytes(wth->random_fh, pd + hdrlen, bytes_to_read,
err, err_info))
return FALSE;
}
#define GENERATE_CASE_FULL(rec,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
PACKET_DESCRIBE(rec,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
#define GENERATE_CASE_FULL_V25(rec,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
PACKET_DESCRIBE(rec,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
#define GENERATE_CASE_PART(rec,ver,HEADERVER) \
case NSPR_PDPKTRACEPARTTX_V##ver:\
case NSPR_PDPKTRACEPARTTXB_V##ver:\
case NSPR_PDPKTRACEPARTRX_V##ver:\
PACKET_DESCRIBE(rec,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
#define GENERATE_CASE_PART_V25(rec,ver,HEADERVER) \
case NSPR_PDPKTRACEPARTTX_V##ver:\
case NSPR_PDPKTRACEPARTTXB_V##ver:\
case NSPR_PDPKTRACEPARTRX_V##ver:\
case NSPR_PDPKTRACEPARTNEWRX_V##ver:\
PACKET_DESCRIBE(rec,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
switch ((( nspr_hd_v20_t*)pd)->phd_RecordType)
{
GENERATE_CASE_FULL(rec,20,200)
GENERATE_CASE_PART(rec,20,200)
GENERATE_CASE_FULL(rec,21,201)
GENERATE_CASE_PART(rec,21,201)
GENERATE_CASE_FULL(rec,22,202)
GENERATE_CASE_PART(rec,22,202)
GENERATE_CASE_FULL(rec,23,203)
GENERATE_CASE_PART(rec,23,203)
GENERATE_CASE_FULL_V25(rec,24,204)
GENERATE_CASE_PART_V25(rec,24,204)
GENERATE_CASE_FULL_V25(rec,25,205)
GENERATE_CASE_PART_V25(rec,25,205)
GENERATE_CASE_FULL_V25(rec,26,206)
GENERATE_CASE_PART_V25(rec,26,206)
}
#undef GENERATE_CASE_FULL
#undef GENERATE_CASE_FULL_V25
#undef GENERATE_CASE_PART
#undef GENERATE_CASE_PART_V25
return TRUE;
}
#undef PACKET_DESCRIBE
#undef SETETHOFFSET_35
#undef SETETHOFFSET_30
#define SETETHOFFSET_35(rec)\
{\
(rec)->rec_header.packet_header.pseudo_header.nstr.eth_offset = pletoh16(&fp->fp_headerlen);\
}
#define SETETHOFFSET_30(rec) ;\
#define PACKET_DESCRIBE(rec,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
do {\
nspr_##structname##_t *fp= (nspr_##structname##_t*)pd;\
(rec)->rec_type = REC_TYPE_PACKET;\
(rec)->block = wtap_block_create(WTAP_BLOCK_PACKET);\
TIMEDEFV##ver((rec),fp,type);\
SETETHOFFSET_##ver(rec);\
FULLPART##SIZEDEFV##ver((rec),fp,ver);\
TRACE_V##ver##_REC_LEN_OFF((rec),enumprefix,type,structname);\
(rec)->rec_header.packet_header.pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
return TRUE;\
}while(0)
static gboolean nstrace_seek_read_v30(wtap *wth, gint64 seek_off,
wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
{
nspr_hd_v20_t hdr;
guint record_length;
guint hdrlen;
guint8 *pd;
unsigned int bytes_to_read;
guint64 nsg_creltime;
*err = 0;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
/*
** Read the first 2 bytes of the record header.
*/
if (!wtap_read_bytes(wth->random_fh, (void *)&hdr, 2, err, err_info))
return FALSE;
hdrlen = 2;
/*
** Is there a third byte? If so, read it.
*/
if (hdr.phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES) {
if (!wtap_read_bytes(wth->random_fh, (void *)&hdr.phd_RecordSizeHigh, 1,
err, err_info))
return FALSE;
hdrlen = 3;
}
/*
** Get the record length.
** The maximum value of the record data size is 65535, which is less
** than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
*/
record_length = nspr_getv20recordsize(&hdr);
/*
** Copy the header to the buffer and read the rest of the record..
*/
ws_buffer_assure_space(buf, record_length);
pd = ws_buffer_start_ptr(buf);
memcpy(pd, (void *)&hdr, hdrlen);
if (record_length > hdrlen) {
bytes_to_read = (unsigned int)(record_length - hdrlen);
if (!wtap_read_bytes(wth->random_fh, pd + hdrlen, bytes_to_read,
err, err_info))
return FALSE;
}
(rec)->rec_header.packet_header.caplen = (rec)->rec_header.packet_header.len = record_length;
#define GENERATE_CASE_V30(rec,ver,HEADERVER) \
case NSPR_PDPKTRACEFULLTX_V##ver:\
case NSPR_PDPKTRACEFULLTXB_V##ver:\
case NSPR_PDPKTRACEFULLRX_V##ver:\
case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
PACKET_DESCRIBE(rec,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
switch ((( nspr_hd_v20_t*)pd)->phd_RecordType)
{
GENERATE_CASE_V30(rec,30, 300);
GENERATE_CASE_V30(rec,35, 350);
}
return TRUE;
}
/*
** Netscaler trace format close routines.
*/
static void nstrace_close(wtap *wth)
{
nstrace_t *nstrace = (nstrace_t *)wth->priv;
g_free(nstrace->pnstrace_buf);
}
#define NSTRACE_1_0 0
#define NSTRACE_2_0 1
#define NSTRACE_3_0 2
#define NSTRACE_3_5 3
typedef struct {
guint version;
guint16 page_offset;
guint16 page_len;
guint32 absrec_time;
gboolean newfile;
} nstrace_dump_t;
/* Returns 0 if we could write the specified encapsulation type,
** an error indication otherwise. */
static int nstrace_10_dump_can_write_encap(int encap)
{
if (encap == WTAP_ENCAP_NSTRACE_1_0)
return 0;
return WTAP_ERR_UNWRITABLE_ENCAP;
}
/* Returns 0 if we could write the specified encapsulation type,
** an error indication otherwise. */
static int nstrace_20_dump_can_write_encap(int encap)
{
if (encap == WTAP_ENCAP_NSTRACE_2_0)
return 0;
return WTAP_ERR_UNWRITABLE_ENCAP;
}
/* Returns 0 if we could write the specified encapsulation type,
** an error indication otherwise. */
static int nstrace_30_dump_can_write_encap(int encap)
{
if (encap == WTAP_ENCAP_NSTRACE_3_0)
return 0;
return WTAP_ERR_UNWRITABLE_ENCAP;
}
/* Returns 0 if we could write the specified encapsulation type,
** an error indication otherwise. */
static int nstrace_35_dump_can_write_encap(int encap)
{
if (encap == WTAP_ENCAP_NSTRACE_3_5)
return 0;
return WTAP_ERR_UNWRITABLE_ENCAP;
}
/* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
** failure */
static gboolean nstrace_dump_open(wtap_dumper *wdh, guint version, int *err _U_,
gchar **err_info _U_)
{
nstrace_dump_t *nstrace;
wdh->subtype_write = nstrace_dump;
nstrace = g_new(nstrace_dump_t, 1);
wdh->priv = (void *)nstrace;
nstrace->version = version;
nstrace->page_offset = 0;
if ((nstrace->version == NSTRACE_3_0) ||
(nstrace->version == NSTRACE_3_5))
nstrace->page_len = NSPR_PAGESIZE_TRACE;
else
nstrace->page_len = NSPR_PAGESIZE;
nstrace->absrec_time = 0;
nstrace->newfile = TRUE;
return TRUE;
}
static gboolean nstrace_10_dump_open(wtap_dumper *wdh, int *err,
gchar **err_info)
{
return nstrace_dump_open(wdh, NSTRACE_1_0, err, err_info);
}
static gboolean nstrace_20_dump_open(wtap_dumper *wdh, int *err,
gchar **err_info)
{
return nstrace_dump_open(wdh, NSTRACE_2_0, err, err_info);
}
static gboolean nstrace_30_dump_open(wtap_dumper *wdh, int *err,
gchar **err_info)
{
return nstrace_dump_open(wdh, NSTRACE_3_0, err, err_info);
}
static gboolean nstrace_35_dump_open(wtap_dumper *wdh, int *err,
gchar **err_info)
{
return nstrace_dump_open(wdh, NSTRACE_3_5, err, err_info);
}
static gboolean nstrace_add_signature(wtap_dumper *wdh, int *err)
{
nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
if (nstrace->version == NSTRACE_1_0)
{
guint16 val16b;
nspr_signature_v10_t sig10;
/* populate the record */
val16b = GUINT16_TO_LE(NSPR_SIGNATURE_V10);
memcpy(sig10.phd.ph_RecordType, &val16b, sizeof sig10.phd.ph_RecordType);
val16b = GUINT16_TO_LE(nspr_signature_v10_s);
memcpy(sig10.phd.ph_RecordSize, &val16b, sizeof sig10.phd.ph_RecordSize);
memset(sig10.sig_Signature, 0, NSPR_SIGSIZE_V10);
(void) g_strlcpy(sig10.sig_Signature, NSPR_SIGSTR_V10, NSPR_SIGSIZE_V10);
/* Write the record into the file */
if (!wtap_dump_file_write(wdh, &sig10, nspr_signature_v10_s,
err))
return FALSE;
/* Move forward the page offset */
nstrace->page_offset += (guint16) nspr_signature_v10_s;
} else if (nstrace->version == NSTRACE_2_0)
{
nspr_signature_v20_t sig20;
sig20.sig_RecordType = NSPR_SIGNATURE_V20;
sig20.sig_RecordSize = nspr_signature_v20_s;
memcpy(sig20.sig_Signature, NSPR_SIGSTR_V20, sizeof(NSPR_SIGSTR_V20));
/* Write the record into the file */
if (!wtap_dump_file_write(wdh, &sig20, sig20.sig_RecordSize,
err))
return FALSE;
/* Move forward the page offset */
nstrace->page_offset += (guint16) sig20.sig_RecordSize;
} else if (nstrace->version == NSTRACE_3_0)
{
nspr_signature_v30_t sig30;
sig30.sig_RecordType = NSPR_SIGNATURE_V30;
sig30.sig_RecordSize = nspr_signature_v30_s;
memcpy(sig30.sig_Signature, NSPR_SIGSTR_V30, sizeof(NSPR_SIGSTR_V30));
/* Write the record into the file */
if (!wtap_dump_file_write(wdh, &sig30, sig30.sig_RecordSize,
err))
return FALSE;
/* Move forward the page offset */
nstrace->page_offset += (guint16) sig30.sig_RecordSize;
} else if (nstrace->version == NSTRACE_3_5)
{
nspr_signature_v35_t sig35;
sig35.sig_RecordType = NSPR_SIGNATURE_V35;
sig35.sig_RecordSize = nspr_signature_v35_s;
memcpy(sig35.sig_Signature, NSPR_SIGSTR_V35, sizeof(NSPR_SIGSTR_V35));
/* Write the record into the file */
if (!wtap_dump_file_write(wdh, &sig35, sig35.sig_RecordSize,
err))
return FALSE;
/* Move forward the page offset */
nstrace->page_offset += (guint16) sig35.sig_RecordSize;
} else
{
ws_assert_not_reached();
return FALSE;
}
return TRUE;
}
static gboolean
nstrace_add_abstime(wtap_dumper *wdh, const wtap_rec *rec,
const guint8 *pd, int *err)
{
nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
guint64 nsg_creltime;
if (nstrace->version == NSTRACE_1_0)
{
guint16 val16;
guint32 reltime;
guint64 abstime;
nspr_abstime_v10_t abs10;
/* populate the record */
val16 = GUINT16_TO_LE(NSPR_ABSTIME_V10);
memcpy(abs10.phd.ph_RecordType, &val16, sizeof abs10.phd.ph_RecordType);
val16 = GUINT16_TO_LE(nspr_abstime_v10_s);
memcpy(abs10.phd.ph_RecordSize, &val16, sizeof abs10.phd.ph_RecordSize);
memcpy(&reltime, ((const nspr_pktracefull_v10_t *)pd)->fp_RelTimeHr, sizeof reltime);
nsg_creltime = ns_hrtime2nsec(reltime);
memset(abs10.abs_RelTime, 0, sizeof abs10.abs_RelTime);
abstime = GUINT32_TO_LE((guint32)rec->ts.secs - (guint32)(nsg_creltime/1000000000));
memcpy(abs10.abs_Time, &abstime, sizeof abs10.abs_Time);
/* Write the record into the file */
if (!wtap_dump_file_write(wdh, &abs10, nspr_abstime_v10_s, err))
return FALSE;
/* Move forward the page offset */
nstrace->page_offset += nspr_abstime_v10_s;
} else if ((nstrace->version == NSTRACE_2_0) ||
(nstrace->version == NSTRACE_3_0) ||
(nstrace->version == NSTRACE_3_5)) {
guint32 reltime;
guint64 abstime;
nspr_abstime_v20_t abs20;
abs20.abs_RecordType = NSPR_ABSTIME_V20;
abs20.abs_RecordSize = nspr_abstime_v20_s;
memcpy(&reltime, ((const nspr_pktracefull_v20_t *)pd)->fp_RelTimeHr, sizeof reltime);
nsg_creltime = ns_hrtime2nsec(reltime);
memset(abs20.abs_RelTime, 0, sizeof abs20.abs_RelTime);
abstime = GUINT32_TO_LE((guint32)rec->ts.secs - (guint32)(nsg_creltime/1000000000));
memcpy(abs20.abs_RelTime, &abstime, sizeof abs20.abs_RelTime);
/* Write the record into the file */
if (!wtap_dump_file_write(wdh, &abs20, nspr_abstime_v20_s, err))
return FALSE;
/* Move forward the page offset */
nstrace->page_offset += nspr_abstime_v20_s;
} else
{
ws_assert_not_reached();
return FALSE;
}
return TRUE;
}
/* Write a record for a packet to a dump file.
Returns TRUE on success, FALSE on failure. */
static gboolean nstrace_dump(wtap_dumper *wdh, const wtap_rec *rec,
const guint8 *pd, int *err, gchar **err_info _U_)
{
nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
/* We can only write packet records. */
if (rec->rec_type != REC_TYPE_PACKET) {
*err = WTAP_ERR_UNWRITABLE_REC_TYPE;
return FALSE;
}
if (nstrace->newfile == TRUE)
{
nstrace->newfile = FALSE;
/* Add the signature record and abs time record */
if (nstrace->version == NSTRACE_1_0)
{
if (!nstrace_add_signature(wdh, err) ||
!nstrace_add_abstime(wdh, rec, pd, err))
return FALSE;
} else if (nstrace->version == NSTRACE_2_0)
{
if (!nstrace_add_signature(wdh, err) ||
!nstrace_add_abstime(wdh, rec, pd, err))
return FALSE;
} else if (nstrace->version == NSTRACE_3_0 ||
nstrace->version == NSTRACE_3_5 )
{
if (!nstrace_add_signature(wdh, err) ||
!nstrace_add_abstime(wdh, rec, pd, err))
return FALSE;
} else
{
ws_assert_not_reached();
return FALSE;
}
}
switch (rec->rec_header.packet_header.pseudo_header.nstr.rec_type)
{
case NSPR_HEADER_VERSION100:
if (nstrace->version == NSTRACE_1_0)
{
if (nstrace->page_offset + rec->rec_header.packet_header.caplen >= nstrace->page_len)
{
/* Start on the next page */
if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
return FALSE;
nstrace->page_offset = 0;
/* Possibly add signature and abstime records and increment offset */
if (!nstrace_add_signature(wdh, err))
return FALSE;
}
/* Write the actual record as is */
if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
return FALSE;
nstrace->page_offset += (guint16) rec->rec_header.packet_header.caplen;
} else if (nstrace->version == NSTRACE_2_0)
{
*err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
}
break;
case NSPR_HEADER_VERSION200:
case NSPR_HEADER_VERSION201:
case NSPR_HEADER_VERSION202:
case NSPR_HEADER_VERSION203:
case NSPR_HEADER_VERSION204:
case NSPR_HEADER_VERSION205:
case NSPR_HEADER_VERSION206:
if (nstrace->version == NSTRACE_1_0)
{
*err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
} else if (nstrace->version == NSTRACE_2_0)
{
if (nstrace->page_offset + rec->rec_header.packet_header.caplen >= nstrace->page_len)
{
/* Start on the next page */
if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
return FALSE;
nstrace->page_offset = 0;
/* Possibly add signature and abstime records and increment offset */
if (!nstrace_add_signature(wdh, err))
return FALSE;
}
/* Write the actual record as is */
if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
return FALSE;
nstrace->page_offset += (guint16) rec->rec_header.packet_header.caplen;
}
break;
case NSPR_HEADER_VERSION300:
case NSPR_HEADER_VERSION350:
if (nstrace->version == NSTRACE_1_0)
{
*err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
} else if (nstrace->version == NSTRACE_2_0)
{
*err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
} else if (nstrace->version == NSTRACE_3_0 || nstrace->version == NSTRACE_3_5)
{
if (nstrace->page_offset + rec->rec_header.packet_header.caplen >= nstrace->page_len)
{
/* Start on the next page */
if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
return FALSE;
nstrace->page_offset = 0;
/* Possibly add signature and abstime records and increment offset */
if (!nstrace_add_signature(wdh, err))
return FALSE;
}
/* Write the actual record as is */
if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
return FALSE;
nstrace->page_offset += (guint16) rec->rec_header.packet_header.caplen;
} else
{
ws_assert_not_reached();
return FALSE;
}
break;
default:
ws_assert_not_reached();
return FALSE;
}
return TRUE;
}
static const struct supported_block_type nstrace_1_0_blocks_supported[] = {
/*
* We support packet blocks, with no comments or other options.
*/
{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
};
static const struct file_type_subtype_info nstrace_1_0_info = {
"NetScaler Trace (Version 1.0)", "nstrace10", NULL, NULL,
TRUE, BLOCKS_SUPPORTED(nstrace_1_0_blocks_supported),
nstrace_10_dump_can_write_encap, nstrace_10_dump_open, NULL
};
static const struct supported_block_type nstrace_2_0_blocks_supported[] = {
/*
* We support packet blocks, with no comments or other options.
*/
{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
};
static const struct file_type_subtype_info nstrace_2_0_info = {
"NetScaler Trace (Version 2.0)", "nstrace20", "cap", NULL,
TRUE, BLOCKS_SUPPORTED(nstrace_2_0_blocks_supported),
nstrace_20_dump_can_write_encap, nstrace_20_dump_open, NULL
};
static const struct supported_block_type nstrace_3_0_blocks_supported[] = {
/*
* We support packet blocks, with no comments or other options.
*/
{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
};
static const struct file_type_subtype_info nstrace_3_0_info = {
"NetScaler Trace (Version 3.0)", "nstrace30", "cap", NULL,
TRUE, BLOCKS_SUPPORTED(nstrace_3_0_blocks_supported),
nstrace_30_dump_can_write_encap, nstrace_30_dump_open, NULL
};
static const struct supported_block_type nstrace_3_5_blocks_supported[] = {
/*
* We support packet blocks, with no comments or other options.
*/
{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
};
static const struct file_type_subtype_info nstrace_3_5_info = {
"NetScaler Trace (Version 3.5)", "nstrace35", "cap", NULL,
TRUE, BLOCKS_SUPPORTED(nstrace_3_5_blocks_supported),
nstrace_35_dump_can_write_encap, nstrace_35_dump_open, NULL
};
void register_nstrace(void)
{
nstrace_1_0_file_type_subtype = wtap_register_file_type_subtype(&nstrace_1_0_info);
nstrace_2_0_file_type_subtype = wtap_register_file_type_subtype(&nstrace_2_0_info);
nstrace_3_0_file_type_subtype = wtap_register_file_type_subtype(&nstrace_3_0_info);
nstrace_3_5_file_type_subtype = wtap_register_file_type_subtype(&nstrace_3_5_info);
wiretap: more work on file type/subtypes. Provide a wiretap routine to get an array of all savable file type/subtypes, sorted with pcap and pcapng at the top, followed by the other types, sorted either by the name or the description. Use that routine to list options for the -F flag for various commands Rename wtap_get_savable_file_types_subtypes() to wtap_get_savable_file_types_subtypes_for_file(), to indicate that it provides an array of all file type/subtypes in which a given file can be saved. Have it sort all types, other than the default type/subtype and, if there is one, the "other" type (both of which are put at the top), by the name or the description. Don't allow wtap_register_file_type_subtypes() to override any existing registrations; have them always register a new type. In that routine, if there are any emply slots in the table, due to an entry being unregistered, use it rather than allocating a new slot. Don't allow unregistration of built-in types. Rename the "dump open table" to the "file type/subtype table", as it has entries for all types/subtypes, even if we can't write them. Initialize that table in a routine that pre-allocates the GArray before filling it with built-in types/subtypes, so it doesn't keep getting reallocated. Get rid of wtap_num_file_types_subtypes - it's just a copy of the size of the GArray. Don't have wtap_file_type_subtype_description() crash if handed an file type/subtype that isn't a valid array index - just return NULL, as we do with wtap_file_type_subtype_name(). In wtap_name_to_file_type_subtype(), don't use WTAP_FILE_TYPE_SUBTYPE_ names for the backwards-compatibility names - map those names to the current names, and then look them up. This reduces the number of uses of hardwired WTAP_FILE_TYPE_SUBTYPE_ values. Clean up the type of wtap_module_count - it has no need to be a gulong. Have built-in wiretap file handlers register names to be used for their file type/subtypes, rather than building the table in init.lua. Add a new Lua C function get_wtap_filetypes() to construct the wtap_filetypes table, based on the registered names, and use it in init.lua. Add a #define WSLUA_INTERNAL_FUNCTION to register functions intended only for internal use in init.lua, so they can be made available from Lua without being documented. Get rid of WTAP_NUM_FILE_TYPES_SUBTYPES - most code has no need to use it, as it can just request arrays of types, and the space of type/subtype codes can be sparse due to registration in any case, so code has to be careful using it. wtap_get_num_file_types_subtypes() is no longer used, so remove it. It returns the number of elements in the file type/subtype array, which is not necessarily the name of known file type/subtypes, as there may have been some deregistered types, and those types do *not* get removed from the array, they just get cleared so that they're available for future allocation (we don't want the indices of any registered types to changes if another type is deregistered, as those indicates are the type/subtype values, so we can't shrink the array). Clean up white space and remove some comments that shouldn't have been added.
2021-02-17 06:24:47 +00:00
/*
* Register names for backwards compatibility with the
* wtap_filetypes table in Lua.
*/
wtap_register_backwards_compatibility_lua_name("NETSCALER_1_0",
nstrace_1_0_file_type_subtype);
wtap_register_backwards_compatibility_lua_name("NETSCALER_2_0",
nstrace_2_0_file_type_subtype);
wtap_register_backwards_compatibility_lua_name("NETSCALER_3_0",
nstrace_3_0_file_type_subtype);
wtap_register_backwards_compatibility_lua_name("NETSCALER_3_5",
nstrace_3_5_file_type_subtype);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/