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