wiretap: Convert ascend.y to Lemon.

Convert wiretap/ascend.y.in from Bison/YACC to Lemon and rename it to
wiretap/ascend_parser.lemon. Tighten up some of our scanning and
parsing. Make the indentation in it and related files consistent. Aside
from the recent IPv4 fragment offset changes, this produces identical
output to the 3.4 branch for the Ascend trace files I have here.

Remove the comment about supporting other commands. Another timeline
might have an Ascend that successfully pivoted to DSL or 15625B+1D
gigabit ISDN, but this one has neither.

This was our last/only Bison/YACC file, so remove Bison/YACC as a
development and packaging dependency and remove references to it from
the documentation.
This commit is contained in:
Gerald Combs 2020-11-18 17:39:19 -08:00 committed by AndersBroman
parent 1fa5687fad
commit f21cd2e23f
20 changed files with 1016 additions and 1173 deletions

View File

@ -1050,7 +1050,6 @@ find_package(GCRYPT "1.4.2" REQUIRED)
reset_find_package(CARES)
find_package(CARES "1.5.0" REQUIRED)
find_package(LEX REQUIRED)
find_package(YACC REQUIRED)
find_package(Perl REQUIRED)
if(CMAKE_VERSION VERSION_LESS "3.12")

View File

@ -46,18 +46,11 @@ operating system. This is the case for Windows XP, which is supported by
Wireshark 1.10 and earlier. In other cases the standard package for
Wireshark might simply be old. This is the case for Solaris and HP-UX.
NOTE: The Makefile depends on GNU "make"; it doesn't appear to
work with the "make" that comes with Solaris 7 nor the BSD "make".
Both Perl and Python 3 are needed, the former for building the man
pages.
Both Perl and Python are needed, the former for building the man pages.
If you decide to modify the yacc grammar or lex scanner, then
you need "flex" - it cannot be built with vanilla "lex" -
and either "bison" or the Berkeley "yacc". Your flex
version must be 2.5.1 or greater. Check this with `flex -V`.
You must therefore install Perl, Python, GNU "make", "flex", and either "bison"
or Berkeley "yacc" on systems that lack them.
You must therefore install Perl, Python, GNU "make", and "flex" (vanilla
"lex" won't work) on systems that lack them.
Full installation instructions can be found in the INSTALL file and in the
Developer's Guide at https://www.wireshark.org/docs/wsdg_html_chunked/

View File

@ -1,60 +0,0 @@
#
# - Find bison/yacc executable
#
INCLUDE(FindChocolatey)
FIND_PROGRAM(YACC_EXECUTABLE
NAMES
win_bison
bison
yacc
PATHS
${CHOCOLATEY_BIN_PATH}
/bin
/usr/bin
/usr/local/bin
/sbin
)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(YACC DEFAULT_MSG YACC_EXECUTABLE)
MARK_AS_ADVANCED(YACC_EXECUTABLE)
# Specifying "%pure-parser" will fail with a deprecation warning in
# Bison 3.4 and later. Specifying "%define api.pure" doesn't work with
# Berkeley YACC and older versions of Bison (such as 2.3, which ships
# with macOS). If we're using Bison and it's new, configure our .y.in
# files with "%define api.pure", otherwise use "%pure-parser".
set(YACC_PURE_PARSER_DIRECTIVE "%pure-parser")
if(YACC_EXECUTABLE)
execute_process(COMMAND ${YACC_EXECUTABLE} -V OUTPUT_VARIABLE _yacc_full_version)
string(REGEX MATCH "[1-9]+\.[0-9]+" _yacc_major_minor ${_yacc_full_version})
if (_yacc_full_version MATCHES "GNU Bison" AND _yacc_major_minor VERSION_GREATER "2.6")
set(YACC_PURE_PARSER_DIRECTIVE "%define api.pure")
endif()
endif()
MACRO(ADD_YACC_FILES _source _generated)
FOREACH (_current_FILE ${ARGN})
configure_file(${_current_FILE}.in ${_current_FILE})
GET_FILENAME_COMPONENT(_in ${CMAKE_CURRENT_BINARY_DIR}/${_current_FILE} ABSOLUTE)
GET_FILENAME_COMPONENT(_basename ${_current_FILE} NAME_WE)
SET(_out ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.c)
ADD_CUSTOM_COMMAND(
OUTPUT ${_out}
COMMAND ${YACC_EXECUTABLE}
-d
-p ${_basename}
-o${_out}
${_in}
DEPENDS ${_in}
)
LIST(APPEND ${_source} ${_in})
LIST(APPEND ${_generated} ${_out})
ENDFOREACH (_current_FILE)
ENDMACRO(ADD_YACC_FILES)

2
debian/control vendored
View File

@ -10,7 +10,7 @@ Build-Depends:
python3, python3-ply, libc-ares-dev, xsltproc, dh-python,
docbook-xsl (>= 1.64.1.0-0), docbook-xml, libxml2-utils, libpcre3-dev,
libcap2-dev [linux-any] | libcap-dev (>= 2.17) [linux-any], lsb-release,
bison, quilt, libparse-yapp-perl,
quilt, libparse-yapp-perl,
# libgnutls28-dev >= 3.2.14-1 is GPLv2+ compatible.
libgnutls28-dev (>= 3.2.14-1~),
libgcrypt-dev, libkrb5-dev, liblua5.2-dev, libsmi2-dev,

View File

@ -58,7 +58,7 @@ command `choco install` (or its shorthand, `cinst`), e.g.
[source,cmd]
----
> rem Flex and Bison are required.
> rem Flex is required.
> choco install -y winflexbison3
> rem Git, CMake, Perl, Python, etc are also required, but can be installed
> rem via their respective installation packages.
@ -254,7 +254,7 @@ Alternatively you can install Winflexbison using Chocolatey:
PS$> choco install -y winflexbison3
----
Chocolatey ensures win_flex.exe and win_bison.exe are on your path.
Chocolatey ensures win_flex.exe is on your path.
==== Install and Prepare Sources

View File

@ -1007,7 +1007,7 @@ your `~/.rpmmacros` file to enable parallel builds:
====
Building the RPM package requires quite a few packages and libraries
including GLib, `gcc`, `bison`, `flex`, Asciidoctor, and Qt development
including GLib, `gcc`, `flex`, Asciidoctor, and Qt development
tools such as `uic` and `moc`. The required Qt packages can usually be
obtained by installing the _qt5-devel_ package. For a complete list of
build requirements, look for the “BuildRequires” lines in

View File

@ -770,59 +770,6 @@ Built 18:08:02 Feb 4 2003
However, the version string may vary.
// Sed is no longer required.
//[[ChToolsSed]]
[[ChToolsBison]]
=== Bison
Bison is a parser generator used for some of Wiresharks file format support.
[[ChToolsUnixBison]]
[discrete]
==== Unix
Bison is available for most UNIX and UNIX-like platforms. See the next
section for native Windows options.
If GNU Bison isn't already installed or available as a package for your
platform you can get it at: https://www.gnu.org/software/bison/bison.html[].
After correct installation running the following
[source,sh]
----
$ bison --version
----
should result in something like:
----
bison (GNU Bison) 2.3
Written by Robert Corbett and Richard Stallman.
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
----
Your version string may vary.
[[ChToolsWindowsBison]]
[discrete]
==== Windows
A native Windows version of bison is available in the _winflexbison3_
https://chocolatey.org/[Chocolatey] package. Note that the executable is named
_win_bison_.
Native packages are available from other sources such as
http://gnuwin32.sourceforge.net/packages/bison.htm[GnuWin].
They aren't officially supported but _should_ work.
[[ChToolsFlex]]
=== Flex
@ -861,13 +808,13 @@ Your version string may vary.
[discrete]
==== Windows
A native Windows version of flex is available in the _winflexbison_
A native Windows version of flex is available in the _winflexbison3_
https://chocolatey.org/[Chocolatey] package. Note that the executable is named
_win_flex_.
[source,cmd]
----
PS:\> choco install winflexbison
PS:\> choco install winflexbison3
----
Native packages are available from other sources such as

View File

@ -59,7 +59,6 @@ BuildRequires: python3
BuildRequires: gcc
BuildRequires: perl
BuildRequires: flex
BuildRequires: bison
%if %{with guides}
# HTML guides
BuildRequires: asciidoctor
@ -538,6 +537,9 @@ update-mime-database %{_datadir}/mime &> /dev/null || :
%{_libdir}/pkgconfig/wireshark.pc
%changelog
* Thu Nov 26 2020 Gerald Combs
- Bison is no longer required
* Tue Sep 29 2020 Lin Sun
- Added opus codec as an option

View File

@ -47,7 +47,6 @@ BASIC_LIST="cmake \
glib-dev \
libgcrypt-dev \
flex \
bison \
perl \
tiff-dev \
c-ares-dev \

View File

@ -152,9 +152,6 @@ echo "libilbc is unavailable"
# Add OS-specific required/optional packages
# Those not listed don't require additions.
case `uname` in
OpenBSD)
add_package ADDITIONAL_LIST bison || echo "bison is unavailable"
;;
NetBSD)
add_package ADDITIONAL_LIST libgcrypt || echo "libgcrypt is unavailable"
;;

View File

