opa: Add dissectors for Intel’s Omni-Path Architecture (OPA)
[metze/wireshark/wip.git] / wiretap / vwr.c
1 /* vwr.c
2  * Copyright (c) 2011 by Tom Alexander <talexander@ixiacom.com>
3  *
4  * Wiretap Library
5  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22 #include "config.h"
23
24 #include <errno.h>
25 #include <string.h>
26
27 #include "wtap-int.h"
28 #include "file_wrappers.h"
29 #include "vwr.h"
30
31
32 /* platform-specific definitions for portability */
33
34 /* unsigned long long constants */
35 #   define NS_IN_US             G_GUINT64_CONSTANT(1000)        /* nanoseconds-to-microseconds */
36 #   define NS_IN_SEC            G_GUINT64_CONSTANT(1000000000)  /* nanoseconds-to-seconds */
37 #   define US_IN_SEC            G_GUINT64_CONSTANT(1000000)     /* microseconds-to-seconds */
38 #   define LL_ZERO              G_GUINT64_CONSTANT(0)           /* zero in unsigned long long */
39
40 /*
41  * Fetch a 64-bit value in "Corey-endian" form.
42  */
43 #define pcoreytohll(p)  ((guint64)*((const guint8 *)(p)+4)<<56|  \
44                          (guint64)*((const guint8 *)(p)+5)<<48|  \
45                          (guint64)*((const guint8 *)(p)+6)<<40|  \
46                          (guint64)*((const guint8 *)(p)+7)<<32|  \
47                          (guint64)*((const guint8 *)(p)+0)<<24|  \
48                          (guint64)*((const guint8 *)(p)+1)<<16|  \
49                          (guint64)*((const guint8 *)(p)+2)<<8|   \
50                          (guint64)*((const guint8 *)(p)+3)<<0)
51
52 /*
53  * Fetch a 48-bit value in "Corey-endian" form; it's stored as
54  * a 64-bit Corey-endian value, with the upper 16 bits ignored.
55  */
56 #define pcorey48tohll(p)  ((guint64)*((const guint8 *)(p)+6)<<40|  \
57                            (guint64)*((const guint8 *)(p)+7)<<32|  \
58                            (guint64)*((const guint8 *)(p)+0)<<24|  \
59                            (guint64)*((const guint8 *)(p)+1)<<16|  \
60                            (guint64)*((const guint8 *)(p)+2)<<8|   \
61                            (guint64)*((const guint8 *)(p)+3)<<0)
62
63 /* .vwr log file defines */
64 #define B_SIZE      32768                           /* max var len message = 32 kB */
65 #define VT_FRAME    0                               /* varlen msg is a frame */
66 #define VT_CPMSG    1                               /* varlen msg is a CP<->PP msg */
67 #define MAX_TRACKED_CLIENTS 1024                    /* track 1024 clients */
68 #define MAX_TRACKED_FLOWS   65536                   /* and 64K flows */
69
70 /*
71  * The file consists of a sequence of records.
72  * A record begins with a 16-byte header, the first 8 bytes of which
73  * begin with a byte containing a command plus transmit-receive flags.
74  *
75  * Following that are two big-endian 32-bit quantities; for some records
76  * one or the other of them is the length of the rest of the record.
77  * Other records contain only the header.
78  */
79 #define VW_RECORD_HEADER_LENGTH 16
80
81 /* Command byte values */
82 #define COMMAND_RX  0x21
83 #define COMMAND_TX  0x31
84
85 /* the metadata headers */
86
87 /* Size of the IxVeriwave common header */
88 #define STATS_COMMON_FIELDS_LEN (2+2+2+4+2+2+4+4+8+8+4)
89
90 /* For VeriWave WLAN and Ethernet metadata headers vw_flags field */
91 #define VW_FLAGS_TXF        0x01                /* frame was transmitted */
92 #define VW_FLAGS_FCSERR     0x02                /* FCS error detected */
93
94 /* For VeriWave WLAN metadata header vw_flags field */
95 #define VW_FLAGS_RETRERR    0x04                /* excess retry error detected */
96 #define VW_FLAGS_DCRERR     0x10                /* decrypt error detected (WLAN) */
97 #define VW_FLAGS_ENCMSK     0x60                /* encryption type mask */
98                                                 /* 0 = none, 1 = WEP, 2 = TKIP, 3 = CCKM */
99 #define VW_FLAGS_IS_WEP     0x20                /* WEP */
100 #define VW_FLAGS_IS_TKIP    0x40                /* TKIP */
101 #define VW_FLAGS_IS_CCMP    0x60                /* CCMP */
102
103 /* Veriwave WLAN metadata header */
104
105 /* Channel flags, for chanflags field */
106 #define CHAN_CCK            0x0020              /* CCK channel */
107 #define CHAN_OFDM           0x0040              /* OFDM channel */
108
109 /* Flags, for flags field */
110 #define FLAGS_SHORTPRE      0x0002              /* sent/received with short preamble */
111 #define FLAGS_WEP           0x0004              /* sent/received with WEP encryption */
112 #define FLAGS_FCS           0x0010              /* frame includes FCS */
113 #define FLAGS_CHAN_HT       0x0040              /* In HT mode */
114 #define FLAGS_CHAN_VHT      0x0080              /* VHT Mode */
115 #define FLAGS_CHAN_SHORTGI  0x0100              /* Short guard interval */
116 #define FLAGS_CHAN_40MHZ    0x0200              /* 40 Mhz channel bandwidth */
117 #define FLAGS_CHAN_80MHZ    0x0400              /* 80 Mhz channel bandwidth */
118 #define FLAGS_CHAN_160MHZ   0x0800              /* 160 Mhz channel bandwidth */
119
120 /* Size of the VeriWave WLAN metadata header */
121 #define EXT_WLAN_FIELDS_LEN (2+2+2+2+1+1+1+1+1+1+1+1+2+2+2+4)
122
123 /* Size of the VeriWave Ethernet metadata header */
124 #define EXT_ETHERNET_FIELDS_LEN (2+2+2+4+4+4)
125
126 /* FPGA-generated frame buffer STATS block offsets and definitions */
127
128 /* definitions for v2.2 frames, Ethernet format */
129 #define v22_E_STATS_LEN          44                 /* length of stats block trailer */
130 #define v22_E_VALID_OFF           0                 /* bit 6 (0x40) is flow-is-valid flag */
131 #define v22_E_MTYPE_OFF           1                 /* offset of modulation type */
132 #define v22_E_VCID_OFF            2                 /* offset of VC ID */
133 #define v22_E_FLOWSEQ_OFF         4                 /* offset of signature sequence number */
134 #define v22_E_FLOWID_OFF          5                 /* offset of flow ID */
135 #define v22_E_OCTET_OFF           8                 /* offset of octets */
136 #define v22_E_ERRORS_OFF         10                 /* offset of error vector */
137 #define v22_E_PATN_OFF           12                 /* offset of pattern match vector */
138 #define v22_E_L4ID_OFF           12
139 #define v22_E_IPLEN_OFF          14
140 #define v22_E_FRAME_TYPE_OFF     16                 /* offset of frame type, 32 bits */
141 #define v22_E_RSSI_OFF           21                 /* RSSI (NOTE: invalid for Ethernet) */
142 #define v22_E_STARTT_OFF         20                 /* offset of start time, 64 bits */
143 #define v22_E_ENDT_OFF           28                 /* offset of end time, 64 bits */
144 #define v22_E_LATVAL_OFF         36                 /* offset of latency, 32 bits */
145 #define v22_E_INFO_OFF           40                 /* NO INFO FIELD IN ETHERNET STATS! */
146 #define v22_E_DIFFERENTIATOR_OFF  0                 /* offset to determine whether */
147                                                     /* eth/802.11, 8 bits */
148 /* Media types */
149 #define v22_E_MT_10_HALF    0                       /* 10 Mb/s half-duplex */
150 #define v22_E_MT_10_FULL    1                       /* 10 Mb/s full-duplex */
151 #define v22_E_MT_100_HALF   2                       /* 100 Mb/s half-duplex */
152 #define v22_E_MT_100_FULL   3                       /* 100 Mb/s full-duplex */
153 #define v22_E_MT_1G_HALF    4                       /* 1 Gb/s half-duplex */
154 #define v22_E_MT_1G_FULL    5                       /* 1 Gb/s full-duplex */
155
156 /* Error flags */
157 #define v22_E_FCS_ERROR           0x0002            /* FCS error flag in error vector */
158 #define v22_E_CRYPTO_ERR          0x1f00            /* RX decrypt error flags (UNUSED) */
159 #define v22_E_SIG_ERR             0x0004            /* signature magic byte mismatch */
160 #define v22_E_PAYCHK_ERR          0x0008            /* payload checksum failure */
161 #define v22_E_RETRY_ERR           0x0400            /* excessive retries on TX fail (UNUSED)*/
162
163 /* Masks and defines */
164 #define v22_E_IS_RX               0x08              /* TX/RX bit in STATS block */
165 #define v22_E_MT_MASK             0x07              /* modulation type mask (UNUSED) */
166
167 #define v22_E_VCID_MASK           0x03ff            /* VC ID is only 10 bits */
168
169 #define v22_E_FLOW_VALID          0x40              /* flow-is-valid flag (else force to 0) */
170
171 #define v22_E_DIFFERENTIATOR_MASK 0X3F              /* mask to differentiate ethernet from */
172
173 /* Bits in FRAME_TYPE field */
174 #define v22_E_IS_TCP              0x00000040        /* TCP */
175 #define v22_E_IS_UDP              0x00000010        /* UDP */
176 #define v22_E_IS_ICMP             0x00000020        /* ICMP */
177 #define v22_E_IS_IGMP             0x00000080        /* IGMP */
178
179 #define v22_E_IS_QOS              0x80              /* QoS bit in MTYPE field (WLAN only) */
180 #define v22_E_IS_VLAN             0x00200000
181
182
183 #define v22_E_RX_DECRYPTS   0x0007                  /* RX-frame-was-decrypted (UNUSED) */
184 #define v22_E_TX_DECRYPTS   0x0007                  /* TX-frame-was-decrypted (UNUSED) */
185
186 #define v22_E_FC_PROT_BIT   0x40                    /* Protected Frame bit in FC1 of frame */
187
188 #define v22_E_IS_ETHERNET   0x00700000              /* bits set in frame type if ethernet */
189 #define v22_E_IS_80211      0x7F000000              /* bits set in frame type if 802.11 */
190
191 /* definitions for v2.2 frames, WLAN format for VW510006 FPGA*/
192 #define v22_W_STATS_LEN          64                 /* length of stats block trailer */
193 #define v22_W_VALID_OFF           0                 /* bit 6 (0x40) is flow-is-valid flag */
194 #define v22_W_MTYPE_OFF           1                 /* offset of modulation type */
195 #define v22_W_VCID_OFF            2                 /* offset of VC ID */
196 #define v22_W_FLOWSEQ_OFF         4                 /* offset of signature sequence number */
197 #define v22_W_FLOWID_OFF          5                 /* offset of flow ID */
198 #define v22_W_OCTET_OFF           8                 /* offset of octets */
199 #define v22_W_ERRORS_OFF         10                 /* offset of error vector */
200 #define v22_W_PATN_OFF           12
201 #define v22_W_L4ID_OFF           12
202 #define v22_W_IPLEN_OFF          14
203 #define v22_W_FRAME_TYPE_OFF     16                 /* offset of frame type, 32 bits */
204 #define v22_W_RSSI_OFF           21                 /* RSSI (NOTE: RSSI must be negated!) */
205 #define v22_W_STARTT_OFF         24                 /* offset of start time, 64 bits */
206 #define v22_W_ENDT_OFF           32                 /* offset of end time, 64 bits */
207 #define v22_W_LATVAL_OFF         40                 /* offset of latency, 32 bits */
208 #define v22_W_INFO_OFF           54                 /* offset of INFO field, 16 LSBs */
209 #define v22_W_DIFFERENTIATOR_OFF 20                 /* offset to determine whether */
210                                                     /*  eth/802.11, 32 bits */
211
212 #define v22_W_PLCP_LENGTH_OFF     4                 /* LENGTH field in the plcp header */
213
214
215 /* Modulation types */
216 #define v22_W_MT_CCKL       0                       /* CCK modulation, long preamble */
217 #define v22_W_MT_CCKS       1                       /* CCK modulation, short preamble */
218 #define v22_W_MT_OFDM       2                       /* OFDM modulation */
219
220 /* Bits in FRAME_TYPE field */
221 #define v22_W_IS_TCP            0x00000040                  /* TCP */
222 #define v22_W_IS_UDP            0x00000010                  /* UDP */
223 #define v22_W_IS_ICMP           0x00000020                  /* ICMP */
224 #define v22_W_IS_IGMP           0x00000080                  /* IGMP */
225
226 /* Bits in MTYPE field (WLAN only) */
227 #define v22_W_IS_QOS            0x80                        /* QoS */
228
229 /* Error flags */
230 #define v22_W_FCS_ERROR     0x0002                  /* FCS error flag in error vector */
231 #define v22_W_CRYPTO_ERR    0x1f00                  /* RX decrypt error flags */
232 #define v22_W_SIG_ERR       0x0004                  /* signature magic byte mismatch */
233 #define v22_W_PAYCHK_ERR    0x0008                  /* payload checksum failure */
234 #define v22_W_RETRY_ERR     0x0400                  /* excessive retries on TX failure */
235
236 /* Masks and defines */
237 #define v22_W_IS_RX         0x08                    /* TX/RX bit in STATS block */
238 #define v22_W_MT_MASK       0x07                    /* modulation type mask */
239
240 #define v22_W_VCID_MASK     0x01ff                  /* VC ID is only 9 bits */
241
242 #define v22_W_FLOW_VALID    0x40                    /* flow-is-valid flag (else force to 0) */
243
244 #define v22_W_DIFFERENTIATOR_MASK 0Xf0ff            /* mask to differentiate ethernet from */
245                                                     /* 802.11 capture */
246
247 #define v22_W_RX_DECRYPTS   0x0007                  /* RX-frame-was-decrypted bits */
248 #define v22_W_TX_DECRYPTS   0x0007                  /* TX-frame-was-decrypted bits */
249
250 /* Info bits */
251 #define v22_W_WEPTYPE               0x0001          /* WEP frame */
252 #define v22_W_TKIPTYPE              0x0002          /* TKIP frame */
253 #define v22_W_CCMPTYPE              0x0004          /* CCMP frame */
254 #define v22_W_MPDU_OF_A_MPDU        0x0400          /* MPDU of A-MPDU */
255 #define v22_W_FIRST_MPDU_OF_A_MPDU  0x0800          /* first MPDU of A-MPDU */
256 #define v22_W_LAST_MPDU_OF_A_MPDU   0x1000          /* last MPDU of A-MPDU */
257 #define v22_W_MSDU_OF_A_MSDU        0x2000          /* MSDU of A-MSDU */
258 #define v22_W_FIRST_MSDU_OF_A_MSDU  0x4000          /* first MSDU of A-MSDU */
259 #define v22_W_LAST_MSDU_OF_A_MSDU   0x8000          /* last MSDU of A-MSDU */
260
261 /* All aggregation flags */
262 #define v22_W_AGGREGATE_FLAGS \
263     (v22_W_MPDU_OF_A_MPDU | \
264      v22_W_FIRST_MPDU_OF_A_MPDU | \
265      v22_W_LAST_MPDU_OF_A_MPDU | \
266      v22_W_MSDU_OF_A_MSDU | \
267      v22_W_FIRST_MSDU_OF_A_MSDU | \
268      v22_W_LAST_MSDU_OF_A_MSDU)
269
270 #define v22_W_FC_PROT_BIT   0x40                    /* Protected Frame bit in FC1 of frame */
271
272 #define v22_W_IS_ETHERNET   0x00100000              /* bits set in frame type if ethernet */
273 #define v22_W_IS_80211      0x7F000000              /* bits set in frame type if 802.11 */
274
275 /* definitions for VW510021 FPGA, WLAN format */
276 /* FORMAT:
277     16 BYTE header
278     8 bytes of stat block
279     plcp stuff (11 bytes plcp + 1 byte pad)
280     data
281     remaining 48 bytes of stat block
282 */
283 /* offsets in the stats block */
284 #define vVW510021_W_STATS_HEADER_LEN     8          /* length of stats block header at beginning of record data */
285 #define vVW510021_W_STATS_TRAILER_LEN   48          /* length of stats block trailer after the plcp portion*/
286 #define vVW510021_W_STARTT_OFF           0          /* offset of start time, 64 bits */
287 #define vVW510021_W_ENDT_OFF             8          /* offset of end time, 64 bits */
288 #define vVW510021_W_ERRORS_OFF          16          /* offset of error vector */
289 #define vVW510021_W_VALID_OFF           20          /* 2 Bytes with different validity bits */
290 #define vVW510021_W_INFO_OFF            22          /* offset of INFO field, 16 LSBs */
291 #define vVW510021_W_FRAME_TYPE_OFF      24
292 #define vVW510021_W_L4ID_OFF            28
293 #define vVW510021_W_IPLEN_OFF           30          /* offset of IP Total Length field */
294 #define vVW510021_W_FLOWSEQ_OFF         32          /* offset of signature sequence number */
295 #define vVW510021_W_FLOWID_OFF          33          /* offset of flow ID */
296 #define vVW510021_W_LATVAL_OFF          36          /* offset of delay/flowtimestamp, 32b */
297 #define vVW510021_W_DEBUG_OFF           40          /* offset of debug, 16 bits */
298 #define S2_W_FPGA_VERSION_OFF           44          /* offset of fpga version, 16 bits */
299 #define vVW510021_W_MATCH_OFF           47          /* offset of pattern match vector */
300
301 /* offsets in the header block */
302 #define vVW510021_W_HEADER_LEN          16          /* length of FRAME header */
303 #define vVW510021_W_RXTX_OFF             0          /* rxtx offset, cmd byte of header */
304 #define vVW510021_W_HEADER_VERSION_OFF   9          /* version, 2bytes */
305 #define vVW510021_MSG_LENGTH_OFF        10          /* MSG LENGTH, 2bytes */
306 #define vVW510021_W_DEVICE_TYPE_OFF      8          /* version, 2bytes */
307
308 /* offsets that occur right after the header */
309 #define vVW510021_W_AFTERHEADER_LEN      8          /* length of STATs info directly after header */
310 #define vVW510021_W_L1P_1_OFF            0          /* offset of 1st byte of layer one info */
311 #define vVW510021_W_L1P_2_OFF            1          /* offset of 2nd byte of layer one info */
312 #define vVW510021_W_MTYPE_OFF           vVW510021_W_L1P_2_OFF
313 #define vVW510021_W_PREAMBLE_OFF        vVW510021_W_L1P_1_OFF
314 #define vVW510021_W_RSSI_TXPOWER_OFF     2          /* RSSI (NOTE: RSSI must be negated!) */
315 #define vVW510021_W_MSDU_LENGTH_OFF      3          /* 7:0 of length, next byte 11:8 in top 4 bits */
316 #define vVW510021_W_BVCV_VALID_OFF       4          /* BV,CV Determine validaity of bssid and txpower */
317 #define vVW510021_W_VCID_OFF             6          /* offset of VC (client) ID */
318 #define vVW510021_W_PLCP_LENGTH_OFF     12          /* LENGTH field in the plcp header */
319
320 /* Masks and defines */
321 #define vVW510021_W_IS_BV               0x04        /* BV bit in STATS block */
322 #define vVW510021_W_IS_CV               0x02        /* BV bit in STATS block */
323 #define vVW510021_W_FLOW_VALID          0x8000      /* valid_off flow-is-valid flag (else 0) */
324 #define vVW510021_W_QOS_VALID           0x4000
325 #define vVW510021_W_HT_VALID            0x2000
326 #define vVW510021_W_L4ID_VALID          0x1000
327 #define vVW510021_W_MOD_SCHEME_MASK     0x3f        /* modulation type mask */
328 #define vVW510021_W_SEL_MASK            0x80
329 #define vVW510021_W_WEP_MASK            0x0001
330 #define vVW510021_W_CBW_MASK            0xC0
331
332 #define vVW510024_W_VCID_MASK           0x03ff      /* VC ID is only 10 bits */
333
334 #define vVW510021_W_MT_SEL_LEGACY       0x00
335
336 #define vVW510021_W_IS_WEP              0x0001
337
338 /* L1p byte 1 info */
339
340 /* Common to Series II and Series III */
341
342 #define vVW510021_W_IS_LONGPREAMBLE     0x40        /* short/long preamble bit */
343 #define vVW510021_W_IS_LONGGI           0x40        /* short/long guard interval bit */
344
345 /* Series II */
346
347 #define vVW510021_W_S2_MCS_INDEX(l1p_1) ((l1p_1) & 0x3f) /* MCS index */
348
349 /* Series III */
350
351 /*
352  * VHT - contains MCS index and number of spatial streams.
353  * The number of spatial streams from the FPGA is zero-based, so we add
354  * 1 to it.
355  */
356 #define vVW510021_W_S3_MCS_INDEX_VHT(l1p_1) ((l1p_1) & 0x0f) /* MCS index */
357 #define vVW510021_W_S3_NSS_VHT(l1p_1)       (((l1p_1) >> 4 & 0x3) + 1) /* NSS */
358
359 /*
360  * HT - contains MCS index
361  */
362 #define vVW510021_W_S3_MCS_INDEX_HT(l1p_1)  ((l1p_1) & 0x3f)
363
364 /* L1p byte 2 info */
365
366 /* Common to Series II and Series III */
367 #define vVW510021_W_BANDWIDTH_VHT(l1p_2) (((l1p_2) >> 4) & 0xf)
368 /* 3 = 40 MHz, 4 = 80 MHz; what about 20 and 160 MHz? */
369
370 /* Series II */
371 #define vVW510021_W_S2_PLCP_TYPE(l1p_2) ((l1p_2) & 0x03) /* PLCP type */
372
373 /* Series III */
374 #define vVW510021_W_S3_PLCP_TYPE(l1p_2) ((l1p_2) & 0x0f) /* PLCP type */
375
376 /* PLCP types */
377 #define vVW510021_W_PLCP_LEGACY         0x00        /* pre-HT (11b/a/g) */
378 #define vVW510021_W_PLCP_MIXED          0x01        /* HT, mixed (11n) */
379 #define vVW510021_W_PLCP_GREENFIELD     0x02        /* HT, greenfield (11n) */
380 #define vVW510021_W_PLCP_VHT_MIXED      0x03        /* VHT (11ac) */
381
382 /* Bits in FRAME_TYPE field */
383 #define vVW510021_W_IS_TCP          0x01000000      /* TCP */
384 #define vVW510021_W_IS_UDP          0x00100000      /* UDP */
385 #define vVW510021_W_IS_ICMP         0x00001000      /* ICMP */
386 #define vVW510021_W_IS_IGMP         0x00010000      /* IGMP */
387
388
389 #define vVW510021_W_HEADER_VERSION      0x00
390 #define vVW510021_W_DEVICE_TYPE         0x15
391 #define vVW510021_W_11n_DEVICE_TYPE     0x20
392 #define S2_W_FPGA_VERSION               0x000C
393 #define vVW510021_W_11n_FPGA_VERSION    0x000D
394
395 /* Error flags */
396 #define vVW510021_W_FCS_ERROR           0x01
397
398 #define vVW510021_W_CRYPTO_ERROR        0x50000
399
400 /* Info bits are the same as for the VWS10006 FPGA */
401
402 /* definitions for VW510024 FPGA, wired ethernet format */
403 /* FORMAT:
404     16 BYTE header
405     52 bytes of stats block trailer
406 */
407 /* offsets in the stats block */
408 #define vVW510024_E_STATS_LEN           48          /* length of stats block trailer */
409 #define vVW510024_E_MSDU_LENGTH_OFF      0          /* MSDU 16 BITS */
410 #define vVW510024_E_BMCV_VALID_OFF       2          /* BM,CV Determine validITY */
411 #define vVW510024_E_VCID_OFF             2          /* offset of VC (client) ID 13:8, */
412                                                     /*  7:0 IN offset 7*/
413 #define vVW510024_E_STARTT_OFF           4          /* offset of start time, 64 bits */
414 #define vVW510024_E_ENDT_OFF            12          /* offset of end time, 64 bits */
415 #define vVW510024_E_ERRORS_OFF          22          /* offset of error vector */
416 #define vVW510024_E_VALID_OFF           24          /* 2 Bytes with different validity bits */
417 #define vVW510024_E_INFO_OFF            26          /* offset of INFO field, 16 LSBs */
418 #define vVW510024_E_FRAME_TYPE_OFF      28
419 #define vVW510024_E_L4ID_OFF            32
420 #define vVW510024_E_IPLEN_OFF           34
421 #define vVW510024_E_FLOWSEQ_OFF         36          /* offset of signature sequence number */
422 #define vVW510024_E_FLOWID_OFF          37          /* offset of flow ID */
423 #define vVW510024_E_LATVAL_OFF          40          /* offset of delay/flowtimestamp, 32 bits */
424 #define vVW510024_E_FPGA_VERSION_OFF    20          /* offset of fpga version, 16 bits */
425 #define vVW510024_E_MATCH_OFF           51          /* offset of pattern match vector */
426
427 /* offsets in the header block */
428 #define vVW510024_E_HEADER_LEN          vVW510021_W_HEADER_LEN      /* length of FRAME header */
429 #define vVW510024_E_RXTX_OFF            vVW510021_W_RXTX_OFF        /* rxtx offset, cmd byte */
430 #define vVW510024_E_HEADER_VERSION_OFF  16                          /* version, 2bytes */
431 #define vVW510024_E_MSG_LENGTH_OFF      vVW510021_MSG_LENGTH_OFF    /* MSG LENGTH, 2bytes */
432 #define vVW510024_E_DEVICE_TYPE_OFF     vVW510021_W_DEVICE_TYPE_OFF /* Device Type, 2bytes */
433
434 /* Masks and defines */
435 #define vVW510024_E_IS_BV               0x80                    /* Bm bit in STATS block */
436 #define vVW510024_E_IS_CV               0x40                    /* cV bit in STATS block */
437 #define vVW510024_E_FLOW_VALID          0x8000                  /* valid_off flow-is-valid flag (else force to 0) */
438 #define vVW510024_E_QOS_VALID           0x0000                  /** not valid for ethernet **/
439 #define vVW510024_E_L4ID_VALID          0x1000
440 #define vVW510024_E_CBW_MASK            0xC0
441
442 #define vVW510024_E_VCID_MASK           0x3fff                  /* VCID is only 14 bits */
443
444 #define vVW510024_E_IS_TCP          0x01000000                  /* TCP bit in FRAME_TYPE field */
445 #define vVW510024_E_IS_UDP          0x00100000                  /* UDP bit in FRAME_TYPE field */
446 #define vVW510024_E_IS_ICMP         0x00001000                  /* ICMP bit in FRAME_TYPE field */
447 #define vVW510024_E_IS_IGMP         0x00010000
448 #define vVW510024_E_IS_VLAN         0x4000
449
450 #define vVW510024_E_HEADER_VERSION      0x00
451 #define vVW510024_E_DEVICE_TYPE         0x18
452 #define vVW510024_E_FPGA_VERSION        0x0001
453
454 #define FPGA_VER_NOT_APPLICABLE         0
455
456 #define UNKNOWN_FPGA                    0
457 #define S2_W_FPGA                       1
458 #define S1_W_FPGA                       2
459 #define vVW510012_E_FPGA                3
460 #define vVW510024_E_FPGA                4
461 #define S3_W_FPGA                       5
462
463     /* the flow signature is:
464     Byte Description
465 0   Magic Number (0xDD)
466 1   Chassis Number[7:0]
467 2   Slot Number[7:0]
468 3   Port Number[7:0]
469 4   Flow ID[7:0]
470 5   Flow ID[15:8]
471 6   Flow ID[23:16]
472 7   Flow Sequence Number[7:0]
473 8   Timestamp[7:0]
474 9   Timestamp[15:8]
475 10  Timestamp[23:16]
476 11  Timestamp[31:24]
477 12  Timestamp[39:32]
478 13  Timestamp[47:40]
479 14  CRC16
480 15  CRC16
481
482 */
483 #define SIG_SIZE        16                           /* size of signature field, bytes     */
484 #define SIG_FID_OFF      4                           /* offset of flow ID in signature     */
485 #define SIG_FSQ_OFF      7                           /* offset of flow seqnum in signature */
486 #define SIG_TS_OFF       8                           /* offset of flow seqnum in signature */
487
488
489
490 /*--------------------------------------------------------------------------------------*/
491 /* Per-capture file private data structure */
492
493 typedef struct {
494     /* offsets in stats block; these are dependent on the frame type (Ethernet/WLAN) and */
495     /* version number of .vwr file, and are set up by setup_defaults() */
496     guint32      STATS_LEN;                      /* length of stats block trailer */
497     guint32      STATS_START_OFF;                /* STATS OFF AFTER HEADER */
498     guint32      VALID_OFF;                      /* bit 6 (0x40) is flow-is-valid flag */
499     guint32      MTYPE_OFF;                      /* offset of modulation type */
500     guint32      VCID_OFF;                       /* offset of VC ID */
501     guint32      FLOWSEQ_OFF;                    /* offset of signature sequence number */
502     guint32      FLOWID_OFF;                     /* offset of flow ID */
503     guint32      OCTET_OFF;                      /* offset of octets */
504     guint32      ERRORS_OFF;                     /* offset of error vector */
505     guint32      PATN_OFF;                       /* offset of pattern match vector */
506     guint32      RSSI_OFF;                       /* RSSI (NOTE: RSSI must be negated!) */
507     guint32      STARTT_OFF;                     /* offset of start time, 64 bits */
508     guint32      ENDT_OFF;                       /* offset of end time, 64 bits */
509     guint32      LATVAL_OFF;                     /* offset of latency, 32 bits */
510     guint32      INFO_OFF;                       /* offset of INFO field, 16 bits */
511     guint32      L1P_1_OFF;                      /* offset 1ST Byte of l1params */
512     guint32      L1P_2_OFF;                      /* offset 2nd Byte of l1params */
513     guint32      L4ID_OFF;                       /* LAYER 4 id offset*/
514     guint32      IPLEN_OFF;                      /* */
515     guint32      PLCP_LENGTH_OFF;                /* offset of length field in the PLCP header */
516     guint32      FPGA_VERSION_OFF;               /* offset of fpga version field, 16 bits */
517     guint32      HEADER_VERSION_OFF;             /* offset of header version, 16 bits */
518     guint32      RXTX_OFF;                       /* offset of CMD bit, rx or tx */
519     guint32      FRAME_TYPE_OFF;
520
521     /* other information about the file in question */
522     guint32      MT_10_HALF;                     /* 10 Mb/s half-duplex */
523     guint32      MT_10_FULL;                     /* 10 Mb/s full-duplex */
524     guint32      MT_100_HALF;                    /* 100 Mb/s half-duplex */
525     guint32      MT_100_FULL;                    /* 100 Mb/s full-duplex */
526     guint32      MT_1G_HALF;                     /* 1 Gb/s half-duplex */
527     guint32      MT_1G_FULL;                     /* 1 Gb/s full-duplex */
528     guint32      FCS_ERROR;                      /* FCS error in frame */
529     guint32      CRYPTO_ERR;                     /* RX decrypt error flags */
530     guint32      PAYCHK_ERR;                     /* payload checksum failure */
531     guint32      RETRY_ERR;                      /* excessive retries on TX failure */
532     guint8       IS_RX;                          /* TX/RX bit in STATS block */
533     guint8       MT_MASK;                        /* modulation type mask */
534     guint16      VCID_MASK;                      /* VC ID might not be a full 16 bits */
535     guint32      FLOW_VALID;                     /* flow-is-valid flag (else force to 0) */
536     guint16      QOS_VALID;
537     guint32      RX_DECRYPTS;                    /* RX-frame-was-decrypted bits */
538     guint32      TX_DECRYPTS;                    /* TX-frame-was-decrypted bits */
539     guint32      FC_PROT_BIT;                    /* Protected Frame bit in FC1 of frame */
540     guint32      MT_CCKL;                        /* CCK modulation, long preamble */
541     guint32      MT_CCKS;                        /* CCK modulation, short preamble */
542     guint32      MT_OFDM;                        /* OFDM modulation */
543     guint32      FPGA_VERSION;
544     guint32      WEPTYPE;                        /* frame is WEP */
545     guint32      TKIPTYPE;                       /* frame is TKIP */
546     guint32      CCMPTYPE;                       /* frame is CCMP */
547     guint32      IS_TCP;
548     guint32      IS_UDP;
549     guint32      IS_ICMP;
550     guint32      IS_IGMP;
551     guint16      IS_QOS;
552     guint32      IS_VLAN;
553     guint32      MPDU_OFF;
554 } vwr_t;
555
556 /* internal utility functions */
557 static int          decode_msg(register guint8 *, int *, int *);
558 static guint8       get_ofdm_rate(const guint8 *);
559 static guint8       get_cck_rate(const guint8 *plcp);
560 static void         setup_defaults(vwr_t *, guint16);
561
562 static gboolean     vwr_read(wtap *, int *, gchar **, gint64 *);
563 static gboolean     vwr_seek_read(wtap *, gint64, struct wtap_pkthdr *phdr,
564                                   Buffer *, int *, gchar **);
565
566 static gboolean     vwr_read_rec_header(FILE_T, int *, int *, int *, gchar **);
567 static gboolean     vwr_process_rec_data(FILE_T fh, int rec_size,
568                                          struct wtap_pkthdr *phdr, Buffer *buf,
569                                          vwr_t *vwr, int IS_TX, int *err,
570                                          gchar **err_info);
571
572 static int          vwr_get_fpga_version(wtap *, int *, gchar **);
573
574 static gboolean     vwr_read_s1_W_rec(vwr_t *, struct wtap_pkthdr *, Buffer *,
575                                       const guint8 *, int, int *, gchar **);
576 static gboolean     vwr_read_s2_s3_W_rec(vwr_t *, struct wtap_pkthdr *, Buffer *,
577                                          const guint8 *, int, int, int *,
578                                          gchar **);
579 static gboolean     vwr_read_rec_data_ethernet(vwr_t *, struct wtap_pkthdr *,
580                                                Buffer *, const guint8 *, int,
581                                                int, int *, gchar **);
582
583 static int          find_signature(const guint8 *, int, int, register guint32, register guint8);
584 static guint64      get_signature_ts(const guint8 *, int);
585 static float        getRate( guint8 plcpType, guint8 mcsIndex, guint16 rflags, guint8 nss );
586
587 /* Open a .vwr file for reading */
588 /* This does very little, except setting the wiretap header for a VWR file type */
589 /*  and setting the timestamp precision to microseconds.                        */
590
591 wtap_open_return_val vwr_open(wtap *wth, int *err, gchar **err_info)
592 {
593     int    fpgaVer;
594     vwr_t *vwr;
595
596     *err = 0;
597
598     fpgaVer = vwr_get_fpga_version(wth, err, err_info);
599     if (fpgaVer == -1) {
600         return WTAP_OPEN_ERROR; /* I/O error */
601     }
602     if (fpgaVer == UNKNOWN_FPGA) {
603         return WTAP_OPEN_NOT_MINE; /* not a VWR file */
604     }
605
606     /* This is a vwr file */
607     vwr = (vwr_t *)g_malloc0(sizeof(vwr_t));
608     wth->priv = (void *)vwr;
609
610     vwr->FPGA_VERSION = fpgaVer;
611     /* set the local module options first */
612     setup_defaults(vwr, fpgaVer);
613
614     wth->snapshot_length = 0;
615     wth->subtype_read = vwr_read;
616     wth->subtype_seek_read = vwr_seek_read;
617     wth->file_tsprec = WTAP_TSPREC_USEC;
618     wth->file_encap = WTAP_ENCAP_IXVERIWAVE;
619
620     if (fpgaVer == S2_W_FPGA || fpgaVer == S1_W_FPGA || fpgaVer == S3_W_FPGA)
621         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_VWR_80211;
622     else if (fpgaVer == vVW510012_E_FPGA || fpgaVer == vVW510024_E_FPGA)
623         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_VWR_ETH;
624
625     return WTAP_OPEN_MINE;
626 }
627
628
629 /* Read the next packet */
630 /* Note that the VWR file format consists of a sequence of fixed 16-byte record headers of */
631 /*  different types; some types, including frame record headers, are followed by           */
632 /*  variable-length data.                                                                  */
633 /* A frame record consists of: the above 16-byte record header, a 1-16384 byte raw PLCP    */
634 /*  frame, and a 64-byte statistics block trailer.                                         */
635 /* The PLCP frame consists of a 4-byte or 6-byte PLCP header, followed by the MAC frame    */
636
637 static gboolean vwr_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
638 {
639     vwr_t *vwr      = (vwr_t *)wth->priv;
640     int    rec_size = 0, IS_TX;
641
642     /* read the next frame record header in the capture file; if no more frames, return */
643     if (!vwr_read_rec_header(wth->fh, &rec_size, &IS_TX, err, err_info))
644         return FALSE;                                   /* Read error or EOF */
645
646     /*
647      * We're past the header; return the offset of the header, not of
648      * the data past the header.
649      */
650     *data_offset = (file_tell(wth->fh) - VW_RECORD_HEADER_LENGTH);
651
652     /* got a frame record; read and process it */
653     if (!vwr_process_rec_data(wth->fh, rec_size, &wth->phdr,
654                               wth->frame_buffer, vwr, IS_TX, err, err_info))
655        return FALSE;
656
657     /* If the per-file encapsulation isn't known, set it to this packet's encapsulation. */
658     /* If it *is* known, and it isn't this packet's encapsulation, set it to             */
659     /*  WTAP_ENCAP_PER_PACKET, as this file doesn't have a single encapsulation for all  */
660     /*  packets in the file.                                                             */
661     if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
662         wth->file_encap = wth->phdr.pkt_encap;
663     else {
664         if (wth->file_encap != wth->phdr.pkt_encap)
665             wth->file_encap = WTAP_ENCAP_PER_PACKET;
666     }
667
668     return TRUE;
669 }
670
671 /* read a random record in the middle of a file; the start of the record is @ seek_off */
672
673 static gboolean vwr_seek_read(wtap *wth, gint64 seek_off,
674     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
675 {
676     vwr_t *vwr = (vwr_t *)wth->priv;
677     int    rec_size, IS_TX;
678
679     /* first seek to the indicated record header */
680     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
681         return FALSE;
682
683     /* read in the record header */
684     if (!vwr_read_rec_header(wth->random_fh, &rec_size, &IS_TX, err, err_info))
685         return FALSE;                                  /* Read error or EOF */
686
687     return vwr_process_rec_data(wth->random_fh, rec_size, phdr, buf,
688                                 vwr, IS_TX, err, err_info);
689 }
690
691 /* Scan down in the input capture file to find the next frame header.       */
692 /* Decode and skip over all non-frame messages that are in the way.         */
693 /* Return TRUE on success, FALSE on EOF or error.                           */
694 /* Also return the frame size in bytes and the "is transmitted frame" flag. */
695
696 static gboolean vwr_read_rec_header(FILE_T fh, int *rec_size, int *IS_TX, int *err, gchar **err_info)
697 {
698     int     f_len, v_type;
699     guint8  header[VW_RECORD_HEADER_LENGTH];
700
701     *rec_size = 0;
702
703     /* Read out the file data in 16-byte messages, stopping either after we find a frame,  */
704     /*  or if we run out of data.                                                          */
705     /* Each 16-byte message is decoded; if we run across a non-frame message followed by a */
706     /*  variable-length item, we read the variable length item out and discard it.         */
707     /* If we find a frame, we return (with the header in the passed buffer).               */
708     while (1) {
709         if (!wtap_read_bytes_or_eof(fh, header, VW_RECORD_HEADER_LENGTH, err, err_info))
710             return FALSE;
711
712         /* Got a header; invoke decode-message function to parse and process it.     */
713         /* If the function returns a length, then a frame or variable-length message */
714         /*  follows the 16-byte message.                                             */
715         /* If the variable length message is not a frame, simply skip over it.       */
716         if ((f_len = decode_msg(header, &v_type, IS_TX)) != 0) {
717             if (f_len > B_SIZE) {
718                 *err = WTAP_ERR_BAD_FILE;
719                 *err_info = g_strdup_printf("vwr: Invalid message record length %d", f_len);
720                 return FALSE;
721             }
722             else if (v_type != VT_FRAME) {
723                 if (!file_skip(fh, f_len, err))
724                     return FALSE;
725             }
726             else {
727                 *rec_size = f_len;
728                 return TRUE;
729             }
730         }
731     }
732 }
733
734 /* Figure out the FPGA version (and also see whether this is a VWR file type. */
735 /* Return FPGA version if it's a known version, UNKNOWN_FPGA if it's not,     */
736 /*  and -1 on an I/O error.                                                   */
737
738 static int vwr_get_fpga_version(wtap *wth, int *err, gchar **err_info)
739 {
740     guint8   rec[B_SIZE];         /* local buffer (holds input record) */
741     guint8   header[VW_RECORD_HEADER_LENGTH];
742     int      rec_size     = 0;
743     guint8   i;
744     guint8  *s_510006_ptr = NULL;
745     guint8  *s_510024_ptr = NULL;
746     guint8  *s_510012_ptr = NULL; /* stats pointers */
747     gint64   filePos;
748     guint32  frame_type   = 0;
749     int      f_len, v_type;
750     guint16  data_length  = 0;
751     guint16  fpga_version;
752     int      valid_but_empty_file = -1;
753
754     filePos = file_tell(wth->fh);
755     if (filePos == -1) {
756         *err = file_error(wth->fh, err_info);
757         return -1;
758     }
759
760     fpga_version = 1000;
761     /* Got a frame record; see if it is vwr  */
762     /* If we don't get it all, then declare an error, we can't process the frame.          */
763     /* Read out the file data in 16-byte messages, stopping either after we find a frame,  */
764     /*  or if we run out of data.                                                          */
765     /* Each 16-byte message is decoded; if we run across a non-frame message followed by a */
766     /*  variable-length item, we read the variable length item out and discard it.         */
767     /* If we find a frame, we return (with the header in the passed buffer).               */
768     while (wtap_read_bytes(wth->fh, header, VW_RECORD_HEADER_LENGTH, err, err_info)) {
769         /* Got a header; invoke decode-message function to parse and process it.     */
770         /* If the function returns a length, then a frame or variable-length message */
771         /*  follows the 16-byte message.                                             */
772         /* If the variable length message is not a frame, simply skip over it.       */
773         if ((f_len = decode_msg(header, &v_type, NULL)) != 0) {
774             if (f_len > B_SIZE) {
775                 /* Treat this here as an indication that the file probably */
776                 /*  isn't a vwr file. */
777                 return UNKNOWN_FPGA;
778             }
779             else if (v_type != VT_FRAME) {
780                 if (file_seek(wth->fh, f_len, SEEK_CUR, err) < 0)
781                     return -1;
782                 else if (v_type == VT_CPMSG)
783                     valid_but_empty_file = 1;
784             }
785             else {
786                 rec_size = f_len;
787                 /* Got a frame record; read over entire record (frame + trailer) into a local buffer */
788                 /* If we don't get it all, assume this isn't a vwr file */
789                 if (!wtap_read_bytes(wth->fh, rec, rec_size, err, err_info)) {
790                     if (*err == WTAP_ERR_SHORT_READ)
791                         return UNKNOWN_FPGA; /* short read - not a vwr file */
792                     return -1;
793                 }
794
795
796                 /*  I'll grab the bytes where the Ethernet "octets" field should be and the bytes where */
797                 /*   the 802.11 "octets" field should be. Then if I do rec_size - octets -              */
798                 /*   size_of_stats_block and it's 0, I can select the correct type.                     */
799                 /*  octets + stats_len = rec_size only when octets have been incremented to nearest     */
800                 /*   number divisible by 4.                                                             */
801
802                 /* First check for series I WLAN since the check is more rigorous. */
803                 if (rec_size > v22_W_STATS_LEN) {
804                     s_510006_ptr = &(rec[rec_size - v22_W_STATS_LEN]);      /* point to 510006 WLAN */
805                                                                             /* stats block */
806
807                     data_length = pntoh16(&s_510006_ptr[v22_W_OCTET_OFF]);
808                     i = 0;
809                     while (((data_length + i) % 4) != 0)
810                         i = i + 1;
811
812                     frame_type = pntoh32(&s_510006_ptr[v22_W_FRAME_TYPE_OFF]);
813
814                     if (rec_size == (data_length + v22_W_STATS_LEN + i) && (frame_type & v22_W_IS_80211) == 0x1000000) {
815                         fpga_version = S1_W_FPGA;
816                     }
817                 }
818
819                 /* Next for the series I Ethernet */
820                 if ((rec_size > v22_E_STATS_LEN) && (fpga_version == 1000)) {
821                     s_510012_ptr = &(rec[rec_size - v22_E_STATS_LEN]);      /* point to 510012 enet */
822                                                                             /* stats block */
823                     data_length = pntoh16(&s_510012_ptr[v22_E_OCTET_OFF]);
824                     i = 0;
825                     while (((data_length + i) % 4) != 0)
826                         i = i + 1;
827
828                     if (rec_size == (data_length + v22_E_STATS_LEN + i))
829                         fpga_version = vVW510012_E_FPGA;
830                 }
831
832
833                 /* Next the series II WLAN */
834                 if ((rec_size > vVW510021_W_STATS_TRAILER_LEN) && (fpga_version == 1000)) {
835                     /* stats block */
836
837                     if ((header[8] == 48) || (header[8] == 61) || (header[8] == 68))
838                         fpga_version = S3_W_FPGA;
839                     else {
840                         data_length = (256 * (rec[vVW510021_W_MSDU_LENGTH_OFF + 1] & 0x1f)) + rec[vVW510021_W_MSDU_LENGTH_OFF];
841
842                         i = 0;
843                         while (((data_length + i) % 4) != 0)
844                             i = i + 1;
845
846                         /*the 12 is from the 12 bytes of plcp header */
847                         if (rec_size == (data_length + vVW510021_W_STATS_TRAILER_LEN +vVW510021_W_AFTERHEADER_LEN+12+i))
848                             fpga_version = S2_W_FPGA;
849                     }
850                 }
851
852                 /* Finally the Series II Ethernet */
853                 if ((rec_size > vVW510024_E_STATS_LEN) && (fpga_version == 1000)) {
854                     s_510024_ptr = &(rec[rec_size - vVW510024_E_STATS_LEN]);    /* point to 510024 ENET */
855                     data_length = pntoh16(&s_510024_ptr[vVW510024_E_MSDU_LENGTH_OFF]);
856
857                     i = 0;
858                     while (((data_length + i) % 4) != 0)
859                         i = i + 1;
860
861                     if (rec_size == (data_length + vVW510024_E_STATS_LEN + i))
862                         fpga_version = vVW510024_E_FPGA;
863                 }
864                 if (fpga_version != 1000)
865                 {
866                     /* reset the file position offset */
867                     if (file_seek (wth->fh, filePos, SEEK_SET, err) == -1) {
868                         return (-1);
869                     }
870                     /* We found an FPGA that works */
871                     return fpga_version;
872                 }
873             }
874         }
875     }
876
877     /* Is this a valid but empty file?  If so, claim it's the S3_W_FPGA FPGA. */
878     if (valid_but_empty_file > 0)
879         return(S3_W_FPGA);
880
881     if (*err == WTAP_ERR_SHORT_READ)
882         return UNKNOWN_FPGA; /* short read - not a vwr file */
883     return -1;
884 }
885
886 /* Copy the actual packet data from the capture file into the target data block. */
887 /* The packet is constructed as a 38-byte VeriWave metadata header plus the raw */
888 /*  MAC octets. */
889
890 static gboolean vwr_read_s1_W_rec(vwr_t *vwr, struct wtap_pkthdr *phdr,
891                                   Buffer *buf, const guint8 *rec, int rec_size,
892                                   int *err, gchar **err_info)
893 {
894     guint8           *data_ptr;
895     int              bytes_written = 0;                   /* bytes output to buf so far */
896     const guint8     *s_ptr, *m_ptr;                      /* stats pointer */
897     guint16          msdu_length, actual_octets;          /* octets in frame */
898     guint16          plcp_hdr_len;                        /* PLCP header length */
899     guint16          rflags;
900     guint8           m_type;                              /* mod type (CCK-L/CCK-S/OFDM), seqnum */
901     guint            flow_seq;
902     guint64          s_time = LL_ZERO, e_time = LL_ZERO;  /* start/end */
903                                                           /* times, nsec */
904     guint32          latency;
905     guint64          start_time, s_sec, s_usec = LL_ZERO; /* start time, sec + usec */
906     guint64          end_time;                            /* end time */
907     guint32          info;                                /* INFO/ERRORS fields in stats blk */
908     gint8            rssi;                                /* RSSI, signed 8-bit number */
909     int              f_tx;                                /* flag: if set, is a TX frame */
910     guint8           plcp_type, mcs_index, nss;           /* PLCP type 0: Legacy, 1: Mixed, 2: Green field, 3: VHT Mixed */
911     guint16          vc_id, ht_len=0;                     /* VC ID, total ip length */
912     guint            flow_id;                             /* flow ID */
913     guint32          d_time, errors;                      /* packet duration & errors */
914     int              sig_off, pay_off;                    /* MAC+SNAP header len, signature offset */
915     guint64          sig_ts;                              /* 32 LSBs of timestamp in signature */
916     guint16          phyRate;
917     guint16          vw_flags;                            /* VeriWave-specific packet flags */
918
919     /*
920      * The record data must be large enough to hold the statistics trailer.
921      */
922     if (rec_size < v22_W_STATS_LEN) {
923         *err_info = g_strdup_printf("vwr: Invalid record length %d (must be at least %u)",
924                                     rec_size, v22_W_STATS_LEN);
925         *err = WTAP_ERR_BAD_FILE;
926         return FALSE;
927     }
928
929     /* Calculate the start of the statistics block in the buffer */
930     /* Also get a bunch of fields from the stats block */
931     s_ptr    = &(rec[rec_size - v22_W_STATS_LEN]); /* point to it */
932     m_type   = s_ptr[v22_W_MTYPE_OFF] & 0x7;
933     f_tx     = !(s_ptr[v22_W_MTYPE_OFF] & 0x8);
934     actual_octets   = pntoh16(&s_ptr[v22_W_OCTET_OFF]);
935     vc_id    = pntoh16(&s_ptr[v22_W_VCID_OFF]) & 0x3ff;
936     flow_seq = s_ptr[v22_W_FLOWSEQ_OFF];
937
938     latency = (guint32)pcorey48tohll(&s_ptr[v22_W_LATVAL_OFF]);
939
940     flow_id = pntoh16(&s_ptr[v22_W_FLOWID_OFF+1]);  /* only 16 LSBs kept */
941     errors  = pntoh16(&s_ptr[v22_W_ERRORS_OFF]);
942
943     info = pntoh16(&s_ptr[v22_W_INFO_OFF]);
944     rssi = (s_ptr[v22_W_RSSI_OFF] & 0x80) ? (-1 * (s_ptr[v22_W_RSSI_OFF] & 0x7f)) : s_ptr[v22_W_RSSI_OFF];
945
946     /*
947      * Sanity check the octets field to determine if it's greater than
948      * the packet data available in the record - i.e., the record size
949      * minus the length of the statistics block.
950      *
951      * Report an error if it is.
952      */
953     if (actual_octets > rec_size - v22_W_STATS_LEN) {
954         *err_info = g_strdup_printf("vwr: Invalid data length %u (runs past the end of the record)",
955                                     actual_octets);
956         *err = WTAP_ERR_BAD_FILE;
957         return FALSE;
958     }
959
960     /* Decode OFDM or CCK PLCP header and determine rate and short preamble flag. */
961     /* The SIGNAL byte is always the first byte of the PLCP header in the frame.  */
962     plcp_type = 0;
963     nss = 1;
964     if (m_type == vwr->MT_OFDM)
965         mcs_index = get_ofdm_rate(rec);
966     else if ((m_type == vwr->MT_CCKL) || (m_type == vwr->MT_CCKS))
967         mcs_index = get_cck_rate(rec);
968     else
969         mcs_index = 1;
970     rflags  = (m_type == vwr->MT_CCKS) ? FLAGS_SHORTPRE : 0;
971     /* Calculate the MPDU size/ptr stuff; MPDU starts at 4 or 6 depending on OFDM/CCK. */
972     /* Note that the number of octets in the frame also varies depending on OFDM/CCK,  */
973     /*  because the PLCP header is prepended to the actual MPDU.                       */
974     plcp_hdr_len = (m_type == vwr->MT_OFDM) ? 4 : 6;
975     if (actual_octets >= plcp_hdr_len)
976        actual_octets -= plcp_hdr_len;
977     else {
978         *err_info = g_strdup_printf("vwr: Invalid data length %u (too short to include %u-byte PLCP header)",
979                                     actual_octets, plcp_hdr_len);
980         *err = WTAP_ERR_BAD_FILE;
981         return FALSE;
982     }
983     m_ptr = &rec[plcp_hdr_len];
984     msdu_length = actual_octets;
985
986     /*
987      * The MSDU length includes the FCS.
988      *
989      * The packet data does *not* include the FCS - it's just 4 bytes
990      * of junk - so we have to remove it.
991      *
992      * We'll be stripping off an FCS (?), so make sure we have at
993      * least 4 octets worth of FCS.
994      */
995     if (actual_octets < 4) {
996         *err_info = g_strdup_printf("vwr: Invalid data length %u (too short to include %u-byte PLCP header and 4 bytes of FCS)",
997                                     actual_octets, plcp_hdr_len);
998         *err = WTAP_ERR_BAD_FILE;
999         return FALSE;
1000     }
1001     actual_octets -= 4;
1002
1003     /* Calculate start & end times (in sec/usec), converting 64-bit times to usec. */
1004     /* 64-bit times are "Corey-endian" */
1005     s_time = pcoreytohll(&s_ptr[v22_W_STARTT_OFF]);
1006     e_time = pcoreytohll(&s_ptr[v22_W_ENDT_OFF]);
1007
1008     /* find the packet duration (difference between start and end times) */
1009     d_time = (guint32)((e_time - s_time) / NS_IN_US);   /* find diff, converting to usec */
1010
1011     /* also convert the packet start time to seconds and microseconds */
1012     start_time = s_time / NS_IN_US;                /* convert to microseconds first  */
1013     s_sec      = (start_time / US_IN_SEC);         /* get the number of seconds      */
1014     s_usec     = start_time - (s_sec * US_IN_SEC); /* get the number of microseconds */
1015
1016     /* also convert the packet end time to seconds and microseconds */
1017     end_time = e_time / NS_IN_US;                       /* convert to microseconds first */
1018
1019     /* extract the 32 LSBs of the signature timestamp field from the data block*/
1020     pay_off = 42;    /* 24 (MAC) + 8 (SNAP) + IP */
1021     sig_off = find_signature(m_ptr, rec_size - 6, pay_off, flow_id, flow_seq);
1022     if ((m_ptr[sig_off] == 0xdd) && (sig_off + 15 <= (rec_size - v22_W_STATS_LEN)))
1023         sig_ts = get_signature_ts(m_ptr, sig_off);
1024     else
1025         sig_ts = 0;
1026
1027     /*
1028      * Fill up the per-packet header.
1029      *
1030      * We also zero out 16 bytes PLCP header and 1 byte of L1P for user
1031      * position.
1032      *
1033      * XXX - for S1, do we even have that?  The current Veriwave dissector
1034      * just blindly assumes there's a 17-byte blob before the 802.11
1035      * header, which is why we fill in those extra zero bytes.
1036      *
1037      * We include the length of the metadata headers in the packet lengths.
1038      *
1039      * The maximum value of actual_octets is 65535, which, even after
1040      * adding the lengths of the metadata headers, is less than
1041      * WTAP_MAX_PACKET_SIZE will ever be, so we don't need to check it.
1042      */
1043     phdr->len = STATS_COMMON_FIELDS_LEN + EXT_WLAN_FIELDS_LEN + 1 + 16 + actual_octets;
1044     phdr->caplen = STATS_COMMON_FIELDS_LEN + EXT_WLAN_FIELDS_LEN + 1 + 16 + actual_octets;
1045
1046     phdr->ts.secs   = (time_t)s_sec;
1047     phdr->ts.nsecs  = (int)(s_usec * 1000);
1048     phdr->pkt_encap = WTAP_ENCAP_IXVERIWAVE;
1049
1050     phdr->rec_type = REC_TYPE_PACKET;
1051     phdr->presence_flags = WTAP_HAS_TS;
1052
1053     ws_buffer_assure_space(buf, phdr->caplen);
1054     data_ptr = ws_buffer_start_ptr(buf);
1055
1056     /*
1057      * Generate and copy out the common metadata headers,
1058      * set the port type to 0 (WLAN).
1059      *
1060      * All values are copied out in little-endian byte order.
1061      */
1062     phtoles(&data_ptr[bytes_written], 0); /* port_type */
1063     bytes_written += 2;
1064     phtoles(&data_ptr[bytes_written], STATS_COMMON_FIELDS_LEN); /* it_len */
1065     bytes_written += 2;
1066     phtoles(&data_ptr[bytes_written], msdu_length);
1067     bytes_written += 2;
1068     phtolel(&data_ptr[bytes_written], flow_id);
1069     bytes_written += 4;
1070     phtoles(&data_ptr[bytes_written], vc_id);
1071     bytes_written += 2;
1072     phtoles(&data_ptr[bytes_written], flow_seq);
1073     bytes_written += 2;
1074     if (!f_tx && sig_ts != 0) {
1075         phtolel(&data_ptr[bytes_written], latency);
1076     } else {
1077         phtolel(&data_ptr[bytes_written], 0);
1078     }
1079     bytes_written += 4;
1080     phtolel(&data_ptr[bytes_written], sig_ts); /* 32 LSBs of signature timestamp (nsec) */
1081     bytes_written += 4;
1082     phtolell(&data_ptr[bytes_written], start_time); /* record start & end times of frame */
1083     bytes_written += 8;
1084     phtolell(&data_ptr[bytes_written], end_time);
1085     bytes_written += 8;
1086     phtolel(&data_ptr[bytes_written], d_time);
1087     bytes_written += 4;
1088
1089     /*
1090      * Generate and copy out the WLAN metadata headers.
1091      *
1092      * All values are copied out in little-endian byte order.
1093      */
1094     phtoles(&data_ptr[bytes_written], EXT_WLAN_FIELDS_LEN);
1095     bytes_written += 2;
1096     phtoles(&data_ptr[bytes_written], rflags);
1097     bytes_written += 2;
1098     if (m_type == vwr->MT_OFDM) {
1099         phtoles(&data_ptr[bytes_written], CHAN_OFDM);
1100     } else {
1101         phtoles(&data_ptr[bytes_written], CHAN_CCK);
1102     }
1103     bytes_written += 2;
1104     phyRate = (guint16)(getRate(plcp_type, mcs_index, rflags, nss) * 10);
1105     phtoles(&data_ptr[bytes_written], phyRate);
1106     bytes_written += 2;
1107     data_ptr[bytes_written] = plcp_type;
1108     bytes_written += 1;
1109     data_ptr[bytes_written] = mcs_index;
1110     bytes_written += 1;
1111     data_ptr[bytes_written] = nss;
1112     bytes_written += 1;
1113     data_ptr[bytes_written] = rssi;
1114     bytes_written += 1;
1115     /* antennae b, c, d signal power */
1116     data_ptr[bytes_written] = 100;
1117     bytes_written += 1;
1118     data_ptr[bytes_written] = 100;
1119     bytes_written += 1;
1120     data_ptr[bytes_written] = 100;
1121     bytes_written += 1;
1122     /* padding */
1123     data_ptr[bytes_written] = 0;
1124     bytes_written += 1;
1125
1126     /* fill in the VeriWave flags field */
1127     vw_flags = 0;
1128     if (f_tx)
1129         vw_flags |= VW_FLAGS_TXF;
1130     if (errors & vwr->FCS_ERROR)
1131         vw_flags |= VW_FLAGS_FCSERR;
1132     if (!f_tx && (errors & vwr->CRYPTO_ERR))
1133         vw_flags |= VW_FLAGS_DCRERR;
1134     if (!f_tx && (errors & vwr->RETRY_ERR))
1135         vw_flags |= VW_FLAGS_RETRERR;
1136     if (info & vwr->WEPTYPE)
1137         vw_flags |= VW_FLAGS_IS_WEP;
1138     else if (info & vwr->TKIPTYPE)
1139         vw_flags |= VW_FLAGS_IS_TKIP;
1140     else if (info & vwr->CCMPTYPE)
1141         vw_flags |= VW_FLAGS_IS_CCMP;
1142     phtoles(&data_ptr[bytes_written], vw_flags);
1143     bytes_written += 2;
1144
1145     phtoles(&data_ptr[bytes_written], ht_len);
1146     bytes_written += 2;
1147     phtoles(&data_ptr[bytes_written], info);
1148     bytes_written += 2;
1149     phtolel(&data_ptr[bytes_written], errors);
1150     bytes_written += 4;
1151
1152     /*
1153      * No VHT, no VHT NDP flag, so just zero.
1154      *
1155      * XXX - is this supposed to be the RX L1 info, i.e. the "1 byte of L1P
1156      * for user position"?
1157      */
1158     data_ptr[bytes_written] = 0;
1159     bytes_written += 1;
1160
1161     /*
1162      * XXX - put a PLCP header here?  That's what's done for S3.
1163      */
1164     memset(&data_ptr[bytes_written], 0, 16);
1165     bytes_written += 16;
1166
1167     /*
1168      * Finally, copy the whole MAC frame to the packet buffer as-is.
1169      * This does not include the PLCP; the MPDU starts at 4 or 6
1170      * depending on OFDM/CCK.
1171      * This also does not include the last 4 bytes, as those don't
1172      * contain an FCS, they just contain junk.
1173      */
1174     memcpy(&data_ptr[bytes_written], &rec[plcp_hdr_len], actual_octets);
1175
1176     return TRUE;
1177 }
1178
1179
1180 static gboolean vwr_read_s2_s3_W_rec(vwr_t *vwr, struct wtap_pkthdr *phdr,
1181                                      Buffer *buf, const guint8 *rec, int rec_size,
1182                                      int IS_TX, int *err, gchar **err_info)
1183 {
1184     guint8           *data_ptr;
1185     int              bytes_written = 0;                   /* bytes output to buf so far */
1186     register int     i;                                   /* temps */
1187     const guint8     *s_start_ptr,*s_trail_ptr, *plcp_ptr, *m_ptr; /* stats & MPDU ptr */
1188     guint32          msdu_length, actual_octets;          /* octets in frame */
1189     guint8           l1p_1,l1p_2, plcp_type, mcs_index, nss;   /* mod (CCK-L/CCK-S/OFDM) */
1190     guint            flow_seq;
1191     guint64          s_time = LL_ZERO, e_time = LL_ZERO;  /* start/end */
1192                                                           /*  times, nsec */
1193     guint64          latency = LL_ZERO;
1194     guint64          start_time, s_sec, s_usec = LL_ZERO; /* start time, sec + usec */
1195     guint64          end_time;                            /* end time */
1196     guint16          info;                                /* INFO/ERRORS fields in stats blk */
1197     guint32          errors;
1198     gint8            rssi[] = {0,0,0,0};                  /* RSSI, signed 8-bit number */
1199     int              f_tx;                                /* flag: if set, is a TX frame */
1200     guint16          vc_id, ht_len=0;                     /* VC ID , total ip length*/
1201     guint32          flow_id, d_time;                     /* flow ID, packet duration*/
1202     int              sig_off, pay_off;                    /* MAC+SNAP header len, signature offset */
1203     guint64          sig_ts, tsid;                        /* 32 LSBs of timestamp in signature */
1204     guint16          chanflags = 0;                       /* channel flags for WLAN metadata header */
1205     guint16          radioflags = 0;                      /* flags for WLAN metadata header */
1206     guint64          delta_b;                             /* Used for calculating latency */
1207     guint16          phyRate;
1208     guint16          vw_flags;                            /* VeriWave-specific packet flags */
1209     guint8           vht_ndp_flag = 0;
1210
1211     /*
1212      * The record data must be large enough to hold the statistics header,
1213      * the PLCP, and the statistics trailer.
1214      */
1215     if ((guint)rec_size < vwr->MPDU_OFF + vVW510021_W_STATS_TRAILER_LEN) {
1216         *err_info = g_strdup_printf("vwr: Invalid record length %d (must be at least %u)",
1217                                     rec_size,
1218                                     vwr->MPDU_OFF + vVW510021_W_STATS_TRAILER_LEN);
1219         *err = WTAP_ERR_BAD_FILE;
1220         return FALSE;
1221     }
1222
1223     /* Calculate the start of the statistics blocks in the buffer */
1224     /* Also get a bunch of fields from the stats blocks */
1225     s_start_ptr = &(rec[0]);                              /* point to stats header */
1226     s_trail_ptr = &(rec[rec_size - vVW510021_W_STATS_TRAILER_LEN]);      /* point to stats trailer */
1227
1228     /* L1p info is different for series III and for Series II - need to check */
1229     l1p_1 = s_start_ptr[vVW510021_W_L1P_1_OFF];
1230     l1p_2 = s_start_ptr[vVW510021_W_L1P_2_OFF];
1231     if (vwr->FPGA_VERSION == S2_W_FPGA)
1232     {
1233         mcs_index = vVW510021_W_S2_MCS_INDEX(l1p_1);
1234         plcp_type = vVW510021_W_S2_PLCP_TYPE(l1p_2);
1235         /* we do the range checks at the end before copying the values
1236            into the wtap header */
1237         msdu_length = ((s_start_ptr[vVW510021_W_MSDU_LENGTH_OFF+1] & 0x1f) << 8)
1238                         + s_start_ptr[vVW510021_W_MSDU_LENGTH_OFF];
1239
1240         vc_id = pntoh16(&s_start_ptr[vVW510021_W_VCID_OFF]);
1241         if (IS_TX)
1242         {
1243             rssi[0] = (s_start_ptr[vVW510021_W_RSSI_TXPOWER_OFF] & 0x80) ?
1244                        -1 * (s_start_ptr[vVW510021_W_RSSI_TXPOWER_OFF] & 0x7f) :
1245                        s_start_ptr[vVW510021_W_RSSI_TXPOWER_OFF] & 0x7f;
1246         }
1247         else
1248         {
1249             rssi[0] = (s_start_ptr[vVW510021_W_RSSI_TXPOWER_OFF] & 0x80) ?
1250                       (s_start_ptr[vVW510021_W_RSSI_TXPOWER_OFF]- 256) :
1251                       s_start_ptr[vVW510021_W_RSSI_TXPOWER_OFF];
1252         }
1253         rssi[1] = 100;
1254         rssi[2] = 100;
1255         rssi[3] = 100;
1256
1257         nss = 0;
1258
1259         /* XXX - S2 claims to have 11 bytes of PLCP and 1 byte of pad */
1260         plcp_ptr = &(rec[8]);
1261     }
1262     else
1263     {
1264         /* XXX - what indicates which packets include the FCS? */
1265         radioflags |= FLAGS_FCS;
1266         plcp_type = vVW510021_W_S3_PLCP_TYPE(l1p_2);
1267         if (plcp_type == vVW510021_W_PLCP_VHT_MIXED)
1268         {
1269             /* VHT */
1270             mcs_index = vVW510021_W_S3_MCS_INDEX_VHT(l1p_1);
1271             nss = vVW510021_W_S3_NSS_VHT(l1p_1);
1272         }
1273         else
1274         {
1275             /* HT */
1276             mcs_index = vVW510021_W_S3_MCS_INDEX_HT(l1p_1);
1277             nss = 0;
1278         }
1279
1280         /*** Extract NDP Flag if it is a received frame ***/
1281         if (!IS_TX){
1282             vht_ndp_flag = s_start_ptr[8];
1283         }
1284
1285         msdu_length = pntoh24(&s_start_ptr[9]);
1286         vc_id = pntoh16(&s_start_ptr[14]) & vVW510024_W_VCID_MASK;
1287         for (i = 0; i < 4; i++)
1288         {
1289             if (IS_TX)
1290             {
1291                 rssi[i] = (s_start_ptr[4+i] & 0x80) ? -1 * (s_start_ptr[4+i] & 0x7f) : s_start_ptr[4+i] & 0x7f;
1292             }
1293             else
1294             {
1295                 rssi[i] = (s_start_ptr[4+i] >= 128) ? (s_start_ptr[4+i] - 256) : s_start_ptr[4+i];
1296             }
1297         }
1298
1299         /*** 16 bytes of PLCP header + 1 byte of L1P for user position ***/
1300         /* XXX - S3 claims to have 16 bytes of stats block and 16 bytes of
1301            *something*. Are those 16 bytes the PLCP? */
1302         plcp_ptr = &(rec[16]);
1303     }
1304     actual_octets = msdu_length;
1305
1306     /*
1307      * Sanity check the octets field to determine if it's greater than
1308      * the packet data available in the record - i.e., the record size
1309      * minus the sum of (length of statistics header + PLCP) and
1310      * (length of statistics trailer).
1311      *
1312      * Report an error if it is.
1313      */
1314     if (actual_octets > rec_size - (vwr->MPDU_OFF + vVW510021_W_STATS_TRAILER_LEN)) {
1315         *err_info = g_strdup_printf("vwr: Invalid data length %u (runs past the end of the record)",
1316                                     actual_octets);
1317         *err = WTAP_ERR_BAD_FILE;
1318         return FALSE;
1319     }
1320
1321     f_tx = IS_TX;
1322     flow_seq = s_trail_ptr[vVW510021_W_FLOWSEQ_OFF];
1323
1324     latency = 0x00000000;                        /* clear latency */
1325     flow_id = pntoh24(&s_trail_ptr[vVW510021_W_FLOWID_OFF]);         /* all 24 bits valid */
1326     /* For tx latency is duration, for rx latency is timestamp */
1327     /* Get 48-bit latency value */
1328     tsid = pcorey48tohll(&s_trail_ptr[vVW510021_W_LATVAL_OFF]);
1329
1330     errors = pntoh32(&s_trail_ptr[vVW510021_W_ERRORS_OFF]);
1331     info = pntoh16(&s_trail_ptr[vVW510021_W_INFO_OFF]);
1332     if ((info & v22_W_AGGREGATE_FLAGS) != 0)
1333     /* this length includes the Start_Spacing + Delimiter + MPDU + Padding for each piece of the aggregate*/
1334         ht_len = pletoh16(&s_start_ptr[vwr->PLCP_LENGTH_OFF]);
1335
1336
1337     /* decode OFDM or CCK PLCP header and determine rate and short preamble flag */
1338     /* the SIGNAL byte is always the first byte of the PLCP header in the frame */
1339     if (plcp_type == vVW510021_W_PLCP_LEGACY){
1340         /*
1341          * From IEEE Std 802.11-2012:
1342          *
1343          * According to section 17.2.2 "PPDU format", the PLCP header
1344          * for the High Rate DSSS PHY (11b) has a SIGNAL field that's
1345          * 8 bits, followed by a SERVICE field that's 8 bits, followed
1346          * by a LENGTH field that's 16 bits, followed by a CRC field
1347          * that's 16 bits.  The PSDU follows it.  Section 17.2.3 "PPDU
1348          * field definitions" describes those fields.
1349          *
1350          * According to sections 18.3.2 "PLCP frame format" and 18.3.4
1351          * "SIGNAL field", the PLCP for the OFDM PHY (11a) has a SIGNAL
1352          * field that's 24 bits, followed by a service field that's
1353          * 16 bits, followed by the PSDU.  Section 18.3.5.2 "SERVICE
1354          * field" describes the SERVICE field.
1355          *
1356          * According to section 19.3.2 "PPDU format", the frames for the
1357          * Extended Rate PHY (11g) either extend the 11b format, using
1358          * additional bits in the SERVICE field, or extend the 11a
1359          * format.
1360          */
1361         if (mcs_index < 4) {
1362             chanflags |= CHAN_CCK;
1363         }
1364         else {
1365             chanflags |= CHAN_OFDM;
1366         }
1367     }
1368     else if (plcp_type == vVW510021_W_PLCP_MIXED) {
1369         /*
1370          * According to section 20.3.2 "PPDU format", the HT-mixed
1371          * PLCP header has a "Non-HT SIGNAL field" (L-SIG), which
1372          * looks like an 11a SIGNAL field, followed by an HT SIGNAL
1373          * field (HT-SIG) described in section 20.3.9.4.3 "HT-SIG
1374          * definition".
1375          *
1376          * This means that the first octet of HT-SIG is at
1377          * plcp_ptr[3], skipping the 3 octets of the L-SIG field.
1378          *
1379          * 0x80 is the CBW 20/40 bit of HT-SIG.
1380          */
1381         /* set the appropriate flags to indicate HT mode and CB */
1382         radioflags |= FLAGS_CHAN_HT | ((plcp_ptr[3] & 0x80) ? FLAGS_CHAN_40MHZ : 0) |
1383                       ((l1p_1 & vVW510021_W_IS_LONGGI) ? 0 : FLAGS_CHAN_SHORTGI);
1384         chanflags  |= CHAN_OFDM;
1385     }
1386     else if (plcp_type == vVW510021_W_PLCP_GREENFIELD) {
1387         /*
1388          * According to section 20.3.2 "PPDU format", the HT-greenfield
1389          * PLCP header just has the HT SIGNAL field (HT-SIG) above, with
1390          * no L-SIG field.
1391          *
1392          * This means that the first octet of HT-SIG is at
1393          * plcp_ptr[0], as there's no L-SIG field to skip.
1394          *
1395          * 0x80 is the CBW 20/40 bit of HT-SIG.
1396          */
1397         /* set the appropriate flags to indicate HT mode and CB */
1398         radioflags |= FLAGS_CHAN_HT | ((plcp_ptr[0] & 0x80) ? FLAGS_CHAN_40MHZ : 0) |
1399                       ((l1p_1 & vVW510021_W_IS_LONGGI) ?  0 : FLAGS_CHAN_SHORTGI);
1400         chanflags  |= CHAN_OFDM;
1401     }
1402     else if (plcp_type == vVW510021_W_PLCP_VHT_MIXED) {
1403         /*
1404          * According to section 22.3.2 "VHTPPDU format" of IEEE Std
1405          * 802.11ac-2013, the VHT PLCP header has a "non-HT SIGNAL field"
1406          * (L-SIG), which looks like an 11a SIGNAL field, followed by
1407          * a VHT Signal A field (VHT-SIG-A) described in section
1408          * 22.3.8.3.3 "VHT-SIG-A definition", with training fields
1409          * between it and a VHT Signal B field (VHT-SIG-B) described
1410          * in section 22.3.8.3.6 "VHT-SIG-B definition", followed by
1411          * the PSDU.
1412          */
1413         guint8 SBW = vVW510021_W_BANDWIDTH_VHT(l1p_2);
1414         radioflags |= FLAGS_CHAN_VHT | ((l1p_1 & vVW510021_W_IS_LONGGI) ?  0 : FLAGS_CHAN_SHORTGI);
1415         chanflags |= CHAN_OFDM;
1416         if (SBW == 3)
1417             radioflags |= FLAGS_CHAN_40MHZ;
1418         else if (SBW == 4)
1419             radioflags |= FLAGS_CHAN_80MHZ;
1420     }
1421
1422     /* Calculate start & end times (in sec/usec), converting 64-bit times to usec. */
1423     /* 64-bit times are "Corey-endian" */
1424     s_time = pcoreytohll(&s_trail_ptr[vVW510021_W_STARTT_OFF]);
1425     e_time = pcoreytohll(&s_trail_ptr[vVW510021_W_ENDT_OFF]);
1426
1427     /* find the packet duration (difference between start and end times) */
1428     d_time = (guint32)((e_time - s_time) / NS_IN_US);  /* find diff, converting to usec */
1429
1430     /* also convert the packet start time to seconds and microseconds */
1431     start_time = s_time / NS_IN_US;                     /* convert to microseconds first */
1432     s_sec = (start_time / US_IN_SEC);                   /* get the number of seconds */
1433     s_usec = start_time - (s_sec * US_IN_SEC);          /* get the number of microseconds */
1434
1435     /* also convert the packet end time to seconds and microseconds */
1436     end_time = e_time / NS_IN_US;                       /* convert to microseconds first */
1437
1438     /* extract the 32 LSBs of the signature timestamp field */
1439     m_ptr = &(rec[8+12]);
1440     pay_off = 42;         /* 24 (MAC) + 8 (SNAP) + IP */
1441     sig_off = find_signature(m_ptr, rec_size - 20, pay_off, flow_id, flow_seq);
1442     if ((m_ptr[sig_off] == 0xdd) && (sig_off + 15 <= (rec_size - vVW510021_W_STATS_TRAILER_LEN)))
1443         sig_ts = get_signature_ts(m_ptr, sig_off);
1444     else
1445         sig_ts = 0;
1446
1447     /* Set latency based on rx/tx and signature timestamp */
1448     if (!IS_TX) {
1449         if (tsid < s_time) {
1450             latency = s_time - tsid;
1451           } else {
1452             /* Account for the rollover case. Since we cannot use 0x100000000 - l_time + s_time */
1453             /* we look for a large difference between l_time and s_time. */
1454             delta_b = tsid - s_time;
1455             if (delta_b >  0x10000000)
1456               latency = 0;
1457             else
1458               latency = delta_b;
1459           }
1460     }
1461
1462     /*
1463      * Fill up the per-packet header.
1464      *
1465      * We also copy over 16 bytes of PLCP header + 1 byte of L1P for user
1466      * position.
1467      *
1468      * XXX - for S2, we don't have 16 bytes of PLCP header; do we have
1469      * the 1 byte of L1P?  The current Veriwave dissector just blindly
1470      * assumes there's a 17-byte blob before the 802.11 header.
1471      *
1472      * We include the length of the metadata headers in the packet lengths.
1473      */
1474     phdr->len = STATS_COMMON_FIELDS_LEN + EXT_WLAN_FIELDS_LEN + 1 + 16 + actual_octets;
1475     phdr->caplen = STATS_COMMON_FIELDS_LEN + EXT_WLAN_FIELDS_LEN + 1 + 16 + actual_octets;
1476     if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
1477         /*
1478          * Probably a corrupt capture file; return an error,
1479          * so that our caller doesn't blow up trying to allocate
1480          * space for an immensely-large packet.
1481          */
1482         *err_info = g_strdup_printf("vwr: File has %u-byte packet, bigger than maximum of %u",
1483                                     phdr->caplen, WTAP_MAX_PACKET_SIZE);
1484         *err = WTAP_ERR_BAD_FILE;
1485         return FALSE;
1486     }
1487
1488     phdr->ts.secs   = (time_t)s_sec;
1489     phdr->ts.nsecs  = (int)(s_usec * 1000);
1490     phdr->pkt_encap = WTAP_ENCAP_IXVERIWAVE;
1491
1492     phdr->rec_type = REC_TYPE_PACKET;
1493     phdr->presence_flags = WTAP_HAS_TS;
1494
1495     ws_buffer_assure_space(buf, phdr->caplen);
1496     data_ptr = ws_buffer_start_ptr(buf);
1497
1498     /*
1499      * Generate and copy out the common metadata headers,
1500      * set the port type to 0 (WLAN).
1501      *
1502      * All values are copied out in little-endian byte order.
1503      */
1504     /*** msdu_length = msdu_length + 16; ***/
1505     phtoles(&data_ptr[bytes_written], 0); /* port_type */
1506     bytes_written += 2;
1507     phtoles(&data_ptr[bytes_written], STATS_COMMON_FIELDS_LEN); /* it_len */
1508     bytes_written += 2;
1509     phtoles(&data_ptr[bytes_written], msdu_length);
1510     bytes_written += 2;
1511     phtolel(&data_ptr[bytes_written], flow_id);
1512     bytes_written += 4;
1513     phtoles(&data_ptr[bytes_written], vc_id);
1514     bytes_written += 2;
1515     phtoles(&data_ptr[bytes_written], flow_seq);
1516     bytes_written += 2;
1517     if (!f_tx && sig_ts != 0) {
1518         phtolel(&data_ptr[bytes_written], latency);
1519     } else {
1520         phtolel(&data_ptr[bytes_written], 0);
1521     }
1522     bytes_written += 4;
1523     phtolel(&data_ptr[bytes_written], sig_ts); /* 32 LSBs of signature timestamp (nsec) */
1524     bytes_written += 4;
1525     phtolell(&data_ptr[bytes_written], start_time); /* record start & end times of frame */
1526     bytes_written += 8;
1527     phtolell(&data_ptr[bytes_written], end_time);
1528     bytes_written += 8;
1529     phtolel(&data_ptr[bytes_written], d_time);
1530     bytes_written += 4;
1531
1532     /*
1533      * Generate and copy out the WLAN metadata headers.
1534      *
1535      * All values are copied out in little-endian byte order.
1536      */
1537     phtoles(&data_ptr[bytes_written], EXT_WLAN_FIELDS_LEN);
1538     bytes_written += 2;
1539     if (info & vVW510021_W_IS_WEP)
1540         radioflags |= FLAGS_WEP;
1541     if (!(l1p_1 & vVW510021_W_IS_LONGPREAMBLE) && (plcp_type == vVW510021_W_PLCP_LEGACY))
1542         radioflags |= FLAGS_SHORTPRE;
1543     phtoles(&data_ptr[bytes_written], radioflags);
1544     bytes_written += 2;
1545     phtoles(&data_ptr[bytes_written], chanflags);
1546     bytes_written += 2;
1547     phyRate = (guint16)(getRate(plcp_type, mcs_index, radioflags, nss) * 10);
1548     phtoles(&data_ptr[bytes_written], phyRate);
1549     bytes_written += 2;
1550
1551     /*** If received frame populate the ndp_flag in the same byte as plcp_type***/
1552
1553     if (!IS_TX) {
1554         plcp_type = vht_ndp_flag  + plcp_type;
1555     }
1556
1557     data_ptr[bytes_written] = plcp_type;
1558     bytes_written += 1;
1559
1560     data_ptr[bytes_written] = mcs_index;
1561     bytes_written += 1;
1562
1563     data_ptr[bytes_written] = nss;
1564     bytes_written += 1;
1565     data_ptr[bytes_written] = rssi[0];
1566     bytes_written += 1;
1567     data_ptr[bytes_written] = rssi[1];
1568     bytes_written += 1;
1569     data_ptr[bytes_written] = rssi[2];
1570     bytes_written += 1;
1571     data_ptr[bytes_written] = rssi[3];
1572     bytes_written += 1;
1573     /* padding */
1574     data_ptr[bytes_written] = 0;
1575     bytes_written += 1;
1576
1577     /* fill in the VeriWave flags field */
1578     vw_flags  = 0;
1579     if (f_tx)
1580         vw_flags |= VW_FLAGS_TXF;
1581     if (errors & 0x1f)  /* If any error is flagged, then set the FCS error bit */
1582         vw_flags |= VW_FLAGS_FCSERR;
1583     if (!f_tx && (errors & vwr->CRYPTO_ERR))
1584         vw_flags |= VW_FLAGS_DCRERR;
1585     if (!f_tx && (errors & vwr->RETRY_ERR))
1586         vw_flags |= VW_FLAGS_RETRERR;
1587     if (info & vwr->WEPTYPE)
1588         vw_flags |= VW_FLAGS_IS_WEP;
1589     else if (info & vwr->TKIPTYPE)
1590         vw_flags |= VW_FLAGS_IS_TKIP;
1591     else if (info & vwr->CCMPTYPE)
1592         vw_flags |= VW_FLAGS_IS_CCMP;
1593     phtoles(&data_ptr[bytes_written], vw_flags);
1594     bytes_written += 2;
1595
1596     phtoles(&data_ptr[bytes_written], ht_len);
1597     bytes_written += 2;
1598     phtoles(&data_ptr[bytes_written], info);
1599     bytes_written += 2;
1600     phtolel(&data_ptr[bytes_written], errors);
1601     bytes_written += 4;
1602
1603     /*
1604      * XXX - is this supposed to be the RX L1 info, i.e. the "1 byte of L1P
1605      * for user position"?
1606      */
1607     if (!IS_TX){
1608       data_ptr[bytes_written] = vht_ndp_flag;
1609     } else {
1610       data_ptr[bytes_written] = 0;
1611     }
1612     bytes_written += 1;
1613
1614     /*
1615      * Copy PLCP header.
1616      *
1617      * XXX - shouldn't that use plcp_ptr?
1618      *
1619      * XXX - what about S2, where we don't have 16 bytes of PLCP?
1620      */
1621     memcpy(&data_ptr[bytes_written], &rec[16], 16);
1622     bytes_written += 16;
1623
1624     /*
1625      * Finally, copy the whole MAC frame to the packet buffer as-is.
1626      * This does not include the stats header or the PLCP header.
1627      */
1628     memcpy(&data_ptr[bytes_written], &rec[vwr->MPDU_OFF], actual_octets);
1629
1630     return TRUE;
1631 }
1632
1633 /* read an Ethernet packet */
1634 /* Copy the actual packet data from the capture file into the target data block.         */
1635 /* The packet is constructed as a 38-byte VeriWave-extended Radiotap header plus the raw */
1636 /*  MAC octets.                                                                          */
1637
1638 static gboolean vwr_read_rec_data_ethernet(vwr_t *vwr, struct wtap_pkthdr *phdr,
1639                                            Buffer *buf, const guint8 *rec,
1640                                            int rec_size, int IS_TX, int *err,
1641                                            gchar **err_info)
1642 {
1643     guint8           *data_ptr;
1644     int              bytes_written = 0;                   /* bytes output to buf so far */
1645     const guint8 *s_ptr, *m_ptr;                          /* stats and MPDU pointers */
1646     guint16          msdu_length, actual_octets;          /* octets in frame */
1647     guint            flow_seq;                            /* seqnum */
1648     guint64          s_time = LL_ZERO, e_time = LL_ZERO;  /* start/end */
1649                                                           /* times, nsec */
1650     guint32          latency = 0;
1651     guint64          start_time, s_sec, s_usec = LL_ZERO; /* start time, sec + usec */
1652     guint64          end_time;                            /* end time */
1653     guint            l4id;
1654     guint16          info, validityBits;                  /* INFO/ERRORS fields in stats */
1655     guint32          errors;
1656     guint16          vc_id;                               /* VC ID, total (incl of aggregates) */
1657     guint32          flow_id, d_time;                     /* packet duration */
1658     int              f_flow;                              /* flags: flow valid */
1659     guint32          frame_type;                          /* frame type field */
1660     int              mac_len, sig_off, pay_off;           /* MAC header len, signature offset */
1661     /* XXX - the code here fetched tsid, but never used it! */
1662     guint64          sig_ts/*, tsid*/;                    /* 32 LSBs of timestamp in signature */
1663     guint64          delta_b;                             /* Used for calculating latency */
1664     guint16          vw_flags;                            /* VeriWave-specific packet flags */
1665
1666     if ((guint)rec_size < vwr->STATS_LEN) {
1667         *err_info = g_strdup_printf("vwr: Invalid record length %d (must be at least %u)", rec_size, vwr->STATS_LEN);
1668         *err = WTAP_ERR_BAD_FILE;
1669         return FALSE;
1670     }
1671
1672     /* Calculate the start of the statistics block in the buffer. */
1673     /* Also get a bunch of fields from the stats block.           */
1674     m_ptr = &(rec[0]);                              /* point to the data block */
1675     s_ptr = &(rec[rec_size - vwr->STATS_LEN]);      /* point to the stats block */
1676
1677     msdu_length = pntoh16(&s_ptr[vwr->OCTET_OFF]);
1678     actual_octets = msdu_length;
1679
1680     /*
1681      * Sanity check the octets field to determine if it's greater than
1682      * the packet data available in the record - i.e., the record size
1683      * minus the length of the statistics block.
1684      *
1685      * Report an error if it is.
1686      */
1687     if (actual_octets > rec_size - vwr->STATS_LEN) {
1688         *err_info = g_strdup_printf("vwr: Invalid data length %u (runs past the end of the record)",
1689                                     actual_octets);
1690         *err = WTAP_ERR_BAD_FILE;
1691         return FALSE;
1692     }
1693     /*
1694      * The maximum value of actual_octets is 65535, which, even after
1695      * adding the lengths of the metadata headers, is less than
1696      * WTAP_MAX_PACKET_SIZE will ever be, so we don't need to check it.
1697      */
1698
1699     vc_id = pntoh16(&s_ptr[vwr->VCID_OFF]) & vwr->VCID_MASK;
1700     flow_seq   = s_ptr[vwr->FLOWSEQ_OFF];
1701     frame_type = pntoh32(&s_ptr[vwr->FRAME_TYPE_OFF]);
1702
1703     if (vwr->FPGA_VERSION == vVW510024_E_FPGA) {
1704         validityBits = pntoh16(&s_ptr[vwr->VALID_OFF]);
1705         f_flow = validityBits & vwr->FLOW_VALID;
1706
1707         mac_len = (validityBits & vwr->IS_VLAN) ? 16 : 14;           /* MAC hdr length based on VLAN tag */
1708
1709
1710         errors = pntoh16(&s_ptr[vwr->ERRORS_OFF]);
1711     }
1712     else {
1713         f_flow  = s_ptr[vwr->VALID_OFF] & vwr->FLOW_VALID;
1714         mac_len = (frame_type & vwr->IS_VLAN) ? 16 : 14;             /* MAC hdr length based on VLAN tag */
1715
1716
1717         /* for older fpga errors is only represented by 16 bits) */
1718         errors = pntoh16(&s_ptr[vwr->ERRORS_OFF]);
1719     }
1720
1721     info = pntoh16(&s_ptr[vwr->INFO_OFF]);
1722     /*  24 LSBs */
1723     flow_id = pntoh24(&s_ptr[vwr->FLOWID_OFF]);
1724
1725 #if 0
1726     /* For tx latency is duration, for rx latency is timestamp. */
1727     /* Get 64-bit latency value. */
1728     tsid = pcorey48tohll(&s_ptr[vwr->LATVAL_OFF]);
1729 #endif
1730
1731     l4id = pntoh16(&s_ptr[vwr->L4ID_OFF]);
1732
1733     /*
1734      * The MSDU length includes the FCS.
1735      *
1736      * The packet data does *not* include the FCS - it's just 4 bytes
1737      * of junk - so we have to remove it.
1738      *
1739      * We'll be stripping off an FCS (?), so make sure we have at
1740      * least 4 octets worth of FCS.
1741      */
1742     if (actual_octets < 4) {
1743         *err_info = g_strdup_printf("vwr: Invalid data length %u (too short to include 4 bytes of FCS)",
1744                                     actual_octets);
1745         *err = WTAP_ERR_BAD_FILE;
1746         return FALSE;
1747     }
1748     actual_octets -= 4;
1749
1750     /* Calculate start & end times (in sec/usec), converting 64-bit times to usec. */
1751     /* 64-bit times are "Corey-endian"                                             */
1752     s_time = pcoreytohll(&s_ptr[vwr->STARTT_OFF]);
1753     e_time = pcoreytohll(&s_ptr[vwr->ENDT_OFF]);
1754
1755     /* find the packet duration (difference between start and end times) */
1756     d_time = (guint32)((e_time - s_time));  /* find diff, leaving in nsec for Ethernet */
1757
1758     /* also convert the packet start time to seconds and microseconds */
1759     start_time = s_time / NS_IN_US;                     /* convert to microseconds first */
1760     s_sec = (start_time / US_IN_SEC);                   /* get the number of seconds */
1761     s_usec = start_time - (s_sec * US_IN_SEC);          /* get the number of microseconds */
1762
1763     /* also convert the packet end time to seconds and microseconds */
1764     end_time = e_time / NS_IN_US;                       /* convert to microseconds first */
1765
1766     if (frame_type & vwr->IS_TCP)                       /* signature offset for TCP frame */
1767     {
1768         pay_off = mac_len + 40;
1769     }
1770     else if (frame_type & vwr->IS_UDP)                  /* signature offset for UDP frame */
1771     {
1772         pay_off = mac_len + 28;
1773     }
1774     else if (frame_type & vwr->IS_ICMP)                 /* signature offset for ICMP frame */
1775     {
1776         pay_off = mac_len + 24;
1777     }
1778     else if (frame_type & vwr->IS_IGMP)                 /* signature offset for IGMPv2 frame */
1779     {
1780         pay_off = mac_len + 28;
1781     }
1782     else                                                /* signature offset for raw IP frame */
1783     {
1784         pay_off = mac_len + 20;
1785     }
1786
1787     sig_off = find_signature(m_ptr, rec_size, pay_off, flow_id, flow_seq);
1788     if ((m_ptr[sig_off] == 0xdd) && (sig_off + 15 <= msdu_length) && (f_flow != 0))
1789         sig_ts = get_signature_ts(m_ptr, sig_off);
1790     else
1791         sig_ts = 0;
1792
1793     /* Set latency based on rx/tx and signature timestamp */
1794     if (!IS_TX) {
1795         if (sig_ts < s_time) {
1796             latency = (guint32)(s_time - sig_ts);
1797         } else {
1798             /* Account for the rollover case. Since we cannot use 0x100000000 - l_time + s_time */
1799             /*  we look for a large difference between l_time and s_time.                       */
1800             delta_b = sig_ts - s_time;
1801             if (delta_b >  0x10000000) {
1802                 latency = 0;
1803             } else
1804                 latency = (guint32)delta_b;
1805         }
1806     }
1807
1808     /*
1809      * Fill up the per-packet header.
1810      *
1811      * We include the length of the metadata headers in the packet lengths.
1812      */
1813     phdr->len = STATS_COMMON_FIELDS_LEN + EXT_ETHERNET_FIELDS_LEN + actual_octets;
1814     phdr->caplen = STATS_COMMON_FIELDS_LEN + EXT_ETHERNET_FIELDS_LEN + actual_octets;
1815
1816     phdr->ts.secs   = (time_t)s_sec;
1817     phdr->ts.nsecs  = (int)(s_usec * 1000);
1818     phdr->pkt_encap = WTAP_ENCAP_IXVERIWAVE;
1819
1820     phdr->rec_type = REC_TYPE_PACKET;
1821     phdr->presence_flags = WTAP_HAS_TS;
1822
1823     /*etap_hdr.vw_ip_length = (guint16)ip_len;*/
1824
1825     ws_buffer_assure_space(buf, phdr->caplen);
1826     data_ptr = ws_buffer_start_ptr(buf);
1827
1828     /*
1829      * Generate and copy out the common metadata headers,
1830      * set the port type to 1 (Ethernet).
1831      *
1832      * All values are copied out in little-endian byte order.
1833      */
1834     phtoles(&data_ptr[bytes_written], 1);
1835     bytes_written += 2;
1836     phtoles(&data_ptr[bytes_written], STATS_COMMON_FIELDS_LEN);
1837     bytes_written += 2;
1838     phtoles(&data_ptr[bytes_written], msdu_length);
1839     bytes_written += 2;
1840     phtolel(&data_ptr[bytes_written], flow_id);
1841     bytes_written += 4;
1842     phtoles(&data_ptr[bytes_written], vc_id);
1843     bytes_written += 2;
1844     phtoles(&data_ptr[bytes_written], flow_seq);
1845     bytes_written += 2;
1846     if (!IS_TX && (sig_ts != 0)) {
1847         phtolel(&data_ptr[bytes_written], latency);
1848     } else {
1849         phtolel(&data_ptr[bytes_written], 0);
1850     }
1851     bytes_written += 4;
1852     phtolel(&data_ptr[bytes_written], sig_ts);
1853     bytes_written += 4;
1854     phtolell(&data_ptr[bytes_written], start_time)                  /* record start & end times of frame */
1855     bytes_written += 8;
1856     phtolell(&data_ptr[bytes_written], end_time);
1857     bytes_written += 8;
1858     phtolel(&data_ptr[bytes_written], d_time);
1859     bytes_written += 4;
1860
1861     /*
1862      * Generate and copy out the Ethernet metadata headers.
1863      *
1864      * All values are copied out in little-endian byte order.
1865      */
1866     phtoles(&data_ptr[bytes_written], EXT_ETHERNET_FIELDS_LEN);
1867     bytes_written += 2;
1868     vw_flags = 0;
1869     if (IS_TX)
1870         vw_flags |= VW_FLAGS_TXF;
1871     if (errors & vwr->FCS_ERROR)
1872         vw_flags |= VW_FLAGS_FCSERR;
1873     phtoles(&data_ptr[bytes_written], vw_flags);
1874     bytes_written += 2;
1875     phtoles(&data_ptr[bytes_written], info);
1876     bytes_written += 2;
1877     phtolel(&data_ptr[bytes_written], errors);
1878     bytes_written += 4;
1879     phtolel(&data_ptr[bytes_written], l4id);
1880     bytes_written += 4;
1881
1882     /* Add in pad */
1883     phtolel(&data_ptr[bytes_written], 0);
1884     bytes_written += 4;
1885
1886     /*
1887      * Finally, copy the whole MAC frame to the packet buffer as-is.
1888      * This also does not include the last 4 bytes, as those don't
1889      * contain an FCS, they just contain junk.
1890      */
1891     memcpy(&data_ptr[bytes_written], m_ptr, actual_octets);
1892
1893     return TRUE;
1894 }
1895
1896 /*--------------------------------------------------------------------------------------*/
1897 /* utility to split up and decode a 16-byte message record */
1898
1899 static int decode_msg(guint8 *rec, int *v_type, int *IS_TX)
1900 {
1901     guint8  cmd;                        /* components of message */
1902     guint32 wd2, wd3;
1903     int     v_size = 0;                 /* size of var-len message */
1904                                         /* assume it's zero */
1905
1906     /* break up the message record into its pieces */
1907     cmd = rec[0];            /* command byte */
1908     wd2 = pntoh32(&rec[8]);  /* first 32-bit quantity */
1909     wd3 = pntoh32(&rec[12]); /* second 32-bit quantity */
1910
1911     /* now decode based on the command byte */
1912     switch (cmd) {
1913         case COMMAND_RX:
1914             if (IS_TX != NULL)
1915                 *IS_TX = 0;
1916             v_size  = (int)(wd2 & 0xffff);
1917             *v_type = VT_FRAME;
1918             break;
1919
1920         case COMMAND_TX:
1921             if (IS_TX != NULL)
1922                 *IS_TX = 1;
1923             v_size  = (int)(wd2 & 0xffff);
1924             *v_type = VT_FRAME;
1925             break;
1926
1927         case 0xc1:
1928         case 0x8b:
1929             if (IS_TX != NULL)
1930                 *IS_TX = 2; /*NULL case*/
1931             v_size  = (int)(wd2 & 0xffff);
1932             *v_type = VT_CPMSG;
1933             break;
1934
1935         case 0xfe:
1936             if (IS_TX != NULL)
1937                 *IS_TX = 2; /*NULL case*/
1938             v_size  = (int)(wd3 & 0xffff);
1939             *v_type = VT_CPMSG;
1940             break;
1941
1942         default:
1943             if (IS_TX != NULL)
1944                 *IS_TX = 2; /*NULL case*/
1945             break;
1946     }
1947
1948     return v_size;
1949 }
1950
1951
1952 /*---------------------------------------------------------------------------------------*/
1953 /* Utilities to extract and decode the PHY bit rate from 802.11 PLCP headers (OFDM/CCK). */
1954 /* They are passed a pointer to 4 or 6 consecutive bytes of PLCP header.                 */
1955 /* The integer returned by the get_xxx_rate() functions is in units of 0.5 Mb/s.         */
1956 /* The string returned by the decode_xxx_rate() functions is 3 characters wide.          */
1957
1958 static guint8 get_ofdm_rate(const guint8 *plcp)
1959 {
1960     /* extract the RATE field (LS nibble of first byte) then convert it to the MCS index used by the L1p fields */
1961     switch (plcp[0] & 0x0f) {
1962         case 0x0b:  return  4;
1963         case 0x0f:  return  5;
1964         case 0x0a:  return  6;
1965         case 0x0e:  return  7;
1966         case 0x09:  return  8;
1967         case 0x0d:  return  9;
1968         case 0x08:  return 10;
1969         case 0x0c:  return 11;
1970         default:    return  0;
1971     }
1972 }
1973
1974 static guint8 get_cck_rate(const guint8 *plcp)
1975 {
1976     /* extract rate from the SIGNAL field then convert it to the MCS index used by the L1p fields */
1977     switch (plcp[0]) {
1978         case 0x0a:  return 0;
1979         case 0x14:  return 1;
1980         case 0x37:  return 2;
1981         case 0x6e:  return 3;
1982         default:    return 0;
1983     }
1984 }
1985
1986 /*--------------------------------------------------------------------------------------*/
1987 /* utility to set up offsets and bitmasks for decoding the stats blocks */
1988
1989 static void setup_defaults(vwr_t *vwr, guint16 fpga)
1990 {
1991     switch (fpga) {
1992         /* WLAN frames */
1993         case S2_W_FPGA:
1994             vwr->STATS_LEN          = vVW510021_W_STATS_TRAILER_LEN;
1995
1996             vwr->VALID_OFF          = vVW510021_W_VALID_OFF;
1997             vwr->MTYPE_OFF          = vVW510021_W_MTYPE_OFF;
1998             vwr->VCID_OFF           = vVW510021_W_VCID_OFF;
1999             vwr->FLOWSEQ_OFF        = vVW510021_W_FLOWSEQ_OFF;
2000             vwr->FLOWID_OFF         = vVW510021_W_FLOWID_OFF;
2001
2002             /*vwr->OCTET_OFF        = v22_W_OCTET_OFF;*/
2003
2004             vwr->ERRORS_OFF         = vVW510021_W_ERRORS_OFF;
2005             vwr->PATN_OFF           = vVW510021_W_MATCH_OFF;
2006             vwr->RSSI_OFF           = vVW510021_W_RSSI_TXPOWER_OFF;
2007             vwr->STARTT_OFF         = vVW510021_W_STARTT_OFF;
2008             vwr->ENDT_OFF           = vVW510021_W_ENDT_OFF;
2009             vwr->LATVAL_OFF         = vVW510021_W_LATVAL_OFF;
2010             vwr->INFO_OFF           = vVW510021_W_INFO_OFF;
2011             vwr->FPGA_VERSION_OFF   = S2_W_FPGA_VERSION_OFF;
2012             vwr->HEADER_VERSION_OFF = vVW510021_W_HEADER_VERSION_OFF;
2013             vwr->OCTET_OFF          = vVW510021_W_MSDU_LENGTH_OFF;
2014             vwr->L1P_1_OFF          = vVW510021_W_L1P_1_OFF;
2015             vwr->L1P_2_OFF          = vVW510021_W_L1P_2_OFF;
2016             vwr->L4ID_OFF           = vVW510021_W_L4ID_OFF;
2017             vwr->IPLEN_OFF          = vVW510021_W_IPLEN_OFF;
2018             vwr->PLCP_LENGTH_OFF    = vVW510021_W_PLCP_LENGTH_OFF;
2019
2020             vwr->MT_MASK            = vVW510021_W_SEL_MASK;
2021             vwr->VCID_MASK          = 0xffff;
2022             vwr->FLOW_VALID         = vVW510021_W_FLOW_VALID;
2023             vwr->STATS_START_OFF    = vVW510021_W_HEADER_LEN;
2024             vwr->FCS_ERROR          = vVW510021_W_FCS_ERROR;
2025             vwr->CRYPTO_ERR         = v22_W_CRYPTO_ERR;
2026             vwr->RETRY_ERR          = v22_W_RETRY_ERR;
2027
2028             /*vwr->STATS_START_OFF  = 0;*/
2029
2030             vwr->RXTX_OFF           = vVW510021_W_RXTX_OFF;
2031
2032             vwr->MT_10_HALF         = 0;
2033             vwr->MT_10_FULL         = 0;
2034             vwr->MT_100_HALF        = 0;
2035             vwr->MT_100_FULL        = 0;
2036             vwr->MT_1G_HALF         = 0;
2037             vwr->MT_1G_FULL         = 0;
2038             vwr->MT_CCKL            = v22_W_MT_CCKL;
2039             vwr->MT_CCKS            = v22_W_MT_CCKS;
2040             /*vwr->MT_OFDM          = vVW510021_W_MT_OFDM;*/
2041
2042             vwr->WEPTYPE            = v22_W_WEPTYPE;
2043             vwr->TKIPTYPE           = v22_W_TKIPTYPE;
2044             vwr->CCMPTYPE           = v22_W_CCMPTYPE;
2045
2046             vwr->FRAME_TYPE_OFF     =   vVW510021_W_FRAME_TYPE_OFF;
2047             vwr->IS_TCP             =   vVW510021_W_IS_TCP;
2048             vwr->IS_UDP             =   vVW510021_W_IS_UDP;
2049             vwr->IS_ICMP            =   vVW510021_W_IS_ICMP;
2050             vwr->IS_IGMP            =   vVW510021_W_IS_IGMP;
2051             vwr->IS_QOS             =   vVW510021_W_QOS_VALID;
2052
2053             /*
2054              * The 12 is for 11 bytes of PLCP  and 1 byte of pad
2055              * before the data.
2056              */
2057             vwr->MPDU_OFF           = vVW510021_W_STATS_HEADER_LEN + 12;
2058
2059             break;
2060
2061         case S3_W_FPGA:
2062             vwr->STATS_LEN       = vVW510021_W_STATS_TRAILER_LEN;
2063             vwr->PLCP_LENGTH_OFF = 16;
2064
2065             /*
2066              * The first 16 is from the 16 bytes of stats block that
2067              * precede the PLCP; the 16 is for 16 bytes of PLCP.
2068              */
2069             vwr->MPDU_OFF        = 16 + 16;
2070
2071             break;
2072
2073         case vVW510012_E_FPGA:
2074             vwr->STATS_LEN      = v22_E_STATS_LEN;
2075
2076             vwr->VALID_OFF      = v22_E_VALID_OFF;
2077             vwr->MTYPE_OFF      = v22_E_MTYPE_OFF;
2078             vwr->VCID_OFF       = v22_E_VCID_OFF;
2079             vwr->FLOWSEQ_OFF    = v22_E_FLOWSEQ_OFF;
2080             vwr->FLOWID_OFF     = v22_E_FLOWID_OFF;
2081             vwr->OCTET_OFF      = v22_E_OCTET_OFF;
2082             vwr->ERRORS_OFF     = v22_E_ERRORS_OFF;
2083             vwr->PATN_OFF       = v22_E_PATN_OFF;
2084             vwr->RSSI_OFF       = v22_E_RSSI_OFF;
2085             vwr->STARTT_OFF     = v22_E_STARTT_OFF;
2086             vwr->ENDT_OFF       = v22_E_ENDT_OFF;
2087             vwr->LATVAL_OFF     = v22_E_LATVAL_OFF;
2088             vwr->INFO_OFF       = v22_E_INFO_OFF;
2089             vwr->L4ID_OFF       = v22_E_L4ID_OFF;
2090
2091             vwr->IS_RX          = v22_E_IS_RX;
2092             vwr->MT_MASK        = v22_E_MT_MASK;
2093             vwr->VCID_MASK      = v22_E_VCID_MASK;
2094             vwr->FLOW_VALID     = v22_E_FLOW_VALID;
2095             vwr->FCS_ERROR      = v22_E_FCS_ERROR;
2096
2097             vwr->RX_DECRYPTS    = v22_E_RX_DECRYPTS;
2098             vwr->TX_DECRYPTS    = v22_E_TX_DECRYPTS;
2099             vwr->FC_PROT_BIT    = v22_E_FC_PROT_BIT;
2100
2101             vwr->MT_10_HALF     = v22_E_MT_10_HALF;
2102             vwr->MT_10_FULL     = v22_E_MT_10_FULL;
2103             vwr->MT_100_HALF    = v22_E_MT_100_HALF;
2104             vwr->MT_100_FULL    = v22_E_MT_100_FULL;
2105             vwr->MT_1G_HALF     = v22_E_MT_1G_HALF;
2106             vwr->MT_1G_FULL     = v22_E_MT_1G_FULL;
2107             vwr->MT_CCKL        = 0;
2108             vwr->MT_CCKS        = 0;
2109             vwr->MT_OFDM        = 0;
2110
2111             vwr->FRAME_TYPE_OFF =  v22_E_FRAME_TYPE_OFF;
2112             vwr->IS_TCP         =   v22_E_IS_TCP;
2113             vwr->IS_UDP         =   v22_E_IS_UDP;
2114             vwr->IS_ICMP        =   v22_E_IS_ICMP;
2115             vwr->IS_IGMP        =   v22_E_IS_IGMP;
2116             vwr->IS_QOS         =   v22_E_IS_QOS;
2117             vwr->IS_VLAN        =   v22_E_IS_VLAN;
2118
2119             break;
2120
2121             /* WLAN frames */
2122         case S1_W_FPGA:
2123             vwr->STATS_LEN          = v22_W_STATS_LEN;
2124
2125             vwr->MTYPE_OFF          = v22_W_MTYPE_OFF;
2126             vwr->VALID_OFF          = v22_W_VALID_OFF;
2127             vwr->VCID_OFF           = v22_W_VCID_OFF;
2128             vwr->FLOWSEQ_OFF        = v22_W_FLOWSEQ_OFF;
2129             vwr->FLOWID_OFF         = v22_W_FLOWID_OFF;
2130             vwr->OCTET_OFF          = v22_W_OCTET_OFF;
2131             vwr->ERRORS_OFF         = v22_W_ERRORS_OFF;
2132             vwr->PATN_OFF           = v22_W_PATN_OFF;
2133             vwr->RSSI_OFF           = v22_W_RSSI_OFF;
2134             vwr->STARTT_OFF         = v22_W_STARTT_OFF;
2135             vwr->ENDT_OFF           = v22_W_ENDT_OFF;
2136             vwr->LATVAL_OFF         = v22_W_LATVAL_OFF;
2137             vwr->INFO_OFF           = v22_W_INFO_OFF;
2138             vwr->L4ID_OFF           = v22_W_L4ID_OFF;
2139             vwr->IPLEN_OFF          = v22_W_IPLEN_OFF;
2140             vwr->PLCP_LENGTH_OFF    = v22_W_PLCP_LENGTH_OFF;
2141
2142             vwr->FCS_ERROR          = v22_W_FCS_ERROR;
2143             vwr->CRYPTO_ERR         = v22_W_CRYPTO_ERR;
2144             vwr->PAYCHK_ERR         = v22_W_PAYCHK_ERR;
2145             vwr->RETRY_ERR          = v22_W_RETRY_ERR;
2146             vwr->IS_RX              = v22_W_IS_RX;
2147             vwr->MT_MASK            = v22_W_MT_MASK;
2148             vwr->VCID_MASK          = v22_W_VCID_MASK;
2149             vwr->FLOW_VALID         = v22_W_FLOW_VALID;
2150
2151             vwr->RX_DECRYPTS        = v22_W_RX_DECRYPTS;
2152             vwr->TX_DECRYPTS        = v22_W_TX_DECRYPTS;
2153             vwr->FC_PROT_BIT        = v22_W_FC_PROT_BIT;
2154
2155             vwr->MT_10_HALF         = 0;
2156             vwr->MT_10_FULL         = 0;
2157             vwr->MT_100_HALF        = 0;
2158             vwr->MT_100_FULL        = 0;
2159             vwr->MT_1G_HALF         = 0;
2160             vwr->MT_1G_FULL         = 0;
2161             vwr->MT_CCKL            = v22_W_MT_CCKL;
2162             vwr->MT_CCKS            = v22_W_MT_CCKS;
2163             vwr->MT_OFDM            = v22_W_MT_OFDM;
2164
2165             vwr->WEPTYPE            = v22_W_WEPTYPE;
2166             vwr->TKIPTYPE           = v22_W_TKIPTYPE;
2167             vwr->CCMPTYPE           = v22_W_CCMPTYPE;
2168
2169             vwr->FRAME_TYPE_OFF     =   v22_W_FRAME_TYPE_OFF;
2170             vwr->IS_TCP             =   v22_W_IS_TCP;
2171             vwr->IS_UDP             =   v22_W_IS_UDP;
2172             vwr->IS_ICMP            =   v22_W_IS_ICMP;
2173             vwr->IS_IGMP            =   v22_W_IS_IGMP;
2174             vwr->IS_QOS             =   v22_W_IS_QOS;
2175
2176             break;
2177
2178         /* Ethernet frames */
2179         case vVW510024_E_FPGA:
2180             vwr->STATS_LEN          = vVW510024_E_STATS_LEN;
2181
2182             vwr->VALID_OFF          = vVW510024_E_VALID_OFF;
2183             vwr->VCID_OFF           = vVW510024_E_VCID_OFF;
2184             vwr->FLOWSEQ_OFF        = vVW510024_E_FLOWSEQ_OFF;
2185             vwr->FLOWID_OFF         = vVW510024_E_FLOWID_OFF;
2186             vwr->OCTET_OFF          = vVW510024_E_MSDU_LENGTH_OFF;
2187             vwr->ERRORS_OFF         = vVW510024_E_ERRORS_OFF;
2188             vwr->PATN_OFF           = vVW510024_E_MATCH_OFF;
2189             vwr->STARTT_OFF         = vVW510024_E_STARTT_OFF;
2190             vwr->ENDT_OFF           = vVW510024_E_ENDT_OFF;
2191             vwr->LATVAL_OFF         = vVW510024_E_LATVAL_OFF;
2192             vwr->INFO_OFF           = vVW510024_E_INFO_OFF;
2193             vwr->L4ID_OFF           = vVW510024_E_L4ID_OFF;
2194             vwr->IPLEN_OFF          = vVW510024_E_IPLEN_OFF;
2195
2196             vwr->FPGA_VERSION_OFF   = vVW510024_E_FPGA_VERSION_OFF;
2197             vwr->HEADER_VERSION_OFF = vVW510024_E_HEADER_VERSION_OFF;
2198
2199             vwr->VCID_MASK          = vVW510024_E_VCID_MASK;
2200             vwr->FLOW_VALID         = vVW510024_E_FLOW_VALID;
2201             vwr->FCS_ERROR          = v22_E_FCS_ERROR;
2202
2203             vwr->FRAME_TYPE_OFF     =   vVW510024_E_FRAME_TYPE_OFF;
2204             vwr->IS_TCP             =   vVW510024_E_IS_TCP;
2205             vwr->IS_UDP             =   vVW510024_E_IS_UDP;
2206             vwr->IS_ICMP            =   vVW510024_E_IS_ICMP;
2207             vwr->IS_IGMP            =   vVW510024_E_IS_IGMP;
2208             vwr->IS_QOS             =   vVW510024_E_QOS_VALID;
2209             vwr->IS_VLAN            =   vVW510024_E_IS_VLAN;
2210
2211             break;
2212     }
2213 }
2214 #define SIG_SCAN_RANGE  64                          /* range of signature scanning region */
2215
2216 /* Utility routine: check that signature is at specified location; scan for it if not.     */
2217 /* If we can't find a signature at all, then simply return the originally supplied offset. */
2218 int find_signature(const guint8 *m_ptr, int rec_size, int pay_off, guint32 flow_id, guint8 flow_seq)
2219 {
2220     int     tgt;                /* temps */
2221     guint32 fid;
2222
2223     /* initial check is very simple: look for a '0xdd' at the target location */
2224     if (m_ptr[pay_off] == 0xdd)                         /* if magic byte is present */
2225         return pay_off;                                 /* got right offset, return it */
2226
2227     /* Hmmm, signature magic byte is not where it is supposed to be; scan from start of     */
2228     /*  payload until maximum scan range exhausted to see if we can find it.                */
2229     /* The scanning process consists of looking for a '0xdd', then checking for the correct */
2230     /*  flow ID and sequence number at the appropriate offsets.                             */
2231     for (tgt = pay_off; tgt < (rec_size); tgt++) {
2232         if (m_ptr[tgt] == 0xdd) {                       /* found magic byte? check fields */
2233             if ((tgt + 15 < rec_size) && (m_ptr[tgt + 15] == 0xe2)) {
2234                 if (m_ptr[tgt + 4] != flow_seq)
2235                     continue;
2236
2237                 fid = pletoh24(&m_ptr[tgt + 1]);
2238
2239                 if (fid != flow_id)
2240                     continue;
2241
2242                 return (tgt);
2243             }
2244             else if (tgt + SIG_FSQ_OFF < rec_size)
2245             {                                               /* out which one... */
2246                 if (m_ptr[tgt + SIG_FSQ_OFF] != flow_seq)   /* check sequence number */
2247                     continue;                               /* if failed, keep scanning */
2248
2249                 fid = pletoh24(&m_ptr[tgt + SIG_FID_OFF]);  /* assemble flow ID from signature */
2250                 if (fid != flow_id)                         /* check flow ID against expected */
2251                     continue;                               /* if failed, keep scanning */
2252
2253                 /* matched magic byte, sequence number, flow ID; found the signature */
2254                 return (tgt);                               /* return offset of signature */
2255             }
2256         }
2257     }
2258
2259     /* failed to find the signature, return the original offset as default */
2260     return pay_off;
2261 }
2262
2263 /* utility routine: harvest the signature time stamp from the data frame */
2264 guint64 get_signature_ts(const guint8 *m_ptr,int sig_off)
2265 {
2266     int     ts_offset;
2267     guint64 sig_ts;
2268
2269     if (m_ptr[sig_off + 15] == 0xe2)
2270         ts_offset = 5;
2271     else
2272         ts_offset = 8;
2273
2274     sig_ts = pletoh32(&m_ptr[sig_off + ts_offset]);
2275
2276     return (sig_ts & 0xffffffff);
2277 }
2278
2279 static float getRate( guint8 plcpType, guint8 mcsIndex, guint16 rflags, guint8 nss )
2280 {
2281     /* Rate conversion data */
2282     static const float canonical_rate_legacy[]  = {1.0f, 2.0f, 5.5f, 11.0f, 6.0f, 9.0f, 12.0f, 18.0f, 24.0f, 36.0f, 48.0f, 54.0f};
2283
2284     static const int   canonical_ndbps_20_ht[8]  = {26, 52, 78, 104, 156, 208, 234, 260};
2285     static const int   canonical_ndbps_40_ht[8]  = {54, 108, 162, 216, 324, 432, 486, 540};
2286
2287     static const int   canonical_ndbps_20_vht[] = {26, 52, 78, 104, 156, 208, 234, 260, 312};
2288     static const int   canonical_ndbps_40_vht[] = {54, 108, 162, 216, 324, 432, 486, 540, 648, 720};
2289     static const int   canonical_ndbps_80_vht[] = {117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560};
2290
2291     float symbol_tx_time, bitrate  = 0.0f;
2292
2293     if (plcpType == 0)
2294     {
2295         if (mcsIndex < G_N_ELEMENTS(canonical_rate_legacy))
2296             bitrate =  canonical_rate_legacy[mcsIndex];
2297     }
2298     else if (plcpType == 1 || plcpType == 2)
2299     {
2300         int   ndbps;
2301
2302         if ( rflags & FLAGS_CHAN_SHORTGI)
2303             symbol_tx_time = 3.6f;
2304         else
2305             symbol_tx_time = 4.0f;
2306
2307         if ( rflags & FLAGS_CHAN_40MHZ )
2308             ndbps = canonical_ndbps_40_ht[mcsIndex & 0x07];
2309         else
2310             ndbps = canonical_ndbps_20_ht[mcsIndex & 0x07];
2311
2312         bitrate = ( ndbps * (((int)(mcsIndex >> 3) + 1) )) / symbol_tx_time;
2313     }
2314     else
2315     {
2316         if ( rflags & FLAGS_CHAN_SHORTGI)
2317             symbol_tx_time = 3.6f;
2318         else
2319             symbol_tx_time = 4.0f;
2320
2321         /* Check for the out of range mcsIndex.  Should never happen, but if mcs index is greater than 9 assume 9 is the value */
2322         if (mcsIndex > 9) mcsIndex = 9;
2323         if ( rflags & FLAGS_CHAN_40MHZ )
2324             bitrate = (canonical_ndbps_40_vht[ mcsIndex ] * nss) / symbol_tx_time;
2325         else if (rflags & FLAGS_CHAN_80MHZ )
2326             bitrate = (canonical_ndbps_80_vht[ mcsIndex ] * nss) / symbol_tx_time;
2327         else
2328         {
2329             if (mcsIndex == 9 && nss == 3)
2330                 bitrate = 1040 / symbol_tx_time;
2331             else if (mcsIndex < 9)
2332                 bitrate = (canonical_ndbps_20_vht[ mcsIndex ] * nss) / symbol_tx_time;
2333         }
2334     }
2335
2336     return bitrate;
2337 }
2338
2339 static gboolean
2340 vwr_process_rec_data(FILE_T fh, int rec_size,
2341                      struct wtap_pkthdr *phdr, Buffer *buf, vwr_t *vwr,
2342                      int IS_TX, int *err, gchar **err_info)
2343 {
2344     guint8   rec[B_SIZE];       /* local buffer (holds input record) */
2345
2346     /* Read over the entire record (frame + trailer) into a local buffer.         */
2347     /* If we don't get it all, then declare an error, we can't process the frame. */
2348     if (!wtap_read_bytes(fh, rec, rec_size, err, err_info))
2349         return FALSE;
2350
2351     /* now format up the frame data */
2352     switch (vwr->FPGA_VERSION)
2353     {
2354         case S1_W_FPGA:
2355             return vwr_read_s1_W_rec(vwr, phdr, buf, rec, rec_size, err, err_info);
2356             break;
2357         case S2_W_FPGA:
2358         case S3_W_FPGA:
2359             return vwr_read_s2_s3_W_rec(vwr, phdr, buf, rec, rec_size, IS_TX, err, err_info);
2360             break;
2361         case vVW510012_E_FPGA:
2362         case vVW510024_E_FPGA:
2363             return vwr_read_rec_data_ethernet(vwr, phdr, buf, rec, rec_size, IS_TX, err, err_info);
2364             break;
2365         default:
2366             g_assert_not_reached();
2367             return FALSE;
2368     }
2369 }
2370
2371 /*
2372  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2373  *
2374  * Local variables:
2375  * c-basic-offset: 4
2376  * tab-width: 8
2377  * indent-tabs-mode: nil
2378  * End:
2379  *
2380  * vi: set shiftwidth=4 tabstop=8 expandtab:
2381  * :indentSize=4:tabSize=8:noTabs=true:
2382  */