diff options
Diffstat (limited to 'wiretap/netscaler.c')
-rw-r--r-- | wiretap/netscaler.c | 2555 |
1 files changed, 2555 insertions, 0 deletions
diff --git a/wiretap/netscaler.c b/wiretap/netscaler.c new file mode 100644 index 00000000..c1b229e0 --- /dev/null +++ b/wiretap/netscaler.c @@ -0,0 +1,2555 @@ +/* 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 <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. +** 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; + guint32 page_size; + 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*, guint); +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_page(wtap *wth, int *err, gchar **err_info) +{ + nstrace_t *nstrace = (nstrace_t *)wth->priv; + int bytes_read; + + bytes_read = file_read(nstrace->pnstrace_buf, nstrace->page_size, wth->fh); + if (bytes_read < 0) { + *err = file_error(wth->fh, err_info); + return FALSE; + } + if (bytes_read == 0) { + /* + * EOF. + */ + *err = 0; + return FALSE; + } + nstrace->nstrace_buflen = (guint32)bytes_read; + 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 = NSPR_PAGESIZE; + + /* + * Read the first page, so we can look for a signature. + * A short read is OK, as a file may have fewer records + * than required to fill up a page. + */ + bytes_read = file_read(nstrace_buf, NSPR_PAGESIZE, wth->fh); + if (bytes_read < 0) { + *err = file_error(wth->fh, err_info); + g_free(nstrace_buf); + return WTAP_OPEN_ERROR; + } + if (bytes_read == 0) { + /* An empty file. */ + g_free(nstrace_buf); + return WTAP_OPEN_NOT_MINE; + } + + /* + * Scan it for a signature block. + */ + file_version = nspm_signature_version(nstrace_buf, (guint)bytes_read); + 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; + /* + * File pages are larger in version 3.0; grow the buffer. + * (XXX - use g_realloc()?) + */ + g_free(nstrace_buf); + nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE_TRACE); + page_size = NSPR_PAGESIZE_TRACE; + break; + + case NSPM_SIGNATURE_3_5: + wth->file_type_subtype = nstrace_3_5_file_type_subtype; + wth->file_encap = WTAP_ENCAP_NSTRACE_3_5; + /* + * File pages are larger in version 3.5; grow the buffer. + * (XXX - use g_realloc()?) + */ + g_free(nstrace_buf); + nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE_TRACE); + page_size = NSPR_PAGESIZE_TRACE; + break; + + default: + /* No known signature found, assume it's not NetScaler */ + g_free(nstrace_buf); + 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->page_size = page_size; + nstrace->xxx_offset = 0; + 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; + + /* + * Seek back to the beginning of the file and read the first page, + * now that we know the page size. + */ + if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1) + { + g_free(nstrace_buf); + return WTAP_OPEN_ERROR; + } + if (!nstrace_read_page(wth, err, err_info)) { + if (*err == 0) { + /* EOF, so an empty file. */ + g_free(nstrace_buf); + return WTAP_OPEN_NOT_MINE; + } + /* Read error. */ + return WTAP_OPEN_ERROR; + } + + /* 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 (!nstrace_read_page(wth, err, err_info)) { + if (*err == 0) { + /* EOF, so an empty file. */ + g_free(nstrace_buf); + return WTAP_OPEN_NOT_MINE; + } + /* Read error. */ + 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; +} + +/* +** 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. +** +** 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? +*/ +#define nspm_signature_func(ver) \ + 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 +** 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, guint len) +{ + gchar *dp = nstrace_buf; + + for ( ; len > 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 (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 (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) + + +/* + * For a given file version, this defines a routine to find an absolute + * time record in a file of that version and set the start time based on + * that. + * + * The routine called from the open routine after a file has been recognized + * as a NetScaler trace. + */ +#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_page(wth, 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 {\ + /* Make sure the record header is entirely contained in the page */\ + if ((nstrace_buflen - nstrace_buf_offset) < sizeof(nspr_pktrace##fullpart##_v##ver##_t)) {\ + *err = WTAP_ERR_BAD_FILE;\ + *err_info = g_strdup("nstrace: record header crosses page boundary");\ + return FALSE;\ + }\ + nspr_pktrace##fullpart##_v##ver##_t *type = (nspr_pktrace##fullpart##_v##ver##_t *) &nstrace_buf[nstrace_buf_offset];\ + /* 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: + { + if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_pktracefull_v10_t), err, err_info)) + return FALSE; + 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: + { + if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_pktracefull_v10_t), err, err_info)) + return FALSE; + 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: + { + if (!nstrace_ensure_buflen(nstrace, nstrace_buf_offset, sizeof(nspr_pktracefull_v10_t), err, err_info)) + return FALSE; + 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_page(wth, 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_page(wth, 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 {\ + /* Make sure the record header is entirely contained in the page */\ + if ((nstrace->nstrace_buflen - nstrace_buf_offset) < sizeof(nspr_##structname##_t)) {\ + *err = WTAP_ERR_BAD_FILE;\ + *err_info = g_strdup("nstrace: record header crosses page boundary");\ + g_free(nstrace_tmpbuff);\ + return FALSE;\ + }\ + nspr_##structname##_t *fp = (nspr_##structname##_t *) &nstrace_buf[nstrace_buf_offset];\ + (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; + } + + /* + * Make sure this packet doesn't have a link-layer type that + * differs from the one for the file. + */ + if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) { + *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; + 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); + + /* + * 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: + */ |