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