@ -100,7 +100,7 @@ PATH_SPECIFIC_ALLOWED_LICENSES = {
'cmake/TestFileOffsetBits.c': [
'UNKNOWN',
],
# Generated header files by lex/yacc/whatever
# Generated header files by lex/lemon/whatever
'epan/dtd_grammar.h': [
'UNKNOWN',
],

View File

@ -58,7 +58,6 @@ BASIC_LIST="libglib2.0-dev \
qt5-default \
libc-ares-dev \
libpcap-dev \
bison \
flex \
make \
python3 \

View File

@ -43,7 +43,6 @@ BASIC_LIST="cmake \
gcc \
gcc-c++ \
flex \
bison \
python3 \
perl \
desktop-file-utils \

View File

@ -96,11 +96,8 @@ add_lex_files(LEX_FILES WIRETAP_FILES
k12text.l
)
add_yacc_files(YACC_FILES WIRETAP_FILES
ascend.y
)
add_lemon_files(LEMON_FILES WIRETAP_FILES
ascend_parser.lemon
busmaster_parser.lemon
candump_parser.lemon
)
@ -162,7 +159,6 @@ CHECKAPI(
${WIRETAP_NONGENERATED_FILES}
# LEX files commented out due to use of malloc, free etc.
# ${LEX_FILES}
${YACC_FILES}
${LEMON_FILES}
)

View File

@ -13,34 +13,44 @@
#define __ASCEND_INT_H__
#include <glib.h>
#include <stdbool.h>
#include "ws_symbol_export.h"
typedef struct {
time_t inittime;
gboolean adjusted;
gint64 next_packet_seek_start;
time_t inittime;
gboolean adjusted;
gint64 next_packet_seek_start;
} ascend_t;
typedef struct {
FILE_T fh;
const gchar *ascend_parse_error;
int err;
gchar *err_info;
struct ascend_phdr *pseudo_header;
guint8 *pkt_data;
int length;
guint32 u32_val;
guint16 u16_val;
guint8 u8_val;
char str_val[ASCEND_MAX_STR_LEN];
} ascend_token_t;
gboolean saw_timestamp;
guint32 timestamp;
typedef struct {
FILE_T fh;
const gchar *ascend_parse_error;
int err;
gchar *err_info;
struct ascend_phdr *pseudo_header;
guint8 *pkt_data;
gint64 first_hexbyte;
guint32 wirelen;
guint32 caplen;
time_t secs;
guint32 usecs;
gboolean saw_timestamp;
guint32 timestamp;
gint64 first_hexbyte;
guint32 wirelen;
guint32 caplen;
time_t secs;
guint32 usecs;
ascend_token_t token;
} ascend_state_t;
extern int
run_ascend_parser(FILE_T fh, wtap_rec *rec, guint8 *pd,
ascend_state_t *parser_state, int *err, gchar **err_info);
extern bool
run_ascend_parser(guint8 *pd, ascend_state_t *parser_state, int *err, gchar **err_info);
#endif /* ! __ASCEND_INT_H__ */

View File

@ -1,519 +0,0 @@
/*
* We want a reentrant parser.
* Berkeley YACC and older versions of Bison use "%pure-parser" and newer
* versions of Bison use "%define api.pure".
* As https://code.wireshark.org/review/#/c/33771/
* says, "This doesn't work with Berkeley YACC, and I'd *really* prefer not to require Bison."
*/
${YACC_PURE_PARSER_DIRECTIVE}
/*
* We also want a reentrant scanner, so we have to pass the
* handle for the reentrant scanner to the parser, and the
* parser has to pass it to the lexical analyzer.
*
* We use void * rather than yyscan_t because, at least with some
* versions of Flex and Bison, if you use yyscan_t in %parse-param and
* %lex-param, you have to include the ascend_lex_scanner.h before
* ascend.h to get yyscan_t declared, and you have to include ascend.h
* before ascend_lex_scanner.h to get YYSTYPE declared. Using void *
* breaks the cycle; the Flex documentation says yyscan_t is just a void *.
*/
%parse-param {void *yyscanner}
%lex-param {void *yyscanner}
/*
* And we need to pass the parser/scanner state to the parser.
*/
%parse-param {ascend_state_t *parser_state}
%{
/* ascend.y
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/*
Example 'pridisp' output data - one paragraph/frame:
PRI-XMIT-27: (task "l1Task" at 0x10216fe0, time: 560194.01) 4 octets @ 0x1027c5b0
[0000]: 00 01 01 a9 ....
PRI-RCV-27: (task "idle task" at 0x10123570, time: 560194.01) 4 octets @ 0x1027fb00
[0000]: 00 01 01 dd
Example 'pridisp' output data - two paragraphs/frame for XMIT case only:
PRI-XMIT-19/1: (task "l1Task" at 0x10216840, time: 274759.98) 4 octets @ 0x1027f230
[0000]: 00 01 30 d8 ..0.
PRI-XMIT-19/2 (task "l1Task" at 0x10216840, time: 274759.98) 11 octets @ 0x1027f234
[0000]: 08 02 8c bf 02 18 04 e9 82 83 8f ........ ...
Example 'ether-disp' output data:
ETHER3ND RECV: (task "_sarTask" at 0x802c6eb0, time: 259848.03) 775 octets @ 0xa8fb2020
[0000]: 00 d0 52 04 e7 1e 08 00 20 ae 51 b5 08 00 45 00 ..R..... .Q...E.
[0010]: 02 f9 05 e6 40 00 3f 11 6e 39 87 fe c4 95 3c 3c ....@.?. n9....<<
[0020]: 3c 05 13 c4 13 c4 02 e5 ef ed 49 4e 56 49 54 45 <....... ..INVITE
[0030]: 20 73 69 70 3a 35 32 30 37 33 40 36 30 2e 36 30 sip:520 73@60.60
[0040]: 2e 36 30 2e 35 20 53 49 50 2f 32 2e 30 0d 0a 56 .60.5 SI P/2.0..V
[0050]: 69 61 3a 20 53 49 50 2f 32 2e 30 2f 55 44 50 20 ia: SIP/ 2.0/UDP
[0060]: 31 33 35 2e 135.
Example 'wandsess' output data:
RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94
[0000]: FF 03 00 3D C0 06 CA 22 2F 45 00 00 28 6A 3B 40
[0010]: 00 3F 03 D7 37 CE 41 62 12 CF 00 FB 08 20 27 00
[0020]: 50 E4 08 DD D7 7C 4C 71 92 50 10 7D 78 67 C8 00
[0030]: 00
XMIT-iguana:241:(task: B04E12C0, time: 1975432.85) 53 octets @ 8009EB16
[0000]: FF 03 00 3D C0 09 1E 31 21 45 00 00 2C 2D BD 40
[0010]: 00 7A 06 D8 B1 CF 00 FB 08 CE 41 62 12 00 50 20
[0020]: 29 7C 4C 71 9C 9A 6A 93 A4 60 12 22 38 3F 10 00
[0030]: 00 02 04 05 B4
Example 'wdd' output data:
Date: 01/12/1990. Time: 12:22:33
Cause an attempt to place call to 14082750382
WD_DIALOUT_DISP: chunk 2515EE type IP.
(task: 251790, time: 994953.28) 44 octets @ 2782B8
[0000]: 00 C0 7B 71 45 6C 00 60 08 16 AA 51 08 00 45 00
[0010]: 00 2C 66 1C 40 00 80 06 53 F6 AC 14 00 18 CC 47
[0020]: C8 45 0A 31 00 50 3B D9 5B 75 00 00
The following output comes from a MAX with Software 7.2.3:
RECV-187:(task: B050B480, time: 18042248.03) 100 octets @ 800012C0
[0000]: FF 03 00 21 45 00 00 60 E3 49 00 00 7F 11 FD 7B
[0010]: C0 A8 F7 05 8A C8 18 51 00 89 00 89 00 4C C7 C1
[0020]: CC 8E 40 00 00 01 00 00 00 00 00 01 20 45 4A 45
[0030]: 42 45 43 45 48 43 4E 46 43 46 41 43 41 43 41 43
[0040]: 41 43 41 43 41 43 41 43 41 43 41 42 4E 00 00 20
[0050]: 00 01 C0 0C 00 20 00 01 00 04 93 E0 00 06 60 00
[0060]: C0 A8 F7 05
XMIT-187:(task: B0292CA0, time: 18042248.04) 60 octets @ 800AD576
[0000]: FF 03 00 21 45 00 00 38 D7 EE 00 00 0F 01 11 2B
[0010]: 0A FF FF FE C0 A8 F7 05 03 0D 33 D3 00 00 00 00
[0020]: 45 00 00 60 E3 49 00 00 7E 11 FE 7B C0 A8 F7 05
[0030]: 8A C8 18 51 00 89 00 89 00 4C C7 C1
RECV-187:(task: B0292CA0, time: 18042251.92) 16 octets @ 800018E8
[0000]: FF 03 C0 21 09 01 00 0C DE 61 96 4B 00 30 94 92
In TAOS 8.0, Lucent slightly changed the format as follows:
Example 'wandisp' output data (TAOS 8.0.3): (same format is used
for 'wanopen' and 'wannext' command)
RECV-14: (task "idle task" at 0xb05e6e00, time: 1279.01) 29 octets @ 0x8000e0fc
[0000]: ff 03 c0 21 01 01 00 19 01 04 05 f4 11 04 05 f4 ...!.... ........
[0010]: 13 09 03 00 c0 7b 9a 9f 2d 17 04 10 00 .....{.. -....
XMIT-14: (task "idle task" at 0xb05e6e00, time: 1279.02) 38 octets @ 0x8007fd56
[0000]: ff 03 c0 21 01 01 00 22 00 04 00 00 01 04 05 f4 ...!..." ........
[0010]: 03 05 c2 23 05 11 04 05 f4 13 09 03 00 c0 7b 80 ...#.... ......{.
[0020]: 7c ef 17 04 0e 00 |.....
XMIT-14: (task "idle task" at 0xb05e6e00, time: 1279.02) 29 octets @ 0x8007fa36
[0000]: ff 03 c0 21 02 01 00 19 01 04 05 f4 11 04 05 f4 ...!.... ........
[0010]: 13 09 03 00 c0 7b 9a 9f 2d 17 04 10 00 .....{.. -....
Example 'wandsess' output data (TAOS 8.0.3):
RECV-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.50) 20 octets @ 0x8000d198
[0000]: ff 03 00 3d c0 00 00 04 80 fd 02 01 00 0a 11 06 ...=.... ........
[0010]: 00 01 01 03 ....
XMIT-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.51) 26 octets @ 0x800806b6
[0000]: ff 03 00 3d c0 00 00 00 80 21 01 01 00 10 02 06 ...=.... .!......
[0010]: 00 2d 0f 01 03 06 89 64 03 08 .-.....d ..
XMIT-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.51) 20 octets @ 0x8007f716
[0000]: ff 03 00 3d c0 00 00 01 80 fd 01 01 00 0a 11 06 ...=.... ........
[0010]: 00 01 01 03 ....
The changes since TAOS 7.X are:
1) White space is added before "(task".
2) Task has a name, indicated by a subsequent string surrounded by a
double-quote.
3) Address expressed in hex number has a preceding "0x".
4) Hex numbers are in lower case.
5) There is a character display corresponding to hex data in each line.
*/
#include "config.h"
#if defined(_MSC_VER) && !defined(__STDC_VERSION__)
/*
* MSVC doesn't, by default, define __STDC_VERSION__, which
* means that the code generated by newer versions of winflexbison3's
* Bison end up defining YYPTRDIFF_T as long, which is wrong on
* 64-bit Windows, as that's an LLP64 platform, not an LP64 platform,
* and causes warnings to be generated. Those warnings turn into
* errors.
*
* With MSVC, if __STDC_VERSION__ isn't defined, Forcibly include
* <stdint.h> here to work around that.
*/
#include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "wtap-int.h"
#include <wsutil/buffer.h>
#include "ascendtext.h"
#include "ascend-int.h"
DIAG_OFF_BYACC
#include "ascend.h"
#include "ascend_scanner_lex.h"
DIAG_ON_BYACC
#include "file_wrappers.h"
#define NO_USER "<none>"
extern void yyerror (void *yyscanner, ascend_state_t *state, FILE_T fh _U_, const char *s);
DIAG_OFF_BYACC
%}
%union {
gchar *s;
guint32 d;
guint8 b;
}
%token <s> STRING KEYWORD WDD_DATE WDD_CHUNK COUNTER SLASH_SUFFIX
%token <d> WDS_PREFIX ISDN_PREFIX ETHER_PREFIX DECNUM HEXNUM
%token <b> HEXBYTE
%type <s> string dataln datagroup
%type <d> wds_prefix isdn_prefix ether_prefix decnum hexnum
%type <b> byte bytegroup
%parse-param { FILE_T fh }
%%
data_packet:
| ether_hdr datagroup
| deferred_isdn_hdr datagroup deferred_isdn_hdr datagroup
| isdn_hdr datagroup
| wds_hdr datagroup
| wds8_hdr datagroup
| wdp7_hdr datagroup
| wdp8_hdr datagroup
| wdd_date wdd_hdr datagroup
| wdd_hdr datagroup
;
isdn_prefix: ISDN_PREFIX;
ether_prefix: ETHER_PREFIX;
wds_prefix: WDS_PREFIX;
string: STRING;
decnum: DECNUM;
hexnum: HEXNUM;
/*
pridisp special case - I-frame header printed separately from contents,
one frame across two messages.
PRI-XMIT-0/1: (task "l1Task" at 0x80152b20, time: 283529.65) 4 octets @
0x80128220
[0000]: 00 01 ae b2 ....
PRI-XMIT-0/2 (task "l1Task" at 0x80152b20, time: 283529.65) 10 octets @
0x80128224
[0000]: 08 02 d7 e3 02 18 03 a9 83 8a ........
*/
deferred_isdn_hdr: isdn_prefix decnum SLASH_SUFFIX KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen += $11;
parser_state->secs = $9;
parser_state->usecs = $10;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->sess = $2;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $7;
}
/* because we have two data groups */
parser_state->first_hexbyte = 0;
}
;
/*
PRI-XMIT-19: (task "l1Task" at 0x10216840, time: 274758.67) 4 octets @ 0x1027c1c0
... or ...
PRI-RCV-27: (task "idle task" at 0x10123570, time: 560194.01) 4 octets @ 0x1027fb00
*/
isdn_hdr: isdn_prefix decnum KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen = $10;
parser_state->secs = $8;
parser_state->usecs = $9;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->sess = $2;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $6;
}
parser_state->first_hexbyte = 0;
}
;
/*
ETHER3ND XMIT: (task "_sarTask" at 0x802c6eb0, time: 259848.11) 414 octets @ 0xa
885f80e
*/
ether_hdr: ether_prefix string KEYWORD string KEYWORD hexnum KEYWORD decnum decnum
decnum KEYWORD HEXNUM {
parser_state->wirelen = $10;
parser_state->secs = $8;
parser_state->usecs = $9;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $6;
}
}
;
/* RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94 */
/* 1 2 3 4 5 6 7 8 9 10 11 */
wds_hdr: wds_prefix string decnum KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen = $9;
parser_state->secs = $7;
parser_state->usecs = $8;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->sess = $3;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $5;
}
}
;
/* RECV-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.50) 20 octets @ 0x8000d198 */
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 */
wds8_hdr: wds_prefix string decnum KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen = $11;
parser_state->secs = $9;
parser_state->usecs = $10;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->sess = $3;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $7;
}
}
;
/* RECV-187:(task: B050B480, time: 18042248.03) 100 octets @ 800012C0 */
/* 1 2 3 4 5 6 7 8 9 10 */
wdp7_hdr: wds_prefix decnum KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen = $8;
parser_state->secs = $6;
parser_state->usecs = $7;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->sess = $2;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $4;
}
}
;
/* XMIT-44: (task "freedm_task" at 0xe051fd10, time: 6258.66) 29 octets @ 0x606d1f00 */
/* 1 2 3 4 5 6 7 8 9 10 11 12 */
wdp8_hdr: wds_prefix decnum KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen = $10;
parser_state->secs = $8;
parser_state->usecs = $9;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = $1;
parser_state->pseudo_header->sess = $2;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = $6;
}
}
;
/*
Date: 01/12/1990. Time: 12:22:33
Cause an attempt to place call to 14082750382
*/
/* 1 2 3 4 5 6 7 8 9 10*/
wdd_date: WDD_DATE decnum decnum decnum KEYWORD decnum decnum decnum KEYWORD string {
/*
* Supply the date/time value to the code above us; it will use the
* first date/time value supplied as the capture start date/time.
*/
struct tm wddt;
wddt.tm_sec = $8;
wddt.tm_min = $7;
wddt.tm_hour = $6;
wddt.tm_mday = $3;
wddt.tm_mon = $2 - 1;
wddt.tm_year = ($4 > 1970) ? $4 - 1900 : 70;
wddt.tm_isdst = -1;
parser_state->timestamp = (guint32) mktime(&wddt);
parser_state->saw_timestamp = TRUE;
}
;
/*
WD_DIALOUT_DISP: chunk 2515EE type IP.
(task: 251790, time: 994953.28) 44 octets @ 2782B8
*/
/* 1 2 3 4 5 6 7 8 9 10 11*/
wdd_hdr: WDD_CHUNK hexnum KEYWORD KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
parser_state->wirelen = $9;
parser_state->secs = $7;
parser_state->usecs = $8;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->call_num is set in ascend_scanner.l */
parser_state->pseudo_header->type = ASCEND_PFX_WDD;
parser_state->pseudo_header->user[0] = '\0';
parser_state->pseudo_header->sess = 0;
parser_state->pseudo_header->chunk = $2;
parser_state->pseudo_header->task = $5;
}
}
;
byte: HEXBYTE {
/* remember the position of the data group in the trace, to tip off
ascend_find_next_packet() as to where to look for the next header. */
if (parser_state->first_hexbyte == 0)
parser_state->first_hexbyte = file_tell(fh);
/* XXX - if this test fails, it means that we parsed more bytes than
the header claimed there were. */
if (parser_state->caplen < parser_state->wirelen) {
parser_state->pkt_data[parser_state->caplen] = $1;
parser_state->caplen++;
}
/* arbitrary safety maximum... */
if (parser_state->caplen >= ASCEND_MAX_PKT_LEN)
YYACCEPT;
}
;
/* XXX There must be a better way to do this... */
bytegroup: byte
| byte byte
| byte byte byte
| byte byte byte byte
| byte byte byte byte byte
| byte byte byte byte byte byte
| byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte
| byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte
;
dataln: COUNTER bytegroup;
datagroup: dataln
| dataln dataln
| dataln dataln dataln
| dataln dataln dataln dataln
| dataln dataln dataln dataln dataln
| dataln dataln dataln dataln dataln dataln
| dataln dataln dataln dataln dataln dataln dataln
| dataln dataln dataln dataln dataln dataln dataln dataln
;
%%
DIAG_ON_BYACC
/* Run the parser. */
int
run_ascend_parser(FILE_T fh, wtap_rec *rec, guint8 *pd,
ascend_state_t *parser_state, int *err, gchar **err_info)
{
yyscan_t scanner = NULL;
int status;
if (ascendlex_init(&scanner) != 0) {
/* errno is set if this fails */
*err = errno;
*err_info = NULL;
return 1;
}
/* Associate the parser state with the lexical analyzer state */
ascendset_extra(parser_state, scanner);
parser_state->fh = fh;
parser_state->ascend_parse_error = NULL;
parser_state->err = 0;
parser_state->err_info = NULL;
parser_state->pseudo_header = &rec->rec_header.packet_header.pseudo_header.ascend;
parser_state->pkt_data = pd;
/*
* We haven't seen a time stamp yet.
*/
parser_state->saw_timestamp = FALSE;
parser_state->timestamp = 0;
parser_state->first_hexbyte = 0;
parser_state->caplen = 0;
parser_state->wirelen = 0;
parser_state->secs = 0;
parser_state->usecs = 0;
/*
* Not all packets in a "wdd" dump necessarily have a "Cause an
* attempt to place call to" header (I presume this can happen if
* there was a call in progress when the packet was sent or
* received), so we won't necessarily have the phone number for
* the packet.
*
* XXX - we could assume, in the sequential pass, that it's the
* phone number from the last call, and remember that for use
* when doing random access.
*/
parser_state->pseudo_header->call_num[0] = '\0';
status = yyparse(scanner, parser_state, fh);
ascendlex_destroy(scanner);
*err = parser_state->err;
*err_info = parser_state->err_info;
return status;
}
void
yyerror (void *yyscanner, ascend_state_t *state _U_, FILE_T fh _U_, const char *s)
{
ascendget_extra(yyscanner)->ascend_parse_error = s;
}
DIAG_OFF_BYACC

