Allow bigger snapshot lengths for D-Bus captures.
[metze/wireshark/wip.git] / wiretap / netscaler.c
1 /* netscaler.c
2  *
3  * Wiretap Library
4  * Copyright (c) 2006 by Ravi Kondamuru <Ravi.Kondamuru@citrix.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22 #include <errno.h>
23 #include <string.h>
24 #include "wtap-int.h"
25 #include "file_wrappers.h"
26 #include "netscaler.h"
27
28 /* Defines imported from netscaler code: nsperfrc.h */
29
30 #define NSPR_SIGSTR_V10 "NetScaler Performance Data"
31 #define NSPR_SIGSTR_V20 "NetScaler V20 Performance Data"
32 #define NSPR_SIGSTR     NSPR_SIGSTR_V20
33 #define NSPR_SIGSTR_V30 "Netscaler V30 Performance Data"
34 #define NSPR_SIGSTR_V35 "Netscaler V35 Performance Data"
35 /* Defined but not used */
36 #define NSPR_SIGSTR_V21 "NetScaler V21 Performance Data"
37 #define NSPR_SIGSTR_V22 "NetScaler V22 Performance Data"
38
39 /*
40  * NetScaler trace files are divided into 8K pages, with each page
41  * containing one or more records.  The last page of the file
42  * might be less than 8K bytes.
43  *
44  * Records are not split across page boundaries; if a record doesn't
45  * fit in what remains in a page, the page is padded with null bytes
46  * and the next record is put at the beginning of the next page.
47  * A record type value of 0 means "unused space", so if there are
48  * enough null bytes to constitute a record type value, it will
49  * look as if there's an "unused space" record (which has no fields
50  * other than the type and zero or more additional padding bytes).
51  */
52 #define NSPR_PAGESIZE   8192
53 #define NSPR_PAGESIZE_TRACE (2*NSPR_PAGESIZE)
54
55 /* The different record types
56 ** NOTE: The Record Type is two byte fields and unused space is recognized by
57 ** either bytes being zero, therefore no record should any byte value as
58 ** zero.
59 **
60 ** New Performance Record Type is only one byte.
61 */
62 #define NSPR_UNUSEDSPACE_V10    0x0000  /* rest of the page is unused */
63 #define NSPR_UNUSEDSPACE_V20    0x00    /* rest of the page is unused */
64 #define NSPR_SIGNATURE_V10      0x0101  /* signature */
65 #define NSPR_SIGNATURE_V20      0x01    /* signature */
66 #define NSPR_SIGNATURE_V30      NSPR_SIGNATURE_V20
67 #define NSPR_SIGNATURE_V35      NSPR_SIGNATURE_V20
68 #define NSPR_ABSTIME_V10        0x0107  /* data capture time in secs from 1970*/
69 #define NSPR_ABSTIME_V20        0x07    /* data capture time in secs from 1970*/
70 #define NSPR_RELTIME_V10        0x0108  /* relative time in ms from last time */
71 #define NSPR_RELTIME_V20        0x08    /* relative time in ms from last time */
72 #define NSPR_RELTIMEHR_V10      0x0109  /* high resolution relative time */
73 #define NSPR_RELTIMEHR_V20      0x09    /* high resolution relative time */
74 #define NSPR_SYSTARTIME_V10     0x010A  /* system start time */
75 #define NSPR_SYSTARTIME_V20     0x0A    /* system start time */
76 #define NSPR_RELTIME2B_V10      0x010B  /* relative time in ms from last time */
77 #define NSPR_RELTIME2B_V20      0x0B    /* relative time in ms from last time */
78
79
80 /* The high resolution relative time format.
81 ** The MS 2 bits of the high resoltion time is defined as follows:
82 ** 00 : time value is in seconds
83 ** 01 : time value is in milliseconds
84 ** 10 : time value is in microseconds
85 ** 11 : time value is in nanoseconds
86 */
87 #define NSPR_HRTIME_MASKTM      0x3FFFFFFF /* mask to get time value */
88 #define NSPR_HRTIME_MASKFMT     0xC0000000 /* time value format mask */
89 #define NSPR_HRTIME_SEC         0x00000000 /* time value in second */
90 #define NSPR_HRTIME_MSEC        0x40000000 /* time value in mili second */
91 #define NSPR_HRTIME_USEC        0x80000000 /* time value in micro second */
92 #define NSPR_HRTIME_NSEC        0xC0000000 /* time value in nano second */
93
94
95 typedef struct nspr_header_v10
96 {
97     guint8 ph_RecordType[2]; /* Record Type */
98     guint8 ph_RecordSize[2]; /* Record Size including header */
99 } nspr_header_v10_t;
100 #define nspr_header_v10_s    ((guint32)sizeof(nspr_header_v10_t))
101
102 /* This is V20 short header (2 bytes long) to be included where needed */
103 #define NSPR_HEADER_V20(prefix) \
104     guint8 prefix##_RecordType; /* Record Type */ \
105     guint8 prefix##_RecordSize  /* Record Size including header */ \
106                                 /* end of declaration */
107
108 /* This is new long header (3 bytes long) to be included where needed */
109 #define NSPR_HEADER3B_V20(prefix) \
110     guint8 prefix##_RecordType;    /* Record Type */ \
111     guint8 prefix##_RecordSizeLow; /* Record Size including header */ \
112     guint8 prefix##_RecordSizeHigh /* Record Size including header */ \
113                                    /* end of declaration */
114 #define NSPR_HEADER3B_V21 NSPR_HEADER3B_V20
115 #define NSPR_HEADER3B_V22 NSPR_HEADER3B_V20
116 #define NSPR_HEADER3B_V30 NSPR_HEADER3B_V20
117
118 typedef struct nspr_hd_v20
119 {
120     NSPR_HEADER3B_V20(phd); /* long performance header */
121
122 } nspr_hd_v20_t;
123 #define nspr_hd_v20_s    ((guint32)sizeof(nspr_hd_v20_t))
124
125
126 /*
127 ** How to know if header size is short or long?
128 ** The short header size can be 0-127 bytes long. If MS Bit of ph_RecordSize
129 ** is set then record size has 2 bytes
130 */
131 #define NSPR_V20RECORDSIZE_2BYTES       0x80U
132
133 /* Performance Data Header with device number */
134 typedef struct nspr_headerdev_v10
135 {
136     guint8 ph_RecordType[2]; /* Record Type */
137     guint8 ph_RecordSize[2]; /* Record Size including header */
138     guint8 ph_DevNo[4];      /* Network Device (NIC/CONN) number */
139 } nspr_headerdev_v10_t;
140 #define nspr_headerdev_v10_s    ((guint32)sizeof(nspr_headerdev_v10_t))
141
142 typedef struct nspr_hd_v10
143 {
144     nspr_header_v10_t phd; /* performance header */
145 } nspr_hd_v10_t;
146 #define nspr_hd_v10_s    ((guint32)sizeof(nspr_hd_v10_t))
147
148 typedef struct nspr_hdev_v10
149 {
150     nspr_headerdev_v10_t phd; /* performance header */
151 } nspr_hdev_v10_t;
152 #define nspr_hdev_v10_s    ((guint32)sizeof(nspr_hdev_v10_t))
153
154 /* if structure has defined phd as first field, it can use following names */
155 #define nsprRecordType    phd.ph_RecordType
156 #define nsprRecordSize    phd.ph_RecordSize
157 #define nsprReserved      phd.ph_Reserved
158 #define nsprRecordTypeOrg phd.ph_Reserved
159 #define nsprDevNo         phd.ph_DevNo
160
161 /* NSPR_SIGNATURE_V10 structure */
162 #define NSPR_SIGSIZE_V10        56 /* signature value size in bytes */
163 typedef struct nspr_signature_v10
164 {
165     nspr_header_v10_t phd; /* performance header */
166     guint8 sig_EndianType; /* Endian Type for the data */
167     guint8 sig_Reserved0;
168     guint8 sig_Reserved1[2];
169     gchar sig_Signature[NSPR_SIGSIZE_V10]; /* Signature value */
170 } nspr_signature_v10_t;
171 #define nspr_signature_v10_s    ((guint32)sizeof(nspr_signature_v10_t))
172
173 /* NSPR_SIGNATURE_V20 structure */
174 #define NSPR_SIGSIZE_V20        sizeof(NSPR_SIGSTR_V20) /* signature value size in bytes */
175 typedef struct nspr_signature_v20
176 {
177     NSPR_HEADER_V20(sig);  /* short performance header */
178     guint8 sig_EndianType; /* Endian Type for the data */
179     gchar sig_Signature[NSPR_SIGSIZE_V20]; /* Signature value */
180 } nspr_signature_v20_t;
181 #define nspr_signature_v20_s    ((guint32)sizeof(nspr_signature_v20_t))
182
183 /* NSPR_SIGNATURE_V30 structure */
184 #define NSPR_SIGSIZE_V30        sizeof(NSPR_SIGSTR_V30) /* signature value size in bytes */
185 typedef struct nspr_signature_v30
186 {
187     NSPR_HEADER_V20(sig);  /* short performance header */
188     guint8 sig_EndianType; /* Endian Type for the data */
189     gchar sig_Signature[NSPR_SIGSIZE_V30]; /* Signature value */
190 } nspr_signature_v30_t;
191 #define nspr_signature_v30_s    ((guint32)sizeof(nspr_signature_v30_t))
192
193 #define NSPR_SIGSIZE_V35        sizeof(NSPR_SIGSTR_V35) /* signature value size in bytes */
194 typedef struct nspr_signature_v35
195 {
196     NSPR_HEADER_V20(sig);  /* short performance header */
197     guint8 sig_EndianType; /* Endian Type for the data */
198     gchar sig_Signature[NSPR_SIGSIZE_V35]; /* Signature value */
199 } nspr_signature_v35_t;
200 #define nspr_signature_v35_s    ((guint32)sizeof(nspr_signature_v35_t))
201
202 /* NSPR_ABSTIME_V10 and NSPR_SYSTARTIME_V10 structure */
203 typedef struct nspr_abstime_v10
204 {
205     nspr_header_v10_t phd; /* performance header */
206     guint8 abs_RelTime[4]; /* relative time is ms from last time */
207     guint8 abs_Time[4];    /* absolute time in seconds from 1970 */
208 } nspr_abstime_v10_t;
209 #define nspr_abstime_v10_s    ((guint32)sizeof(nspr_abstime_v10_t))
210
211
212 /* NSPR_ABSTIME_V20 and NSPR_SYSTARTIME_V20 structure */
213 typedef struct nspr_abstime_v20
214 {
215     NSPR_HEADER_V20(abs);  /* short performance header */
216     guint8 abs_RelTime[2]; /* relative time is ms from last time */
217     guint8 abs_Time[4];    /* absolute time in seconds from 1970 */
218 } nspr_abstime_v20_t;
219 #define nspr_abstime_v20_s    ((guint32)sizeof(nspr_abstime_v20_t))
220
221
222
223 /* full packet trace structure */
224 typedef struct nspr_pktracefull_v10
225 {
226     nspr_headerdev_v10_t phd; /* performance header */
227     guint8 fp_RelTimeHr[4];   /* High resolution relative time */
228 } nspr_pktracefull_v10_t;
229 #define nspr_pktracefull_v10_s    ((guint32)(sizeof(nspr_pktracefull_v10_t)))
230
231 /* new full packet trace structure v20 */
232 typedef struct nspr_pktracefull_v20
233 {
234     NSPR_HEADER3B_V20(fp);  /* long performance header */
235     guint8 fp_DevNo;        /* Network Device (NIC) number */
236     guint8 fp_RelTimeHr[4]; /* High resolution relative time */
237 } nspr_pktracefull_v20_t;
238 #define nspr_pktracefull_v20_s    ((guint32)(sizeof(nspr_pktracefull_v20_t)))
239
240 /* new full packet trace structure v21 */
241 typedef struct nspr_pktracefull_v21
242 {
243     NSPR_HEADER3B_V21(fp);  /* long performance header */
244     guint8 fp_DevNo;        /* Network Device (NIC) number */
245     guint8 fp_RelTimeHr[4]; /* High resolution relative time */
246     guint8 fp_PcbDevNo[4];  /* PCB devno */
247     guint8 fp_lPcbDevNo[4]; /* link PCB devno */
248 } nspr_pktracefull_v21_t;
249 #define nspr_pktracefull_v21_s    ((guint32)(sizeof(nspr_pktracefull_v21_t)))
250
251 /* new full packet trace structure v22 */
252 typedef struct nspr_pktracefull_v22
253 {
254     NSPR_HEADER3B_V22(fp);  /* long performance header */
255     guint8 fp_DevNo;        /* Network Device (NIC) number */
256     guint8 fp_RelTimeHr[4]; /* High resolution relative time */
257     guint8 fp_PcbDevNo[4];  /* PCB devno */
258     guint8 fp_lPcbDevNo[4]; /* link PCB devno */
259     guint8 fp_VlanTag[2];   /* vlan tag */
260 } nspr_pktracefull_v22_t;
261 #define nspr_pktracefull_v22_s    ((guint32)(sizeof(nspr_pktracefull_v22_t)))
262
263 typedef struct nspr_pktracefull_v23
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 */
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 } nspr_pktracefull_v23_t;
273 #define nspr_pktracefull_v23_s    ((guint32)(sizeof(nspr_pktracefull_v23_t)))
274
275 /* New full packet trace structure v24 for cluster tracing */
276 typedef struct nspr_pktracefull_v24
277 {
278     NSPR_HEADER3B_V22(fp);   /* long performance header */
279     guint8 fp_DevNo;         /* Network Device (NIC) number */
280     guint8 fp_AbsTimeHr[8];  /* High resolution absolute time in nanosec */
281     guint8 fp_PcbDevNo[4];   /* PCB devno */
282     guint8 fp_lPcbDevNo[4];  /* link PCB devno */
283     guint8 fp_VlanTag[2];    /* vlan tag */
284     guint8 fp_Coreid[2];     /* coreid of the packet */
285     guint8 fp_srcNodeId[2];  /* source node # */
286     guint8 fp_destNodeId[2]; /* destination node # */
287     guint8 fp_clFlags;       /* cluster flags */
288 } nspr_pktracefull_v24_t;
289 #define nspr_pktracefull_v24_s    ((guint32)(sizeof(nspr_pktracefull_v24_t)))
290
291 /* New full packet trace structure v25 for vm info tracing */
292 typedef struct nspr_pktracefull_v25
293 {
294     NSPR_HEADER3B_V22(fp);    /* long performance header */
295     guint8 fp_DevNo;          /* Network Device (NIC) number */
296     guint8 fp_AbsTimeHr[8];   /* High resolution absolute time in nanosec */
297     guint8 fp_PcbDevNo[4];    /* PCB devno */
298     guint8 fp_lPcbDevNo[4];   /* link PCB devno */
299     guint8 fp_VlanTag[2];     /* vlan tag */
300     guint8 fp_Coreid[2];      /* coreid of the packet */
301     guint8 fp_srcNodeId[2];   /* source node # */
302     guint8 fp_destNodeId[2];  /* destination node # */
303     guint8 fp_clFlags;        /* cluster flags */
304     guint8 fp_src_vmname_len; /* vm src info */
305     guint8 fp_dst_vmname_len; /* vm src info */
306 } nspr_pktracefull_v25_t;
307 #define nspr_pktracefull_v25_s    ((guint32)(sizeof(nspr_pktracefull_v25_t)))
308
309 /* New full packet trace structure v26 for vm info tracing */
310 typedef struct nspr_pktracefull_v26
311 {
312     NSPR_HEADER3B_V22(fp);     /* long performance header */
313     guint8 fp_DevNo;           /* Network Device (NIC) number */
314     guint8 fp_AbsTimeHr[8];    /* High resolution absolute time in nanosec */
315     guint8 fp_PcbDevNo[4];     /* PCB devno */
316     guint8 fp_lPcbDevNo[4];    /* link PCB devno */
317     guint8 fp_VlanTag[2];      /* vlan tag */
318     guint8 fp_Coreid[2];       /* coreid of the packet */
319     guint8 fp_srcNodeId[2];    /* source node # */
320     guint8 fp_destNodeId[2];   /* destination node # */
321     guint8 fp_clFlags;         /* cluster flags */
322     guint8 fp_src_vmname_len;  /* vm src info */
323     guint8 fp_dst_vmname_len;  /* vm src info */
324     guint8 fp_reserved;
325     guint8 fp_ns_activity[4];
326     guint8 fp_reserved_32[12]; /* Adding more field to reduce wireshark changes every time */
327 } nspr_pktracefull_v26_t;
328 #define nspr_pktracefull_v26_s    ((guint32)(sizeof(nspr_pktracefull_v26_t)))
329
330 /* partial packet trace structure */
331 typedef struct nspr_pktracepart_v10
332 {
333     nspr_headerdev_v10_t phd; /* performance header */
334     guint8 pp_RelTimeHr[4];   /* High resolution relative time */
335     guint8 pp_PktSizeOrg[2];  /* Original packet size */
336     guint8 pp_PktOffset[2];   /* starting offset in packet */
337 } nspr_pktracepart_v10_t;
338 #define nspr_pktracepart_v10_s    ((guint32)(sizeof(nspr_pktracepart_v10_t)))
339
340 /* new partial packet trace structure */
341 typedef struct nspr_pktracepart_v20
342 {
343     NSPR_HEADER3B_V20(pp);   /* long performance header */
344     guint8 pp_DevNo;         /* Network Device (NIC) number */
345     guint8 pp_RelTimeHr[4];  /* High resolution relative time */
346     guint8 pp_PktSizeOrg[2]; /* Original packet size */
347     guint8 pp_PktOffset[2];  /* starting offset in packet */
348 } nspr_pktracepart_v20_t;
349 #define nspr_pktracepart_v20_s    ((guint32)(sizeof(nspr_pktracepart_v20_t)))
350
351 /* new partial packet trace structure */
352 typedef struct nspr_pktracepart_v21
353 {
354     NSPR_HEADER3B_V21(pp);   /* long performance header */
355     guint8 pp_DevNo;         /* Network Device (NIC) number */
356     guint8 pp_RelTimeHr[4];  /* High resolution relative time */
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 } nspr_pktracepart_v21_t;
362 #define nspr_pktracepart_v21_s    ((guint32)(sizeof(nspr_pktracepart_v21_t)))
363
364 /* new partial packet trace structure v22 */
365 typedef struct nspr_pktracepart_v22
366 {
367     NSPR_HEADER3B_V22(pp);   /* long performance header */
368     guint8 pp_DevNo;         /* Network Device (NIC) number */
369     guint8 pp_RelTimeHr[4];  /* High resolution relative time */
370     guint8 pp_PktSizeOrg[2]; /* Original packet size */
371     guint8 pp_PktOffset[2];  /* starting offset in packet */
372     guint8 pp_PcbDevNo[4];   /* PCB devno */
373     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
374     guint8 pp_VlanTag[2];    /* Vlan Tag */
375 } nspr_pktracepart_v22_t;
376 #define nspr_pktracepart_v22_s    ((guint32)(sizeof(nspr_pktracepart_v22_t)))
377
378 typedef struct nspr_pktracepart_v23
379 {
380     NSPR_HEADER3B_V22(pp);   /* long performance header */
381     guint8 pp_DevNo;         /* Network Device (NIC) number */
382     guint8 pp_AbsTimeHr[8];  /* High resolution absolute time */
383     guint8 pp_PktSizeOrg[2]; /* Original packet size */
384     guint8 pp_PktOffset[2];  /* starting offset in packet */
385     guint8 pp_PcbDevNo[4];   /* PCB devno */
386     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
387     guint8 pp_VlanTag[2];    /* vlan tag */
388     guint8 pp_Coreid[2];     /* Coreid of the packet */
389 } nspr_pktracepart_v23_t;
390 #define nspr_pktracepart_v23_s    ((guint32)(sizeof(nspr_pktracepart_v23_t)))
391
392 /* New partial packet trace structure v24 for cluster tracing */
393 typedef struct nspr_pktracepart_v24
394 {
395     NSPR_HEADER3B_V22(pp);   /* long performance header */
396     guint8 pp_DevNo;         /* Network Device (NIC) number */
397     guint8 pp_AbsTimeHr[8];  /*High resolution absolute time in nanosec*/
398     guint8 pp_PktSizeOrg[2]; /* Original packet size */
399     guint8 pp_PktOffset[2];  /* starting offset in packet */
400     guint8 pp_PcbDevNo[4];   /* PCB devno */
401     guint8 pp_lPcbDevNo[4];  /* link PCB devno */
402     guint8 pp_VlanTag[2];    /* vlan tag */
403     guint8 pp_Coreid[2];     /* Coreid of the packet */
404     guint8 pp_srcNodeId[2];  /* source node # */
405     guint8 pp_destNodeId[2]; /* destination node # */
406     guint8 pp_clFlags;       /* cluster flags */
407 } nspr_pktracepart_v24_t;
408 #define nspr_pktracepart_v24_s    ((guint32)(sizeof(nspr_pktracepart_v24_t)))
409
410 /* New partial packet trace structure v25 for vm info tracing */
411 typedef struct nspr_pktracepart_v25
412 {
413     NSPR_HEADER3B_V22(pp);    /* long performance header */
414     guint8 pp_DevNo;          /* Network Device (NIC) number */
415     guint8 pp_AbsTimeHr[8];   /*High resolution absolute time in nanosec*/
416     guint8 pp_PktSizeOrg[2];  /* Original packet size */
417     guint8 pp_PktOffset[2];   /* starting offset in packet */
418     guint8 pp_PcbDevNo[4];    /* PCB devno */
419     guint8 pp_lPcbDevNo[4];   /* link PCB devno */
420     guint8 pp_VlanTag[2];     /* vlan tag */
421     guint8 pp_Coreid[2];      /* Coreid of the packet */
422     guint8 pp_srcNodeId[2];   /* source node # */
423     guint8 pp_destNodeId[2];  /* destination node # */
424     guint8 pp_clFlags;        /* cluster flags */
425     guint8 pp_src_vmname_len; /* vm info */
426     guint8 pp_dst_vmname_len; /* vm info */
427 } nspr_pktracepart_v25_t;
428 #define nspr_pktracepart_v25_s    ((guint32)(sizeof(nspr_pktracepart_v25_t)))
429
430 /* New full packet trace structure v30 for multipage spanning data */
431 typedef struct  nspr_pktracefull_v30
432 {
433     NSPR_HEADER3B_V30(fp);  /* long performance header */
434     guint8 fp_DevNo;   /* Network Device (NIC) number */
435     guint8 fp_AbsTimeHr[8];  /*High resolution absolute time in nanosec*/
436     guint8 fp_PcbDevNo[4];    /* PCB devno */
437     guint8 fp_lPcbDevNo[4];   /* link PCB devno */
438     guint8 fp_PktSizeOrg[2];  /* Original packet size */
439     guint8 fp_VlanTag[2]; /* vlan tag */
440     guint8 fp_Coreid[2]; /* coreid of the packet */
441     guint8 fp_srcNodeId[2]; /* cluster nodeid of the packet */
442     guint8 fp_destNodeId[2];
443     guint8 fp_clFlags;
444     guint8 fp_src_vmname_len;
445     guint8 fp_dst_vmname_len;
446     guint8 fp_reserved[3];
447     guint8 fp_ns_activity[4];
448     guint8 fp_reserved_32[12];
449 } nspr_pktracefull_v30_t;
450 #define nspr_pktracefull_v30_s  ((guint32)(sizeof(nspr_pktracefull_v30_t)))
451
452 /* New full packet trace structure v35 for multipage spanning data */
453 typedef struct  nspr_pktracefull_v35
454 {
455     NSPR_HEADER3B_V30(fp);  /* long performance header */
456     guint8 fp_DevNo;   /* Network Device (NIC) number */
457     guint8 fp_AbsTimeHr[8];  /*High resolution absolute time in nanosec*/
458     guint8 fp_PcbDevNo[4];    /* PCB devno */
459     guint8 fp_lPcbDevNo[4];   /* link PCB devno */
460     guint8 fp_PktSizeOrg[2];  /* Original packet size */
461     guint8 fp_VlanTag[2]; /* vlan tag */
462     guint8 fp_Coreid[2]; /* coreid of the packet */
463     guint8 fp_headerlen[2];
464     guint8 fp_errorcode;
465     guint8 fp_app;
466     guint8 fp_ns_activity[4];
467     guint8 fp_nextrectype;
468 } nspr_pktracefull_v35_t;
469 #define nspr_pktracefull_v35_s  ((guint32)(sizeof(nspr_pktracefull_v35_t)))
470
471 /* New partial packet trace structure v26 for vm info tracing */
472 typedef struct nspr_pktracepart_v26
473 {
474     NSPR_HEADER3B_V22(pp);     /* long performance header */
475     guint8 pp_DevNo;           /* Network Device (NIC) number */
476     guint8 pp_AbsTimeHr[8];    /*High resolution absolute time in nanosec*/
477     guint8 pp_PktSizeOrg[2];   /* Original packet size */
478     guint8 pp_PktOffset[2];    /* starting offset in packet */
479     guint8 pp_PcbDevNo[4];     /* PCB devno */
480     guint8 pp_lPcbDevNo[4];    /* link PCB devno */
481     guint8 pp_VlanTag[2];      /* vlan tag */
482     guint8 pp_Coreid[2];       /* Coreid of the packet */
483     guint8 pp_srcNodeId[2];    /* source node # */
484     guint8 pp_destNodeId[2];   /* destination node # */
485     guint8 pp_clFlags;         /* cluster flags */
486     guint8 pp_src_vmname_len;  /* vm info */
487     guint8 pp_dst_vmname_len;  /* vm info */
488     guint8 pp_reserved;
489     guint8 pp_ns_activity[4];
490     guint8 pp_reserved_32[12]; /* Adding more field to reduce wireshark changes every time */
491 } nspr_pktracepart_v26_t;
492 #define nspr_pktracepart_v26_s    ((guint32)(sizeof(nspr_pktracepart_v26_t)))
493
494 #define __TNDO(phdr,enumprefix,structname,hdrname)\
495     static const guint8 enumprefix##_##hdrname##_offset = (guint8)sizeof(nspr_##structname##_t);
496
497 #define __TNO(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
498     static const guint8 enumprefix##_##hdrname##_offset = (guint8)GPOINTER_TO_INT(offsetof(nspr_##structname##_t,structprefix##_##structfieldname));
499
500 #define __TNL(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
501     static const guint8 enumprefix##_##hdrname##_len = (guint8)sizeof(((nspr_##structname##_t*)0)->structprefix##_##structfieldname);
502
503 #define __TNV1O(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
504     static const guint8 enumprefix##_##hdrname##_offset = (guint8)GPOINTER_TO_INT(offsetof(nspr_##structname##_t,structfieldname));
505
506 #define __TNV1L(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
507     static const guint8 enumprefix##_##hdrname##_len = (guint8)sizeof(((nspr_##structname##_t*)0)->structfieldname);
508
509 #define TRACE_V10_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
510     __TNV1O(phdr,enumprefix,structprefix,structname,dir,phd.ph_RecordType)\
511     __TNV1L(phdr,enumprefix,structprefix,structname,dir,phd.ph_RecordType)\
512     __TNV1O(phdr,enumprefix,structprefix,structname,nicno,phd.ph_DevNo)\
513     __TNV1L(phdr,enumprefix,structprefix,structname,nicno,phd.ph_DevNo)\
514     __TNDO(phdr,enumprefix,structname,eth)
515
516 #define TRACE_V20_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
517     __TNO(phdr,enumprefix,structprefix,structname,dir,RecordType)\
518     __TNL(phdr,enumprefix,structprefix,structname,dir,RecordType)\
519     __TNO(phdr,enumprefix,structprefix,structname,nicno,DevNo)\
520     __TNL(phdr,enumprefix,structprefix,structname,nicno,DevNo)\
521     __TNDO(phdr,enumprefix,structname,eth)
522
523 #define TRACE_V21_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
524     TRACE_V20_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
525     __TNO(phdr,enumprefix,structprefix,structname,pcb,PcbDevNo)\
526     __TNO(phdr,enumprefix,structprefix,structname,l_pcb,lPcbDevNo)
527
528 #define TRACE_V22_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
529     TRACE_V21_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
530     __TNO(phdr,enumprefix,structprefix,structname,vlantag,VlanTag)
531
532 #define TRACE_V23_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
533     TRACE_V22_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
534     __TNO(phdr,enumprefix,structprefix,structname,coreid,Coreid)
535
536 #define TRACE_V24_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
537     TRACE_V23_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
538     __TNO(phdr,enumprefix,structprefix,structname,srcnodeid,srcNodeId)\
539     __TNO(phdr,enumprefix,structprefix,structname,destnodeid,destNodeId)\
540     __TNO(phdr,enumprefix,structprefix,structname,clflags,clFlags)
541
542 #define TRACE_V25_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
543     TRACE_V24_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
544     __TNO(phdr,enumprefix,structprefix,structname,src_vmname_len,src_vmname_len)\
545     __TNO(phdr,enumprefix,structprefix,structname,dst_vmname_len,dst_vmname_len)\
546     __TNDO(phdr,enumprefix,structname,data)
547
548 #define TRACE_V26_REC_LEN_OFF(phdr,enumprefix,structprefix,structname) \
549     TRACE_V25_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
550     __TNO(phdr,enumprefix,structprefix,structname,ns_activity,ns_activity)\
551
552 #define TRACE_V30_REC_LEN_OFF(phdr, enumprefix, structprefix, structname) \
553     TRACE_V26_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
554
555 #define TRACE_V35_REC_LEN_OFF(phdr, enumprefix, structprefix, structname) \
556     TRACE_V23_REC_LEN_OFF(phdr,enumprefix,structprefix,structname)\
557     __TNDO(phdr,enumprefix,structname,data)\
558     __TNO(phdr,enumprefix,structprefix,structname,ns_activity,ns_activity)
559
560     TRACE_V10_REC_LEN_OFF(NULL,v10_part,pp,pktracepart_v10)
561     TRACE_V10_REC_LEN_OFF(NULL,v10_full,fp,pktracefull_v10)
562     TRACE_V20_REC_LEN_OFF(NULL,v20_part,pp,pktracepart_v20)
563     TRACE_V20_REC_LEN_OFF(NULL,v20_full,fp,pktracefull_v20)
564     TRACE_V21_REC_LEN_OFF(NULL,v21_part,pp,pktracepart_v21)
565     TRACE_V21_REC_LEN_OFF(NULL,v21_full,fp,pktracefull_v21)
566     TRACE_V22_REC_LEN_OFF(NULL,v22_part,pp,pktracepart_v22)
567     TRACE_V22_REC_LEN_OFF(NULL,v22_full,fp,pktracefull_v22)
568     TRACE_V23_REC_LEN_OFF(NULL,v23_part,pp,pktracepart_v23)
569     TRACE_V23_REC_LEN_OFF(NULL,v23_full,fp,pktracefull_v23)
570     TRACE_V24_REC_LEN_OFF(NULL,v24_part,pp,pktracepart_v24)
571     TRACE_V24_REC_LEN_OFF(NULL,v24_full,fp,pktracefull_v24)
572     TRACE_V25_REC_LEN_OFF(NULL,v25_part,pp,pktracepart_v25)
573     TRACE_V25_REC_LEN_OFF(NULL,v25_full,fp,pktracefull_v25)
574     TRACE_V26_REC_LEN_OFF(NULL,v26_part,pp,pktracepart_v26)
575     TRACE_V26_REC_LEN_OFF(NULL,v26_full,fp,pktracefull_v26)
576     TRACE_V30_REC_LEN_OFF(NULL,v30_full,fp,pktracefull_v30)
577     TRACE_V35_REC_LEN_OFF(NULL,v35_full,fp,pktracefull_v35)
578
579 #undef __TNV1O
580 #undef __TNV1L
581 #undef __TNO
582 #undef __TNDO
583 #undef __TNL
584
585
586 #define ns_setabstime(nstrace, AbsoluteTime, RelativeTimems) \
587     do { \
588         (nstrace)->nspm_curtime = AbsoluteTime; \
589         (nstrace)->nspm_curtimemsec += RelativeTimems; \
590         (nstrace)->nspm_curtimelastmsec = nstrace->nspm_curtimemsec; \
591     } while(0)
592
593
594 #define ns_setrelativetime(nstrace, RelativeTimems) \
595     do { \
596         guint32    rsec; \
597         (nstrace)->nspm_curtimemsec += RelativeTimems; \
598         rsec = (guint32)((nstrace)->nspm_curtimemsec - (nstrace)->nspm_curtimelastmsec)/1000; \
599         (nstrace)->nspm_curtime += rsec; \
600         (nstrace)->nspm_curtimelastmsec += rsec * 1000; \
601     } while (0)
602
603
604 typedef struct {
605     gchar  *pnstrace_buf;
606     gint64  xxx_offset;
607     guint32 nstrace_buf_offset;
608     guint32 nstrace_buflen;
609     /* Performance Monitor Time variables */
610     guint32 nspm_curtime;         /* current time since 1970 */
611     guint64 nspm_curtimemsec;     /* current time in milliseconds */
612     guint64 nspm_curtimelastmsec; /* nspm_curtime last update time in milliseconds */
613     guint64 nsg_creltime;
614     guint64 file_size;
615 } nstrace_t;
616
617 static guint32 nspm_signature_version(wtap*, gchar*, gint32);
618 static gboolean nstrace_read_v10(wtap *wth, int *err, gchar **err_info,
619                                  gint64 *data_offset);
620 static gboolean nstrace_read_v20(wtap *wth, int *err, gchar **err_info,
621                                  gint64 *data_offset);
622 static gboolean nstrace_read_v30(wtap *wth, int *err, gchar **err_info,
623                                  gint64 *data_offset);
624 static gboolean nstrace_seek_read_v10(wtap *wth, gint64 seek_off,
625                                       struct wtap_pkthdr *phdr,
626                                       Buffer *buf,
627                                       int *err, gchar **err_info);
628 static gboolean nstrace_seek_read_v20(wtap *wth, gint64 seek_off,
629                                       struct wtap_pkthdr *phdr,
630                                       Buffer *buf,
631                                       int *err, gchar **err_info);
632 static gboolean nstrace_seek_read_v30(wtap *wth, gint64 seek_off,
633                                       struct wtap_pkthdr *phdr,
634                                       Buffer *buf,
635                                       int *err, gchar **err_info);
636 static void nstrace_close(wtap *wth);
637
638 static gboolean nstrace_set_start_time_v10(wtap *wth, int *err,
639                                            gchar **err_info);
640 static gboolean nstrace_set_start_time_v20(wtap *wth, int *err,
641                                            gchar **err_info);
642 static gboolean nstrace_set_start_time(wtap *wth, int *err, gchar **err_info);
643 static guint64 ns_hrtime2nsec(guint32 tm);
644
645 static gboolean nstrace_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
646                              const guint8 *pd, int *err, gchar **err_info);
647
648
649 /*
650  * Minimum of the page size and the amount of data left in the file;
651  * the last page of a file can be short.
652  */
653 #define GET_READ_PAGE_SIZE(remaining_file_size) ((gint32)((remaining_file_size>NSPR_PAGESIZE)?NSPR_PAGESIZE:remaining_file_size))
654 #define GET_READ_PAGE_SIZEV3(remaining_file_size) ((gint32)((remaining_file_size>NSPR_PAGESIZE_TRACE)?NSPR_PAGESIZE_TRACE:remaining_file_size))
655
656 static guint64 ns_hrtime2nsec(guint32 tm)
657 {
658     guint32    val = tm & NSPR_HRTIME_MASKTM;
659     switch(tm & NSPR_HRTIME_MASKFMT)
660     {
661     case NSPR_HRTIME_SEC:     return (guint64)val*1000000000;
662     case NSPR_HRTIME_MSEC:    return (guint64)val*1000000;
663     case NSPR_HRTIME_USEC:    return (guint64)val*1000;
664     case NSPR_HRTIME_NSEC:    return val;
665     }
666     return tm;
667 }
668
669 static gboolean
670 nstrace_read_buf(FILE_T fh, void *buf, guint32 buflen, int *err,
671     gchar **err_info)
672 {
673     int bytes_read;
674
675     bytes_read = file_read(buf, buflen, fh);
676     if (bytes_read < 0) {
677         *err = file_error(fh, err_info);
678         return FALSE;
679     }
680     if ((guint32)bytes_read != buflen) {
681         /*
682          * XXX - for which files can the last page be short?
683          */
684         *err = 0;
685         return FALSE;
686     }
687     return TRUE;
688 }
689
690 /*
691 ** Netscaler trace format open routines
692 */
693 wtap_open_return_val nstrace_open(wtap *wth, int *err, gchar **err_info)
694 {
695     gchar *nstrace_buf;
696     gint64 file_size;
697     gint32 page_size;
698     nstrace_t *nstrace;
699
700
701     if ((file_size = wtap_file_size(wth, err)) == -1)
702         return WTAP_OPEN_NOT_MINE;
703
704     nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE);
705     page_size = GET_READ_PAGE_SIZE(file_size);
706
707     switch ((wth->file_type_subtype = nspm_signature_version(wth, nstrace_buf, page_size)))
708     {
709     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0:
710         wth->file_encap = WTAP_ENCAP_NSTRACE_1_0;
711         break;
712
713     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0:
714         wth->file_encap = WTAP_ENCAP_NSTRACE_2_0;
715         break;
716
717     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0:
718         wth->file_encap = WTAP_ENCAP_NSTRACE_3_0;
719         g_free(nstrace_buf);
720         nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE_TRACE);
721         page_size = GET_READ_PAGE_SIZEV3(file_size);
722         break;
723
724     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5:
725         wth->file_encap = WTAP_ENCAP_NSTRACE_3_5;
726         g_free(nstrace_buf);
727         nstrace_buf = (gchar *)g_malloc(NSPR_PAGESIZE_TRACE);
728         page_size = GET_READ_PAGE_SIZEV3(file_size);
729         break;
730
731     default:
732         /* No known signature found, assume it's not NetScaler */
733         g_free(nstrace_buf);
734         return WTAP_OPEN_NOT_MINE;
735     }
736
737     if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1)
738     {
739         g_free(nstrace_buf);
740         return WTAP_OPEN_ERROR;
741     }
742
743     if (!wtap_read_bytes(wth->fh, nstrace_buf, page_size, err, err_info))
744     {
745         g_free(nstrace_buf);
746         if (*err != WTAP_ERR_SHORT_READ)
747             return WTAP_OPEN_ERROR;
748         return WTAP_OPEN_NOT_MINE;
749     }
750
751     switch (wth->file_type_subtype)
752     {
753     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0:
754         wth->subtype_read = nstrace_read_v10;
755         wth->subtype_seek_read = nstrace_seek_read_v10;
756         break;
757
758     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0:
759         wth->subtype_read = nstrace_read_v20;
760         wth->subtype_seek_read = nstrace_seek_read_v20;
761         break;
762
763     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0:
764         wth->subtype_read = nstrace_read_v30;
765         wth->subtype_seek_read = nstrace_seek_read_v30;
766         break;
767
768     case WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5:
769         wth->subtype_read = nstrace_read_v30;
770         wth->subtype_seek_read = nstrace_seek_read_v30;
771         break;
772     }
773     wth->subtype_close = nstrace_close;
774
775     nstrace = (nstrace_t *)g_malloc(sizeof(nstrace_t));
776     wth->priv = (void *)nstrace;
777     nstrace->pnstrace_buf = nstrace_buf;
778     nstrace->xxx_offset = 0;
779     nstrace->nstrace_buflen = page_size;
780     nstrace->nstrace_buf_offset = 0;
781     nstrace->nspm_curtime = 0;
782     nstrace->nspm_curtimemsec = 0;
783     nstrace->nspm_curtimelastmsec = 0;
784     nstrace->nsg_creltime = 0;
785     nstrace->file_size = file_size;
786
787
788     /* Set the start time by looking for the abstime record */
789     if ((nstrace_set_start_time(wth, err, err_info)) == FALSE)
790     {
791         /*
792          * No absolute time record seen, so we just reset the read
793          * pointer to the start of the file, so we start reading
794          * at the first record, rather than skipping records up
795          * to and including an absolute time record.
796          */
797         if (*err != 0)
798         {
799             /* We got an error reading the records. */
800             return WTAP_OPEN_ERROR;
801         }
802         if ((file_seek(wth->fh, 0, SEEK_SET, err)) == -1)
803         {
804             return WTAP_OPEN_ERROR;
805         }
806
807         /* Read the first page of data */
808         if (!wtap_read_bytes(wth->fh, nstrace_buf, page_size, err, err_info))
809         {
810             return WTAP_OPEN_ERROR;
811         }
812
813         /* reset the buffer offset */
814         nstrace->nstrace_buf_offset = 0;
815     }
816
817     wth->file_tsprec = WTAP_TSPREC_NSEC;
818     wth->phdr.ts.secs = nstrace->nspm_curtime;
819     wth->phdr.ts.nsecs = 0;
820
821     *err = 0;
822     return WTAP_OPEN_MINE;
823 }
824
825
826 #define nspm_signature_func(ver) \
827     static guint32 nspm_signature_isv##ver(gchar *sigp) {\
828         return strncmp(sigp,NSPR_SIGSTR_V##ver,(sizeof(NSPR_SIGSTR_V##ver)-1));\
829     }
830
831 nspm_signature_func(10)
832 nspm_signature_func(20)
833 nspm_signature_func(30)
834 nspm_signature_func(35)
835
836 /*
837 ** Check signature and return the file type and subtype for files with
838 ** that signature.  If it finds no signature that it recognizes, it
839 ** returns WTAP_FILE_TYPE_SUBTYPE_UNKNOWN. At the time of return from
840 ** this function we might not be at the first page. So after a call to
841 ** this function, there has to be a file seek to return to the start
842 ** of the first page.
843 */
844 static guint32
845 nspm_signature_version(wtap *wth, gchar *nstrace_buf, gint32 len)
846 {
847     gchar *dp = nstrace_buf;
848     int bytes_read;
849
850     bytes_read = file_read(dp, len, wth->fh);
851     if (bytes_read == len) {
852
853         for ( ; len > (gint32)(MIN(sizeof(NSPR_SIGSTR_V10), sizeof(NSPR_SIGSTR_V20))); dp++, len--)
854         {
855 #define sigv10p    ((nspr_signature_v10_t*)dp)
856             if ((pletoh16(&sigv10p->nsprRecordType) == NSPR_SIGNATURE_V10) &&
857                 (pletoh16(&sigv10p->nsprRecordSize) <= len) &&
858                 ((gint32)sizeof(NSPR_SIGSTR_V10) <= len) &&
859                 (!nspm_signature_isv10(sigv10p->sig_Signature)))
860                 return WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0;
861 #undef    sigv10p
862
863 #define sigv20p    ((nspr_signature_v20_t*)dp)
864             if ((sigv20p->sig_RecordType == NSPR_SIGNATURE_V20) &&
865                 (sigv20p->sig_RecordSize <= len) &&
866                 ((gint32)sizeof(NSPR_SIGSTR_V20) <= len))
867             {
868                 if (!nspm_signature_isv20(sigv20p->sig_Signature)){
869                     return WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0;
870                 } else if (!nspm_signature_isv30(sigv20p->sig_Signature)){
871                     return WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0;
872                 }else if (!nspm_signature_isv35(sigv20p->sig_Signature)){
873                     return WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5;
874                 }
875             }
876 #undef    sigv20p
877         }
878     }
879
880     return WTAP_FILE_TYPE_SUBTYPE_UNKNOWN;    /* no version found */
881 }
882
883 #define nspr_getv10recordtype(hdp) (pletoh16(&(hdp)->nsprRecordType))
884 #define nspr_getv10recordsize(hdp) (pletoh16(&(hdp)->nsprRecordSize))
885 #define nspr_getv20recordtype(hdp) ((hdp)->phd_RecordType)
886 #define nspr_getv20recordsize(hdp) \
887     (guint32)(((hdp)->phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES)? \
888         (((hdp)->phd_RecordSizeHigh * NSPR_V20RECORDSIZE_2BYTES)+ \
889          ((hdp)->phd_RecordSizeLow & ~NSPR_V20RECORDSIZE_2BYTES)) : \
890           (hdp)->phd_RecordSizeLow)
891
892
893 #define nstrace_set_start_time_ver(ver) \
894     gboolean nstrace_set_start_time_v##ver(wtap *wth, int *err, gchar **err_info) \
895     {\
896         nstrace_t *nstrace = (nstrace_t *)wth->priv;\
897         gchar* nstrace_buf = nstrace->pnstrace_buf;\
898         guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;\
899         guint32 nstrace_buflen = nstrace->nstrace_buflen;\
900         guint32 record_size;\
901         do\
902         {\
903             while (nstrace_buf_offset < nstrace_buflen)\
904             {\
905                 nspr_hd_v##ver##_t *fp = (nspr_hd_v##ver##_t *) &nstrace_buf[nstrace_buf_offset];\
906                 switch (nspr_getv##ver##recordtype(fp))\
907                 {\
908                     case NSPR_ABSTIME_V##ver:\
909                         ns_setabstime(nstrace, pletoh32(&((nspr_abstime_v##ver##_t *) fp)->abs_Time), pletoh16(&((nspr_abstime_v##ver##_t *) fp)->abs_RelTime));\
910                         nstrace->nstrace_buf_offset = nstrace_buf_offset + nspr_getv##ver##recordsize(fp);\
911                         nstrace->nstrace_buflen = nstrace_buflen;\
912                         return TRUE;\
913                      case NSPR_UNUSEDSPACE_V10:\
914                         nstrace_buf_offset = nstrace_buflen;\
915                         break;\
916                     default:\
917                         record_size = nspr_getv##ver##recordsize(fp);\
918                         if (record_size == 0) {\
919                             *err = WTAP_ERR_BAD_FILE;\
920                             *err_info = g_strdup("nstrace: zero size record found");\
921                             return FALSE;\
922                         }\
923                         nstrace_buf_offset += record_size;\
924                 }\
925             }\
926             nstrace_buf_offset = 0;\
927             nstrace->xxx_offset += nstrace_buflen;\
928             nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));\
929         }while((nstrace_buflen > 0) && (nstrace_read_buf(wth->fh, nstrace_buf, nstrace_buflen, err, err_info)));\
930         return FALSE;\
931     }
932
933 nstrace_set_start_time_ver(10)
934 nstrace_set_start_time_ver(20)
935
936 #undef nspr_getv10recordtype
937 #undef nspr_getv20recordtype
938
939 /*
940 ** Set the start time of the trace file. We look for the first ABSTIME record. We use that
941 ** to set the start time. Apart from that we also make sure that we remember the position of
942 ** the next record after the ABSTIME record. Inorder to report correct time values, all trace
943 ** records before the ABSTIME record are ignored.
944 */
945 static gboolean nstrace_set_start_time(wtap *wth, int *err, gchar **err_info)
946 {
947     if (wth->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
948         return nstrace_set_start_time_v10(wth, err, err_info);
949     else if (wth->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0)
950         return nstrace_set_start_time_v20(wth, err, err_info);
951     else if (wth->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0)
952         return nstrace_set_start_time_v20(wth, err, err_info);
953     return FALSE;
954 }
955
956 #define __TNDO(phdr,enumprefix,structname,hdrname)\
957     (phdr)->pseudo_header.nstr.hdrname##_offset = enumprefix##_##hdrname##_offset;
958
959 #define __TNO(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
960     (phdr)->pseudo_header.nstr.hdrname##_offset = enumprefix##_##hdrname##_offset;
961
962 #define __TNL(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
963     (phdr)->pseudo_header.nstr.hdrname##_len = enumprefix##_##hdrname##_len;
964
965 #define __TNV1O(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
966     __TNO(phdr,enumprefix,structprefix,structname,hdrname,structfieldname)
967
968 #define __TNV1L(phdr,enumprefix,structprefix,structname,hdrname,structfieldname) \
969     __TNL(phdr,enumprefix,structprefix,structname,hdrname,structfieldname)
970
971
972
973 /*
974 ** Netscaler trace format read routines.
975 **
976 ** The maximum value of the record data size is 65535, which is less than
977 ** WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
978 */
979 #define TIMEDEFV10(phdr,fp,type) \
980     do {\
981         (phdr)->presence_flags = WTAP_HAS_TS;\
982         nsg_creltime += ns_hrtime2nsec(pletoh32(&type->type##_RelTimeHr));\
983         (phdr)->ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
984         (phdr)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
985     }while(0)
986
987 #define PARTSIZEDEFV10(phdr,pp,ver) \
988     do {\
989         (phdr)->presence_flags |= WTAP_HAS_CAP_LEN;\
990         (phdr)->len = pletoh16(&pp->pp_PktSizeOrg) + nspr_pktracepart_v##ver##_s;\
991         (phdr)->caplen = pletoh16(&pp->nsprRecordSize);\
992     }while(0)
993
994 #define FULLSIZEDEFV10(phdr,fp,ver) \
995     do {\
996         (phdr)->len = pletoh16(&(fp)->nsprRecordSize);\
997         (phdr)->caplen = (phdr)->len;\
998     }while(0)
999
1000 #define PACKET_DESCRIBE(phdr,FULLPART,fullpart,ver,type,HEADERVER) \
1001     do {\
1002         nspr_pktrace##fullpart##_v##ver##_t *type = (nspr_pktrace##fullpart##_v##ver##_t *) &nstrace_buf[nstrace_buf_offset];\
1003         /* Make sure the record header is entirely contained in the page */\
1004         if ((nstrace_buflen - nstrace_buf_offset) < sizeof *type) {\
1005             *err = WTAP_ERR_BAD_FILE;\
1006             *err_info = g_strdup("nstrace: record header crosses page boundary");\
1007             return FALSE;\
1008         }\
1009         /* Check sanity of record size */\
1010         if (pletoh16(&type->nsprRecordSize) < sizeof *type) {\
1011             *err = WTAP_ERR_BAD_FILE;\
1012             *err_info = g_strdup("nstrace: record size is less than record header size");\
1013             return FALSE;\
1014         }\
1015         (phdr)->rec_type = REC_TYPE_PACKET;\
1016         TIMEDEFV##ver((phdr),fp,type);\
1017         FULLPART##SIZEDEFV##ver((phdr),type,ver);\
1018         TRACE_V##ver##_REC_LEN_OFF((phdr),v##ver##_##fullpart,type,pktrace##fullpart##_v##ver);\
1019         /* Make sure the record is entirely contained in the page */\
1020         if ((nstrace_buflen - nstrace_buf_offset) < (phdr)->caplen) {\
1021             *err = WTAP_ERR_BAD_FILE;\
1022             *err_info = g_strdup("nstrace: record crosses page boundary");\
1023             return FALSE;\
1024         }\
1025         ws_buffer_assure_space(wth->frame_buffer, (phdr)->caplen);\
1026         memcpy(ws_buffer_start_ptr(wth->frame_buffer), type, (phdr)->caplen);\
1027         *data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
1028         nstrace->nstrace_buf_offset = nstrace_buf_offset + (phdr)->caplen;\
1029         nstrace->nstrace_buflen = nstrace_buflen;\
1030         nstrace->nsg_creltime = nsg_creltime;\
1031         return TRUE;\
1032     }while(0)
1033
1034 static gboolean nstrace_read_v10(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
1035 {
1036     nstrace_t *nstrace = (nstrace_t *)wth->priv;
1037     guint64 nsg_creltime = nstrace->nsg_creltime;
1038     gchar *nstrace_buf = nstrace->pnstrace_buf;
1039     guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
1040     guint32 nstrace_buflen = nstrace->nstrace_buflen;
1041
1042     *err = 0;
1043     *err_info = NULL;
1044     do
1045     {
1046         while ((nstrace_buf_offset < nstrace_buflen) &&
1047             ((nstrace_buflen - nstrace_buf_offset) >= ((gint32)sizeof((( nspr_header_v10_t*)&nstrace_buf[nstrace_buf_offset])->ph_RecordType))))
1048         {
1049
1050 #define GENERATE_CASE_FULL(phdr,ver,HEADERVER) \
1051         case NSPR_PDPKTRACEFULLTX_V##ver:\
1052         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1053         case NSPR_PDPKTRACEFULLRX_V##ver:\
1054             PACKET_DESCRIBE(phdr,FULL,full,ver,fp,HEADERVER);
1055
1056 #define GENERATE_CASE_PART(phdr,ver,HEADERVER) \
1057         case NSPR_PDPKTRACEPARTTX_V##ver:\
1058         case NSPR_PDPKTRACEPARTTXB_V##ver:\
1059         case NSPR_PDPKTRACEPARTRX_V##ver:\
1060             PACKET_DESCRIBE(phdr,PART,part,ver,pp,HEADERVER);
1061
1062             switch (pletoh16(&(( nspr_header_v10_t*)&nstrace_buf[nstrace_buf_offset])->ph_RecordType))
1063             {
1064                 GENERATE_CASE_FULL(&wth->phdr,10,100)
1065                 GENERATE_CASE_PART(&wth->phdr,10,100)
1066
1067 #undef GENERATE_CASE_FULL
1068 #undef GENERATE_CASE_PART
1069
1070                 case NSPR_ABSTIME_V10:
1071                 {
1072                     nspr_pktracefull_v10_t *fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
1073                     if (pletoh16(&fp->nsprRecordSize) == 0) {
1074                         *err = WTAP_ERR_BAD_FILE;
1075                         *err_info = g_strdup("nstrace: zero size record found");
1076                         return FALSE;
1077                     }
1078                     ns_setabstime(nstrace, pletoh32(((nspr_abstime_v10_t *) fp)->abs_Time), pletoh32(&((nspr_abstime_v10_t *) fp)->abs_RelTime));
1079                     nstrace_buf_offset += pletoh16(&fp->nsprRecordSize);
1080                     break;
1081                 }
1082
1083                 case NSPR_RELTIME_V10:
1084                 {
1085                     nspr_pktracefull_v10_t *fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
1086                     if (pletoh16(&fp->nsprRecordSize) == 0) {
1087                         *err = WTAP_ERR_BAD_FILE;
1088                         *err_info = g_strdup("nstrace: zero size record found");
1089                         return FALSE;
1090                     }
1091                     ns_setrelativetime(nstrace, pletoh32(((nspr_abstime_v10_t *) fp)->abs_RelTime));
1092                     nstrace_buf_offset += pletoh16(&fp->nsprRecordSize);
1093                     break;
1094                 }
1095
1096                 case NSPR_UNUSEDSPACE_V10:
1097                     nstrace_buf_offset = nstrace_buflen;
1098                     break;
1099
1100                 default:
1101                 {
1102                     nspr_pktracefull_v10_t *fp = (nspr_pktracefull_v10_t *) &nstrace_buf[nstrace_buf_offset];
1103                     if (pletoh16(&fp->nsprRecordSize) == 0) {
1104                         *err = WTAP_ERR_BAD_FILE;
1105                         *err_info = g_strdup("nstrace: zero size record found");
1106                         return FALSE;
1107                     }
1108                     nstrace_buf_offset += pletoh16(&fp->nsprRecordSize);
1109                     break;
1110                 }
1111             }
1112         }
1113
1114         nstrace_buf_offset = 0;
1115         nstrace->xxx_offset += nstrace_buflen;
1116         nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));
1117     }while((nstrace_buflen > 0) && (nstrace_read_buf(wth->fh, nstrace_buf, nstrace_buflen, err, err_info)));
1118
1119     return FALSE;
1120 }
1121
1122 #undef PACKET_DESCRIBE
1123
1124 #define TIMEDEFV20(phdr,fp,type) \
1125     do {\
1126         (phdr)->presence_flags = WTAP_HAS_TS;\
1127         nsg_creltime += ns_hrtime2nsec(pletoh32(fp->type##_RelTimeHr));\
1128         (phdr)->ts.secs = nstrace->nspm_curtime + (guint32) (nsg_creltime / 1000000000);\
1129         (phdr)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
1130     }while(0)
1131
1132 #define TIMEDEFV23(phdr,fp,type) \
1133     do {\
1134         (phdr)->presence_flags = WTAP_HAS_TS;\
1135         /* access _AbsTimeHr as a 64bit value */\
1136         nsg_creltime = pletoh64(fp->type##_AbsTimeHr);\
1137         (phdr)->ts.secs = (guint32) (nsg_creltime / 1000000000);\
1138         (phdr)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
1139     }while(0)
1140
1141 #define TIMEDEFV21(phdr,fp,type) TIMEDEFV20(phdr,fp,type)
1142 #define TIMEDEFV22(phdr,fp,type) TIMEDEFV20(phdr,fp,type)
1143 #define TIMEDEFV24(phdr,fp,type) TIMEDEFV23(phdr,fp,type)
1144 #define TIMEDEFV25(phdr,fp,type) TIMEDEFV24(phdr,fp,type)
1145 #define TIMEDEFV26(phdr,fp,type) TIMEDEFV24(phdr,fp,type)
1146
1147 /*
1148 ** The maximum value of the record data size is 65535, which is less than
1149 ** WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
1150 */
1151 #define PARTSIZEDEFV20(phdr,pp,ver) \
1152     do {\
1153         (phdr)->presence_flags |= WTAP_HAS_CAP_LEN;\
1154         (phdr)->len = pletoh16(&pp->pp_PktSizeOrg) + nspr_pktracepart_v##ver##_s;\
1155         (phdr)->caplen = nspr_getv20recordsize((nspr_hd_v20_t *)pp);\
1156     }while(0)
1157
1158 #define PARTSIZEDEFV21(phdr,pp,ver) PARTSIZEDEFV20(phdr,pp,ver)
1159 #define PARTSIZEDEFV22(phdr,pp,ver) PARTSIZEDEFV20(phdr,pp,ver)
1160 #define PARTSIZEDEFV23(phdr,pp,ver) PARTSIZEDEFV20(phdr,pp,ver)
1161 #define PARTSIZEDEFV24(phdr,pp,ver) PARTSIZEDEFV20(phdr,pp,ver)
1162 #define PARTSIZEDEFV25(phdr,pp,ver) PARTSIZEDEFV20(phdr,pp,ver)
1163 #define PARTSIZEDEFV26(phdr,pp,ver) PARTSIZEDEFV20(phdr,pp,ver)
1164
1165 #define FULLSIZEDEFV20(phdr,fp,ver)\
1166     do {\
1167         (phdr)->len = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
1168         (phdr)->caplen = (phdr)->len;\
1169     }while(0)
1170
1171 #define FULLSIZEDEFV21(phdr,fp,ver) FULLSIZEDEFV20(phdr,fp,ver)
1172 #define FULLSIZEDEFV22(phdr,fp,ver) FULLSIZEDEFV20(phdr,fp,ver)
1173 #define FULLSIZEDEFV23(phdr,fp,ver) FULLSIZEDEFV20(phdr,fp,ver)
1174 #define FULLSIZEDEFV24(phdr,fp,ver) FULLSIZEDEFV20(phdr,fp,ver)
1175 #define FULLSIZEDEFV25(phdr,fp,ver) FULLSIZEDEFV20(phdr,fp,ver)
1176 #define FULLSIZEDEFV26(phdr,fp,ver) FULLSIZEDEFV20(phdr,fp,ver)
1177
1178 #define PACKET_DESCRIBE(phdr,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
1179     do {\
1180         nspr_##structname##_t *fp= (nspr_##structname##_t*)&nstrace_buf[nstrace_buf_offset];\
1181         /* Make sure the record header is entirely contained in the page */\
1182         if ((nstrace_buflen - nstrace_buf_offset) < sizeof *fp) {\
1183             *err = WTAP_ERR_BAD_FILE;\
1184             *err_info = g_strdup("nstrace: record header crosses page boundary");\
1185             return FALSE;\
1186         }\
1187         /* Check sanity of record size */\
1188         if (nspr_getv20recordsize((nspr_hd_v20_t *)fp) < sizeof *fp) {\
1189             *err = WTAP_ERR_BAD_FILE;\
1190             *err_info = g_strdup("nstrace: record size is less than record header size");\
1191             return FALSE;\
1192         }\
1193         (phdr)->rec_type = REC_TYPE_PACKET;\
1194         TIMEDEFV##ver((phdr),fp,type);\
1195         FULLPART##SIZEDEFV##ver((phdr),fp,ver);\
1196         TRACE_V##ver##_REC_LEN_OFF((phdr),enumprefix,type,structname);\
1197         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
1198         /* Make sure the record is entirely contained in the page */\
1199         if ((nstrace_buflen - nstrace_buf_offset) < (phdr)->caplen) {\
1200             *err = WTAP_ERR_BAD_FILE;\
1201             *err_info = g_strdup("nstrace: record crosses page boundary");\
1202             return FALSE;\
1203         }\
1204         ws_buffer_assure_space(wth->frame_buffer, (phdr)->caplen);\
1205         memcpy(ws_buffer_start_ptr(wth->frame_buffer), fp, (phdr)->caplen);\
1206         *data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
1207         nstrace->nstrace_buf_offset = nstrace_buf_offset + nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
1208         nstrace->nstrace_buflen = nstrace_buflen;\
1209         nstrace->nsg_creltime = nsg_creltime;\
1210         return TRUE;\
1211     }while(0)
1212
1213 static gboolean nstrace_read_v20(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
1214 {
1215     nstrace_t *nstrace = (nstrace_t *)wth->priv;
1216     guint64 nsg_creltime = nstrace->nsg_creltime;
1217     gchar *nstrace_buf = nstrace->pnstrace_buf;
1218     guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
1219     guint32 nstrace_buflen = nstrace->nstrace_buflen;
1220
1221     *err = 0;
1222     *err_info = NULL;
1223     do
1224     {
1225         while ((nstrace_buf_offset < nstrace_buflen) &&
1226             ((nstrace_buflen - nstrace_buf_offset) >= ((gint32)sizeof((( nspr_hd_v20_t*)&nstrace_buf[nstrace_buf_offset])->phd_RecordType))))
1227         {
1228             switch ((( nspr_hd_v20_t*)&nstrace_buf[nstrace_buf_offset])->phd_RecordType)
1229             {
1230
1231 #define GENERATE_CASE_FULL(phdr,ver,HEADERVER) \
1232         case NSPR_PDPKTRACEFULLTX_V##ver:\
1233         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1234         case NSPR_PDPKTRACEFULLRX_V##ver:\
1235             PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1236
1237 #define GENERATE_CASE_FULL_V25(phdr,ver,HEADERVER) \
1238         case NSPR_PDPKTRACEFULLTX_V##ver:\
1239         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1240         case NSPR_PDPKTRACEFULLRX_V##ver:\
1241         case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
1242             PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1243
1244 #define GENERATE_CASE_PART(phdr,ver,HEADERVER) \
1245         case NSPR_PDPKTRACEPARTTX_V##ver:\
1246         case NSPR_PDPKTRACEPARTTXB_V##ver:\
1247         case NSPR_PDPKTRACEPARTRX_V##ver:\
1248             PACKET_DESCRIBE(phdr,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
1249
1250 #define GENERATE_CASE_PART_V25(phdr,ver,HEADERVER) \
1251         case NSPR_PDPKTRACEPARTTX_V##ver:\
1252         case NSPR_PDPKTRACEPARTTXB_V##ver:\
1253         case NSPR_PDPKTRACEPARTRX_V##ver:\
1254         case NSPR_PDPKTRACEPARTNEWRX_V##ver:\
1255             PACKET_DESCRIBE(phdr,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
1256
1257                 GENERATE_CASE_FULL(&wth->phdr,20,200);
1258                 GENERATE_CASE_PART(&wth->phdr,20,200);
1259                 GENERATE_CASE_FULL(&wth->phdr,21,201);
1260                 GENERATE_CASE_PART(&wth->phdr,21,201);
1261                 GENERATE_CASE_FULL(&wth->phdr,22,202);
1262                 GENERATE_CASE_PART(&wth->phdr,22,202);
1263                 GENERATE_CASE_FULL(&wth->phdr,23,203);
1264                 GENERATE_CASE_PART(&wth->phdr,23,203);
1265                 GENERATE_CASE_FULL_V25(&wth->phdr,24,204);
1266                 GENERATE_CASE_PART_V25(&wth->phdr,24,204);
1267                 GENERATE_CASE_FULL_V25(&wth->phdr,25,205);
1268                 GENERATE_CASE_PART_V25(&wth->phdr,25,205);
1269                 GENERATE_CASE_FULL_V25(&wth->phdr,26,206);
1270                 GENERATE_CASE_PART_V25(&wth->phdr,26,206);
1271
1272 #undef GENERATE_CASE_FULL
1273 #undef GENERATE_CASE_FULL_V25
1274 #undef GENERATE_CASE_PART
1275 #undef GENERATE_CASE_PART_V25
1276
1277                 case NSPR_ABSTIME_V20:
1278                 {
1279                     nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
1280                     if (nspr_getv20recordsize((nspr_hd_v20_t *)fp20) == 0) {
1281                         *err = WTAP_ERR_BAD_FILE;
1282                         *err_info = g_strdup("nstrace: zero size record found");
1283                         return FALSE;
1284                     }
1285                     nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
1286                     ns_setabstime(nstrace, pletoh32(&((nspr_abstime_v20_t *) fp20)->abs_Time), pletoh16(&((nspr_abstime_v20_t *) fp20)->abs_RelTime));
1287                     break;
1288                 }
1289
1290                 case NSPR_RELTIME_V20:
1291                 {
1292                     nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
1293                     if (nspr_getv20recordsize((nspr_hd_v20_t *)fp20) == 0) {
1294                         *err = WTAP_ERR_BAD_FILE;
1295                         *err_info = g_strdup("nstrace: zero size record found");
1296                         return FALSE;
1297                     }
1298                     ns_setrelativetime(nstrace, pletoh16(&((nspr_abstime_v20_t *) fp20)->abs_RelTime));
1299                     nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
1300                     break;
1301                   }
1302
1303                 case NSPR_UNUSEDSPACE_V20:
1304                 {
1305                     if (nstrace_buf_offset >= NSPR_PAGESIZE/2)
1306                         nstrace_buf_offset = nstrace_buflen;
1307                     else
1308                         nstrace_buf_offset = NSPR_PAGESIZE/2;
1309                     break;
1310                   }
1311
1312                 default:
1313                 {
1314                     nspr_pktracefull_v20_t *fp20 = (nspr_pktracefull_v20_t *) &nstrace_buf[nstrace_buf_offset];
1315                     if (nspr_getv20recordsize((nspr_hd_v20_t *)fp20) == 0) {
1316                         *err = WTAP_ERR_BAD_FILE;
1317                         *err_info = g_strdup("nstrace: zero size record found");
1318                         return FALSE;
1319                     }
1320                     nstrace_buf_offset += nspr_getv20recordsize((nspr_hd_v20_t *)fp20);
1321                     break;
1322                 }
1323             }
1324         }
1325
1326         nstrace_buf_offset = 0;
1327         nstrace->xxx_offset += nstrace_buflen;
1328         nstrace_buflen = GET_READ_PAGE_SIZE((nstrace->file_size - nstrace->xxx_offset));
1329     }while((nstrace_buflen > 0) && (nstrace_read_buf(wth->fh, nstrace_buf, nstrace_buflen, err, err_info)));
1330
1331     return FALSE;
1332 }
1333
1334 #undef PACKET_DESCRIBE
1335
1336 #define SETETHOFFSET_35(phdr)\
1337   (phdr)->pseudo_header.nstr.eth_offset = pletoh16(&fp->fp_headerlen);\
1338
1339 #define SETETHOFFSET_30(phdr) ;\
1340
1341 #define TIMEDEFV30(phdr,fp,type) \
1342     do {\
1343         (phdr)->presence_flags = WTAP_HAS_TS;\
1344         /* access _AbsTimeHr as a 64bit value */\
1345         nsg_creltime = pletoh64(fp->type##_AbsTimeHr);\
1346         (phdr)->ts.secs = (guint32) (nsg_creltime / 1000000000);\
1347         (phdr)->ts.nsecs = (guint32) (nsg_creltime % 1000000000);\
1348     }while(0)
1349
1350 #define TIMEDEFV35 TIMEDEFV30
1351
1352 /*
1353 ** The maximum value of the record data size is 65535, which is less than
1354 ** WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
1355 */
1356 #define FULLSIZEDEFV30(phdr,fp,ver)\
1357     do {\
1358         (phdr)->presence_flags |= WTAP_HAS_CAP_LEN;\
1359         (phdr)->len = pletoh16(&fp->fp_PktSizeOrg) + nspr_pktracefull_v##ver##_s + fp->fp_src_vmname_len + fp->fp_dst_vmname_len;\
1360         (phdr)->caplen = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
1361     }while(0)
1362
1363 #define FULLSIZEDEFV35(phdr,fp,ver)\
1364     do {\
1365         (phdr)->presence_flags |= WTAP_HAS_CAP_LEN;\
1366         (phdr)->len = pletoh16(&fp->fp_PktSizeOrg) + pletoh16(&fp->fp_headerlen);\
1367         (phdr)->caplen = nspr_getv20recordsize((nspr_hd_v20_t *)fp);\
1368     }while(0)
1369
1370 #define PACKET_DESCRIBE(phdr,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
1371     do {\
1372         nspr_##structname##_t *fp = (nspr_##structname##_t *) &nstrace_buf[nstrace_buf_offset];\
1373         /* Make sure the record header is entirely contained in the page */\
1374         if ((nstrace->nstrace_buflen - nstrace_buf_offset) < sizeof *fp) {\
1375             *err = WTAP_ERR_BAD_FILE;\
1376             *err_info = g_strdup("nstrace: record header crosses page boundary");\
1377             g_free(nstrace_tmpbuff);\
1378             return FALSE;\
1379         }\
1380         (phdr)->rec_type = REC_TYPE_PACKET;\
1381         TIMEDEFV##ver((phdr),fp,type);\
1382         FULLPART##SIZEDEFV##ver((phdr),fp,ver);\
1383         TRACE_V##ver##_REC_LEN_OFF((phdr),enumprefix,type,structname);\
1384         SETETHOFFSET_##ver(phdr)\
1385         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
1386         /* Check sanity of record size */\
1387         if ((phdr)->caplen < sizeof *fp) {\
1388             *err = WTAP_ERR_BAD_FILE;\
1389             *err_info = g_strdup("nstrace: record size is less than record header size");\
1390             g_free(nstrace_tmpbuff);\
1391             return FALSE;\
1392         }\
1393         ws_buffer_assure_space(wth->frame_buffer, (phdr)->caplen);\
1394         *data_offset = nstrace->xxx_offset + nstrace_buf_offset;\
1395         /* Copy record header */\
1396         while (nstrace_tmpbuff_off < nspr_##structname##_s) {\
1397             nstrace_tmpbuff[nstrace_tmpbuff_off++] = nstrace_buf[nstrace_buf_offset++];\
1398         }\
1399         nst_dataSize = nspr_getv20recordsize(hdp);\
1400         rec_size = nst_dataSize - nstrace_tmpbuff_off;\
1401         nsg_nextPageOffset = ((nstrace_buf_offset + rec_size) >= (guint)nstrace->nstrace_buflen) ?\
1402         ((nstrace_buf_offset + rec_size) - (NSPR_PAGESIZE_TRACE - 1)) : 0;\
1403         /* Copy record data */\
1404         while (nsg_nextPageOffset) {\
1405             /* Copy everything from this page */\
1406             while (nstrace_buf_offset < nstrace->nstrace_buflen) {\
1407                 nstrace_tmpbuff[nstrace_tmpbuff_off++] = nstrace_buf[nstrace_buf_offset++];\
1408             }\
1409             nstrace->xxx_offset += nstrace_buflen;\
1410             nstrace_buflen = NSPR_PAGESIZE_TRACE;\
1411             /* Read the next page */\
1412             bytes_read = file_read(nstrace_buf, NSPR_PAGESIZE_TRACE, wth->fh);\
1413             if ( !file_eof(wth->fh) && bytes_read != NSPR_PAGESIZE_TRACE) {\
1414                 g_free(nstrace_tmpbuff);\
1415                 return FALSE;\
1416             } else {\
1417                 nstrace_buf_offset = 0;\
1418             }\
1419             nstrace_buflen = bytes_read;\
1420             rec_size = nst_dataSize - nstrace_tmpbuff_off;\
1421             nsg_nextPageOffset = ((nstrace_buf_offset + rec_size) >= (guint)nstrace->nstrace_buflen) ?\
1422             ((nstrace_buf_offset + rec_size) - (NSPR_PAGESIZE_TRACE- 1)): 0;\
1423         } \
1424         /* Copy the rest of the record */\
1425         while (nstrace_tmpbuff_off < nst_dataSize) {\
1426             nstrace_tmpbuff[nstrace_tmpbuff_off++] = nstrace_buf[nstrace_buf_offset++];\
1427         }\
1428         memcpy(ws_buffer_start_ptr(wth->frame_buffer), nstrace_tmpbuff, (phdr)->caplen);\
1429         nstrace->nstrace_buf_offset = nstrace_buf_offset;\
1430         nstrace->nstrace_buflen = nstrace_buflen;\
1431         nstrace->nsg_creltime = nsg_creltime;\
1432         g_free(nstrace_tmpbuff);\
1433         return TRUE;\
1434     } while(0)
1435
1436 static gboolean nstrace_read_v30(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
1437 {
1438     nstrace_t *nstrace = (nstrace_t *)wth->priv;
1439     guint64 nsg_creltime;
1440     gchar *nstrace_buf = nstrace->pnstrace_buf;
1441     guint32 nstrace_buf_offset = nstrace->nstrace_buf_offset;
1442     guint32 nstrace_buflen = nstrace->nstrace_buflen;
1443     guint8* nstrace_tmpbuff;
1444     guint32 nstrace_tmpbuff_off=0,nst_dataSize=0,rec_size=0,nsg_nextPageOffset=0;
1445     nspr_hd_v20_t *hdp;
1446     int bytes_read = 0;
1447     *err = 0;
1448     *err_info = NULL;
1449     if(nstrace_buflen == 0){
1450       return FALSE; /* Reached End Of File */
1451     }
1452
1453     nstrace_tmpbuff = (guint8*)g_malloc(65536);
1454
1455     do
1456     {
1457         if (!nstrace_buf[nstrace_buf_offset] && nstrace_buf_offset <= NSPR_PAGESIZE_TRACE){
1458             nstrace_buf_offset = NSPR_PAGESIZE_TRACE;
1459         }
1460         if (file_eof(wth->fh) && bytes_read > 0 && bytes_read < NSPR_PAGESIZE_TRACE){
1461             memset(&nstrace_buf[bytes_read], 0, NSPR_PAGESIZE_TRACE-bytes_read);
1462         }
1463         while ((nstrace_buf_offset < NSPR_PAGESIZE_TRACE) &&
1464             nstrace_buf[nstrace_buf_offset])
1465         {
1466             hdp = (nspr_hd_v20_t *) &nstrace_buf[nstrace_buf_offset];
1467             if (nspr_getv20recordsize(hdp) == 0) {
1468                 *err = WTAP_ERR_BAD_FILE;
1469                 *err_info = g_strdup("nstrace: zero size record found");
1470                 g_free(nstrace_tmpbuff);
1471                 return FALSE;
1472             }
1473             switch (hdp->phd_RecordType)
1474             {
1475
1476 #define GENERATE_CASE_FULL_V30(phdr,ver,HEADERVER) \
1477         case NSPR_PDPKTRACEFULLTX_V##ver:\
1478         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1479         case NSPR_PDPKTRACEFULLRX_V##ver:\
1480         case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
1481             PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1482
1483                 GENERATE_CASE_FULL_V30(&wth->phdr,30,300);
1484
1485 #undef GENERATE_CASE_FULL_V30
1486
1487 #define GENERATE_CASE_FULL_V35(phdr,ver,HEADERVER) \
1488         case NSPR_PDPKTRACEFULLTX_V##ver:\
1489         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1490         case NSPR_PDPKTRACEFULLRX_V##ver:\
1491         case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
1492             PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1493                 GENERATE_CASE_FULL_V35(&wth->phdr,35,350);
1494
1495 #undef GENERATE_CASE_FULL_V35
1496
1497                 case NSPR_ABSTIME_V20:
1498                 {
1499                     nstrace_buf_offset += nspr_getv20recordsize(hdp);
1500                     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));
1501                     break;
1502                 }
1503
1504                 case NSPR_RELTIME_V20:
1505                 {
1506                     ns_setrelativetime(nstrace, pletoh16(&((nspr_abstime_v20_t *) &nstrace_buf[nstrace_buf_offset])->abs_RelTime));
1507                     nstrace_buf_offset += nspr_getv20recordsize(hdp);
1508                     break;
1509                 }
1510
1511                 default:
1512                 {
1513                     nstrace_buf_offset += nspr_getv20recordsize(hdp);
1514                     break;
1515                 }
1516             }
1517         }
1518         nstrace_buf_offset = 0;
1519         nstrace->xxx_offset += nstrace_buflen;
1520         nstrace_buflen = NSPR_PAGESIZE_TRACE;
1521     } while((nstrace_buflen > 0) && (bytes_read = file_read(nstrace_buf, nstrace_buflen, wth->fh)) > 0 && (file_eof(wth->fh) || (guint32)bytes_read == nstrace_buflen));
1522
1523     if (bytes_read < 0)
1524         *err = file_error(wth->fh, err_info);
1525     else
1526         *err = 0;
1527     g_free(nstrace_tmpbuff);
1528     return FALSE;
1529 }
1530
1531 #undef PACKET_DESCRIBE
1532
1533 /*
1534  * XXX - for these, we can't set the time stamp in the seek-read
1535  * routine, because the time stamps are relative.
1536  */
1537 #undef TIMEDEFV10
1538 #define TIMEDEFV10(phdr,fp,type) \
1539     do {\
1540         (phdr)->presence_flags = 0;\
1541     }while(0)
1542
1543 #define PACKET_DESCRIBE(phdr,FULLPART,fullpart,ver,type,HEADERVER) \
1544     do {\
1545         nspr_pktrace##fullpart##_v##ver##_t *type = (nspr_pktrace##fullpart##_v##ver##_t *) pd;\
1546         (phdr)->rec_type = REC_TYPE_PACKET;\
1547         TIMEDEFV##ver((phdr),fp,type);\
1548         FULLPART##SIZEDEFV##ver((phdr),type,ver);\
1549         TRACE_V##ver##_REC_LEN_OFF(phdr,v##ver##_##fullpart,type,pktrace##fullpart##_v##ver);\
1550         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
1551     }while(0)
1552
1553 static gboolean nstrace_seek_read_v10(wtap *wth, gint64 seek_off,
1554     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
1555 {
1556     nspr_hd_v10_t hdr;
1557     guint record_length;
1558     guint8 *pd;
1559     unsigned int bytes_to_read;
1560
1561     *err = 0;
1562
1563     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1564         return FALSE;
1565
1566     /*
1567     ** Read the record header.
1568     */
1569     if (!wtap_read_bytes(wth->random_fh, (void *)&hdr, sizeof hdr,
1570                          err, err_info))
1571         return FALSE;
1572
1573     /*
1574     ** Get the record length.
1575     */
1576     record_length = nspr_getv10recordsize(&hdr);
1577
1578     /*
1579     ** Copy the header to the buffer and read the rest of the record..
1580     */
1581     ws_buffer_assure_space(buf, record_length);
1582     pd = ws_buffer_start_ptr(buf);
1583     memcpy(pd, (void *)&hdr, sizeof hdr);
1584     if (record_length > sizeof hdr) {
1585         bytes_to_read = (unsigned int)(record_length - sizeof hdr);
1586         if (!wtap_read_bytes(wth->random_fh, pd + sizeof hdr, bytes_to_read,
1587                              err, err_info))
1588             return FALSE;
1589     }
1590
1591     /*
1592     ** Fill in what part of the struct wtap_pkthdr we can.
1593     */
1594 #define GENERATE_CASE_FULL(phdr,type,HEADERVER) \
1595         case NSPR_PDPKTRACEFULLTX_V##type:\
1596         case NSPR_PDPKTRACEFULLTXB_V##type:\
1597         case NSPR_PDPKTRACEFULLRX_V##type:\
1598             PACKET_DESCRIBE(phdr,FULL,full,type,fp,HEADERVER);\
1599             break;
1600
1601 #define GENERATE_CASE_PART(phdr,type,HEADERVER) \
1602         case NSPR_PDPKTRACEPARTTX_V##type:\
1603         case NSPR_PDPKTRACEPARTTXB_V##type:\
1604         case NSPR_PDPKTRACEPARTRX_V##type:\
1605             PACKET_DESCRIBE(phdr,PART,part,type,pp,HEADERVER);\
1606             break;
1607
1608     switch (pletoh16(&(( nspr_header_v10_t*)pd)->ph_RecordType))
1609     {
1610         GENERATE_CASE_FULL(phdr,10,100)
1611         GENERATE_CASE_PART(phdr,10,100)
1612     }
1613
1614 #undef GENERATE_CASE_FULL
1615 #undef GENERATE_CASE_PART
1616
1617     return TRUE;
1618 }
1619
1620 #undef PACKET_DESCRIBE
1621
1622 /*
1623  * XXX - for these, we can't set the time stamp in the seek-read
1624  * routine, because the time stamps are relative.
1625  */
1626 #undef TIMEDEFV20
1627 #define TIMEDEFV20(phdr,fp,type) \
1628     do {\
1629         (phdr)->presence_flags = 0;\
1630     }while(0)
1631
1632 #undef TIMEDEFV21
1633 #undef TIMEDEFV22
1634 #define TIMEDEFV21(phdr,fp,type) TIMEDEFV20(phdr,fp,type)
1635 #define TIMEDEFV22(phdr,fp,type) TIMEDEFV20(phdr,fp,type)
1636
1637 #define PACKET_DESCRIBE(phdr,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
1638     do {\
1639         nspr_##structname##_t *fp= (nspr_##structname##_t*)pd;\
1640         (phdr)->rec_type = REC_TYPE_PACKET;\
1641         TIMEDEFV##ver((phdr),fp,type);\
1642         FULLPART##SIZEDEFV##ver((phdr),fp,ver);\
1643         TRACE_V##ver##_REC_LEN_OFF((phdr),enumprefix,type,structname);\
1644         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
1645         return TRUE;\
1646     }while(0)
1647
1648 static gboolean nstrace_seek_read_v20(wtap *wth, gint64 seek_off,
1649     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
1650 {
1651     nspr_hd_v20_t hdr;
1652     guint record_length;
1653     guint hdrlen;
1654     guint8 *pd;
1655     unsigned int bytes_to_read;
1656     guint64 nsg_creltime;
1657
1658     *err = 0;
1659
1660     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1661         return FALSE;
1662
1663     /*
1664     ** Read the first 2 bytes of the record header.
1665     */
1666     if (!wtap_read_bytes(wth->random_fh, (void *)&hdr, 2, err, err_info))
1667         return FALSE;
1668     hdrlen = 2;
1669
1670     /*
1671     ** Is there a third byte?  If so, read it.
1672     */
1673     if (hdr.phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES) {
1674         if (!wtap_read_bytes(wth->random_fh, (void *)&hdr.phd_RecordSizeHigh, 1,
1675                              err, err_info))
1676             return FALSE;
1677         hdrlen = 3;
1678     }
1679
1680     /*
1681     ** Get the record length.
1682     */
1683     record_length = nspr_getv20recordsize(&hdr);
1684
1685     /*
1686     ** Copy the header to the buffer and read the rest of the record..
1687     */
1688     ws_buffer_assure_space(buf, record_length);
1689     pd = ws_buffer_start_ptr(buf);
1690     memcpy(pd, (void *)&hdr, hdrlen);
1691     if (record_length > hdrlen) {
1692         bytes_to_read = (unsigned int)(record_length - hdrlen);
1693         if (!wtap_read_bytes(wth->random_fh, pd + hdrlen, bytes_to_read,
1694                              err, err_info))
1695             return FALSE;
1696     }
1697
1698 #define GENERATE_CASE_FULL(phdr,ver,HEADERVER) \
1699         case NSPR_PDPKTRACEFULLTX_V##ver:\
1700         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1701         case NSPR_PDPKTRACEFULLRX_V##ver:\
1702             PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1703
1704 #define GENERATE_CASE_FULL_V25(phdr,ver,HEADERVER) \
1705         case NSPR_PDPKTRACEFULLTX_V##ver:\
1706         case NSPR_PDPKTRACEFULLTXB_V##ver:\
1707         case NSPR_PDPKTRACEFULLRX_V##ver:\
1708         case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
1709             PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1710
1711 #define GENERATE_CASE_PART(phdr,ver,HEADERVER) \
1712         case NSPR_PDPKTRACEPARTTX_V##ver:\
1713         case NSPR_PDPKTRACEPARTTXB_V##ver:\
1714         case NSPR_PDPKTRACEPARTRX_V##ver:\
1715             PACKET_DESCRIBE(phdr,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
1716
1717 #define GENERATE_CASE_PART_V25(phdr,ver,HEADERVER) \
1718         case NSPR_PDPKTRACEPARTTX_V##ver:\
1719         case NSPR_PDPKTRACEPARTTXB_V##ver:\
1720         case NSPR_PDPKTRACEPARTRX_V##ver:\
1721         case NSPR_PDPKTRACEPARTNEWRX_V##ver:\
1722             PACKET_DESCRIBE(phdr,PART,ver,v##ver##_part,pp,pktracepart_v##ver,HEADERVER);
1723
1724     switch ((( nspr_hd_v20_t*)pd)->phd_RecordType)
1725     {
1726         GENERATE_CASE_FULL(phdr,20,200)
1727         GENERATE_CASE_PART(phdr,20,200)
1728         GENERATE_CASE_FULL(phdr,21,201)
1729         GENERATE_CASE_PART(phdr,21,201)
1730         GENERATE_CASE_FULL(phdr,22,202)
1731         GENERATE_CASE_PART(phdr,22,202)
1732         GENERATE_CASE_FULL(phdr,23,203)
1733         GENERATE_CASE_PART(phdr,23,203)
1734         GENERATE_CASE_FULL_V25(phdr,24,204)
1735         GENERATE_CASE_PART_V25(phdr,24,204)
1736         GENERATE_CASE_FULL_V25(phdr,25,205)
1737         GENERATE_CASE_PART_V25(phdr,25,205)
1738         GENERATE_CASE_FULL_V25(phdr,26,206)
1739         GENERATE_CASE_PART_V25(phdr,26,206)
1740     }
1741
1742 #undef GENERATE_CASE_FULL
1743 #undef GENERATE_CASE_FULL_V25
1744 #undef GENERATE_CASE_PART
1745 #undef GENERATE_CASE_PART_V25
1746
1747     return TRUE;
1748 }
1749
1750 #undef PACKET_DESCRIBE
1751 #undef SETETHOFFSET_35
1752 #undef SETETHOFFSET_30
1753
1754 #define SETETHOFFSET_35(phdr)\
1755    {\
1756     (phdr)->pseudo_header.nstr.eth_offset = pletoh16(&fp->fp_headerlen);\
1757    }
1758
1759 #define SETETHOFFSET_30(phdr) ;\
1760
1761 #define PACKET_DESCRIBE(phdr,FULLPART,ver,enumprefix,type,structname,HEADERVER)\
1762     do {\
1763         nspr_##structname##_t *fp= (nspr_##structname##_t*)pd;\
1764         (phdr)->rec_type = REC_TYPE_PACKET;\
1765         TIMEDEFV##ver((phdr),fp,type);\
1766         SETETHOFFSET_##ver(phdr);\
1767         FULLPART##SIZEDEFV##ver((phdr),fp,ver);\
1768         TRACE_V##ver##_REC_LEN_OFF((phdr),enumprefix,type,structname);\
1769         (phdr)->pseudo_header.nstr.rec_type = NSPR_HEADER_VERSION##HEADERVER;\
1770         return TRUE;\
1771     }while(0)
1772
1773 static gboolean nstrace_seek_read_v30(wtap *wth, gint64 seek_off,
1774     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
1775 {
1776     nspr_hd_v20_t hdr;
1777     guint record_length;
1778     guint hdrlen;
1779     guint8 *pd;
1780     unsigned int bytes_to_read;
1781     guint64 nsg_creltime;
1782
1783     *err = 0;
1784
1785     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1786         return FALSE;
1787     /*
1788     ** Read the first 2 bytes of the record header.
1789     */
1790     if (!wtap_read_bytes(wth->random_fh, (void *)&hdr, 2, err, err_info))
1791         return FALSE;
1792     hdrlen = 2;
1793
1794     /*
1795     ** Is there a third byte?  If so, read it.
1796     */
1797     if (hdr.phd_RecordSizeLow & NSPR_V20RECORDSIZE_2BYTES) {
1798         if (!wtap_read_bytes(wth->random_fh, (void *)&hdr.phd_RecordSizeHigh, 1,
1799                              err, err_info))
1800             return FALSE;
1801         hdrlen = 3;
1802     }
1803
1804     /*
1805     ** Get the record length.
1806     ** The maximum value of the record data size is 65535, which is less
1807     ** than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check it.
1808     */
1809     record_length = nspr_getv20recordsize(&hdr);
1810
1811     /*
1812     ** Copy the header to the buffer and read the rest of the record..
1813     */
1814     ws_buffer_assure_space(buf, record_length);
1815     pd = ws_buffer_start_ptr(buf);
1816     memcpy(pd, (void *)&hdr, hdrlen);
1817     if (record_length > hdrlen) {
1818         bytes_to_read = (unsigned int)(record_length - hdrlen);
1819         if (!wtap_read_bytes(wth->random_fh, pd + hdrlen, bytes_to_read,
1820                              err, err_info))
1821             return FALSE;
1822     }
1823
1824     (phdr)->caplen = (phdr)->len = record_length;
1825
1826 #define GENERATE_CASE_V30(phdr,ver,HEADERVER) \
1827     case NSPR_PDPKTRACEFULLTX_V##ver:\
1828     case NSPR_PDPKTRACEFULLTXB_V##ver:\
1829     case NSPR_PDPKTRACEFULLRX_V##ver:\
1830     case NSPR_PDPKTRACEFULLNEWRX_V##ver:\
1831         PACKET_DESCRIBE(phdr,FULL,ver,v##ver##_full,fp,pktracefull_v##ver,HEADERVER);
1832
1833         switch ((( nspr_hd_v20_t*)pd)->phd_RecordType)
1834         {
1835             GENERATE_CASE_V30(phdr,30, 300);
1836             GENERATE_CASE_V30(phdr,35, 350);
1837         }
1838
1839     return TRUE;
1840 }
1841
1842
1843 /*
1844 ** Netscaler trace format close routines.
1845 */
1846 static void nstrace_close(wtap *wth)
1847 {
1848     nstrace_t *nstrace = (nstrace_t *)wth->priv;
1849
1850     g_free(nstrace->pnstrace_buf);
1851 }
1852
1853
1854 typedef struct {
1855     guint16 page_offset;
1856     guint16 page_len;
1857     guint32 absrec_time;
1858     gboolean newfile;
1859 } nstrace_dump_t;
1860
1861 /* Returns 0 if we could write the specified encapsulation type,
1862 ** an error indication otherwise. */
1863 int nstrace_10_dump_can_write_encap(int encap)
1864 {
1865     if (encap == WTAP_ENCAP_NSTRACE_1_0)
1866         return 0;
1867
1868     return WTAP_ERR_UNWRITABLE_ENCAP;
1869 }
1870
1871
1872 /* Returns 0 if we could write the specified encapsulation type,
1873 ** an error indication otherwise. */
1874 int nstrace_20_dump_can_write_encap(int encap)
1875 {
1876     if (encap == WTAP_ENCAP_NSTRACE_2_0)
1877         return 0;
1878
1879     return WTAP_ERR_UNWRITABLE_ENCAP;
1880 }
1881
1882 /* Returns 0 if we could write the specified encapsulation type,
1883 ** an error indication otherwise. */
1884 int nstrace_30_dump_can_write_encap(int encap)
1885 {
1886     if (encap == WTAP_ENCAP_NSTRACE_3_0)
1887         return 0;
1888
1889     return WTAP_ERR_UNWRITABLE_ENCAP;
1890 }
1891
1892 /* Returns 0 if we could write the specified encapsulation type,
1893 ** an error indication otherwise. */
1894 int nstrace_35_dump_can_write_encap(int encap)
1895 {
1896     if (encap == WTAP_ENCAP_NSTRACE_3_5)
1897         return 0;
1898
1899     return WTAP_ERR_UNWRITABLE_ENCAP;
1900 }
1901
1902 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
1903 ** failure */
1904 gboolean nstrace_dump_open(wtap_dumper *wdh, int *err _U_)
1905 {
1906     nstrace_dump_t *nstrace;
1907
1908     wdh->subtype_write = nstrace_dump;
1909
1910     nstrace = (nstrace_dump_t *)g_malloc(sizeof(nstrace_dump_t));
1911     wdh->priv = (void *)nstrace;
1912     nstrace->page_offset = 0;
1913     if ((wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0) ||
1914       (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5))
1915       nstrace->page_len = NSPR_PAGESIZE_TRACE;
1916     else
1917       nstrace->page_len = NSPR_PAGESIZE;
1918
1919     nstrace->absrec_time = 0;
1920     nstrace->newfile = TRUE;
1921
1922     return TRUE;
1923 }
1924
1925
1926 static gboolean nstrace_add_signature(wtap_dumper *wdh, int *err)
1927 {
1928     nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
1929
1930     if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
1931     {
1932         guint16 val16b;
1933         nspr_signature_v10_t sig10;
1934
1935         /* populate the record */
1936         val16b = GUINT16_TO_LE(NSPR_SIGNATURE_V10);
1937         memcpy(sig10.phd.ph_RecordType, &val16b, sizeof sig10.phd.ph_RecordType);
1938         val16b = GUINT16_TO_LE(nspr_signature_v10_s);
1939         memcpy(sig10.phd.ph_RecordSize, &val16b, sizeof sig10.phd.ph_RecordSize);
1940         memset(sig10.sig_Signature, 0, NSPR_SIGSIZE_V10);
1941         g_strlcpy(sig10.sig_Signature, NSPR_SIGSTR_V10, NSPR_SIGSIZE_V10);
1942
1943         /* Write the record into the file */
1944         if (!wtap_dump_file_write(wdh, &sig10, nspr_signature_v10_s,
1945             err))
1946             return FALSE;
1947
1948         /* Move forward the page offset */
1949         nstrace->page_offset += (guint16) nspr_signature_v10_s;
1950
1951     } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0)
1952     {
1953         nspr_signature_v20_t sig20;
1954
1955         sig20.sig_RecordType = NSPR_SIGNATURE_V20;
1956         sig20.sig_RecordSize = nspr_signature_v20_s;
1957         memcpy(sig20.sig_Signature, NSPR_SIGSTR_V20, sizeof(NSPR_SIGSTR_V20));
1958
1959         /* Write the record into the file */
1960         if (!wtap_dump_file_write(wdh, &sig20, sig20.sig_RecordSize,
1961             err))
1962             return FALSE;
1963
1964         /* Move forward the page offset */
1965         nstrace->page_offset += (guint16) sig20.sig_RecordSize;
1966
1967     } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0)
1968     {
1969         nspr_signature_v30_t sig30;
1970
1971         sig30.sig_RecordType = NSPR_SIGNATURE_V30;
1972         sig30.sig_RecordSize = nspr_signature_v30_s;
1973         memcpy(sig30.sig_Signature, NSPR_SIGSTR_V30, sizeof(NSPR_SIGSTR_V30));
1974
1975         /* Write the record into the file */
1976         if (!wtap_dump_file_write(wdh, &sig30, sig30.sig_RecordSize,
1977             err))
1978             return FALSE;
1979
1980         /* Move forward the page offset */
1981         nstrace->page_offset += (guint16) sig30.sig_RecordSize;
1982     } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5)
1983     {
1984         nspr_signature_v35_t sig35;
1985
1986         sig35.sig_RecordType = NSPR_SIGNATURE_V35;
1987         sig35.sig_RecordSize = nspr_signature_v35_s;
1988         memcpy(sig35.sig_Signature, NSPR_SIGSTR_V35, sizeof(NSPR_SIGSTR_V35));
1989
1990         /* Write the record into the file */
1991         if (!wtap_dump_file_write(wdh, &sig35, sig35.sig_RecordSize,
1992             err))
1993             return FALSE;
1994
1995         /* Move forward the page offset */
1996         nstrace->page_offset += (guint16) sig35.sig_RecordSize;
1997     } else
1998     {
1999         g_assert_not_reached();
2000         return FALSE;
2001     }
2002
2003     return TRUE;
2004 }
2005
2006
2007 static gboolean
2008 nstrace_add_abstime(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
2009      const guint8 *pd, int *err)
2010 {
2011     nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
2012     guint64 nsg_creltime;
2013
2014     if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
2015     {
2016         guint16 val16;
2017         guint32 reltime;
2018         guint64 abstime;
2019         nspr_abstime_v10_t abs10;
2020
2021         /* populate the record */
2022         val16 = GUINT16_TO_LE(NSPR_ABSTIME_V10);
2023         memcpy(abs10.phd.ph_RecordType, &val16, sizeof abs10.phd.ph_RecordType);
2024         val16 = GUINT16_TO_LE(nspr_abstime_v10_s);
2025         memcpy(abs10.phd.ph_RecordSize, &val16, sizeof abs10.phd.ph_RecordSize);
2026
2027         memcpy(&reltime, ((const nspr_pktracefull_v10_t *)pd)->fp_RelTimeHr, sizeof reltime);
2028         nsg_creltime = ns_hrtime2nsec(reltime);
2029
2030         memset(abs10.abs_RelTime, 0, sizeof abs10.abs_RelTime);
2031         abstime = GUINT32_TO_LE((guint32)phdr->ts.secs - (guint32)(nsg_creltime/1000000000));
2032         memcpy(abs10.abs_Time, &abstime, sizeof abs10.abs_Time);
2033
2034         /* Write the record into the file */
2035         if (!wtap_dump_file_write(wdh, &abs10, nspr_abstime_v10_s, err))
2036             return FALSE;
2037
2038         /* Move forward the page offset */
2039         nstrace->page_offset += nspr_abstime_v10_s;
2040
2041     } else if ((wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0) ||
2042         (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0) ||
2043         (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5))    {
2044         guint32 reltime;
2045         guint64 abstime;
2046         nspr_abstime_v20_t abs20;
2047
2048         abs20.abs_RecordType = NSPR_ABSTIME_V20;
2049         abs20.abs_RecordSize = nspr_abstime_v20_s;
2050
2051         memcpy(&reltime, ((const nspr_pktracefull_v20_t *)pd)->fp_RelTimeHr, sizeof reltime);
2052         nsg_creltime = ns_hrtime2nsec(reltime);
2053
2054         memset(abs20.abs_RelTime, 0, sizeof abs20.abs_RelTime);
2055         abstime = GUINT32_TO_LE((guint32)phdr->ts.secs - (guint32)(nsg_creltime/1000000000));
2056         memcpy(abs20.abs_RelTime, &abstime, sizeof abs20.abs_RelTime);
2057
2058         /* Write the record into the file */
2059         if (!wtap_dump_file_write(wdh, &abs20, nspr_abstime_v20_s, err))
2060             return FALSE;
2061
2062         /* Move forward the page offset */
2063         nstrace->page_offset += nspr_abstime_v20_s;
2064
2065     } else
2066     {
2067         g_assert_not_reached();
2068         return FALSE;
2069     }
2070
2071     return TRUE;
2072 }
2073
2074
2075 /* Write a record for a packet to a dump file.
2076    Returns TRUE on success, FALSE on failure. */
2077 static gboolean nstrace_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
2078     const guint8 *pd, int *err, gchar **err_info _U_)
2079 {
2080     nstrace_dump_t *nstrace = (nstrace_dump_t *)wdh->priv;
2081
2082     /* We can only write packet records. */
2083     if (phdr->rec_type != REC_TYPE_PACKET) {
2084         *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
2085         return FALSE;
2086     }
2087
2088     if (nstrace->newfile == TRUE)
2089     {
2090         nstrace->newfile = FALSE;
2091         /* Add the signature record and abs time record */
2092         if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
2093         {
2094             if (!nstrace_add_signature(wdh, err) ||
2095                 !nstrace_add_abstime(wdh, phdr, pd, err))
2096                 return FALSE;
2097         } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0)
2098         {
2099             if (!nstrace_add_signature(wdh, err) ||
2100                 !nstrace_add_abstime(wdh, phdr, pd, err))
2101                 return FALSE;
2102         } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0 ||
2103                    wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5 )
2104         {
2105             if (!nstrace_add_signature(wdh, err) ||
2106                 !nstrace_add_abstime(wdh, phdr, pd, err))
2107                 return FALSE;
2108         } else
2109         {
2110             g_assert_not_reached();
2111             return FALSE;
2112         }
2113     }
2114
2115     switch (phdr->pseudo_header.nstr.rec_type)
2116     {
2117     case NSPR_HEADER_VERSION100:
2118
2119         if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
2120         {
2121             if (nstrace->page_offset + phdr->caplen >= nstrace->page_len)
2122             {
2123                 /* Start on the next page */
2124                 if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
2125                     return FALSE;
2126
2127                 nstrace->page_offset = 0;
2128
2129                 /* Possibly add signature and abstime records and increment offset */
2130                 if (!nstrace_add_signature(wdh, err))
2131                     return FALSE;
2132             }
2133
2134             /* Write the actual record as is */
2135             if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
2136                 return FALSE;
2137
2138             nstrace->page_offset += (guint16) phdr->caplen;
2139         } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0)
2140         {
2141             *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
2142             return FALSE;
2143         }
2144
2145         break;
2146
2147     case NSPR_HEADER_VERSION200:
2148     case NSPR_HEADER_VERSION201:
2149     case NSPR_HEADER_VERSION202:
2150     case NSPR_HEADER_VERSION203:
2151     case NSPR_HEADER_VERSION204:
2152     case NSPR_HEADER_VERSION205:
2153     case NSPR_HEADER_VERSION206:
2154         if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
2155         {
2156             *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
2157             return FALSE;
2158         } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0)
2159         {
2160             if (nstrace->page_offset + phdr->caplen >= nstrace->page_len)
2161             {
2162                 /* Start on the next page */
2163                 if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
2164                     return FALSE;
2165
2166                 nstrace->page_offset = 0;
2167
2168                 /* Possibly add signature and abstime records and increment offset */
2169                 if (!nstrace_add_signature(wdh, err))
2170                     return FALSE;
2171             }
2172
2173             /* Write the actual record as is */
2174             if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
2175                 return FALSE;
2176
2177             nstrace->page_offset += (guint16) phdr->caplen;
2178         }
2179
2180         break;
2181
2182     case NSPR_HEADER_VERSION300:
2183     case NSPR_HEADER_VERSION350:
2184         if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0)
2185         {
2186             *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
2187             return FALSE;
2188         } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0)
2189         {
2190             *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
2191             return FALSE;
2192         } else if (wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_0 || wdh->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_NETSCALER_3_5)
2193         {
2194             if (nstrace->page_offset + phdr->caplen >= nstrace->page_len)
2195             {
2196                 /* Start on the next page */
2197                 if (wtap_dump_file_seek(wdh, (nstrace->page_len - nstrace->page_offset), SEEK_CUR, err) == -1)
2198                     return FALSE;
2199
2200                 nstrace->page_offset = 0;
2201
2202                 /* Possibly add signature and abstime records and increment offset */
2203                 if (!nstrace_add_signature(wdh, err))
2204                     return FALSE;
2205             }
2206
2207             /* Write the actual record as is */
2208             if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
2209                 return FALSE;
2210
2211             nstrace->page_offset += (guint16) phdr->caplen;
2212         } else
2213         {
2214             g_assert_not_reached();
2215             return FALSE;
2216         }
2217         break;
2218
2219     default:
2220         g_assert_not_reached();
2221         return FALSE;
2222     }
2223
2224     return TRUE;
2225 }
2226
2227 /*
2228  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2229  *
2230  * Local variables:
2231  * c-basic-offset: 4
2232  * tab-width: 8
2233  * indent-tabs-mode: nil
2234  * End:
2235  *
2236  * vi: set shiftwidth=4 tabstop=8 expandtab:
2237  * :indentSize=4:tabSize=8:noTabs=true:
2238  */