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