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