505
wiretap/ascend_parser.lemon Normal file
View File

@ -0,0 +1,505 @@
%include {
/* ascend_parser.lemon
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/*
Example 'pridisp' output data - one paragraph/frame:
PRI-XMIT-27: (task "l1Task" at 0x10216fe0, time: 560194.01) 4 octets @ 0x1027c5b0
[0000]: 00 01 01 a9 ....
PRI-RCV-27: (task "idle task" at 0x10123570, time: 560194.01) 4 octets @ 0x1027fb00
[0000]: 00 01 01 dd
Example 'pridisp' output data - two paragraphs/frame for XMIT case only:
PRI-XMIT-19/1: (task "l1Task" at 0x10216840, time: 274759.98) 4 octets @ 0x1027f230
[0000]: 00 01 30 d8 ..0.
PRI-XMIT-19/2 (task "l1Task" at 0x10216840, time: 274759.98) 11 octets @ 0x1027f234
[0000]: 08 02 8c bf 02 18 04 e9 82 83 8f ........ ...
Example 'ether-disp' output data:
ETHER3ND RECV: (task "_sarTask" at 0x802c6eb0, time: 259848.03) 775 octets @ 0xa8fb2020
[0000]: 00 d0 52 04 e7 1e 08 00 20 ae 51 b5 08 00 45 00 ..R..... .Q...E.
[0010]: 02 f9 05 e6 40 00 3f 11 6e 39 87 fe c4 95 3c 3c ....@.?. n9....<<
[0020]: 3c 05 13 c4 13 c4 02 e5 ef ed 49 4e 56 49 54 45 <....... ..INVITE
[0030]: 20 73 69 70 3a 35 32 30 37 33 40 36 30 2e 36 30 sip:520 73@60.60
[0040]: 2e 36 30 2e 35 20 53 49 50 2f 32 2e 30 0d 0a 56 .60.5 SI P/2.0..V
[0050]: 69 61 3a 20 53 49 50 2f 32 2e 30 2f 55 44 50 20 ia: SIP/ 2.0/UDP
[0060]: 31 33 35 2e 135.
Example 'wandsess' output data:
RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94
[0000]: FF 03 00 3D C0 06 CA 22 2F 45 00 00 28 6A 3B 40
[0010]: 00 3F 03 D7 37 CE 41 62 12 CF 00 FB 08 20 27 00
[0020]: 50 E4 08 DD D7 7C 4C 71 92 50 10 7D 78 67 C8 00
[0030]: 00
XMIT-iguana:241:(task: B04E12C0, time: 1975432.85) 53 octets @ 8009EB16
[0000]: FF 03 00 3D C0 09 1E 31 21 45 00 00 2C 2D BD 40
[0010]: 00 7A 06 D8 B1 CF 00 FB 08 CE 41 62 12 00 50 20
[0020]: 29 7C 4C 71 9C 9A 6A 93 A4 60 12 22 38 3F 10 00
[0030]: 00 02 04 05 B4
Example 'wdd' output data:
Date: 01/12/1990. Time: 12:22:33
Cause an attempt to place call to 14082750382
WD_DIALOUT_DISP: chunk 2515EE type IP.
(task: 251790, time: 994953.28) 44 octets @ 2782B8
[0000]: 00 C0 7B 71 45 6C 00 60 08 16 AA 51 08 00 45 00
[0010]: 00 2C 66 1C 40 00 80 06 53 F6 AC 14 00 18 CC 47
[0020]: C8 45 0A 31 00 50 3B D9 5B 75 00 00
The following output comes from a MAX with Software 7.2.3:
RECV-187:(task: B050B480, time: 18042248.03) 100 octets @ 800012C0
[0000]: FF 03 00 21 45 00 00 60 E3 49 00 00 7F 11 FD 7B
[0010]: C0 A8 F7 05 8A C8 18 51 00 89 00 89 00 4C C7 C1
[0020]: CC 8E 40 00 00 01 00 00 00 00 00 01 20 45 4A 45
[0030]: 42 45 43 45 48 43 4E 46 43 46 41 43 41 43 41 43
[0040]: 41 43 41 43 41 43 41 43 41 43 41 42 4E 00 00 20
[0050]: 00 01 C0 0C 00 20 00 01 00 04 93 E0 00 06 60 00
[0060]: C0 A8 F7 05
XMIT-187:(task: B0292CA0, time: 18042248.04) 60 octets @ 800AD576
[0000]: FF 03 00 21 45 00 00 38 D7 EE 00 00 0F 01 11 2B
[0010]: 0A FF FF FE C0 A8 F7 05 03 0D 33 D3 00 00 00 00
[0020]: 45 00 00 60 E3 49 00 00 7E 11 FE 7B C0 A8 F7 05
[0030]: 8A C8 18 51 00 89 00 89 00 4C C7 C1
RECV-187:(task: B0292CA0, time: 18042251.92) 16 octets @ 800018E8
[0000]: FF 03 C0 21 09 01 00 0C DE 61 96 4B 00 30 94 92
In TAOS 8.0, Lucent slightly changed the format as follows:
Example 'wandisp' output data (TAOS 8.0.3): (same format is used
for 'wanopen' and 'wannext' command)
RECV-14: (task "idle task" at 0xb05e6e00, time: 1279.01) 29 octets @ 0x8000e0fc
[0000]: ff 03 c0 21 01 01 00 19 01 04 05 f4 11 04 05 f4 ...!.... ........
[0010]: 13 09 03 00 c0 7b 9a 9f 2d 17 04 10 00 .....{.. -....
XMIT-14: (task "idle task" at 0xb05e6e00, time: 1279.02) 38 octets @ 0x8007fd56
[0000]: ff 03 c0 21 01 01 00 22 00 04 00 00 01 04 05 f4 ...!..." ........
[0010]: 03 05 c2 23 05 11 04 05 f4 13 09 03 00 c0 7b 80 ...#.... ......{.
[0020]: 7c ef 17 04 0e 00 |.....
XMIT-14: (task "idle task" at 0xb05e6e00, time: 1279.02) 29 octets @ 0x8007fa36
[0000]: ff 03 c0 21 02 01 00 19 01 04 05 f4 11 04 05 f4 ...!.... ........
[0010]: 13 09 03 00 c0 7b 9a 9f 2d 17 04 10 00 .....{.. -....
Example 'wandsess' output data (TAOS 8.0.3):
RECV-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.50) 20 octets @ 0x8000d198
[0000]: ff 03 00 3d c0 00 00 04 80 fd 02 01 00 0a 11 06 ...=.... ........
[0010]: 00 01 01 03 ....
XMIT-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.51) 26 octets @ 0x800806b6
[0000]: ff 03 00 3d c0 00 00 00 80 21 01 01 00 10 02 06 ...=.... .!......
[0010]: 00 2d 0f 01 03 06 89 64 03 08 .-.....d ..
XMIT-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.51) 20 octets @ 0x8007f716
[0000]: ff 03 00 3d c0 00 00 01 80 fd 01 01 00 0a 11 06 ...=.... ........
[0010]: 00 01 01 03 ....
The changes since TAOS 7.X are:
1) White space is added before "(task".
2) Task has a name, indicated by a subsequent string surrounded by a
double-quote.
3) Address expressed in hex number has a preceding "0x".
4) Hex numbers are in lower case.
5) There is a character display corresponding to hex data in each line.
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "wtap-int.h"
#include "ascendtext.h"
#include "ascend-int.h"
#include "ascend_parser.h"
#include "ascend_scanner_lex.h"
#include "file_wrappers.h"
#define NO_USER "<none>"
#if 0
#define ASCEND_PARSER_DEBUG 1
#undef NDEBUG
#define ascend_debug(...) g_warning(__VA_ARGS__)
#else
#define ascend_debug(...)
#endif
} // %include
%name AscendParser
%extra_argument { ascend_state_t *parser_state }
%token_type { ascend_token_t }
%token_destructor {
(void) parser_state;
(void) yypminor;
}
%type STRING { ascend_token_t* }
%type KEYWORD { ascend_token_t* }
%type WDD_DATE { ascend_token_t* }
%type WDD_DECNUM { ascend_token_t* }
%type WDD_TIME { ascend_token_t* }
%type WDD_CAUSE { ascend_token_t* }
%type WDD_CALLNUM { ascend_token_t* }
%type WDD_CHUNK { ascend_token_t* }
%type COUNTER { ascend_token_t* }
%type SLASH_SUFFIX { ascend_token_t* }
%type WDS_PREFIX { ascend_token_t* }
%type ISDN_PREFIX { ascend_token_t* }
%type ETHER_PREFIX { ascend_token_t* }
%type DECNUM { ascend_token_t* }
%type YEAR { ascend_token_t* }
%type MONTH { ascend_token_t* }
%type MDAY { ascend_token_t* }
%type HEXNUM { ascend_token_t* }
%type HEXBYTE { ascend_token_t* }
data_packet ::= ether_hdr datagroup .
data_packet ::= deferred_isdn_hdr datagroup deferred_isdn_hdr datagroup .
data_packet ::= isdn_hdr datagroup .
data_packet ::= wds_hdr datagroup .
data_packet ::= wds8_hdr datagroup .
data_packet ::= wdp7_hdr datagroup .
data_packet ::= wdp8_hdr datagroup .
data_packet ::= wdd_date wdd_hdr datagroup .
data_packet ::= wdd_hdr datagroup .
%type isdn_prefix { guint16 }
isdn_prefix(U16) ::= ISDN_PREFIX(A_TOK) . { U16 = A_TOK.u16_val; }
%type ether_prefix { guint16 }
ether_prefix(U16) ::= ETHER_PREFIX(A_TOK) . { U16 = A_TOK.u16_val; }
%type wds_prefix { guint16 }
wds_prefix(U16) ::= WDS_PREFIX(A_TOK) . { U16 = A_TOK.u16_val; }
string ::= STRING .
%type decnum { guint32 }
decnum(U32) ::= DECNUM(A_TOK) . { U32 = A_TOK.u32_val; }
%type hexnum { guint32 }
hexnum(U32) ::= HEXNUM(A_TOK) . { U32 = A_TOK.u32_val; }
%type wdd_decnum { guint32 }
wdd_decnum(U32) ::= WDD_DECNUM(A_TOK) . { U32 = A_TOK.u32_val; }
/*
pridisp special case - I-frame header printed separately from contents,
one frame across two messages.
PRI-XMIT-0/1: (task "l1Task" at 0x80152b20, time: 283529.65) 4 octets @
0x80128220
[0000]: 00 01 ae b2 ....
PRI-XMIT-0/2 (task "l1Task" at 0x80152b20, time: 283529.65) 10 octets @
0x80128224
[0000]: 08 02 d7 e3 02 18 03 a9 83 8a ........
*/
deferred_isdn_hdr ::= isdn_prefix(TYPE) decnum(SESS) SLASH_SUFFIX KEYWORD string KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->sess = SESS;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
/* because we have two data groups */
parser_state->first_hexbyte = 0;
}
/*
PRI-XMIT-19: (task "l1Task" at 0x10216840, time: 274758.67) 4 octets @ 0x1027c1c0
... or ...
PRI-RCV-27: (task "idle task" at 0x10123570, time: 560194.01) 4 octets @ 0x1027fb00
*/
isdn_hdr ::= isdn_prefix(TYPE) decnum(SESS) KEYWORD string KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->sess = SESS;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
parser_state->first_hexbyte = 0;
}
/*
ETHER3ND XMIT: (task "_sarTask" at 0x802c6eb0, time: 259848.11) 414 octets @ 0xa
885f80e
*/
ether_hdr ::= ether_prefix(TYPE) string KEYWORD string KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
}
/* RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94 */
/* 1 2 3 4 5 6 7 8 9 10 11 */
wds_hdr ::= wds_prefix(TYPE) string decnum(SESS) KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->sess = SESS;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
}
/* RECV-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.50) 20 octets @ 0x8000d198 */
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 */
wds8_hdr ::= wds_prefix(TYPE) string decnum(SESS) KEYWORD string KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->sess = SESS;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
}
/* RECV-187:(task: B050B480, time: 18042248.03) 100 octets @ 800012C0 */
/* 1 2 3 4 5 6 7 8 9 10 */
wdp7_hdr ::= wds_prefix(TYPE) decnum(SESS) KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->sess = SESS;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
}
/* XMIT-44: (task "freedm_task" at 0xe051fd10, time: 6258.66) 29 octets @ 0x606d1f00 */
/* 1 2 3 4 5 6 7 8 9 10 11 12 */
wdp8_hdr ::= wds_prefix(TYPE) decnum(SESS) KEYWORD string KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen += WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
/* parser_state->pseudo_header->user is set in ascend_scanner.l */
parser_state->pseudo_header->type = TYPE;
parser_state->pseudo_header->sess = SESS;
parser_state->pseudo_header->call_num[0] = '\0';
parser_state->pseudo_header->chunk = 0;
parser_state->pseudo_header->task = TASK;
}
}
/*
Date: 01/12/1990. Time: 12:22:33
Cause an attempt to place call to 14082750382
*/
/* 1 2 3 4 5 6 7 8 9 10*/
wdd_date ::= WDD_DATE wdd_decnum(MONTH) wdd_decnum(MDAY) wdd_decnum(YEAR) WDD_TIME wdd_decnum(HOUR) wdd_decnum(MINUTE) wdd_decnum(SECOND) WDD_CAUSE WDD_CALLNUM(CN_T) . {
/*
* Supply the date/time value to the code above us; it will use the
* first date/time value supplied as the capture start date/time.
*/
struct tm wddt;
wddt.tm_sec = SECOND;
wddt.tm_min = MINUTE;
wddt.tm_hour = HOUR;
wddt.tm_mday = MDAY;
wddt.tm_mon = MONTH - 1;
wddt.tm_year = (YEAR > 1970) ? YEAR - 1900 : 70;
wddt.tm_isdst = -1;
parser_state->timestamp = (guint32) mktime(&wddt);
parser_state->saw_timestamp = TRUE;
g_strlcpy(parser_state->pseudo_header->call_num, CN_T.str_val, ASCEND_MAX_STR_LEN);
}
/*
WD_DIALOUT_DISP: chunk 2515EE type IP.
(task: 251790, time: 994953.28) 44 octets @ 2782B8
*/
/* 1 2 3 4 5 6 7 8 9 10 11*/
wdd_hdr ::= WDD_CHUNK hexnum(CHUNK) KEYWORD KEYWORD hexnum(TASK) KEYWORD decnum(SECS) decnum(USECS) decnum(WIRELEN) KEYWORD HEXNUM . {
parser_state->wirelen = WIRELEN;
parser_state->secs = SECS;
parser_state->usecs = USECS;
if (parser_state->pseudo_header != NULL) {
parser_state->pseudo_header->type = ASCEND_PFX_WDD;
parser_state->pseudo_header->user[0] = '\0';
parser_state->pseudo_header->sess = 0;
parser_state->pseudo_header->chunk = CHUNK;
parser_state->pseudo_header->task = TASK;
}
}
byte ::= HEXBYTE(A_TOK) . {
/* remember the position of the data group in the trace, to tip off
ascend_find_next_packet() as to where to look for the next header. */
if (parser_state->first_hexbyte == 0) {
parser_state->first_hexbyte = file_tell(parser_state->fh) - A_TOK.length;
}
/* XXX - if this test fails, it means that we parsed more bytes than
the header claimed there were. */
if (parser_state->caplen < parser_state->wirelen) {
parser_state->pkt_data[parser_state->caplen] = A_TOK.u8_val;
parser_state->caplen++;
}
}
/* XXX There must be a better way to do this... */
bytegroup ::= byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte byte .
bytegroup ::= byte byte byte byte byte .
bytegroup ::= byte byte byte byte .
bytegroup ::= byte byte byte .
bytegroup ::= byte byte .
bytegroup ::= byte .
dataln ::= COUNTER bytegroup .
datagroup ::= dataln dataln dataln dataln dataln dataln dataln dataln .
datagroup ::= dataln dataln dataln dataln dataln dataln dataln .
datagroup ::= dataln dataln dataln dataln dataln dataln .
datagroup ::= dataln dataln dataln dataln dataln .
datagroup ::= dataln dataln dataln dataln .
datagroup ::= dataln dataln dataln .
datagroup ::= dataln dataln .
datagroup ::= dataln .
%syntax_error
{
/*
* We might be parsing output that includes console session output along
* with packet dumps.
*/
(void)yypParser;
(void)yyminor;
static char *err = "non-packet data";
parser_state->ascend_parse_error = err;
}
%code {
/* Run the parser. */
bool
run_ascend_parser(guint8 *pd, ascend_state_t *parser_state, int *err, gchar **err_info)
{
yyscan_t scanner = NULL;
void *parser;
if (ascend_lex_init(&scanner) != 0) {
/* errno is set if this fails */
*err = errno;
*err_info = NULL;
return false;
}
/* Associate the parser state with the lexical analyzer state */
ascend_set_extra(parser_state, scanner);
parser_state->ascend_parse_error = NULL;
parser_state->err = 0;
parser_state->err_info = NULL;
parser_state->pkt_data = pd;
/*
* We haven't seen a time stamp yet.
*/
parser_state->saw_timestamp = FALSE;
parser_state->timestamp = 0;
parser_state->first_hexbyte = 0;
parser_state->caplen = 0;
parser_state->wirelen = 0;
parser_state->secs = 0;
parser_state->usecs = 0;
/*
* Not all packets in a "wdd" dump necessarily have a "Cause an
* attempt to place call to" header (I presume this can happen if
* there was a call in progress when the packet was sent or
* received), so we won't necessarily have the phone number for
* the packet.
*
* XXX - we could assume, in the sequential pass, that it's the
* phone number from the last call, and remember that for use
* when doing random access.
*/
parser_state->pseudo_header->call_num[0] = '\0';
parser = AscendParserAlloc(g_malloc);
#ifdef ASCEND_PARSER_DEBUG
AscendParserTrace(stderr, "=AP ");
#endif
int token_id;
do {
token_id = ascend_lex(scanner);
ascend_debug("Got token %d at %" G_GINT64_MODIFIER "d", token_id, file_tell(parser_state->fh));
AscendParser(parser, token_id, parser_state->token, parser_state);
} while (token_id && !parser_state->err && !parser_state->ascend_parse_error && parser_state->caplen < ASCEND_MAX_PKT_LEN);
AscendParserFree(parser, g_free);
ascend_lex_destroy(scanner);
if (parser_state->err) {
*err = parser_state->err;
*err_info = parser_state->err_info;
return false;
}
return true;
}
} // %code

