From Tomasz Mon via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8503 :
[metze/wireshark/wip.git] / wiretap / netscaler.c
1 /* netscaler.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 2006 by Ravi Kondamuru <Ravi.Kondamuru@citrix.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include <errno.h>
25 #include <string.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "buffer.h"
29 #include "netscaler.h"
30
31 /* Defines imported from netscaler code: nsperfrc.h */
32
33 #define NSPR_SIGSTR_V10 "NetScaler Performance Data"
34 #define NSPR_SIGSTR_V20 "NetScaler V20 Performance Data"
35 #define NSPR_SIGSTR     NSPR_SIGSTR_V20
36 /* Defined but not used */
37 #define NSPR_SIGSTR_V21 "NetScaler V21 Performance Data"
38 #define NSPR_SIGSTR_V22 "NetScaler V22 Performance Data"
39
40 #define NSPR_PAGESIZE   8192
41
42 /* The different record types
43 ** NOTE: The Record Type is two byte fields and unused space is recognized by
44 ** either bytes being zero, therefore no record should any byte value as
45 ** zero.
46 **
47 ** New Performance Record Type is only one byte.
48 */
49 #define NSPR_UNUSEDSPACE_V10    0x0000  /* rest of the page is unused */
50 #define NSPR_UNUSEDSPACE_V20    0x00    /* rest of the page is unused */
51 #define NSPR_SIGNATURE_V10      0x0101  /* signature */
52 #define NSPR_SIGNATURE_V20      0x01    /* signature */
53 #define NSPR_ABSTIME_V10        0x0107  /* data capture time in secs from 1970*/
54 #define NSPR_ABSTIME_V20        0x07    /* data capture time in secs from 1970*/
55 #define NSPR_RELTIME_V10        0x0108  /* relative time in ms from last time */
56 #define NSPR_RELTIME_V20        0x08    /* relative time in ms from last time */
57 #define NSPR_RELTIMEHR_V10      0x0109  /* high resolution relative time */
58 #define NSPR_RELTIMEHR_V20      0x09    /* high resolution relative time */
59 #define NSPR_SYSTARTIME_V10     0x010A  /* system start time */
60 #define NSPR_SYSTARTIME_V20     0x0A    /* system start time */
61 #define NSPR_RELTIME2B_V10      0x010B  /* relative time in ms from last time */
62 #define NSPR_RELTIME2B_V20      0x0B    /* relative time in ms from last time */
63
64
65 /* The high resolution relative time format.
66 ** The MS 2 bits of the high resoltion time is defined as follows:
67 ** 00 : time value is in second
68 ** 01 : time value is in mili second
69 ** 10 : time value is in micro second
70 ** 11 : time value is in nano second
71 */
72 #define NSPR_HRTIME_MASKTM      0x3FFFFFFF /* mask to get time value */
73 #define NSPR_HRTIME_MASKFMT     0xC0000000 /* time value format mask */
74 #define NSPR_HRTIME_SEC         0x00000000 /* time value in second */
75 #define NSPR_HRTIME_MSEC        0x40000000 /* time value in mili second */
76 #define NSPR_HRTIME_USEC        0x80000000 /* time value in micro second */
77 #define NSPR_HRTIME_NSEC        0xC0000000 /* time value in nano second */
78
79
80 typedef struct nspr_header_v10
81 {
82     guint8 ph_RecordType[2]; /* Record Type */
83     guint8 ph_RecordSize[2]; /* Record Size including header */
84 } nspr_header_v10_t;
85 #define nspr_header_v10_s    ((guint32)sizeof(nspr_header_v10_t))
86
87 /* This is V20 short header (2 bytes long) to be included where needed */
88 #define NSPR_HEADER_V20(prefix) \
89     guint8 prefix##_RecordType; /* Record Type */ \
90     guint8 prefix##_RecordSize  /* Record Size including header */ \
91                                 /* end of declaration */
92
93 /* This is new long header (3 bytes long) to be included where needed */
94 #define NSPR_HEADER3B_V20(prefix) \
95     guint8 prefix##_RecordType;    /* Record Type */ \
96     guint8 prefix##_RecordSizeLow; /* Record Size including header */ \
97     guint8 prefix##_RecordSizeHigh /* Record Size including header */ \
98                                    /* end of declaration */
99 #define NSPR_HEADER3B_V21 NSPR_HEADER3B_V20
100 #define NSPR_HEADER3B_V22 NSPR_HEADER3B_V20
101
102 typedef struct nspr_hd_v20
103 {
104     NSPR_HEADER3B_V20(phd); /* long performance header */
105
106 } nspr_hd_v20_t;
107 #define nspr_hd_v20_s    ((guint32)sizeof(nspr_hd_v20_t))
108
109
110 /*
111 ** How to know if header size is short or long?
112 ** The short header size can be 0-127 bytes long. If MS Bit of ph_RecordSize
113 ** is set then record size has 2 bytes
114 */
115 #define NSPR_V20RECORDSIZE_2BYTES       0x80
116
117 /* Performance Data Header with device number */
118 typedef struct nspr_headerdev_v10
119 {
120     guint8 ph_RecordType[2]; /* Record Type */
121     guint8 ph_RecordSize[2]; /* Record Size including header */
122     guint8 ph_DevNo[4];      /* Network Device (NIC/CONN) number */
123 } nspr_headerdev_v10_t;
124 #define nspr_headerdev_v10_s    ((guint32)sizeof(nspr_headerdev_v10_t))
125
126 typedef struct nspr_hd_v10
127 {
128     nspr_header_v10_t phd; /* performance header */
129 } nspr_hd_v10_t;
130 #define nspr_hd_v10_s    ((guint32)sizeof(nspr_hd_v10_t))
131
132 typedef struct nspr_hdev_v10
133 {
134     nspr_headerdev_v10_t phd; /* performance header */
135 } nspr_hdev_v10_t;
136 #define nspr_hdev_v10_s    ((guint32)sizeof(nspr_hdev_v10_t))
137
138 /* if structure has defined phd as first field, it can use following names */
139 #define nsprRecordType    phd.ph_RecordType
140 #define nsprRecordSize    phd.ph_RecordSize
141 #define nsprReserved      phd.ph_Reserved
142 #define nsprRecordTypeOrg phd.ph_Reserved
143 #define nsprDevNo         phd.ph_DevNo
144
145 /* NSPR_SIGNATURE_V10 structure */
146 #define NSPR_SIGSIZE_V10        56 /* signature value size in bytes */
147 typedef struct nspr_signature_v10
148 {
149     nspr_header_v10_t phd; /* performance header */
150     guint8 sig_EndianType; /* Endian Type for the data */
151     guint8 sig_Reserved0;
152     guint8 sig_Reserved1[2];
153     gchar sig_Signature[NSPR_SIGSIZE_V10]; /* Signature value */
154 } nspr_signature_v10_t;
155 #define nspr_signature_v10_s    ((guint32)sizeof(nspr_signature_v10_t))
156
157 /* NSPR_SIGNATURE_V20 structure */
158 #define NSPR_SIGSIZE_V20        sizeof(NSPR_SIGSTR_V20) /* signature value size in bytes */
159 typedef struct nspr_signature_v20
160 {
161     NSPR_HEADER_V20(sig);  /* short performance header */
162     guint8 sig_EndianType; /* Endian Type for the data */
163     gchar sig_Signature[NSPR_SIGSIZE_V20]; /* Signature value */
164 } nspr_signature_v20_t;
165 #define nspr_signature_v20_s    ((guint32)sizeof(nspr_signature_v20_t))
166
167 /* NSPR_ABSTIME_V10 and NSPR_SYSTARTIME_V10 structure */
168 typedef struct nspr_abstime_v10
169 {
170     nspr_header_v10_t phd; /* performance header */
171     guint8 abs_RelTime[4]; /* relative time is ms from last time */
172     guint8 abs_Time[4];    /* absolute time in seconds from 1970 */
173 } nspr_abstime_v10_t;
174 #define nspr_abstime_v10_s    ((guint32)sizeof(nspr_abstime_v10_t))
175
176
177 /* NSPR_ABSTIME_V20 and NSPR_SYSTARTIME_V20 structure */
178 typedef struct nspr_abstime_v20
179 {
180     NSPR_HEADER_V20(abs);  /* short performance header */
181     guint8 abs_RelTime[2]; /* relative time is ms from last time */
182     guint8 abs_Time[4];    /* absolute time in seconds from 1970 */
183 } nspr_abstime_v20_t;
184 #define nspr_abstime_v20_s    ((guint32)sizeof(nspr_abstime_v20_t))
185
186
187
188 /* full packet trace structure */
189 typedef struct nspr_pktracefull_v10
190 {
191     nspr_headerdev_v10_t phd; /* performance header */
192     guint8 fp_RelTimeHr[4];   /* High resolution relative time */
193     guint8 fp_Data[1];        /* packet data starts here */
194 } nspr_pktracefull_v10_t;
195 #define nspr_pktracefull_v10_s    (nspr_hdev_v10_s + 4)
196
197 /* new full packet trace structure v20 */
198 typedef struct nspr_pktracefull_v20
199 {
200     NSPR_HEADER3B_V20(fp);  /* long performance header */
201     guint8 fp_DevNo;        /* Network Device (NIC) number */
202     guint8 fp_RelTimeHr[4]; /* High resolution relative time */
203     guint8 fp_Data[4];      /* packet data starts here */
204 } nspr_pktracefull_v20_t;
205 #define nspr_pktracefull_v20_s    ((guint32)(sizeof(nspr_pktracefull_v20_t) - 4))
206
207 /* new full packet trace structure v21 */
208 typedef struct nspr_pktracefull_v21
209 {
210     NSPR_HEADER3B_V21(fp);  /* long performance header */
211     guint8 fp_DevNo;        /* Network Device (NIC) number */
212     guint8 fp_RelTimeHr[4]; /* High resolution relative time */
213     guint8 fp_PcbDevNo[4];  /* PCB devno */
214     guint8 fp_lPcbDevNo[4]; /* link PCB devno */
215     guint8 fp_Data[4];      /* packet data starts here */
216 } nspr_pktracefull_v21_t;
217 #define nspr_pktracefull_v21_s    ((guint32)(sizeof(nspr_pktracefull_v21_t) - 4))
218
219 /* new full packet trace structure v22 */
220 typedef struct nspr_pktracefull_v22
221 {
222     NSPR_HEADER3B_V22(fp);  /* long performance header */
223     guint8 fp_DevNo;        /* Network Device (NIC) number */
224     guint8 fp_RelTimeHr[4]; /* High resolution relative time */
225     guint8 fp_PcbDevNo[4];  /* PCB devno */
226     guint8 fp_lPcbDevNo[4]; /* link PCB devno */
227     guint8 fp_VlanTag[2];   /* vlan tag */
228     guint8 fp_Data[2];      /* packet data starts here */
229 } nspr_pktracefull_v22_t;
230 #define nspr_pktracefull_v22_s    ((guint32)(sizeof(nspr_pktracefull_v22_t) - 2))
231
232 typedef struct nspr_pktracefull_v23
233 {
234     NSPR_HEADER3B_V22(fp);  /* long performance header */
235     guint8 fp_DevNo;        /* Network Device (NIC) number */
236     guint8 fp_AbsTimeHr[8]; /* High resolution absolute time */
237     guint8 fp_PcbDevNo[4];  /* PCB devno */
238     guint8 fp_lPcbDevNo[4]; /* link PCB devno */
239     guint8 fp_VlanTag[2];   /* vlan tag */
240     guint8 fp_Coreid[2];    /* coreid of the packet */
241     guint8 fp_Data[2];      /* packet data starts here */
242 } nspr_pktracefull_v23_t;
243 #define nspr_pktracefull_v23_s    ((guint32)(sizeof(nspr_pktracefull_v23_t) - 2))
244
245 /* New full packet trace structure v24 for cluster tracing */
246 typedef struct nspr_pktracefull_v24
247 {
248     NSPR_HEADER3B_V22(fp);   /* long performance header */
249     guint8 fp_DevNo;         /* Network Device (NIC) number */
250     guint8 fp_AbsTimeHr[8];  /* High resolution absolute time in nanosec */
251     guint8 fp_PcbDevNo[4];   /* PCB devno */
252     guint8 fp_lPcbDevNo[4];  /* link PCB devno */
253     guint8 fp_VlanTag[2];    /* vlan tag */
254     guint8 fp_Coreid[2];     /* coreid of the packet */
255     guint8 fp_srcNodeId[2];  /* source node # */
256     guint8 fp_destNodeId[2]; /* destination node # */
257     guint8 fp_clFlags;       /* cluster flags */
258     guint8 fp_Data[2];       /* packet data starts here */
259 } nspr_pktracefull_v24_t;
260 #define nspr_pktracefull_v24_s    ((guint32)(sizeof(nspr_pktracefull_v24_t) - 4))
261
262 /* New full packet trace structure v25 for vm info tracing */
263 typedef struct nspr_pktracefull_v25
264 {
265     NSPR_HEADER3B_V22(fp);    /* long performance header */
266     guint8 fp_DevNo;          /* Network Device (NIC) number */
267     guint8 fp_AbsTimeHr[8];   /* High resolution absolute time in nanosec */
268     guint8 fp_PcbDevNo[4];    /* PCB devno */
269     guint8 fp_lPcbDevNo[4];   /* link PCB devno */
270     guint8 fp_VlanTag[2];     /* vlan tag */
271     guint8 fp_Coreid[2];      /* coreid of the packet */
272     guint8 fp_srcNodeId[2];   /* source node # */
273     guint8 fp_destNodeId[2];  /* destination node # */
274     guint8 fp_clFlags;        /* cluster flags */
275     guint8 fp_src_vmname_len; /* vm src info */
276     guint8 fp_dst_vmname_len; /* vm src info */
277     guint8 fp_Data[4];        /* packet data starts here */
278 } nspr_pktracefull_v25_t;
279 #define nspr_pktracefull_v25_s    ((guint32)(sizeof(nspr_pktracefull_v25_t) - 4))
280 #define fp_src_vmname    fp_Data
281 #define fp_src_vmname    fp_Data
282
283
284 /* partial packet trace structure */
285 typedef struct nspr_pktracepart_v10
286 {
287     nspr_headerdev_v10_t phd; /* performance header */
288     guint8 pp_RelTimeHr[4];   /* High resolution relative time */
289     guint8 pp_PktSizeOrg[2];  /* Original packet size */
290     guint8 pp_PktOffset[2];   /* starting offset in packet */
291     guint8 pp_Data[1];        /* packet data starts here */
292 } nspr_pktracepart_v10_t;
293 #define nspr_pktracepart_v10_s    (nspr_pktracefull_v10_s + 4)
294
295 /* new partial packet trace structure */
296 typedef struct nspr_pktracepart_v20
297 {
298     NSPR_HEADER3B_V20(pp);   /* long performance header */
299     guint8 pp_DevNo;         /* Network Device (NIC) number */
300     guint8 pp_RelTimeHr[4];  /* High resolution relative time */
301     guint8 pp_PktSizeOrg[2]; /* Original packet size */
302     guint8 pp_PktOffset[2];  /* starting offset in packet */
303     guint8 pp_Data[4];       /* packet data starts here */
304 } nspr_pktracepart_v20_t;
305 #define nspr_pktracepart_v20_s    ((guint32)(sizeof(nspr_pktracepart_v20_t) -4))
306
307 /* new partial packet trace structure */
308 typedef struct nspr_pktracepart_v21
309 {
310     NSPR_HEADER3B_V21(pp);   /* long performance header */
311     guint8 pp_DevNo;         /* Network Device (NIC) number */
312     guint8 pp_RelTimeHr[4];  /* High resolution relative time */
313     guint8 pp_PktSizeOrg[2]; /* Original packet size */
314     guint8 pp_PktOffset[2];  /* starting offset in packet */
315     guint8 pp_PcbDevNo[4];   /* PCB devno */
316     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
317     guint8 pp_Data[4];       /* packet data starts here */
318 } nspr_pktracepart_v21_t;
319 #define nspr_pktracepart_v21_s    ((guint32)(sizeof(nspr_pktracepart_v21_t) -4))
320
321 /* new partial packet trace structure v22 */
322 typedef struct nspr_pktracepart_v22
323 {
324     NSPR_HEADER3B_V22(pp);   /* long performance header */
325     guint8 pp_DevNo;         /* Network Device (NIC) number */
326     guint8 pp_RelTimeHr[4];  /* High resolution relative time */
327     guint8 pp_PktSizeOrg[2]; /* Original packet size */
328     guint8 pp_PktOffset[2];  /* starting offset in packet */
329     guint8 pp_PcbDevNo[4];   /* PCB devno */
330     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
331     guint8 pp_VlanTag[2];    /* Vlan Tag */
332     guint8 pp_Data[2];       /* packet data starts here */
333 } nspr_pktracepart_v22_t;
334 #define nspr_pktracepart_v22_s    ((guint32)(sizeof(nspr_pktracepart_v22_t) -2))
335
336 typedef struct nspr_pktracepart_v23
337 {
338     NSPR_HEADER3B_V22(pp);   /* long performance header */
339     guint8 pp_DevNo;         /* Network Device (NIC) number */
340     guint8 pp_AbsTimeHr[8];  /* High resolution absolute time */
341     guint8 pp_PktSizeOrg[2]; /* Original packet size */
342     guint8 pp_PktOffset[2];  /* starting offset in packet */
343     guint8 pp_PcbDevNo[4];   /* PCB devno */
344     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
345     guint8 pp_VlanTag[2];    /* vlan tag */
346     guint8 pp_Coreid[2];     /* Coreid of the packet */
347     guint8 pp_Data[4];       /* packet data starts here */
348 } nspr_pktracepart_v23_t;
349 #define nspr_pktracepart_v23_s    ((guint32)(sizeof(nspr_pktracepart_v23_t) -4))
350
351 /* New partial packet trace structure v24 for cluster tracing */
352 typedef struct nspr_pktracepart_v24
353 {
354     NSPR_HEADER3B_V22(pp);   /* long performance header */
355     guint8 pp_DevNo;         /* Network Device (NIC) number */
356     guint8 pp_AbsTimeHr[8];  /*High resolution absolute time in nanosec*/
357     guint8 pp_PktSizeOrg[2]; /* Original packet size */
358     guint8 pp_PktOffset[2];  /* starting offset in packet */
359     guint8 pp_PcbDevNo[4];   /* PCB devno */
360     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
361     guint8 pp_VlanTag[2];    /* vlan tag */
362     guint8 pp_Coreid[2];     /* Coreid of the packet */
363     guint8 pp_srcNodeId[2];  /* source node # */
364     guint8 pp_destNodeId[2]; /* destination node # */
365     guint8 pp_clFlags;       /* cluster flags */
366     guint8 pp_Data[4];       /* packet data starts here */
367 } nspr_pktracepart_v24_t;
368 #define nspr_pktracepart_v24_s    ((guint32)(sizeof(nspr_pktracepart_v24_t) -4))
369
370 /* New partial packet trace structure v25 for vm info tracing */
371 typedef struct nspr_pktracepart_v25
372 {
373     NSPR_HEADER3B_V22(pp);    /* long performance header */
374     guint8 pp_DevNo;          /* Network Device (NIC) number */
375     guint8 pp_AbsTimeHr[8];   /*High resolution absolute time in nanosec*/
376     guint8 pp_PktSizeOrg[2];  /* Original packet size */
377     guint8 pp_PktOffset[2];   /* starting offset in packet */
378     guint8 pp_PcbDevNo[4];    /* PCB devno */
379     guint8 pp_lPcbDevNo[4];   /* link PCB devno */
380     guint8 pp_VlanTag[2];     /* vlan tag */
381     guint8 pp_Coreid[2];      /* Coreid of the packet */
382     guint8 pp_srcNodeId[2];   /* source node # */
383     guint8 pp_destNodeId[2];  /* destination node # */
384     guint8 pp_clFlags;        /* cluster flags */
385     guint8 pp_src_vmname_len; /* vm info */
386     guint8 pp_dst_vmname_len; /* vm info */
387     guint8 pp_Data[4];        /* packet data starts here */
388 } nspr_pktracepart_v25_t;
389 #define nspr_pktracepart_v25_s    ((guint32)(sizeof(nspr_pktracepart_v25_t) -4))
390 #define pp_src_vmname    pp_Data
391 #define pp_dst_vmname    pp_Data
392
393 #define myoffsetof(type,fieldname) (&(((type*)0)->fieldname))
394
395 #define __TNO(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
396     guint8 enumprefix##_##hdrname##_offset = (guint8)GPOINTER_TO_INT(myoffsetof(nspr_##structname##_t,structprefix##_##structfieldname));
397
398 #define __TNL(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
399     guint8 enumprefix##_##hdrname##_len = (guint8)sizeof(((nspr_##structname##_t*)0)->structprefix##_##structfieldname);
400
401 #define __TNV1O(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
402     guint8 enumprefix##_##hdrname##_offset = (guint8)GPOINTER_TO_INT(myoffsetof(nspr_##structname##_t,structfieldname));
403
404 #define __TNV1L(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
405     guint8 enumprefix##_##hdrname##_len = (guint8)sizeof(((nspr_##structname##_t*)0)->structfieldname);
406
407 #define TRACE_V10_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
408     __TNV1O(phdr,enumprefix,structprefix,structname,dir,phd.ph_RecordType)\
409     __TNV1L(phdr,enumprefix,structprefix,structname,dir,phd.ph_RecordType)\
410     __TNV1O(phdr,enumprefix,structprefix,structname,nicno,phd.ph_DevNo)\
411     __TNV1L(phdr,enumprefix,structprefix,structname,nicno,phd.ph_DevNo)\
412     __TNO(phdr,enumprefix,structprefix,structname,eth,Data)
413
414 #define TRACE_FULL_V10_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
415     (phdr)->len = pletohs(&(fp)->nsprRecordSize);\
416     (phdr)->caplen = (phdr)->len;\
417     TRACE_V10_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)        
418
419 #define TRACE_PART_V10_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
420     (phdr)->presence_flags |= WTAP_HAS_CAP_LEN;\
421     (phdr)->len =  pletohs(&pp->pp_PktSizeOrg) + nspr_pktracepart_v10_s;\
422     (phdr)->caplen =  pletohs(&pp->nsprRecordSize);\
423     TRACE_V10_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)
424
425 #define TRACE_V20_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
426     __TNO(phdr,enumprefix,structprefix,structname,dir,RecordType)\
427     __TNL(phdr,enumprefix,structprefix,structname,dir,RecordType)\
428     __TNO(phdr,enumprefix,structprefix,structname,nicno,DevNo)\
429     __TNL(phdr,enumprefix,structprefix,structname,nicno,DevNo)\
430     __TNO(phdr,enumprefix,structprefix,structname,eth,Data)
431
432 #define TRACE_V21_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
433     TRACE_V20_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
434     __TNO(phdr,enumprefix,structprefix,structname,pcb,PcbDevNo)\
435     __TNO(phdr,enumprefix,structprefix,structname,l_pcb,lPcbDevNo)
436
437 #define TRACE_V22_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
438     TRACE_V21_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
439     __TNO(phdr,enumprefix,structprefix,structname,vlantag,VlanTag)
440
441 #define TRACE_V23_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
442     TRACE_V22_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
443     __TNO(phdr,enumprefix,structprefix,structname,coreid,Coreid)
444
445 #define TRACE_V24_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
446     TRACE_V23_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
447     __TNO(phdr,enumprefix,structprefix,structname,srcnodeid,srcNodeId)\
448     __TNO(phdr,enumprefix,structprefix,structname,destnodeid,destNodeId)\
449     __TNO(phdr,enumprefix,structprefix,structname,clflags,clFlags)
450
451 #define TRACE_V25_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
452     TRACE_V24_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
453     __TNO(phdr,enumprefix,structprefix,structname,src_vmname_len,src_vmname_len)\
454     __TNO(phdr,enumprefix,structprefix,structname,dst_vmname_len,dst_vmname_len)\
455     __TNO(phdr,enumprefix,structprefix,structname,data,Data)
456     
457     TRACE_V10_REC_LEN_OFF(NULL,v10_part,pp,pktracepart_v10)
458     TRACE_V10_REC_LEN_OFF(NULL,v10_full,fp,pktracefull_v10)
459     TRACE_V20_REC_LEN_OFF(NULL,v20_part,pp,pktracepart_v20)
460     TRACE_V20_REC_LEN_OFF(NULL,v20_full,fp,pktracefull_v20)
461     TRACE_V21_REC_LEN_OFF(NULL,v21_part,pp,pktracepart_v21)
462     TRACE_V21_REC_LEN_OFF(NULL,v21_full,fp,pktracefull_v21)
463     TRACE_V22_REC_LEN_OFF(NULL,v22_part,pp,pktracepart_v22)
464     TRACE_V22_REC_LEN_OFF(NULL,v22_full,fp,pktracefull_v22)
465     TRACE_V23_REC_LEN_OFF(NULL,v23_part,pp,pktracepart_v23)
466     TRACE_V23_REC_LEN_OFF(NULL,v23_full,fp,pktracefull_v23)
467     TRACE_V24_REC_LEN_OFF(NULL,v24_part,pp,pktracepart_v24)
468     TRACE_V24_REC_LEN_OFF(NULL,v24_full,fp,pktracefull_v24)
469     TRACE_V25_REC_LEN_OFF(NULL,v25_part,pp,pktracepart_v25)
470     TRACE_V25_REC_LEN_OFF(NULL,v25_full,fp,pktracefull_v25)
471
472 #undef __TNV1O
473 #undef __TNV1L
474 #undef __TNO
475 #undef __TNL
476
477
478 #define ns_setabstime(nstrace, AbsoluteTime, RelativeTimems) \
479     do { \
480         (nstrace)->nspm_curtime = AbsoluteTime; \
481         (nstrace)->nspm_curtimemsec += RelativeTimems; \
482         (nstrace)->nspm_curtimelastmsec = nstrace->nspm_curtimemsec; \
483     } while(0)
484
485
486 #define ns_setrelativetime(nstrace, RelativeTimems) \
487     do { \
488         guint32    rsec; \
489         (nstrace)->nspm_curtimemsec += RelativeTimems; \
490         rsec = (guint32)((nstrace)->nspm_curtimemsec - (nstrace)->nspm_curtimelastmsec)/1000; \
491         (nstrace)->nspm_curtime += rsec; \
492         (nstrace)->nspm_curtimelastmsec += rsec * 1000; \
493     } while (0)
494
495
496 typedef struct {
497     gchar  *pnstrace_buf;
498     gint64  xxx_offset;
499     gint32  nstrace_buf_offset;
500     gint32  nstrace_buflen;
501     /* Performance Monitor Time variables */
502     guint32 nspm_curtime;         /* current time since 1970 */
503     guint64 nspm_curtimemsec;     /* current time in milliseconds */
504     guint64 nspm_curtimelastmsec; /* nspm_curtime last update time in milliseconds */
505     guint64 nsg_creltime;
506     guint64 file_size;
507 } nstrace_t;
508
509 static guint32 nspm_signature_version(wtap*, gchar*, gint32);
510 static gboolean nstrace_read_v10(wtap *wth, int *err, gchar **err_info,
511                                  gint64 *data_offset);
512 static gboolean nstrace_read_v20(wtap *wth, int *err, gchar **err_info,
513                                  gint64 *data_offset);
514 static gboolean nstrace_seek_read_v10(wtap *wth, gint64 seek_off,
515                                       struct wtap_pkthdr *phdr,
516                                       guint8 *pd, int length,
517                                       int *err, gchar **err_info);
518 static gboolean nstrace_seek_read_v20(wtap *wth, gint64 seek_off,
519                                       struct wtap_pkthdr *phdr,
520                                       guint8 *pd, int length,
521                                       int *err, gchar **err_info);
522 static void nstrace_close(wtap *wth);
523
524 static gboolean nstrace_set_start_time_v10(wtap *wth);
525 static gboolean nstrace_set_start_time_v20(wtap *wth);
526 static gboolean nstrace_set_start_time(wtap *wth);
527 static guint64 ns_hrtime2nsec(guint32 tm);
528
529 static gboolean nstrace_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
530                              const guint8 *pd, int *err);
531
532
533 #define GET_READ_PAGE_SIZE(remaining_file_size) ((gint32)((remaining_file_size>NSPR_PAGESIZE)?NSPR_PAGESIZE:remaining_file_size))
534
535
536 static guint64 ns_hrtime2nsec(guint32 tm)
537 {
538     guint32    val = tm & NSPR_HRTIME_MASKTM;
539     switch(tm & NSPR_HRTIME_MASKFMT)
540     {
541     case NSPR_HRTIME_SEC:    return (guint64)val*1000000000;
542     case NSPR_HRTIME_MSEC:    return (guint64)val*1000000;
543     case NSPR_HRTIME_USEC:    return (guint64)val*1000;
544     case NSPR_HRTIME_NSEC:    return val;
545     }
546     return tm;
547 }
548
549
550 /*
551 ** Netscaler trace format open routines
552 */
553 int nstrace_open(wtap *wth, int *err, gchar **err_info)
554 {
555     gchar *nstrace_buf;
556     gint64 file_size;
557     gint32 page_size;
558     nstrace_t *nstrace;
559     int bytes_read;
560
561     errno = WTAP_ERR_CANT_READ;
562
563     if ((file_size = wtap_file_size(wth, err)) == -1)
564         return 0;
565
566     nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE);
567     page_size = GET_READ_PAGE_SIZE(file_size);
568
569     switch ((wth->file_type = nspm_signature_version(wth, nstrace_buf, page_size)))
570     {
571     case WTAP_FILE_NETSCALER_1_0:
572         wth->file_encap = WTAP_ENCAP_NSTRACE_1_0;
573         break;
574
575     case WTAP_FILE_NETSCALER_2_0:
576         wth->file_encap = WTAP_ENCAP_NSTRACE_2_0;
577         break;
578
579     default:
580         *err = WTAP_ERR_UNSUPPORTED;
581         *err_info = g_strdup_printf("nstrace: file type %d unsupported", wth->file_type);
582         g_free(nstrace_buf);
583         return 0;
584     }
585
586     if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1)
587     {
588         *err = file_error(wth->fh, err_info);
589         g_free(nstrace_buf);
590         return 0;
591     }
592
593     bytes_read = file_read(nstrace_buf, page_size, wth->fh);
594     if (bytes_read != page_size)
595     {
596         *err = file_error(wth->fh, err_info);
597         g_free(nstrace_buf);
598         if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
599             return -1;
600         return 0;
601     }
602
603     switch (wth->file_type)
604     {
605     case WTAP_FILE_NETSCALER_1_0:
606         wth->subtype_read = nstrace_read_v10;
607         wth->subtype_seek_read = nstrace_seek_read_v10;
608         break;
609
610     case WTAP_FILE_NETSCALER_2_0:
611         wth->subtype_read = nstrace_read_v20;
612         wth->subtype_seek_read = nstrace_seek_read_v20;
613         break;
614     }
615     wth->subtype_close = nstrace_close;
616
617     nstrace = (nstrace_t *)g_malloc(sizeof(nstrace_t));
618     wth->priv = (void *)nstrace;
619     nstrace->pnstrace_buf = nstrace_buf;
620     nstrace->xxx_offset = 0;
621     nstrace->nstrace_buflen = page_size;
622     nstrace->nstrace_buf_offset = 0;
623     nstrace->nspm_curtime = 0;
624     nstrace->nspm_curtimemsec = 0;
625     nstrace->nspm_curtimelastmsec = 0;
626     nstrace->nsg_creltime = 0;
627     nstrace->file_size = file_size;
628
629
630     /* Set the start time by looking for the abstime record */
631     if ((nstrace_set_start_time(wth)) == FALSE)
632     {
633         /* Reset the read pointer to start of the file. */
634         if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1)
635         {
636             *err = file_error(wth->fh, err_info);
637             g_free(nstrace->pnstrace_buf);
638             g_free(nstrace);
639             return 0;
640         }
641
642         /* Read the first page of data */
643         bytes_read = file_read(nstrace_buf, page_size, wth->fh);
644         if (bytes_read != page_size)
645         {
646             *err = file_error(wth->fh, err_info);
647             g_free(nstrace->pnstrace_buf);
648             g_free(nstrace);
649             return 0;
650         }
651
652         /* reset the buffer offset */
653         nstrace->nstrace_buf_offset = 0;
654     }
655
656     wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
657     wth->phdr.ts.secs = nstrace->nspm_curtime;
658     wth->phdr.ts.nsecs = 0;
659
660     *err = 0;
661     return 1;
662 }
663
664
665 #define nspm_signature_func(ver) \
666     static guint32 nspm_signature_isv##ver(gchar *sigp) {\
667         return strncmp(sigp,NSPR_SIGSTR_V##ver,(sizeof(NSPR_SIGSTR_V##ver)-1));\
668     }
669
670 nspm_signature_func(10)
671 nspm_signature_func(20)
672
673 /*
674 ** Check signature and return the version number of the signature.
675 ** If not found, it returns 0. At the time of return from this function
676 ** we might not be at the first page. So after a call to this function, there
677 ** has to be a file seek to return to the start of the first page.
678 */
679 static guint32
680 nspm_signature_version(wtap *wth, gchar *nstrace_buf, gint32 len)
681 {
682     gchar *dp = nstrace_buf;
683     int bytes_read;
684
685     bytes_read = file_read(dp, len, wth->fh);
686     if (bytes_read == len) {
687
688         for ( ; len > (gint32)(MIN(sizeof(NSPR_SIGSTR_V10), sizeof(NSPR_SIGSTR_V20))); dp++, len--)
689         {
690 #define sigv10p    ((nspr_signature_v10_t*)dp)
691             if ((pletohs(&sigv10p->nsprRecordType) == NSPR_SIGNATURE_V10) &&
692                 (pletohs(&sigv10p->nsprRecordSize) <= len) &&
693                 ((gint32)sizeof(NSPR_SIGSTR_V10) <= len) &&
694                 (!nspm_signature_isv10(sigv10p->sig_Signature)))
695                 return WTAP_FILE_NETSCALER_1_0;
696 #undef    sigv10p
697
698 #define sigv20p    ((nspr_signature_v20_t*)dp)
699             if ((sigv20p->sig_RecordType == NSPR_SIGNATURE_V20) &&
700                 (sigv20p->sig_RecordSize <= len) &&
701                 ((gint32)sizeof(NSPR_SIGSTR_V20) <= len) &&
702                 (!nspm_signature_isv20(sigv20p->sig_Signature)))
703                 return WTAP_FILE_NETSCALER_2_0;
704 #undef    sigv20p
705         }
706     }
707
708     return 0;    /* no version found */
709 }
710
711 #define nspr_getv10recordtype(hdp) (pletohs(&hdp->nsprRecordType))
712 #define nspr_getv10recordsize(hdp) (pletohs(&hdp->nsprRecordSize))
713 #define nspr_getv20recordtype(hdp) (hdp->phd_RecordType)
714 #define nspr_getv20recordsize(hdp) \
715     (((hdp)->phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES)? \
716         (((hdp)->phd_RecordSizeHigh * NSPR_V20RECORDSIZE_2BYTES)+ \
717          ((hdp)->phd_RecordSizeLow & ~NSPR_V20RECORDSIZE_2BYTES)) : \
718           (hdp)->phd_RecordSizeLow)
719
720
721 #define nstrace_set_start_time_ver(ver) \
722     gboolean nstrace_set_start_time_v##ver(wtap *wth) \
723     {\
724         nstrace_t *nstrace = (nstrace_t *)wth->priv;\
725         gchar* nstrace_buf = nstrace->pnstrace_buf;\
726         gint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;\
727         gint32 nstrace_buflen = nstrace->nstrace_buflen;\
728         int bytes_read;\
729         do\
730         {\
731             while (nstrace_buf_offset < nstrace_buflen)\
732             {\
733                 nspr_hd_v##ver##_t *fp = (nspr_hd_v##ver##_t *) &nstrace_buf[nstrace_buf_offset];\
734                 switch (nspr_getv##ver##recordtype(fp))\
735                 {\
736                     case NSPR_ABSTIME_V##ver:\
737                         ns_setabstime(nstrace, pletohl(&((nspr_abstime_v##ver##_t *) fp)->abs_Time), pletohs(&((nspr_abstime_v##ver##_t *) fp)->abs_RelTime));\
738                         nstrace->nstrace_buf_offset = nstrace_buf_offset + nspr_getv##ver##recordsize(fp);\
739                         nstrace->nstrace_buflen = nstrace_buflen;\
740                         return TRUE;\
741                      case NSPR_UNUSEDSPACE_V10:\
742                         nstrace_buf_offset = nstrace_buflen;\
743                         break;\
744                     default:\
745                         nstrace_buf_offset += nspr_getv##ver##recordsize(fp);\
746                 }\
747             }\
748             nstrace_buf_offset = 0;\
749             nstrace->xxx_offset += nstrace_buflen;\
750             nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));\
751         }while((nstrace_buflen > 0) && (bytes_read = file_read(nstrace_buf, nstrace_buflen, wth->fh)) && bytes_read == nstrace_buflen); \
752         return FALSE;\
753     }
754
755 nstrace_set_start_time_ver(10)
756 nstrace_set_start_time_ver(20)
757
758 #undef nspr_getv10recordtype
759 #undef nspr_getv20recordtype
760 #undef nspr_getv10recordsize
761
762 /*
763 ** Set the start time of the trace file. We look for the first ABSTIME record. We use that
764 ** to set the start time. Apart from that we also make sure that we remember the position of
765 ** the next record after the ABSTIME record. Inorder to report correct time values, all trace
766 ** records before the ABSTIME record are ignored.
767 */
768 static gboolean nstrace_set_start_time(wtap *wth)
769 {
770     if (wth->file_type == WTAP_FILE_NETSCALER_1_0)
771         return nstrace_set_start_time_v10(wth);
772     else if (wth->file_type == WTAP_FILE_NETSCALER_2_0)
773         return nstrace_set_start_time_v20(wth);
774
775     return FALSE;
776 }
777
778 #define __TNO(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
779     (phdr)->pseudo_header.nstr.hdrname##_offset = enumprefix##_##hdrname##_offset;
780
781 #define __TNL(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
782     (phdr)->pseudo_header.nstr.hdrname##_len = enumprefix##_##hdrname##_len;
783
784 #define __TNV1O(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
785     __TNO(phdr,enumprefix,structprefix,structname,hdrname,structfieldname)
786
787 #define __TNV1L(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
788     __TNL(phdr,enumprefix,structprefix,structname,hdrname,structfieldname)
789
790
791
792 /*
793 ** Netscaler trace format read routines.
794 */
795 static gboolean nstrace_read_v10(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
796 {
797     nstrace_t *nstrace = (nstrace_t *)wth->priv;
798     guint64 nsg_creltime = nstrace->nsg_creltime;
799     gchar *nstrace_buf = nstrace->pnstrace_buf;
800     gint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
801     gint32 nstrace_buflen = nstrace->nstrace_buflen;
802     nspr_pktracefull_v10_t *fp;
803     nspr_pktracepart_v10_t *pp;
804     int bytes_read;
805
806     *err = 0;
807     *err_info = NULL;
808     do
809     {
810         while ((nstrace_buf_offset < nstrace_buflen) &&
811             ((nstrace_buflen - nstrace_buf_offset) >= ((gint32)sizeof(fp->nsprRecordType))))
812         {
813
814 #define GENERATE_CASE_FULL(phdr,type,acttype) \
815         case NSPR_PDPKTRACEFULLTX_V##type:\
816         case NSPR_PDPKTRACEFULLTXB_V##type:\
817         case NSPR_PDPKTRACEFULLRX_V##type:\
818             fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];\
819             /*\
820              * XXX - we can't do this in the seek-read routine,\
821              * as the time stamps in the records are relative to\
822              * the previous packet.\
823              */\
824             (phdr)->presence_flags = WTAP_HAS_TS;\
825             nsg_creltime += ns_hrtime2nsec(pletohl(&fp->fp_RelTimeHr));\
826             (phdr)->ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
827             (phdr)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
828             TRACE_FULL_V##type##_REC_LEN_OFF(phdr,v##type##_full,fp,pktracefull_v##type);\
829             buffer_assure_space(wth->frame_buffer, (phdr)->caplen);\
830             memcpy(buffer_start_ptr(wth->frame_buffer), fp, (phdr)->caplen);\
831             *data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
832             nstrace->nstrace_buf_offset = nstrace_buf_offset + (phdr)->len;\
833             nstrace->nstrace_buflen = nstrace_buflen;\
834             nstrace->nsg_creltime = nsg_creltime;\
835             return TRUE;
836
837 #define GENERATE_CASE_PART(phdr,type,acttype) \
838         case NSPR_PDPKTRACEPARTTX_V##type:\
839         case NSPR_PDPKTRACEPARTTXB_V##type:\
840         case NSPR_PDPKTRACEPARTRX_V##type:\
841             pp = (nspr_pktracepart_v10_t *) &nstrace_buf[nstrace_buf_offset];\
842             /*\
843              * XXX - we can't do this in the seek-read routine,\
844              * as the time stamps in the records are relative to\
845              * the previous packet.\
846              */\
847             (phdr)->presence_flags = WTAP_HAS_TS;\
848             nsg_creltime += ns_hrtime2nsec(pletohl(&pp->pp_RelTimeHr));\
849             (phdr)->ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
850             (phdr)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
851             TRACE_PART_V##type##_REC_LEN_OFF(phdr,v##type##_part,pp,pktracepart_v##type);\
852             buffer_assure_space(wth->frame_buffer, (phdr)->caplen);\
853             memcpy(buffer_start_ptr(wth->frame_buffer), pp, (phdr)->caplen);\
854             *data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
855             nstrace->nstrace_buf_offset = nstrace_buf_offset + (phdr)->caplen;\
856             nstrace->nsg_creltime = nsg_creltime;\
857             nstrace->nstrace_buflen = nstrace_buflen;\
858             return TRUE;\
859
860             switch (pletohs(&(( nspr_header_v10_t*)&nstrace_buf[nstrace_buf_offset])->ph_RecordType))
861             {
862                 GENERATE_CASE_FULL(&wth->phdr,10,100)
863                 GENERATE_CASE_PART(&wth->phdr,10,100)
864
865 #undef GENERATE_CASE_FULL
866 #undef GENERATE_CASE_PART
867
868             case NSPR_ABSTIME_V10:
869
870                 fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
871                 ns_setabstime(nstrace, pletohl(((nspr_abstime_v10_t *) fp)->abs_Time), pletohl(&((nspr_abstime_v10_t *) fp)->abs_RelTime));
872                 nstrace_buf_offset += pletohs(&fp->nsprRecordSize);
873                 break;
874
875             case NSPR_RELTIME_V10:
876
877                 fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
878                 ns_setrelativetime(nstrace, pletohl(((nspr_abstime_v10_t *) fp)->abs_RelTime));
879                 nstrace_buf_offset += pletohs(&fp->nsprRecordSize);
880                 break;
881
882             case NSPR_UNUSEDSPACE_V10:
883
884                 nstrace_buf_offset = nstrace_buflen;
885                 break;
886
887             default:
888
889                 fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
890                 nstrace_buf_offset += pletohs(&fp->nsprRecordSize);
891                 break;
892             }
893         }
894
895         nstrace_buf_offset = 0;
896         nstrace->xxx_offset += nstrace_buflen;
897         nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));
898     }while((nstrace_buflen > 0) && (bytes_read = file_read(nstrace_buf, nstrace_buflen, wth->fh)) && (bytes_read == nstrace_buflen));
899
900     return FALSE;
901 }
902
903 #define TIMEDEFV20(fp,type) \
904     do {\
905         wth->phdr.presence_flags |= WTAP_HAS_TS;\
906         nsg_creltime += ns_hrtime2nsec(pletohl(fp->type##_RelTimeHr));\
907         wth->phdr.ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
908         wth->phdr.ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
909     }while(0)
910
911 #define TIMEDEFV23(fp,type) \
912     do {\
913         wth->phdr.presence_flags |= WTAP_HAS_TS;\
914         /* access _AbsTimeHr as a 64bit value */\
915         nsg_creltime = pletohll(fp->type##_AbsTimeHr);\
916         wth->phdr.ts.secs = (guint32) (nsg_creltime / 1000000000);\
917         wth->phdr.ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
918     }while(0)
919
920 #define TIMEDEFV21(fp,type) TIMEDEFV20(fp,type)
921 #define TIMEDEFV22(fp,type) TIMEDEFV20(fp,type)
922 #define TIMEDEFV24(fp,type) TIMEDEFV23(fp,type)
923 #define TIMEDEFV25(fp,type) TIMEDEFV24(fp,type)
924 #define PPSIZEDEFV20(phdr,pp,ver) \
925     do {\
926         (phdr)->presence_flags |= WTAP_HAS_CAP_LEN;\
927         (phdr)->len = pletohs(&pp->pp_PktSizeOrg) + nspr_pktracepart_v##ver##_s;\
928         (phdr)->caplen = nspr_getv20recordsize((nspr_hd_v20_t *)pp);\
929     }while(0)
930
931 #define PPSIZEDEFV21(phdr,pp,ver) PPSIZEDEFV20(phdr,pp,ver)
932 #define PPSIZEDEFV22(phdr,pp,ver) PPSIZEDEFV20(phdr,pp,ver)
933 #define PPSIZEDEFV23(phdr,pp,ver) PPSIZEDEFV20(phdr,pp,ver)
934 #define PPSIZEDEFV24(phdr,pp,ver) PPSIZEDEFV20(phdr,pp,ver)
935 #define PPSIZEDEFV25(phdr,pp,ver) PPSIZEDEFV20(phdr,pp,ver)
936
937 #define FPSIZEDEFV20(phdr,fp,ver)\
938     do {\
939         (phdr)->len = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
940         (phdr)->caplen = (phdr)->len;\
941     }while(0)
942
943 #define FPSIZEDEFV21(phdr,fp,ver) FPSIZEDEFV20(phdr,fp,ver)
944 #define FPSIZEDEFV22(phdr,fp,ver) FPSIZEDEFV20(phdr,fp,ver)
945 #define FPSIZEDEFV23(phdr,fp,ver) FPSIZEDEFV20(phdr,fp,ver)
946 #define FPSIZEDEFV24(phdr,fp,ver) FPSIZEDEFV20(phdr,fp,ver)
947 #define FPSIZEDEFV25(phdr,fp,ver) FPSIZEDEFV20(phdr,fp,ver)
948
949 #define PACKET_DESCRIBE(phdr,FPTIMEDEF,SIZEDEF,ver,enumprefix,type,structname,TYPE)\
950     do {\
951         nspr_##structname##_t *fp= (nspr_##structname##_t*)&nstrace_buf[nstrace_buf_offset];\
952         TIMEDEFV##ver(fp,type);\
953         SIZEDEF##ver((phdr),fp,ver);\
954         TRACE_V##ver##_REC_LEN_OFF((phdr),enumprefix,type,structname);\
955         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##TYPE;\
956         buffer_assure_space(wth->frame_buffer, (phdr)->caplen);\
957         memcpy(buffer_start_ptr(wth->frame_buffer), fp, (phdr)->caplen);\
958         *data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
959         nstrace->nstrace_buf_offset = nstrace_buf_offset + nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
960         nstrace->nstrace_buflen = nstrace_buflen;\
961         nstrace->nsg_creltime = nsg_creltime;\
962         return TRUE;\
963     }while(0)
964
965 static gboolean nstrace_read_v20(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
966 {
967     nstrace_t *nstrace = (nstrace_t *)wth->priv;
968     guint64 nsg_creltime = nstrace->nsg_creltime;
969     gchar *nstrace_buf = nstrace->pnstrace_buf;
970     gint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
971     gint32 nstrace_buflen = nstrace->nstrace_buflen;
972     int bytes_read;
973
974     *err = 0;
975     *err_info = NULL;
976     do
977     {
978         while ((nstrace_buf_offset < nstrace_buflen) &&
979             ((nstrace_buflen - nstrace_buf_offset) >= ((gint32)sizeof((( nspr_hd_v20_t*)&nstrace_buf[nstrace_buf_offset])->phd_RecordType))))
980         {
981             switch ((( nspr_hd_v20_t*)&nstrace_buf[nstrace_buf_offset])->phd_RecordType)
982             {
983
984 #define GENERATE_CASE_FULL(phdr,type,acttype) \
985         case NSPR_PDPKTRACEFULLTX_V##type:\
986         case NSPR_PDPKTRACEFULLTXB_V##type:\
987         case NSPR_PDPKTRACEFULLRX_V##type:\
988             PACKET_DESCRIBE(phdr,TIMEDEF,FPSIZEDEFV,type,v##type##_full,fp,pktracefull_v##type,acttype);
989
990 #define GENERATE_CASE_FULL_V25(phdr,type,acttype) \
991         case NSPR_PDPKTRACEFULLTX_V##type:\
992         case NSPR_PDPKTRACEFULLTXB_V##type:\
993         case NSPR_PDPKTRACEFULLRX_V##type:\
994         case NSPR_PDPKTRACEFULLNEWRX_V##type:\
995             PACKET_DESCRIBE(phdr,TIMEDEF,FPSIZEDEFV,type,v##type##_full,fp,pktracefull_v##type,acttype);
996
997 #define GENERATE_CASE_PART(phdr,type,acttype) \
998         case NSPR_PDPKTRACEPARTTX_V##type:\
999         case NSPR_PDPKTRACEPARTTXB_V##type:\
1000         case NSPR_PDPKTRACEPARTRX_V##type:\
1001             PACKET_DESCRIBE(phdr,TIMEDEF,PPSIZEDEFV,type,v##type##_part,pp,pktracepart_v##type,acttype);
1002
1003 #define GENERATE_CASE_PART_V25(phdr,type,acttype) \
1004         case NSPR_PDPKTRACEPARTTX_V##type:\
1005         case NSPR_PDPKTRACEPARTTXB_V##type:\
1006         case NSPR_PDPKTRACEPARTRX_V##type:\
1007         case NSPR_PDPKTRACEPARTNEWRX_V##type:\
1008             PACKET_DESCRIBE(phdr,TIMEDEF,PPSIZEDEFV,type,v##type##_part,pp,pktracepart_v##type,acttype);
1009
1010                 GENERATE_CASE_FULL(&wth->phdr,20,200);
1011                 GENERATE_CASE_PART(&wth->phdr,20,200);
1012                 GENERATE_CASE_FULL(&wth->phdr,21,201);
1013                 GENERATE_CASE_PART(&wth->phdr,21,201);
1014                 GENERATE_CASE_FULL(&wth->phdr,22,202);
1015                 GENERATE_CASE_PART(&wth->phdr,22,202);
1016                 GENERATE_CASE_FULL(&wth->phdr,23,203);
1017                 GENERATE_CASE_PART(&wth->phdr,23,203);
1018                 GENERATE_CASE_FULL_V25(&wth->phdr,24,204);
1019                 GENERATE_CASE_PART_V25(&wth->phdr,24,204);
1020                 GENERATE_CASE_FULL_V25(&wth->phdr,25,205);
1021                 GENERATE_CASE_PART_V25(&wth->phdr,25,205);
1022
1023 #undef GENERATE_CASE_FULL
1024 #undef GENERATE_CASE_FULL_V25
1025 #undef GENERATE_CASE_PART
1026 #undef GENERATE_CASE_PART_V25
1027
1028                 case NSPR_ABSTIME_V20:
1029                 {
1030                     nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
1031                     nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
1032                     ns_setabstime(nstrace, pletohl(&((nspr_abstime_v20_t *) fp20)->abs_Time), pletohs(&((nspr_abstime_v20_t *) fp20)->abs_RelTime));
1033                     break;
1034                 }
1035
1036                 case NSPR_RELTIME_V20:
1037                 {
1038                     nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
1039                     ns_setrelativetime(nstrace, pletohs(&((nspr_abstime_v20_t *) fp20)->abs_RelTime));
1040                     nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
1041                     break;
1042                   }
1043
1044                 case NSPR_UNUSEDSPACE_V20:
1045                 {
1046                     if (nstrace_buf_offset >= NSPR_PAGESIZE/2)
1047                         nstrace_buf_offset = nstrace_buflen;
1048                     else
1049                         nstrace_buf_offset = NSPR_PAGESIZE/2;
1050                     break;
1051                   }
1052
1053                 default:
1054                 {
1055                     nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
1056                     nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
1057                     break;
1058                 }
1059             }
1060         }
1061
1062         nstrace_buf_offset = 0;
1063         nstrace->xxx_offset += nstrace_buflen;
1064         nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));
1065     }while((nstrace_buflen > 0) && (bytes_read = file_read(nstrace_buf, nstrace_buflen, wth->fh)) && (bytes_read == nstrace_buflen));
1066
1067     return FALSE;
1068 }
1069
1070 #undef PACKET_DESCRIBE
1071
1072 static gboolean nstrace_seek_read_v10(wtap *wth, gint64 seek_off,
1073     struct wtap_pkthdr *phdr, guint8 *pd, int length,
1074     int *err, gchar **err_info)
1075 {
1076     int bytes_read;
1077     nspr_pktracefull_v10_t *fp;
1078     nspr_pktracepart_v10_t *pp;
1079
1080     *err = 0;
1081
1082     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1083         return FALSE;
1084
1085     /*
1086     ** Read the packet data.
1087     */
1088     bytes_read = file_read(pd, length, wth->random_fh);
1089     if (bytes_read != length) {
1090         *err = file_error(wth->random_fh, err_info);
1091         if (*err == 0)
1092             *err = WTAP_ERR_SHORT_READ;
1093         return FALSE;
1094     }
1095
1096 #define GENERATE_CASE_FULL(phdr,type,acttype) \
1097         case NSPR_PDPKTRACEFULLTX_V##type:\
1098         case NSPR_PDPKTRACEFULLTXB_V##type:\
1099         case NSPR_PDPKTRACEFULLRX_V##type:\
1100             fp = (nspr_pktracefull_v10_t *) pd;\
1101             TRACE_FULL_V##type##_REC_LEN_OFF(phdr,v##type##_full,fp,pktracefull_v##type);\
1102             (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##acttype;\
1103             break;
1104
1105 #define GENERATE_CASE_PART(phdr,type,acttype) \
1106         case NSPR_PDPKTRACEPARTTX_V##type:\
1107         case NSPR_PDPKTRACEPARTTXB_V##type:\
1108         case NSPR_PDPKTRACEPARTRX_V##type:\
1109             pp = (nspr_pktracepart_v10_t *) pd;\
1110             TRACE_PART_V##type##_REC_LEN_OFF(phdr,v##type##_part,pp,pktracepart_v##type);\
1111             (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##acttype;\
1112             break;
1113
1114     switch (pletohs(&(( nspr_header_v10_t*)pd)->ph_RecordType))
1115     {
1116         GENERATE_CASE_FULL(phdr,10,100)
1117         GENERATE_CASE_PART(phdr,10,100)
1118     }
1119
1120 #undef GENERATE_CASE_FULL
1121 #undef GENERATE_CASE_PART
1122
1123     return TRUE;
1124 }
1125
1126 #define PACKET_DESCRIBE(phdr,FPTIMEDEF,SIZEDEF,ver,enumprefix,type,structname,TYPE)\
1127     do {\
1128         nspr_##structname##_t *fp= (nspr_##structname##_t*)pd;\
1129         SIZEDEF##ver((phdr),fp,ver);\
1130         TRACE_V##ver##_REC_LEN_OFF((phdr),enumprefix,type,structname);\
1131         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##TYPE;\
1132         return TRUE;\
1133     }while(0)
1134
1135 static gboolean nstrace_seek_read_v20(wtap *wth, gint64 seek_off,
1136     struct wtap_pkthdr *phdr, guint8 *pd, int length,
1137     int *err, gchar **err_info)
1138 {
1139     int bytes_read;
1140
1141     *err = 0;
1142
1143     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1144         return FALSE;
1145
1146     /*
1147     ** Read the packet data.
1148     */
1149     bytes_read = file_read(pd, length, wth->random_fh);
1150     if (bytes_read != length) {
1151         *err = file_error(wth->random_fh, err_info);
1152         if (*err == 0)
1153             *err = WTAP_ERR_SHORT_READ;
1154         return FALSE;
1155     }
1156
1157 #define GENERATE_CASE_FULL(phdr,type,acttype) \
1158         case NSPR_PDPKTRACEFULLTX_V##type:\
1159         case NSPR_PDPKTRACEFULLTXB_V##type:\
1160         case NSPR_PDPKTRACEFULLRX_V##type:\
1161             PACKET_DESCRIBE(phdr,TIMEDEF,FPSIZEDEFV,type,v##type##_full,fp,pktracefull_v##type,acttype);
1162
1163 #define GENERATE_CASE_FULL_V25(phdr,type,acttype) \
1164         case NSPR_PDPKTRACEFULLTX_V##type:\
1165         case NSPR_PDPKTRACEFULLTXB_V##type:\
1166         case NSPR_PDPKTRACEFULLRX_V##type:\
1167         case NSPR_PDPKTRACEFULLNEWRX_V##type:\
1168             PACKET_DESCRIBE(phdr,TIMEDEF,FPSIZEDEFV,type,v##type##_full,fp,pktracefull_v##type,acttype);
1169
1170 #define GENERATE_CASE_PART(phdr,type,acttype) \
1171         case NSPR_PDPKTRACEPARTTX_V##type:\
1172         case NSPR_PDPKTRACEPARTTXB_V##type:\
1173         case NSPR_PDPKTRACEPARTRX_V##type:\
1174             PACKET_DESCRIBE(phdr,TIMEDEF,PPSIZEDEFV,type,v##type##_part,pp,pktracepart_v##type,acttype);
1175
1176 #define GENERATE_CASE_PART_V25(phdr,type,acttype) \
1177         case NSPR_PDPKTRACEPARTTX_V##type:\
1178         case NSPR_PDPKTRACEPARTTXB_V##type:\
1179         case NSPR_PDPKTRACEPARTRX_V##type:\
1180         case NSPR_PDPKTRACEPARTNEWRX_V##type:\
1181             PACKET_DESCRIBE(phdr,TIMEDEF,PPSIZEDEFV,type,v##type##_part,pp,pktracepart_v##type,acttype);
1182
1183     switch ((( nspr_hd_v20_t*)pd)->phd_RecordType)
1184     {
1185         GENERATE_CASE_FULL(phdr,20,200)
1186         GENERATE_CASE_PART(phdr,20,200)
1187         GENERATE_CASE_FULL(phdr,21,201)
1188         GENERATE_CASE_PART(phdr,21,201)
1189         GENERATE_CASE_FULL(phdr,22,202)
1190         GENERATE_CASE_PART(phdr,22,202)
1191         GENERATE_CASE_FULL(phdr,23,203)
1192         GENERATE_CASE_PART(phdr,23,203)
1193         GENERATE_CASE_FULL_V25(phdr,24,204)
1194         GENERATE_CASE_PART_V25(phdr,24,204)
1195         GENERATE_CASE_FULL_V25(phdr,25,205)
1196         GENERATE_CASE_PART_V25(phdr,25,205)
1197     }
1198
1199 #undef GENERATE_CASE_FULL
1200 #undef GENERATE_CASE_FULL_V25
1201 #undef GENERATE_CASE_PART
1202 #undef GENERATE_CASE_PART_V25
1203
1204     return TRUE;
1205 }
1206
1207 /*
1208 ** Netscaler trace format close routines.
1209 */
1210 static void nstrace_close(wtap *wth)
1211 {
1212     nstrace_t *nstrace = (nstrace_t *)wth->priv;
1213
1214     g_free(nstrace->pnstrace_buf);
1215 }
1216
1217
1218 typedef struct {
1219     guint16 page_offset;
1220     guint16 page_len;
1221     guint32 absrec_time;
1222 } nstrace_dump_t;
1223
1224 /* Returns 0 if we could write the specified encapsulation type,
1225 ** an error indication otherwise. */
1226 int nstrace_10_dump_can_write_encap(int encap)
1227 {
1228     if (encap == WTAP_ENCAP_NSTRACE_1_0)
1229         return 0;
1230
1231     return WTAP_ERR_UNSUPPORTED_ENCAP;
1232 }
1233
1234
1235 /* Returns 0 if we could write the specified encapsulation type,
1236 ** an error indication otherwise. */
1237 int nstrace_20_dump_can_write_encap(int encap)
1238 {
1239     if (encap == WTAP_ENCAP_NSTRACE_2_0)
1240         return 0;
1241
1242     return WTAP_ERR_UNSUPPORTED_ENCAP;
1243 }
1244
1245
1246 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
1247 ** failure */
1248 gboolean nstrace_dump_open(wtap_dumper *wdh, int *err _U_)
1249 {
1250     nstrace_dump_t *nstrace;
1251
1252     wdh->subtype_write = nstrace_dump;
1253
1254     nstrace = (nstrace_dump_t *)g_malloc(sizeof(nstrace_dump_t));
1255     wdh->priv = (void *)nstrace;
1256     nstrace->page_offset = 0;
1257     nstrace->page_len = NSPR_PAGESIZE;
1258     nstrace->absrec_time = 0;
1259
1260     return TRUE;
1261 }
1262
1263
1264 static gboolean nstrace_add_signature(wtap_dumper *wdh, int *err)
1265 {
1266     nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
1267
1268     if (wdh->file_type == WTAP_FILE_NETSCALER_1_0)
1269     {
1270         guint16 val16b;
1271         nspr_signature_v10_t sig10;
1272
1273         /* populate the record */
1274         val16b = htoles(NSPR_SIGNATURE_V10);
1275         memcpy(sig10.phd.ph_RecordType, &val16b, sizeof sig10.phd.ph_RecordType);
1276         val16b = htoles(nspr_signature_v10_s);
1277         memcpy(sig10.phd.ph_RecordSize, &val16b, sizeof sig10.phd.ph_RecordSize);
1278         memset(sig10.sig_Signature, 0, NSPR_SIGSIZE_V10);
1279         g_strlcpy(sig10.sig_Signature, NSPR_SIGSTR_V10, NSPR_SIGSIZE_V10);
1280
1281         /* Write the record into the file */
1282         if (!wtap_dump_file_write(wdh, &sig10, nspr_signature_v10_s,
1283             err))
1284             return FALSE;
1285
1286         /* Move forward the page offset */
1287         nstrace->page_offset += (guint16) nspr_signature_v10_s;
1288
1289     } else if (wdh->file_type == WTAP_FILE_NETSCALER_2_0)
1290     {
1291         nspr_signature_v20_t sig20;
1292
1293         sig20.sig_RecordType = NSPR_SIGNATURE_V20;
1294         sig20.sig_RecordSize = nspr_signature_v20_s;
1295         memcpy(sig20.sig_Signature, NSPR_SIGSTR_V20, sizeof(NSPR_SIGSTR_V20));
1296
1297         /* Write the record into the file */
1298         if (!wtap_dump_file_write(wdh, &sig20, sig20.sig_RecordSize,
1299             err))
1300             return FALSE;
1301
1302         /* Move forward the page offset */
1303         nstrace->page_offset += (guint16) sig20.sig_RecordSize;
1304
1305     } else
1306     {
1307         g_assert_not_reached();
1308         return FALSE;
1309     }
1310
1311     return TRUE;
1312 }
1313
1314
1315 static gboolean
1316 nstrace_add_abstime(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1317      const guint8 *pd, int *err)
1318 {
1319     nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
1320     guint64 nsg_creltime;
1321
1322     if (wdh->file_type == WTAP_FILE_NETSCALER_1_0)
1323     {
1324         guint16 val16;
1325         guint32 reltime;
1326         guint64 abstime;
1327         nspr_abstime_v10_t abs10;
1328
1329         /* populate the record */
1330         val16 = htoles(NSPR_ABSTIME_V10);
1331         memcpy(abs10.phd.ph_RecordType, &val16, sizeof abs10.phd.ph_RecordType);
1332         val16 = htoles(nspr_abstime_v10_s);
1333         memcpy(abs10.phd.ph_RecordSize, &val16, sizeof abs10.phd.ph_RecordSize);
1334
1335         memcpy(&reltime, ((const nspr_pktracefull_v10_t *)pd)->fp_RelTimeHr, sizeof reltime);
1336         nsg_creltime = ns_hrtime2nsec(reltime);
1337
1338         memset(abs10.abs_RelTime, 0, sizeof abs10.abs_RelTime);
1339         abstime = htolel((guint32)phdr->ts.secs - (guint32)(nsg_creltime/1000000000));
1340         memcpy(abs10.abs_Time, &abstime, sizeof abs10.abs_Time);
1341
1342         /* Write the record into the file */
1343         if (!wtap_dump_file_write(wdh, &abs10, nspr_abstime_v10_s, err))
1344             return FALSE;
1345
1346         /* Move forward the page offset */
1347         nstrace->page_offset += nspr_abstime_v10_s;
1348
1349     } else if (wdh->file_type == WTAP_FILE_NETSCALER_2_0)
1350     {
1351         guint32 reltime;
1352         guint64 abstime;
1353         nspr_abstime_v20_t abs20;
1354
1355         abs20.abs_RecordType = NSPR_ABSTIME_V20;
1356         abs20.abs_RecordSize = nspr_abstime_v20_s;
1357
1358         memcpy(&reltime, ((const nspr_pktracefull_v20_t *)pd)->fp_RelTimeHr, sizeof reltime);
1359         nsg_creltime = ns_hrtime2nsec(reltime);
1360
1361         memset(abs20.abs_RelTime, 0, sizeof abs20.abs_RelTime);
1362         abstime = htolel((guint32)phdr->ts.secs - (guint32)(nsg_creltime/1000000000));
1363         memcpy(abs20.abs_RelTime, &abstime, sizeof abs20.abs_RelTime);
1364
1365         /* Write the record into the file */
1366         if (!wtap_dump_file_write(wdh, &abs20, nspr_abstime_v20_s, err))
1367             return FALSE;
1368
1369         /* Move forward the page offset */
1370         nstrace->page_offset += nspr_abstime_v20_s;
1371
1372     } else
1373     {
1374         g_assert_not_reached();
1375         return FALSE;
1376     }
1377
1378     return TRUE;
1379 }
1380
1381
1382 /* Write a record for a packet to a dump file.
1383    Returns TRUE on success, FALSE on failure. */
1384 static gboolean nstrace_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1385     const guint8 *pd, int *err)
1386 {
1387     nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
1388
1389     if (nstrace->page_offset == 0)
1390     {
1391         /* Add the signature record and abs time record */
1392         if (wdh->file_type == WTAP_FILE_NETSCALER_1_0)
1393         {
1394             if (!nstrace_add_signature(wdh, err) ||
1395                 !nstrace_add_abstime(wdh, phdr, pd, err))
1396                 return FALSE;
1397         } else if (wdh->file_type == WTAP_FILE_NETSCALER_2_0)
1398         {
1399             if (!nstrace_add_signature(wdh, err) ||
1400                 !nstrace_add_abstime(wdh, phdr, pd, err))
1401                 return FALSE;
1402         } else
1403         {
1404             g_assert_not_reached();
1405             return FALSE;
1406         }
1407     }
1408
1409     switch (phdr->pseudo_header.nstr.rec_type)
1410     {
1411     case NSPR_HEADER_VERSION100:
1412
1413         if (wdh->file_type == WTAP_FILE_NETSCALER_1_0)
1414         {
1415             if (nstrace->page_offset + phdr->caplen >= nstrace->page_len)
1416             {
1417                 /* Start on the next page */
1418                 if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
1419                     return FALSE;
1420
1421                 nstrace->page_offset = 0;
1422
1423                 /* Possibly add signature and abstime records and increment offset */
1424                 if (!nstrace_add_signature(wdh, err))
1425                     return FALSE;
1426             }
1427
1428             /* Write the actual record as is */
1429             if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1430                 return FALSE;
1431
1432             nstrace->page_offset += (guint16) phdr->caplen;
1433         } else if (wdh->file_type == WTAP_FILE_NETSCALER_2_0)
1434         {
1435             *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1436             return FALSE;
1437         }
1438
1439         break;
1440
1441     case NSPR_HEADER_VERSION200:
1442     case NSPR_HEADER_VERSION201:
1443     case NSPR_HEADER_VERSION202:
1444     case NSPR_HEADER_VERSION203:
1445     case NSPR_HEADER_VERSION204:
1446     case NSPR_HEADER_VERSION205:
1447         if (wdh->file_type == WTAP_FILE_NETSCALER_1_0)
1448         {
1449             *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1450             return FALSE;
1451         } else if (wdh->file_type == WTAP_FILE_NETSCALER_2_0)
1452         {
1453             if (nstrace->page_offset + phdr->caplen >= nstrace->page_len)
1454             {
1455                 /* Start on the next page */
1456                 if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
1457                     return FALSE;
1458
1459                 nstrace->page_offset = 0;
1460
1461                 /* Possibly add signature and abstime records and increment offset */
1462                 if (!nstrace_add_signature(wdh, err))
1463                     return FALSE;
1464             }
1465
1466             /* Write the actual record as is */
1467             if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1468                 return FALSE;
1469
1470             nstrace->page_offset += (guint16) phdr->caplen;
1471         }
1472
1473         break;
1474
1475     default:
1476         g_assert_not_reached();
1477         return FALSE;
1478     }
1479
1480     return TRUE;
1481 }
1482