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