View File

@ -8,12 +8,6 @@
*/
%option reentrant
/*
* We want to generate code that can be used by a reentrant parser
* generated by Bison or Berkeley YACC.
*/
%option bison-bridge
/*
* We don't read interactively from the terminal.
*/
@ -30,10 +24,10 @@
%option extra-type="ascend_state_t *"
/*
* Prefix scanner routines with "ascend" rather than "yy", so this scanner
* Prefix scanner routines with "ascend_" rather than "yy", so this scanner
* can coexist with other scanners.
*/
%option prefix="ascend"
%option prefix="ascend_"
/*
* We have to override the memory allocators so that we don't get
@ -63,7 +57,7 @@
#include "wtap-int.h"
#include "ascendtext.h"
#include "ascend-int.h"
#include "ascend.h"
#include "ascend_parser.h"
#include "file_wrappers.h"
/*
@ -71,21 +65,29 @@
*/
DIAG_OFF_FLEX
#define YY_INPUT(buf,result,max_size) { \
ascend_state_t *parser_state = ascendget_extra(yyscanner); \
int c = file_getc(parser_state->fh); \
if (c == EOF) { \
parser_state->err = file_error(parser_state->fh, \
&parser_state->err_info); \
if (parser_state->err == 0) \
parser_state->err = WTAP_ERR_SHORT_READ; \
result = YY_NULL; \
} else { \
buf[0] = c; \
result = 1; \
} \
static int ascend_yyinput(void *buf, ascend_state_t *parser_state) {
int c = file_getc(parser_state->fh);
if (c == EOF) {
parser_state->err = file_error(parser_state->fh,
&parser_state->err_info);
if (parser_state->err == 0)
parser_state->err = WTAP_ERR_SHORT_READ;
return YY_NULL;
} else {
*(char *) buf = c;
return 1;
}
}
#define YY_INPUT(buf, result, max_size) \
do { (result) = ascend_yyinput((buf), yyextra); } while (0)
/* Count bytes read. This is required in order to rewind the file
* to the beginning of the next packet, since flex reads more bytes
* before executing the action that does yyterminate(). */
#define YY_USER_ACTION do { yyextra->token.length = yyleng; } while (0);
#define NO_USER "<none>"
#ifndef HAVE_UNISTD_H
@ -100,9 +102,9 @@ DIAG_OFF_FLEX
/*
* Macros for the allocators, to discard the extra argument.
*/
#define ascendalloc(size, yyscanner) (void *)malloc(size)
#define ascendrealloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size))
#define ascendfree(ptr, yyscanner) free((char *)ptr)
#define ascend_alloc(size, yyscanner) (void *)malloc(size)
#define ascend_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size))
#define ascend_free(ptr, yyscanner) free((char *)ptr)
%}
@ -155,45 +157,45 @@ WDD_TYPE "type "[^\n\r\t ]+
%%
<INITIAL,sc_gen_byte>{ETHER_PFX} {
BEGIN(sc_ether_direction);
yylval->d = ASCEND_PFX_ETHER;
return ETHER_PREFIX;
BEGIN(sc_ether_direction);
yyextra->token.u16_val = ASCEND_PFX_ETHER;
return ETHER_PREFIX;
}
<INITIAL,sc_gen_byte>{ISDN_XPFX} {
BEGIN(sc_isdn_call);
yylval->d = ASCEND_PFX_ISDN_X;
return ISDN_PREFIX;
BEGIN(sc_isdn_call);
yyextra->token.u16_val = ASCEND_PFX_ISDN_X;
return ISDN_PREFIX;
}
<INITIAL,sc_gen_byte>{ISDN_RPFX} {
BEGIN(sc_isdn_call);
yylval->d = ASCEND_PFX_ISDN_R;
return ISDN_PREFIX;
BEGIN(sc_isdn_call);
yyextra->token.u16_val = ASCEND_PFX_ISDN_R;
return ISDN_PREFIX;
}
<INITIAL,sc_gen_byte>{WAN_XPFX} {
BEGIN(sc_wds_user);
yylval->d = ASCEND_PFX_WDS_X;
return WDS_PREFIX;
BEGIN(sc_wds_user);
yyextra->token.u16_val = ASCEND_PFX_WDS_X;
return WDS_PREFIX;
}
<INITIAL,sc_gen_byte>{WAN_RPFX} {
BEGIN(sc_wds_user);
yylval->d = ASCEND_PFX_WDS_R;
return WDS_PREFIX;
BEGIN(sc_wds_user);
yyextra->token.u16_val = ASCEND_PFX_WDS_R;
return WDS_PREFIX;
}
<INITIAL,sc_gen_byte>{PPP_XPFX} {
BEGIN(sc_wds_user);
yylval->d = ASCEND_PFX_WDS_X;
return WDS_PREFIX;
BEGIN(sc_wds_user);
yyextra->token.u16_val = ASCEND_PFX_WDS_X;
return WDS_PREFIX;
}
<INITIAL,sc_gen_byte>{PPP_RPFX} {
BEGIN(sc_wds_user);
yylval->d = ASCEND_PFX_WDS_R;
return WDS_PREFIX;
BEGIN(sc_wds_user);
yyextra->token.u16_val = ASCEND_PFX_WDS_R;
return WDS_PREFIX;
}
/*
@ -206,8 +208,8 @@ WDD_TYPE "type "[^\n\r\t ]+
* XXX - any reason to require at least two of them?
*/
<sc_ether_direction>[^\(]{2,20} {
BEGIN(sc_gen_task);
return STRING;
BEGIN(sc_gen_task);
return STRING;
}
/*
@ -218,171 +220,176 @@ WDD_TYPE "type "[^\n\r\t ]+
* characters. Limit it to 20 characters.
*/
<sc_isdn_call>[^\/\(:]{1,20} {
BEGIN(sc_gen_task);
return DECNUM;
BEGIN(sc_gen_task);
return DECNUM;
}
<sc_wds_user>[^:]{2,20} {
char *atcopy = g_strdup(yytext);
char colon = input(yyscanner);
char after = input(yyscanner);
int retval = STRING;
char *atcopy = g_strdup(yytext);
char colon = input(yyscanner);
char after = input(yyscanner);
int retval = STRING;
unput(after); unput(colon);
unput(after); unput(colon);
if (after != '(' && after != ' ') {
BEGIN(sc_wds_sess);
if (yyextra->pseudo_header != NULL) {
g_strlcpy(yyextra->pseudo_header->user, atcopy, ASCEND_MAX_STR_LEN);
if (after != '(' && after != ' ') {
BEGIN(sc_wds_sess);
if (yyextra->pseudo_header != NULL && yyextra->pseudo_header->user[0] == '\0') {
g_strlcpy(yyextra->pseudo_header->user, atcopy, ASCEND_MAX_STR_LEN);
}
} else { /* We have a version 7 file */
BEGIN(sc_gen_task);
if (yyextra->pseudo_header != NULL && yyextra->pseudo_header->user[0] == '\0') {
g_strlcpy(yyextra->pseudo_header->user, NO_USER, ASCEND_MAX_STR_LEN);
}
/* Are valid values ever > 2^32? If so we need to adjust YYSTYPE and a lot of */
/* upstream code accordingly. */
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
retval = DECNUM;
}
} else { /* We have a version 7 file */
BEGIN(sc_gen_task);
if (yyextra->pseudo_header != NULL) {
g_strlcpy(yyextra->pseudo_header->user, NO_USER, ASCEND_MAX_STR_LEN);
}
/* Are valid values ever > 2^32? If so we need to adjust YYSTYPE and a lot of */
/* upstream code accordingly. */
yylval->d = (guint32) strtoul(yytext, NULL, 10);
retval = DECNUM;
}
g_free (atcopy);
return retval;
g_free (atcopy);
return retval;
}
<sc_wds_sess>{D}* {
BEGIN(sc_gen_task);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_gen_task);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
}
<sc_gen_task>(0x|0X)?{H}{2,8} {
BEGIN(sc_gen_time_s);
yylval->d = (guint32) strtoul(yytext, NULL, 16);
return HEXNUM;
BEGIN(sc_gen_time_s);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 16);
return HEXNUM;
}
<sc_gen_task>\"[A-Za-z0-9_ ]+\" {
return STRING;
return STRING;
}
<sc_gen_time_s>{D}{1,10} {
BEGIN(sc_gen_time_u);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_gen_time_u);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
}
<sc_gen_time_u>{D}{1,6} {
char *atcopy = g_strdup(yytext);
BEGIN(sc_gen_octets);
/* only want the most significant 2 digits. convert to usecs */
if (strlen(atcopy) > 2)
atcopy[2] = '\0';
yylval->d = (guint32) strtoul(atcopy, NULL, 10) * 10000;
g_free(atcopy);
return DECNUM;
char *atcopy = g_strdup(yytext);
BEGIN(sc_gen_octets);
/* only want the most significant 2 digits. convert to usecs */
if (strlen(atcopy) > 2)
atcopy[2] = '\0';
yyextra->token.u32_val = (guint32) strtoul(atcopy, NULL, 10) * 10000;
g_free(atcopy);
return DECNUM;
}
<sc_gen_octets>{D}{1,10} {
BEGIN(sc_gen_counter);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_gen_counter);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
}
<sc_gen_counter,sc_gen_byte>"["{H}{4}"]:" {
BEGIN(sc_gen_byte);
return COUNTER;
BEGIN(sc_gen_byte);
return COUNTER;
}
<sc_gen_byte>{H}{2} {
yylval->b = (guint8)(guint32) strtoul(yytext, NULL, 16);
return HEXBYTE;
yyextra->token.u8_val = (guint8) strtoul(yytext, NULL, 16);
return HEXBYTE;
}
<sc_gen_byte>" "{4} {
BEGIN(sc_chardisp);
BEGIN(sc_chardisp);
}
<sc_chardisp>.* {
BEGIN(sc_gen_byte);
BEGIN(sc_gen_byte);
}
<INITIAL,sc_gen_byte>{WDD_DATE} {
BEGIN(sc_wdd_date_d);
return WDD_DATE;
}
<sc_wdd_date_d>{D}{2} {
BEGIN(sc_wdd_date_m);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_wdd_date_m);
return WDD_DATE;
}
/*
* Scan m/d/y as three separate m, /d/, and y tokens.
* We could alternately treat m/d/y as a single token.
*/
<sc_wdd_date_m>{D}{2} {
BEGIN(sc_wdd_date_y);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_wdd_date_d);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return WDD_DECNUM;
}
<sc_wdd_date_d>\/{D}{2}\/ {
BEGIN(sc_wdd_date_y);
yyextra->token.u32_val = (guint32) strtoul(yytext+1, NULL, 10);
return WDD_DECNUM;
}
<sc_wdd_date_y>{D}{4} {
BEGIN(sc_wdd_time);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_wdd_time);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return WDD_DECNUM;
}
<sc_wdd_time>{WDD_TIME} {
BEGIN(sc_wdd_time_h);
return KEYWORD;
BEGIN(sc_wdd_time_h);
return WDD_TIME;
}
/*
* Scan h:m:s as three separate h, :m:, and s tokens similar to above.
*/
<sc_wdd_time_h>{D}{2} {
BEGIN(sc_wdd_time_m);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_wdd_time_m);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return WDD_DECNUM;
}
<sc_wdd_time_m>{D}{2} {
BEGIN(sc_wdd_time_s);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
<sc_wdd_time_m>:{D}{2}: {
BEGIN(sc_wdd_time_s);
yyextra->token.u32_val = (guint32) strtoul(yytext+1, NULL, 10);
return WDD_DECNUM;
}
<sc_wdd_time_s>{D}{2} {
BEGIN(sc_wdd_cause);
yylval->d = (guint32) strtoul(yytext, NULL, 10);
return DECNUM;
BEGIN(sc_wdd_cause);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 10);
return WDD_DECNUM;
}
<sc_wdd_cause>{WDD_CAUSE} {
BEGIN(sc_wdd_callnum);
return KEYWORD;
BEGIN(sc_wdd_callnum);
return WDD_CAUSE;
}
<sc_wdd_callnum>{WDD_CALLNUM} {
BEGIN(sc_wdd_chunk);
if (yyextra->pseudo_header != NULL) {
g_strlcpy(yyextra->pseudo_header->call_num, yytext, ASCEND_MAX_STR_LEN);
}
return STRING;
BEGIN(sc_wdd_chunk);
g_strlcpy(yyextra->token.str_val, yytext, ASCEND_MAX_STR_LEN);
return WDD_CALLNUM;
}
<INITIAL,sc_wdd_chunk,sc_gen_byte>{WDD_CHUNK} {
BEGIN(sc_wdd_chunknum);
return WDD_CHUNK;
BEGIN(sc_wdd_chunknum);
return WDD_CHUNK;
}
<sc_wdd_chunknum>{H}{1,8} {
BEGIN(sc_wdd_type);
yylval->d = (guint32) strtoul(yytext, NULL, 16);
return HEXNUM;
BEGIN(sc_wdd_type);
yyextra->token.u32_val = (guint32) strtoul(yytext, NULL, 16);
return HEXNUM;
}
<sc_wdd_type>{WDD_TYPE} {
BEGIN(sc_gen_task);
return KEYWORD;
BEGIN(sc_gen_task);
return KEYWORD;
}
<sc_gen_task>\/{D}+ {
return SLASH_SUFFIX;
return SLASH_SUFFIX;
}
(0x|0X)?{H}+ { return HEXNUM; }

