### Bug Summary

File: | builds/wireshark/wireshark/wiretap/dbs-etherwatch.c
Warning: | line 490, column 5 Value stored to 'pd' is never read

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dbs-etherwatch.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /usr/include/libxml2 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D wiretap_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -I /builds/wireshark/wireshark/build/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-03-24-100345-3641-1 -x c /builds/wireshark/wireshark/wiretap/dbs-etherwatch.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* dbs-etherwatch.c
2 | *
3 | * Wiretap Library
4 | * Copyright (c) 2001 by Marc Milgram <ethereal@mmilgram.NOSPAMmail.net>
5 | *
6 | * SPDX-License-Identifier: GPL-2.0-or-later
7 | */
8 |
9 | #include "config.h"
10 | #include "dbs-etherwatch.h"
11 | #include "wtap_module.h"
12 | #include "file_wrappers.h"
13 |
14 | #include <stdlib.h>
15 | #include <string.h>
16 |
17 | #include <wsutil/array.h>
18 | #include <wsutil/pint.h>
19 |
20 | /*
21 | * DBS Etherwatch (text format)
22 | *
23 | * Text output from DBS Etherwatch is supported. DBS Etherwatch is available
24 | * from: https://web.archive.org/web/20070612033348/http://www.users.bigpond.com/dbsneddon/software.htm.
25 | */
26 |
27 | /* This module reads the text output of the 'DBS-ETHERTRACE' command in VMS
28 | * It was initially based on vms.c.
29 | */
30 |
31 | /*
32 | Example 'ETHERWATCH' output data (with "printable" characters in the
33 | "printable characters" section of the output replaced by "." if they have
34 | the 8th bit set, so as not to upset compilers that are expecting text
35 | in comments to be in a particular character encoding that can't handle
36 | those values):
37 | ETHERWATCH X5-008
38 | 42 names and addresses were loaded
39 | Reading recorded data from PERSISTENCE
40 | ------------------------------------------------------------------------------
41 | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
42 | Protocol 08-00 00 00-00-00-00-00, 60 byte buffer at 10-OCT-2001 10:20:45.16
43 | [E..<8...........]- 0-[45 00 00 3C 38 93 00 00 1D 06 D2 12 80 93 11 1A]
44 | [.........(......]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 90 00 00 00 00]
45 | [................]- 32-[A0 02 FF FF 95 BD 00 00 02 04 05 B4 03 03 04 01]
46 | [............ ]- 48-[01 01 08 0A 90 90 E5 14 00 00 00 00]
47 | ------------------------------------------------------------------------------
48 | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
49 | Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17
50 | [E..(8......%....]- 0-[45 00 00 28 38 94 00 00 1D 06 D2 25 80 93 11 1A]
51 | [.........(..Z.4w]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 91 5A 1C 34 77]
52 | [P.#(.s..........]- 32-[50 10 23 28 C1 73 00 00 02 04 05 B4 03 03 00 00]
53 | [.. ]- 48-[02 04]
54 |
55 |
56 | Alternative HEX only output, slightly more efficient and all wireshark needs:
57 | ------------------------------------------------------------------------------
58 | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
59 | Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17
60 | 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6]
61 | 20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00]
62 | 40-[03 30 30 30 30 30 00 00 03 30]
63 | */
64 |
65 | /* Magic text to check for DBS-ETHERWATCH-ness of file */
66 | static const char dbs_etherwatch_hdr_magic[] =
67 | { 'E', 'T', 'H', 'E', 'R', 'W', 'A', 'T', 'C', 'H', ' '};
68 | #define DBS_ETHERWATCH_HDR_MAGIC_SIZE(sizeof (dbs_etherwatch_hdr_magic) / sizeof (dbs_etherwatch_hdr_magic )[0]) \
69 | array_length(dbs_etherwatch_hdr_magic)(sizeof (dbs_etherwatch_hdr_magic) / sizeof (dbs_etherwatch_hdr_magic )[0])
70 |
71 | /* Magic text for start of packet */
72 | static const char dbs_etherwatch_rec_magic[] =
73 | {'F', 'r', 'o', 'm', ' '};
74 | #define DBS_ETHERWATCH_REC_MAGIC_SIZE(sizeof (dbs_etherwatch_rec_magic) / sizeof (dbs_etherwatch_rec_magic )[0]) \
75 | array_length(dbs_etherwatch_rec_magic)(sizeof (dbs_etherwatch_rec_magic) / sizeof (dbs_etherwatch_rec_magic )[0])
76 |
77 | /*
78 | * Default packet size - maximum normal Ethernet packet size, without an
79 | * FCS.
80 | */
81 | #define DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN1514 1514
82 |
83 | static bool_Bool dbs_etherwatch_read(wtap *wth, wtap_rec *rec,
84 | int *err, char **err_info, int64_t *data_offset);
85 | static bool_Bool dbs_etherwatch_seek_read(wtap *wth, int64_t seek_off,
86 | wtap_rec *rec, int *err, char **err_info);
87 | static bool_Bool parse_dbs_etherwatch_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
88 | int *err, char **err_info);
89 | static unsigned parse_single_hex_dump_line(char* rec, Buffer *buf,
90 | int byte_offset);
91 | static unsigned parse_hex_dump(char* dump, Buffer *buf, char separator, char end);
92 |
93 | static int dbs_etherwatch_file_type_subtype = -1;
94 |
95 | void register_dbs_etherwatch(void);
96 |
97 | /* Seeks to the beginning of the next packet, and returns the
98 | byte offset. Returns -1 on failure, and sets "*err" to the error
99 | and "*err_info" to null or an additional error string. */
100 | static int64_t dbs_etherwatch_seek_next_packet(wtap *wth, int *err,
101 | char **err_info)
102 | {
103 | int byte;
104 | unsigned int level = 0;
105 | int64_t cur_off;
106 |
107 | while ((byte = file_getc(wth->fh)) != EOF(-1)) {
108 | if (byte == dbs_etherwatch_rec_magic[level]) {
109 | level++;
110 | if (level >= DBS_ETHERWATCH_REC_MAGIC_SIZE(sizeof (dbs_etherwatch_rec_magic) / sizeof (dbs_etherwatch_rec_magic )[0])) {
111 | /* note: we're leaving file pointer right after the magic characters */
112 | cur_off = file_tell(wth->fh);
113 | if (cur_off == -1) {
114 | /* Error. */
115 | *err = file_error(wth->fh, err_info);
116 | return -1;
117 | }
118 | return cur_off + 1;
119 | }
120 | } else {
121 | level = 0;
122 | }
123 | }
124 | /* EOF or error. */
125 | *err = file_error(wth->fh, err_info);
126 | return -1;
127 | }
128 |
129 | #define DBS_ETHERWATCH_HEADER_LINES_TO_CHECK200 200
130 | #define DBS_ETHERWATCH_LINE_LENGTH240 240
131 |
132 | /* Look through the first part of a file to see if this is
133 | * a DBS Ethertrace text trace file.
134 | *
135 | * Returns true if it is, false if it isn't or if we get an I/O error;
136 | * if we get an I/O error, "*err" will be set to a non-zero value and
137 | * "*err_info" will be set to null or an error string.
138 | */
139 | static bool_Bool dbs_etherwatch_check_file_type(wtap *wth, int *err,
140 | char **err_info)
141 | {
142 | char buf[DBS_ETHERWATCH_LINE_LENGTH240];
143 | int line, byte;
144 | size_t reclen;
145 | unsigned int i, level;
146 |
147 | buf[DBS_ETHERWATCH_LINE_LENGTH240-1] = 0;
148 |
149 | for (line = 0; line < DBS_ETHERWATCH_HEADER_LINES_TO_CHECK200; line++) {
150 | if (file_gets(buf, DBS_ETHERWATCH_LINE_LENGTH240, wth->fh) == NULL((void*)0)) {
151 | /* EOF or error. */
152 | *err = file_error(wth->fh, err_info);
153 | return false0;
154 | }
155 |
156 | reclen = strlen(buf);
157 | if (reclen < DBS_ETHERWATCH_HDR_MAGIC_SIZE(sizeof (dbs_etherwatch_hdr_magic) / sizeof (dbs_etherwatch_hdr_magic )[0]))
158 | continue;
159 |
160 | level = 0;
161 | for (i = 0; i < reclen; i++) {
162 | byte = buf[i];
163 | if (byte == dbs_etherwatch_hdr_magic[level]) {
164 | level++;
165 | if (level >=
166 | DBS_ETHERWATCH_HDR_MAGIC_SIZE(sizeof (dbs_etherwatch_hdr_magic) / sizeof (dbs_etherwatch_hdr_magic )[0])) {
167 | return true1;
168 | }
169 | }
170 | else
171 | level = 0;
172 | }
173 | }
174 | *err = 0;
175 | return false0;
176 | }
177 |
178 |
179 | wtap_open_return_val dbs_etherwatch_open(wtap *wth, int *err, char **err_info)
180 | {
181 | /* Look for DBS ETHERWATCH header */
182 | if (!dbs_etherwatch_check_file_type(wth, err, err_info)) {
183 | if (*err != 0 && *err != WTAP_ERR_SHORT_READ-12)
184 | return WTAP_OPEN_ERROR;
185 | return WTAP_OPEN_NOT_MINE;
186 | }
187 |
188 | wth->file_encap = WTAP_ENCAP_ETHERNET1;
189 | wth->file_type_subtype = dbs_etherwatch_file_type_subtype;
190 | wth->snapshot_length = 0; /* not known */
191 | wth->subtype_read = dbs_etherwatch_read;
192 | wth->subtype_seek_read = dbs_etherwatch_seek_read;
193 | wth->file_tsprec = WTAP_TSPREC_10_MSEC2;
194 |
195 | /*
196 | * Add an IDB; we don't know how many interfaces were
197 | * involved, so we just say one interface, about which
198 | * we only know the link-layer type, snapshot length,
199 | * and time stamp resolution.
200 | */
201 | wtap_add_generated_idb(wth);
202 |
203 | return WTAP_OPEN_MINE;
204 | }
205 |
206 | /* Find the next packet and parse it; called from wtap_read(). */
207 | static bool_Bool dbs_etherwatch_read(wtap *wth, wtap_rec *rec,
208 | int *err, char **err_info, int64_t *data_offset)
209 | {
210 | int64_t offset;
211 |
212 | /* Find the next packet */
213 | offset = dbs_etherwatch_seek_next_packet(wth, err, err_info);
214 | if (offset < 1)
215 | return false0;
216 | *data_offset = offset;
217 |
218 | /* Parse the packet */
219 | return parse_dbs_etherwatch_packet(wth, wth->fh, rec, err, err_info);
220 | }
221 |
222 | /* Used to read packets in random-access fashion */
223 | static bool_Bool
224 | dbs_etherwatch_seek_read(wtap *wth, int64_t seek_off,
225 | wtap_rec *rec, int *err, char **err_info)
226 | {
227 | if (file_seek(wth->random_fh, seek_off - 1, SEEK_SET0, err) == -1)
228 | return false0;
229 |
230 | return parse_dbs_etherwatch_packet(wth, wth->random_fh, rec, err, err_info);
231 | }
232 |
233 | /* Parse a packet */
234 | /*
235 | Packet header:
236 | 1 2 3 4
237 | 0123456789012345678901234567890123456789012345
238 | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
239 | Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17
240 | */
241 | #define MAC_ADDR_LENGTH6 6 /* Length MAC address */
242 | #define DEST_MAC_PREFIX"] to " "] to " /* Prefix to the dest. MAC address */
243 | #define PROTOCOL_LENGTH2 2 /* Length protocol */
244 | #define PROTOCOL_POS9 9 /* Position protocol */
245 | #define SAP_LENGTH2 2 /* Length DSAP+SSAP */
246 | #define SAP_POS9 9 /* Position DSAP+SSAP */
247 | #define CTL_UNNUMB_LENGTH1 1 /* Length unnumbered control field */
248 | #define CTL_NUMB_LENGTH2 2 /* Length numbered control field */
249 | #define CTL_POS15 15 /* Position control field */
250 | #define PID_LENGTH5 5 /* Length PID */
251 | #define PID_POS18 18 /* Position PID */
252 | #define LENGTH_POS33 33 /* Position length */
253 | #define HEX_HDR_SPR'-' '-' /* Separator char header hex values */
254 | #define HEX_HDR_END' ' ' ' /* End char hdr. hex val. except PID */
255 | #define HEX_PID_END',' ',' /* End char PID hex value */
256 | #define IEEE802_LEN_LEN2 2 /* Length of the IEEE 802 len. field */
257 | /*
258 | To check whether it is Ethernet II or IEEE 802 we check the values of the
259 | control field and PID, when they are all 0's we assume it is Ethernet II
260 | else IEEE 802. In IEEE 802 the DSAP and SSAP are behind protocol, the
261 | length in the IEEE data we have to construct.
262 | */
263 | #define ETH_II_CHECK_POS15 15
264 | #define ETH_II_CHECK_STR"00 00-00-00-00-00," "00 00-00-00-00-00,"
265 | /*
266 | To check whether it IEEE 802.3 with SNAP we check that both the DSAP & SSAP
267 | values are 0xAA and the control field 0x03.
268 | */
269 | #define SNAP_CHECK_POS9 9
270 | #define SNAP_CHECK_STR"AA-AA 03" "AA-AA 03"
271 | /*
272 | To check whether the control field is 1 or two octets we check if it is
273 | unnumbered. Unnumbered has length 1, numbered 2.
274 | */
275 | #define CTL_UNNUMB_MASK0x03 0x03
276 | #define CTL_UNNUMB_VALUE0x03 0x03
277 | static bool_Bool
278 | parse_dbs_etherwatch_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
279 | int *err, char **err_info)
280 | {
281 | uint8_t *pd;
282 | char line[DBS_ETHERWATCH_LINE_LENGTH240];
283 | int num_items_scanned;
284 | int pkt_len_signed, csec_signed;
285 | unsigned eth_hdr_len, pkt_len, csec;
286 | unsigned length_pos, length_from, length;
287 | struct tm tm;
288 | char mon[4] = "xxx";
289 | char *p;
290 | static const char months[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
291 | unsigned count, line_count;
292 |
293 | /* Make sure we have enough room for a regular Ethernet packet */
294 | ws_buffer_assure_space(&rec->data, DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN1514);
295 | pd = ws_buffer_start_ptr(&rec->data);
296 |
297 | eth_hdr_len = 0;
298 | memset(&tm, 0, sizeof(tm));
299 | /* Our file pointer should be on the first line containing the
300 | * summary information for a packet. Read in that line and
301 | * extract the useful information
302 | */
303 | if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH240, fh) == NULL((void*)0)) {
304 | *err = file_error(fh, err_info);
305 | if (*err == 0) {
306 | *err = WTAP_ERR_SHORT_READ-12;
307 | }
308 | return false0;
309 | }
310 |
311 | /* Get the destination address */
312 | p = strstr(line, DEST_MAC_PREFIX"] to ");
313 | if(!p) {
314 | *err = WTAP_ERR_BAD_FILE-13;
315 | *err_info = g_strdup("dbs_etherwatch: destination address not found")g_strdup_inline ("dbs_etherwatch: destination address not found" );
316 | return false0;
317 | }
318 | p += strlen(DEST_MAC_PREFIX"] to ");
319 | if(parse_hex_dump(p, &rec->data, HEX_HDR_SPR'-', HEX_HDR_END' ')
320 | != MAC_ADDR_LENGTH6) {
321 | *err = WTAP_ERR_BAD_FILE-13;
322 | *err_info = g_strdup("dbs_etherwatch: destination address not valid")g_strdup_inline ("dbs_etherwatch: destination address not valid" );
323 | return false0;
324 | }
325 | eth_hdr_len += MAC_ADDR_LENGTH6;
326 |
327 | /* Get the source address */
328 | /*
329 | * Since the first part of the line is already skipped in order to find
330 | * the start of the record we cannot index, just look for the first
331 | * 'HEX' character
332 | */
333 | p = line;
334 | while(!g_ascii_isxdigit(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_XDIGIT) != 0)) {
335 | p++;
336 | }
337 | if(parse_hex_dump(p, &rec->data, HEX_HDR_SPR'-',
338 | HEX_HDR_END' ') != MAC_ADDR_LENGTH6) {
339 | *err = WTAP_ERR_BAD_FILE-13;
340 | *err_info = g_strdup("dbs_etherwatch: source address not valid")g_strdup_inline ("dbs_etherwatch: source address not valid");
341 | return false0;
342 | }
343 | eth_hdr_len += MAC_ADDR_LENGTH6;
344 |
345 | /* Read the next line of the record header */
346 | if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH240, fh) == NULL((void*)0)) {
347 | *err = file_error(fh, err_info);
348 | if (*err == 0) {
349 | *err = WTAP_ERR_SHORT_READ-12;
350 | }
351 | return false0;
352 | }
353 |
354 | /* Check the lines is as least as long as the length position */
355 | if(strlen(line) < LENGTH_POS33) {
356 | *err = WTAP_ERR_BAD_FILE-13;
357 | *err_info = g_strdup("dbs_etherwatch: line too short")g_strdup_inline ("dbs_etherwatch: line too short");
358 | return false0;
359 | }
360 |
361 | /*
362 | * %u doesn't fail if the value has a sign; it works like the
363 | * strto*() routines.
364 | *
365 | * Use %d, scan into signed values, and then check whether they're
366 | * < 0.
367 | */
368 | num_items_scanned = sscanf(line + LENGTH_POS33,
369 | "%9d byte buffer at %2d-%3s-%4d %2d:%2d:%2d.%9d",
370 | &pkt_len_signed,
371 | &tm.tm_mday, mon,
372 | &tm.tm_year, &tm.tm_hour, &tm.tm_min,
373 | &tm.tm_sec, &csec_signed);
374 |
375 | if (num_items_scanned != 8) {
376 | *err = WTAP_ERR_BAD_FILE-13;
377 | *err_info = g_strdup("dbs_etherwatch: header line not valid")g_strdup_inline ("dbs_etherwatch: header line not valid");
378 | return false0;
379 | }
380 |
381 | if (pkt_len_signed < 0) {
382 | *err = WTAP_ERR_BAD_FILE-13;
383 | *err_info = g_strdup("dbs_etherwatch: packet header has a negative packet length")g_strdup_inline ("dbs_etherwatch: packet header has a negative packet length" );
384 | return false0;
385 | }
386 |
387 | if (csec_signed < 0) {
388 | *err = WTAP_ERR_BAD_FILE-13;
389 | *err_info = g_strdup("dbs_etherwatch: packet header has a negative microseconds time stamp")g_strdup_inline ("dbs_etherwatch: packet header has a negative microseconds time stamp" );
390 | return false0;
391 | }
392 |
393 | pkt_len = (unsigned) pkt_len_signed;
394 | csec = (unsigned) csec_signed;
395 |
396 | /* Determine whether it is Ethernet II or IEEE 802 */
397 | if(strncmp(&line[ETH_II_CHECK_POS15], ETH_II_CHECK_STR"00 00-00-00-00-00,",
398 | strlen(ETH_II_CHECK_STR"00 00-00-00-00-00,")) == 0) {
399 | /* Ethernet II */
400 | /* Get the Protocol */
401 | if(parse_hex_dump(&line[PROTOCOL_POS9], &rec->data, HEX_HDR_SPR'-',
402 | HEX_HDR_END' ') != PROTOCOL_LENGTH2) {
403 | *err = WTAP_ERR_BAD_FILE-13;
404 | *err_info = g_strdup("dbs_etherwatch: Ethernet II protocol value not valid")g_strdup_inline ("dbs_etherwatch: Ethernet II protocol value not valid" );
405 | return false0;
406 | }
407 | eth_hdr_len += PROTOCOL_LENGTH2;
408 | } else {
409 | /* IEEE 802 */
410 | /* Remember where to put the length in the header */
411 | length_pos = eth_hdr_len;
412 | /* Leave room in the header for the length */
413 | eth_hdr_len += IEEE802_LEN_LEN2;
414 | /* Remember how much of the header should not be added to the length */
415 | length_from = eth_hdr_len;
416 | /* Get the DSAP + SSAP */
417 | if(parse_hex_dump(&line[SAP_POS9], &rec->data, HEX_HDR_SPR'-',
418 | HEX_HDR_END' ') != SAP_LENGTH2) {
419 | *err = WTAP_ERR_BAD_FILE-13;
420 | *err_info = g_strdup("dbs_etherwatch: 802.2 DSAP+SSAP value not valid")g_strdup_inline ("dbs_etherwatch: 802.2 DSAP+SSAP value not valid" );
421 | return false0;
422 | }
423 | eth_hdr_len += SAP_LENGTH2;
424 | /* Get the (first part of the) control field */
425 | if(parse_hex_dump(&line[CTL_POS15], &rec->data, HEX_HDR_SPR'-',
426 | HEX_HDR_END' ') != CTL_UNNUMB_LENGTH1) {
427 | *err = WTAP_ERR_BAD_FILE-13;
428 | *err_info = g_strdup("dbs_etherwatch: 802.2 control field first part not valid")g_strdup_inline ("dbs_etherwatch: 802.2 control field first part not valid" );
429 | return false0;
430 | }
431 | /* Determine whether the control is numbered, and thus longer */
432 | if((pd[eth_hdr_len] & CTL_UNNUMB_MASK0x03) != CTL_UNNUMB_VALUE0x03) {
433 | /* Get the rest of the control field, the first octet in the PID */
434 | if(parse_hex_dump(&line[PID_POS18], &rec->data, HEX_HDR_END' ',
435 | HEX_HDR_SPR'-') != CTL_NUMB_LENGTH2 - CTL_UNNUMB_LENGTH1) {
436 | *err = WTAP_ERR_BAD_FILE-13;
437 | *err_info = g_strdup("dbs_etherwatch: 802.2 control field second part value not valid")g_strdup_inline ("dbs_etherwatch: 802.2 control field second part value not valid" );
438 | return false0;
439 | }
440 | eth_hdr_len += CTL_NUMB_LENGTH2;
441 | } else {
442 | eth_hdr_len += CTL_UNNUMB_LENGTH1;
443 | }
444 | /* Determine whether it is SNAP */
445 | if(strncmp(&line[SNAP_CHECK_POS9], SNAP_CHECK_STR"AA-AA 03",
446 | strlen(SNAP_CHECK_STR"AA-AA 03")) == 0) {
447 | /* Get the PID */
448 | if(parse_hex_dump(&line[PID_POS18], &rec->data, HEX_HDR_SPR'-',
449 | HEX_PID_END',') != PID_LENGTH5) {
450 | *err = WTAP_ERR_BAD_FILE-13;
451 | *err_info = g_strdup("dbs_etherwatch: 802.2 PID value not valid")g_strdup_inline ("dbs_etherwatch: 802.2 PID value not valid");
452 | return false0;
453 | }
454 | eth_hdr_len += PID_LENGTH5;
455 | }
456 | /* Write the length in the header */
457 | length = (eth_hdr_len - length_from) + pkt_len;
458 | phtonu16(&pd[length_pos], length);
459 | }
460 |
461 | wtap_setup_packet_rec(rec, wth->file_encap);
462 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
463 | rec->presence_flags = WTAP_HAS_TS0x00000001|WTAP_HAS_CAP_LEN0x00000002;
464 |
465 | p = strstr(months, mon);
466 | if (p)
467 | tm.tm_mon = (int)(p - months) / 3;
468 | tm.tm_year -= 1900;
469 |
470 | tm.tm_isdst = -1;
471 | rec->ts.secs = mktime(&tm);
472 | rec->ts.nsecs = csec * 10000000;
473 | rec->rec_header.packet_header.caplen = eth_hdr_len + pkt_len;
474 | rec->rec_header.packet_header.len = eth_hdr_len + pkt_len;
475 |
476 | if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD262144U) {
477 | /*
478 | * Probably a corrupt capture file; return an error,
479 | * so that our caller doesn't blow up trying to allocate
480 | * space for an immensely-large packet.
481 | */
482 | *err = WTAP_ERR_BAD_FILE-13;
483 | *err_info = ws_strdup_printf("dbs_etherwatch: File has %u-byte packet, bigger than maximum of %u",wmem_strdup_printf(((void*)0), "dbs_etherwatch: File has %u-byte packet, bigger than maximum of %u" , rec->rec_header.packet_header.caplen, 262144U)
484 | rec->rec_header.packet_header.caplen, WTAP_MAX_PACKET_SIZE_STANDARD)wmem_strdup_printf(((void*)0), "dbs_etherwatch: File has %u-byte packet, bigger than maximum of %u" , rec->rec_header.packet_header.caplen, 262144U);
485 | return false0;
486 | }
487 |
488 | /* Make sure we have enough room, even for an oversized Ethernet packet */
489 | ws_buffer_assure_space(&rec->data, rec->rec_header.packet_header.caplen);
490 | pd = ws_buffer_start_ptr(&rec->data);
| Value stored to 'pd' is never read
491 |
492 | /*
493 | * We don't have an FCS in this frame.
494 | */
495 | rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
496 |
497 | /* Parse the hex dump */
498 | count = 0;
499 | while (count < pkt_len) {
500 | if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH240, fh) == NULL((void*)0)) {
501 | *err = file_error(fh, err_info);
502 | if (*err == 0) {
503 | *err = WTAP_ERR_SHORT_READ-12;
504 | }
505 | return false0;
506 | }
507 | if (!(line_count = parse_single_hex_dump_line(line,
508 | &rec->data, count))) {
509 | *err = WTAP_ERR_BAD_FILE-13;
510 | *err_info = g_strdup("dbs_etherwatch: packet data value not valid")g_strdup_inline ("dbs_etherwatch: packet data value not valid" );
511 | return false0;
512 | }
513 | count += line_count;
514 | if (count > pkt_len) {
515 | *err = WTAP_ERR_BAD_FILE-13;
516 | *err_info = g_strdup("dbs_etherwatch: packet data value has too many bytes")g_strdup_inline ("dbs_etherwatch: packet data value has too many bytes" );
517 | return false0;
518 | }
519 | }
520 | return true1;
521 | }
522 |
523 | /* Parse a hex dump line */
524 | /*
525 | /DISPLAY=BOTH output:
526 |
527 | 1 2 3 4
528 | 0123456789012345678901234567890123456789012345
529 | [E..(8...........]- 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A]
530 | [.........(..Z.4y]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 BF 5A 1C 34 79]
531 | [P.#(.C...00000..]- 32-[50 10 23 28 C1 43 00 00 03 30 30 30 30 30 00 00]
532 | [.0 ]- 48-[03 30]
533 |
534 | /DISPLAY=HEXADECIMAL output:
535 |
536 | 1 2 3 4
537 | 0123456789012345678901234567890123456789012345
538 | 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6]
539 | 20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00]
540 | 40-[03 30 30 30 30 30 00 00 03 30]
541 |
542 | */
543 |
544 | #define TYPE_CHECK_POS2 2 /* Position to check the type of hex dump */
545 | #define TYPE_CHECK_BOTH'[' '[' /* Value at pos. that indicates BOTH type */
546 | #define COUNT_POS_BOTH21 21 /* Count position BOTH type */
547 | #define COUNT_POS_HEX1 1 /* Count position HEX type */
548 | #define COUNT_SIZE5 5 /* Length counter */
549 | #define HEX_DUMP_START'[' '[' /* Start char */
550 | #define HEX_DUMP_SPR' ' ' ' /* Separator char */
551 | #define HEX_DUMP_END']' ']' /* End char */
552 |
553 | /* Take a string representing one line from a hex dump and converts the
554 | * text to binary data. We check the printed offset with the offset
555 | * we are passed to validate the record. We place the bytes in the buffer
556 | * at the specified offset.
557 | *
558 | * Returns length parsed if a good hex dump, 0 if bad.
559 | */
560 | static unsigned
561 | parse_single_hex_dump_line(char* rec, Buffer *buf, int byte_offset) {
562 |
563 | int pos, i;
564 | int value;
565 |
566 |
567 | /* Check that the record is as least as long as the check offset */
568 | for(i = 0; i < TYPE_CHECK_POS2; i++)
569 | {
570 | if(rec[i] == '\0') {
571 | return 0;
572 | }
573 | }
574 | /* determine the format and thus the counter offset and hex dump length */
575 | if(rec[TYPE_CHECK_POS2] == TYPE_CHECK_BOTH'[')
576 | {
577 | pos = COUNT_POS_BOTH21;
578 | }
579 | else
580 | {
581 | pos = COUNT_POS_HEX1;
582 | }
583 |
584 | /* Check that the record is as least as long as the start position */
585 | while(i < pos)
586 | {
587 | if(rec[i] == '\0') {
588 | return 0;
589 | }
590 | i++;
591 | }
592 |
593 | /* Get the byte_offset directly from the record */
594 | value = 0;
595 | for(i = 0; i < COUNT_SIZE5; i++) {
596 | if(!g_ascii_isspace(rec[pos])((g_ascii_table[(guchar) (rec[pos])] & G_ASCII_SPACE) != 0 )) {
597 | if(g_ascii_isdigit(rec[pos])((g_ascii_table[(guchar) (rec[pos])] & G_ASCII_DIGIT) != 0 )) {
598 | value *= 10;
599 | value += rec[pos] - '0';
600 | } else {
601 | return 0;
602 | }
603 | }
604 | pos++;
605 | }
606 |
607 | if (value != byte_offset) {
608 | return 0;
609 | }
610 |
611 | /* find the start of the hex dump */
612 | while(rec[pos] != HEX_DUMP_START'[') {
613 | if(rec[pos] == '\0') {
614 | return 0;
615 | }
616 | pos++;
617 | }
618 | pos++;
619 | return parse_hex_dump(&rec[pos], buf, HEX_DUMP_SPR' ', HEX_DUMP_END']');
620 | }
621 |
622 | /* Parse a hex dump */
623 | static unsigned
624 | parse_hex_dump(char* dump, Buffer *buf, char separator, char end) {
625 | int pos, count;
626 |
627 | /* Parse the hex dump */
628 | pos = 0;
629 | count = 0;
630 | uint8_t *pd = ws_buffer_end_ptr(buf);
631 | while(dump[pos] != end) {
632 | /* Check the hex value */
633 | if(!(g_ascii_isxdigit(dump[pos])((g_ascii_table[(guchar) (dump[pos])] & G_ASCII_XDIGIT) != 0) &&
634 | g_ascii_isxdigit(dump[pos + 1])((g_ascii_table[(guchar) (dump[pos + 1])] & G_ASCII_XDIGIT ) != 0))) {
635 | return 0;
636 | }
637 | /* Get the hex value */
638 | if(g_ascii_isdigit(dump[pos])((g_ascii_table[(guchar) (dump[pos])] & G_ASCII_DIGIT) != 0)) {
639 | pd[count] = (dump[pos] - '0') << 4;
640 | } else {
641 | pd[count] = (g_ascii_toupper(dump[pos]) - 'A' + 10) << 4;
642 | }
643 | pos++;
644 | if(g_ascii_isdigit(dump[pos])((g_ascii_table[(guchar) (dump[pos])] & G_ASCII_DIGIT) != 0)) {
645 | pd[count] += dump[pos] - '0';
646 | } else {
647 | pd[count] += g_ascii_toupper(dump[pos]) - 'A' + 10;
648 | }
649 | pos++;
650 | count++;
651 | /* Skip the separator characters */
652 | while(dump[pos] == separator) {
653 | pos++;
654 | }
655 | }
656 | ws_buffer_increase_length(buf, count);
657 | return count;
658 | }
659 |
660 | static const struct supported_block_type dbs_etherwatch_blocks_supported[] = {
661 | /*
662 | * We support packet blocks, with no comments or other options.
663 | */
664 | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED0, ((void*)0) }
665 | };
666 |
667 | static const struct file_type_subtype_info dbs_etherwatch_info = {
668 | "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL((void*)0),
669 | false0, BLOCKS_SUPPORTED(dbs_etherwatch_blocks_supported)(sizeof (dbs_etherwatch_blocks_supported) / sizeof (dbs_etherwatch_blocks_supported )[0]), dbs_etherwatch_blocks_supported,
670 | NULL((void*)0), NULL((void*)0), NULL((void*)0)
671 | };
672 |
673 | void register_dbs_etherwatch(void)
674 | {
675 | dbs_etherwatch_file_type_subtype = wtap_register_file_type_subtype(&dbs_etherwatch_info);
676 |
677 | /*
678 | * Register name for backwards compatibility with the
679 | * wtap_filetypes table in Lua.
680 | */
681 | wtap_register_backwards_compatibility_lua_name("DBS_ETHERWATCH",
682 | dbs_etherwatch_file_type_subtype);
683 | }
684 |
685 | /*
686 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
687 | *
688 | * Local variables:
689 | * c-basic-offset: 4
690 | * tab-width: 8
691 | * indent-tabs-mode: nil
692 | * End:
693 | *
694 | * vi: set shiftwidth=4 tabstop=8 expandtab:
695 | * :indentSize=4:tabSize=8:noTabs=true:
696 | */