View File

@ -23,46 +23,54 @@
/* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
This module reads the text hex dump output of various TAOS
(Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
(Avaya/Alcatel/Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
* pridisplay traces primary rate ISDN
* ether-display traces Ethernet packets (dangerous! CPU intensive)
* wanopening, wandisplay, wannext, wandsess
traces PPP or other WAN connections
Please see ascend.y for examples.
Please see ascend_parser.lemon for examples.
Detailed documentation on TAOS products was at http://support.lucent.com;
that no longer works, and appears not to be available on the Wayback
Machine.
Some online manuals include:
Some online manuals and other information include:
MAX Administration Guide:
https://downloads.avaya.com/elmodocs2/definity/def_r10_new/max/0678_002.pdf
Support for other commands will be added on an ongoing basis. */
Other MAX documentation:
https://support.avaya.com/products/P1192/max
https://web.archive.org/web/20201127014004/https://support.avaya.com/products/P1192/max#Tab4
Ascend Router Information:
http://maxrouter.rde.net/
https://web.archive.org/web/20200807215418/http://maxrouter.rde.net/
*/
typedef struct _ascend_magic_string {
guint type;
const gchar *strptr;
size_t strlength;
guint type;
const gchar *strptr;
size_t strlength;
} ascend_magic_string;
/* these magic strings signify the headers of a supported debug commands */
#define ASCEND_MAGIC_ENTRY(type, string) \
{ type, string, sizeof string - 1 } /* strlen of a constant string */
{ type, string, sizeof string - 1 } /* strlen of a constant string */
static const ascend_magic_string ascend_magic[] = {
ASCEND_MAGIC_ENTRY(ASCEND_PFX_ISDN_X, "PRI-XMIT-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_ISDN_R, "PRI-RCV-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "XMIT-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "RECV-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "XMIT:"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "RECV:"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "PPP-OUT"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "PPP-IN"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDD, "WD_DIALOUT_DISP:"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_ETHER, "ETHER"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_ISDN_X, "PRI-XMIT-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_ISDN_R, "PRI-RCV-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "XMIT-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "RECV-"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "XMIT:"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "RECV:"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "PPP-OUT"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "PPP-IN"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDD, "WD_DIALOUT_DISP:"),
ASCEND_MAGIC_ENTRY(ASCEND_PFX_ETHER, "ETHER"),
};
#define ASCEND_MAGIC_STRINGS G_N_ELEMENTS(ascend_magic)
@ -80,213 +88,214 @@ static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
Returns -1 on failure. */
static gint64 ascend_find_next_packet(wtap *wth, int *err, gchar **err_info)
{
int byte;
gint64 date_off = -1, cur_off, packet_off;
size_t string_level[ASCEND_MAGIC_STRINGS];
guint string_i = 0;
static const gchar ascend_date[] = ASCEND_DATE;
size_t ascend_date_len = sizeof ascend_date - 1; /* strlen of a constant string */
size_t ascend_date_string_level;
guint excessive_read_count = 262144;
int byte;
gint64 date_off = -1, cur_off, packet_off;
size_t string_level[ASCEND_MAGIC_STRINGS];
guint string_i = 0;
static const gchar ascend_date[] = ASCEND_DATE;
size_t ascend_date_len = sizeof ascend_date - 1; /* strlen of a constant string */
size_t ascend_date_string_level;
guint excessive_read_count = 262144;
memset(&string_level, 0, sizeof(string_level));
ascend_date_string_level = 0;
memset(&string_level, 0, sizeof(string_level));
ascend_date_string_level = 0;
while (((byte = file_getc(wth->fh)) != EOF)) {
excessive_read_count--;
while (((byte = file_getc(wth->fh)) != EOF)) {
excessive_read_count--;
if (!excessive_read_count) {
*err = 0;
return -1;
}
/*
* See whether this is the string_level[string_i]th character of
* Ascend magic string string_i.
*/
for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
const gchar *strptr = ascend_magic[string_i].strptr;
size_t len = ascend_magic[string_i].strlength;
if (byte == *(strptr + string_level[string_i])) {
/*
* Yes, it is, so we need to check for the next character of
* that string.
*/
string_level[string_i]++;
if (!excessive_read_count) {
*err = 0;
return -1;
}
/*
* Have we matched the entire string?
*/
if (string_level[string_i] >= len) {
/*
* Yes.
*/
cur_off = file_tell(wth->fh);
if (cur_off == -1) {
* See whether this is the string_level[string_i]th character of
* Ascend magic string string_i.
*/
for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
const gchar *strptr = ascend_magic[string_i].strptr;
size_t len = ascend_magic[string_i].strlength;
if (byte == *(strptr + string_level[string_i])) {
/*
* Yes, it is, so we need to check for the next character of
* that string.
*/
string_level[string_i]++;
/*
* Have we matched the entire string?
*/
if (string_level[string_i] >= len) {
/*
* Yes.
*/
cur_off = file_tell(wth->fh);
if (cur_off == -1) {
/* Error. */
*err = file_error(wth->fh, err_info);
return -1;
}
/* We matched some other type of header. */
if (date_off == -1) {
/* We haven't yet seen a date header, so this packet
doesn't have one.
Back up over the header we just read; that's where a read
of this packet should start. */
packet_off = cur_off - len;
} else {
/* This packet has a date/time header; a read of it should
start at the beginning of *that* header. */
packet_off = date_off;
}
goto found;
}
} else {
/*
* Not a match for this string, so reset the match process.
*/
string_level[string_i] = 0;
}
}
/*
* See whether this is the date_string_level'th character of
* ASCEND_DATE.
*/
if (byte == *(ascend_date + ascend_date_string_level)) {
/*
* Yes, it is, so we need to check for the next character of
* that string.
*/
ascend_date_string_level++;
/*
* Have we matched the entire string?
*/
if (ascend_date_string_level >= ascend_date_len) {
/* We matched a Date: header. It's a special case;
remember the offset, but keep looking for other
headers.
Reset the amount of Date: header that we've matched,
so that we start the process of matching a Date:
header all over again.
XXX - what if we match multiple Date: headers before
matching some other header? */
cur_off = file_tell(wth->fh);
if (cur_off == -1) {
/* Error. */
*err = file_error(wth->fh, err_info);
return -1;
}
}
/* We matched some other type of header. */
if (date_off == -1) {
/* We haven't yet seen a date header, so this packet
doesn't have one.
Back up over the header we just read; that's where a read
of this packet should start. */
packet_off = cur_off - len;
} else {
/* This packet has a date/time header; a read of it should
start at the beginning of *that* header. */
packet_off = date_off;
}
goto found;
date_off = cur_off - ascend_date_len;
ascend_date_string_level = 0;
}
} else {
} else {
/*
* Not a match for this string, so reset the match process.
*/
string_level[string_i] = 0;
}
}
/*
* See whether this is the date_string_level'th character of
* ASCEND_DATE.
*/
if (byte == *(ascend_date + ascend_date_string_level)) {
/*
* Yes, it is, so we need to check for the next character of
* that string.
*/
ascend_date_string_level++;
/*
* Have we matched the entire string?
*/
if (ascend_date_string_level >= ascend_date_len) {
/* We matched a Date: header. It's a special case;
remember the offset, but keep looking for other
headers.
Reset the amount of Date: header that we've matched,
so that we start the process of matching a Date:
header all over again.
XXX - what if we match multiple Date: headers before
matching some other header? */
cur_off = file_tell(wth->fh);
if (cur_off == -1) {
/* Error. */
*err = file_error(wth->fh, err_info);
return -1;
}
date_off = cur_off - ascend_date_len;
* Not a match for the Date: string, so reset the match process.
*/
ascend_date_string_level = 0;
}
} else {
/*
* Not a match for the Date: string, so reset the match process.
*/
ascend_date_string_level = 0;
}
}
}
*err = file_error(wth->fh, err_info);
return -1;
found:
/*
* Move to where the read for this packet should start, and return
* that seek offset.
*/
if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
*err = file_error(wth->fh, err_info);
return -1;
return packet_off;
found:
/*
* Move to where the read for this packet should start, and return
* that seek offset.
*/
if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
return -1;
return packet_off;
}
wtap_open_return_val ascend_open(wtap *wth, int *err, gchar **err_info)
{
gint64 offset;
guint8 buf[ASCEND_MAX_PKT_LEN];
ascend_state_t parser_state;
ws_statb64 statbuf;
ascend_t *ascend;
wtap_rec rec;
gint64 offset;
guint8 buf[ASCEND_MAX_PKT_LEN];
ascend_state_t parser_state = {0};
ws_statb64 statbuf;
ascend_t *ascend;
wtap_rec rec;
/* We haven't yet allocated a data structure for our private stuff;
set the pointer to null, so that "ascend_find_next_packet()" knows
not to fill it in. */
wth->priv = NULL;
/* We haven't yet allocated a data structure for our private stuff;
set the pointer to null, so that "ascend_find_next_packet()" knows
not to fill it in. */
wth->priv = NULL;
offset = ascend_find_next_packet(wth, err, err_info);
if (offset == -1) {
if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
return WTAP_OPEN_ERROR; /* read error */
return WTAP_OPEN_NOT_MINE; /* EOF */
}
offset = ascend_find_next_packet(wth, err, err_info);
if (offset == -1) {
if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
return WTAP_OPEN_ERROR; /* read error */
return WTAP_OPEN_NOT_MINE; /* EOF */
}
/* Do a trial parse of the first packet just found to see if we might
really have an Ascend file. If it fails with an actual error,
fail; those will be I/O errors. */
if (run_ascend_parser(wth->fh, &rec, buf, &parser_state, err,
err_info) != 0 && *err != 0) {
/* An I/O error. */
return WTAP_OPEN_ERROR;
}
/* Do a trial parse of the first packet just found to see if we might
really have an Ascend file. If it fails with an actual error,
fail; those will be I/O errors. */
parser_state.fh = wth->fh;
parser_state.pseudo_header = &rec.rec_header.packet_header.pseudo_header.ascend;
if (run_ascend_parser(buf, &parser_state, err, err_info) != 0 && *err != 0) {
/* An I/O error. */
return WTAP_OPEN_ERROR;
}
/* Either the parse succeeded, or it failed but didn't get an I/O
error.
/* Either the parse succeeded, or it failed but didn't get an I/O
error.
If we got at least some data, return success even if the parser
reported an error. This is because the debug header gives the
number of bytes on the wire, not actually how many bytes are in
the trace. We won't know where the data ends until we run into
the next packet. */
if (parser_state.caplen == 0) {
/* We read no data, so this presumably isn't an Ascend file. */
return WTAP_OPEN_NOT_MINE;
}
If we got at least some data, return success even if the parser
reported an error. This is because the debug header gives the
number of bytes on the wire, not actually how many bytes are in
the trace. We won't know where the data ends until we run into
the next packet. */
if (parser_state.caplen == 0) {
/* We read no data, so this presumably isn't an Ascend file. */
return WTAP_OPEN_NOT_MINE;
}
wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ASCEND;
wth->file_encap = WTAP_ENCAP_ASCEND;
wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ASCEND;
wth->file_encap = WTAP_ENCAP_ASCEND;
wth->snapshot_length = ASCEND_MAX_PKT_LEN;
wth->subtype_read = ascend_read;
wth->subtype_seek_read = ascend_seek_read;
ascend = (ascend_t *)g_malloc(sizeof(ascend_t));
wth->priv = (void *)ascend;
wth->snapshot_length = ASCEND_MAX_PKT_LEN;
wth->subtype_read = ascend_read;
wth->subtype_seek_read = ascend_seek_read;
ascend = (ascend_t *)g_malloc(sizeof(ascend_t));
wth->priv = (void *)ascend;
/* The first packet we want to read is the one that
"ascend_find_next_packet()" just found; start searching
for it at the offset at which it found it. */
ascend->next_packet_seek_start = offset;
/* The first packet we want to read is the one that
"ascend_find_next_packet()" just found; start searching
for it at the offset at which it found it. */
ascend->next_packet_seek_start = offset;
/* MAXen and Pipelines report the time since reboot. In order to keep
from reporting packet times near the epoch, we subtract the first
packet's timestamp from the capture file's ctime, which gives us an
offset that we can apply to each packet.
*/
if (wtap_fstat(wth, &statbuf, err) == -1) {
return WTAP_OPEN_ERROR;
}
ascend->inittime = statbuf.st_ctime;
ascend->adjusted = FALSE;
wth->file_tsprec = WTAP_TSPREC_USEC;
/* MAXen and Pipelines report the time since reboot. In order to keep
from reporting packet times near the epoch, we subtract the first
packet's timestamp from the capture file's ctime, which gives us an
offset that we can apply to each packet.
*/
if (wtap_fstat(wth, &statbuf, err) == -1) {
return WTAP_OPEN_ERROR;
}
ascend->inittime = statbuf.st_ctime;
ascend->adjusted = FALSE;
wth->file_tsprec = WTAP_TSPREC_USEC;
/*
* Add an IDB; we don't know how many interfaces were
* involved, so we just say one interface, about which
* we only know the link-layer type, snapshot length,
* and time stamp resolution.
*/
wtap_add_generated_idb(wth);
/*
* Add an IDB; we don't know how many interfaces were
* involved, so we just say one interface, about which
* we only know the link-layer type, snapshot length,
* and time stamp resolution.
*/
wtap_add_generated_idb(wth);
return WTAP_OPEN_MINE;
return WTAP_OPEN_MINE;
}
/* Parse the capture file.
@ -296,161 +305,150 @@ parse_ascend(ascend_t *ascend, FILE_T fh, wtap_rec *rec, Buffer *buf,
guint length, gint64 *next_packet_seek_start_ret,
int *err, gchar **err_info)
{
ascend_state_t parser_state;
int retval;
ascend_state_t parser_state = {0};
int retval;
ws_buffer_assure_space(buf, length);
retval = run_ascend_parser(fh, rec, ws_buffer_start_ptr(buf), &parser_state,
err, err_info);
ws_buffer_assure_space(buf, length);
parser_state.fh = fh;
parser_state.pseudo_header = &rec->rec_header.packet_header.pseudo_header.ascend;
/* Did we see any data (hex bytes)? */
if (parser_state.first_hexbyte) {
/* Yes. Provide the offset of the first byte so that our caller can
tip off ascend_find_next_packet() as to where to look for the next
packet, if any. */
if (next_packet_seek_start_ret != NULL)
*next_packet_seek_start_ret = parser_state.first_hexbyte;
} else {
/* No. Maybe this record was broken; sometimes, a header will be
printed but the data will be omitted, or worse -- two headers will
be printed, followed by the data for each.
retval = run_ascend_parser(ws_buffer_start_ptr(buf), &parser_state, err, err_info);
Because of this, we need to be fairly tolerant of what we accept
here. Provide our current offset so that our caller can tell
ascend_find_next_packet() to skip over what we've read so far so
we can try reading a new packet.
/* Did we see any data (hex bytes)? */
if (parser_state.first_hexbyte) {
/* Yes. Provide the offset of the first byte so that our caller can
tip off ascend_find_next_packet() as to where to look for the next
packet, if any. */
if (next_packet_seek_start_ret != NULL)
*next_packet_seek_start_ret = parser_state.first_hexbyte;
} else {
/* No. Maybe this record was broken; sometimes, a header will be
printed but the data will be omitted, or worse -- two headers will
be printed, followed by the data for each.
. That keeps us from getting into an infinite loop reading a broken
trace. */
if (next_packet_seek_start_ret != NULL)
*next_packet_seek_start_ret = file_tell(fh);
Because of this, we need to be fairly tolerant of what we accept
here. Provide our current offset so that our caller can tell
ascend_find_next_packet() to skip over what we've read so far so
we can try reading a new packet.
/* Don't treat that as a fatal error; pretend the parse succeeded. */
retval = 0;
}
. That keeps us from getting into an infinite loop reading a broken
trace. */
if (next_packet_seek_start_ret != NULL)
*next_packet_seek_start_ret = file_tell(fh);
/* if we got at least some data, return success even if the parser
reported an error. This is because the debug header gives the number
of bytes on the wire, not actually how many bytes are in the trace.
We won't know where the data ends until we run into the next packet. */
if (parser_state.caplen) {
if (! ascend->adjusted) {
ascend->adjusted = TRUE;
if (parser_state.saw_timestamp) {
/*
* Capture file contained a date and time.
* We do this only if this is the very first packet we've seen -
* i.e., if "ascend->adjusted" is false - because
* if we get a date and time after the first packet, we can't
* go back and adjust the time stamps of the packets we've already
* processed, and basing the time stamps of this and following
* packets on the time stamp from the file text rather than the
* ctime of the capture file means times before this and after
* this can't be compared.
*/
ascend->inittime = parser_state.timestamp;
}
if (ascend->inittime > parser_state.secs)
ascend->inittime -= parser_state.secs;
/* Don't treat that as a fatal error; pretend the parse succeeded. */
retval = 0;
}
rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
rec->ts.secs = parser_state.secs + ascend->inittime;
rec->ts.nsecs = parser_state.usecs * 1000;
rec->rec_header.packet_header.caplen = parser_state.caplen;
rec->rec_header.packet_header.len = parser_state.wirelen;
return TRUE;
}
/* if we got at least some data, return success even if the parser
reported an error. This is because the debug header gives the number
of bytes on the wire, not actually how many bytes are in the trace.
We won't know where the data ends until we run into the next packet. */
if (parser_state.caplen) {
if (! ascend->adjusted) {
ascend->adjusted = TRUE;
if (parser_state.saw_timestamp) {
/*
* Capture file contained a date and time.
* We do this only if this is the very first packet we've seen -
* i.e., if "ascend->adjusted" is false - because
* if we get a date and time after the first packet, we can't
* go back and adjust the time stamps of the packets we've already
* processed, and basing the time stamps of this and following
* packets on the time stamp from the file text rather than the
* ctime of the capture file means times before this and after
* this can't be compared.
*/
ascend->inittime = parser_state.timestamp;
}
if (ascend->inittime > parser_state.secs)
ascend->inittime -= parser_state.secs;
}
rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
rec->ts.secs = parser_state.secs + ascend->inittime;
rec->ts.nsecs = parser_state.usecs * 1000;
rec->rec_header.packet_header.caplen = parser_state.caplen;
rec->rec_header.packet_header.len = parser_state.wirelen;
/* Didn't see any data. Still, perhaps the parser was happy. */
if (retval) {
if (*err == 0) {
/* Parser failed, but didn't report an I/O error, so a parse error.
Return WTAP_ERR_BAD_FILE, with the parse error as the error string. */
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup((parser_state.ascend_parse_error != NULL) ? parser_state.ascend_parse_error : "parse error");
return TRUE;
}
} else {
if (*err == 0) {
/* Parser succeeded, but got no data, and didn't report an I/O error.
Return WTAP_ERR_BAD_FILE, with a "got no data" error string. */
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("no data returned by parse");
/* Didn't see any data. Still, perhaps the parser was happy. */
if (retval) {
if (*err == 0) {
/* Parser failed, but didn't report an I/O error, so a parse error.
Return WTAP_ERR_BAD_FILE, with the parse error as the error string. */
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup((parser_state.ascend_parse_error != NULL) ? parser_state.ascend_parse_error : "parse error");
}
} else {
if (*err == 0) {
/* Parser succeeded, but got no data, and didn't report an I/O error.
Return WTAP_ERR_BAD_FILE, with a "got no data" error string. */
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("no data returned by parse");
}
}
}
return FALSE;
return FALSE;
}
/* Read the next packet; called from wtap_read(). */
static gboolean ascend_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
gchar **err_info, gint64 *data_offset)
{
ascend_t *ascend = (ascend_t *)wth->priv;
gint64 offset;
ascend_t *ascend = (ascend_t *)wth->priv;
gint64 offset;
/* parse_ascend() will advance the point at which to look for the next
packet's header, to just after the last packet's header (ie. at the
start of the last packet's data). We have to get past the last
packet's header because we might mistake part of it for a new header. */
if (file_seek(wth->fh, ascend->next_packet_seek_start,
SEEK_SET, err) == -1)
return FALSE;
/* parse_ascend() will advance the point at which to look for the next
packet's header, to just after the last packet's header (ie. at the
start of the last packet's data). We have to get past the last
packet's header because we might mistake part of it for a new header. */
if (file_seek(wth->fh, ascend->next_packet_seek_start,
SEEK_SET, err) == -1)
return FALSE;
offset = ascend_find_next_packet(wth, err, err_info);
if (offset == -1) {
/* EOF or read error */
return FALSE;
}
if (!parse_ascend(ascend, wth->fh, rec, buf, wth->snapshot_length,
&ascend->next_packet_seek_start, err, err_info))
return FALSE;
offset = ascend_find_next_packet(wth, err, err_info);
if (offset == -1) {
/* EOF or read error */
return FALSE;
}
if (!parse_ascend(ascend, wth->fh, rec, buf, wth->snapshot_length,
&ascend->next_packet_seek_start, err, err_info))
return FALSE;
/* Flex might have gotten an EOF and caused *err to be set to
WTAP_ERR_SHORT_READ. If so, that's not an error, as the parser
didn't return an error; set *err to 0, and get rid of any error
string. */
*err = 0;
if (*err_info != NULL) {
g_free(*err_info);
*err_info = NULL;
}
*data_offset = offset;
return TRUE;
/* Flex might have gotten an EOF and caused *err to be set to
WTAP_ERR_SHORT_READ. If so, that's not an error, as the parser
didn't return an error; set *err to 0, and get rid of any error
string. */
*err = 0;
if (*err_info != NULL) {
g_free(*err_info);
*err_info = NULL;
}
*data_offset = offset;
return TRUE;
}
static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info)
{
ascend_t *ascend = (ascend_t *)wth->priv;
ascend_t *ascend = (ascend_t *)wth->priv;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
if (!parse_ascend(ascend, wth->random_fh, rec, buf,
wth->snapshot_length, NULL, err, err_info))
return FALSE;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
if (!parse_ascend(ascend, wth->random_fh, rec, buf,
wth->snapshot_length, NULL, err, err_info))
return FALSE;
/* Flex might have gotten an EOF and caused *err to be set to
WTAP_ERR_SHORT_READ. If so, that's not an error, as the parser
didn't return an error; set *err to 0, and get rid of any error
string. */
*err = 0;
if (*err_info != NULL) {
g_free(*err_info);
*err_info = NULL;
}
return TRUE;
/* Flex might have gotten an EOF and caused *err to be set to
WTAP_ERR_SHORT_READ. If so, that's not an error, as the parser
didn't return an error; set *err to 0, and get rid of any error
string. */
*err = 0;
if (*err_info != NULL) {
g_free(*err_info);
*err_info = NULL;
}
return TRUE;
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local Variables:
* c-basic-offset: 2
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=2 tabstop=8 expandtab:
* :indentSize=2:tabSize=8:noTabs=true:
*/

View File

@ -149,13 +149,6 @@ extern "C" {
__pragma(warning(disable:6387)) \
__pragma(warning(disable:28182))
#define DIAG_ON_FLEX __pragma(warning(pop))
/*
* XXX - is there an issue with shadowed definitions with MSVC if
* somebody were to happen to use Berkeley YACC rather than Bison?
*/
#define DIAG_OFF_BYACC
#define DIAG_ON_BYACC
#else
/*
* Suppress:
@ -191,28 +184,6 @@ extern "C" {
#define DIAG_ON_FLEX \
DIAG_ON(sign-compare)
#endif
/*
* Berkeley YACC and, apparently, some versions of Bison, such as the
* one in Fedora 21, generate a global declaration of yylval, or the
* appropriately prefixed version of yylval, in grammar.h, *even
* though it's been told to generate a pure parser, meaning it
* doesn't have any global variables*. Other versions of Bison, such
* as the one in macOS Sierra don't do that.
*
* That causes a warning due to the local declaration in the parser
* shadowing the global declaration.
*
* So, if we have _Pragma, and have pragmas to suppress diagnostics,
* we use it to turn off -Wshadow warnings.
*
* XXX - do this for Bison only in versions of Bison with this
* problem?
*/
#define DIAG_OFF_BYACC \
DIAG_OFF(shadow)
#define DIAG_ON_BYACC \
DIAG_ON(shadow)
#endif
/*