wireshark/wiretap/busmaster_scanner.l
Maksim Salau 9011ad1030 wiretap: Add support for Busmaster log file format
Only CAN protocol is supported. Extra information available in J1939
entries is ignored since the J1939 wireshark dissector works with
raw CAN frames and makes no use of this extra information.
The log format may also encapsulate LIN messages which are not
supported by wireshark and thus are ignored.

The only limitation is that relative timestamp format is not
supported. If a file defines relative format of timestamps, packets
are extracted, but timestamps are omitted, since random access deems
impossible without reparsing the whole file up to the packet of
interest. In order to support relative timestamps we need to parse
the whole file at once on open and either dump into a temporary
PCAP file or keep messages in a private list and provide access
to them on read()/seek_read().

The change also creates a separate header for CAN frame structure
definitions which are used by several file readers (candump and
busmaster for now).

Bug: 15939
Change-Id: I87c5555e4e5e1b142b9984b24544b2591d494fbc
Reviewed-on: https://code.wireshark.org/review/34083
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
2019-08-03 15:46:08 +00:00

199 lines
6.9 KiB
Text

/* busmaster_scanner.l
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* Support for Busmaster log file format
* Copyright (c) 2019 by Maksim Salau <maksim.salau@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
%top {
/* Include this before everything else, for various large-file definitions */
#include "config.h"
}
%option noyywrap
%option noinput
%option nounput
%option batch
%option never-interactive
%option nodefault
%option prefix="busmaster_"
%option reentrant
%option extra-type="busmaster_state_t *"
%option noyy_scan_buffer
%option noyy_scan_bytes
%option noyy_scan_string
/*
* We have to override the memory allocators so that we don't get
* "unused argument" warnings from the yyscanner argument (which
* we don't use, as we have a global memory allocator).
*
* We provide, as macros, our own versions of the routines generated by Flex,
* which just call malloc()/realloc()/free() (as the Flex versions do),
* discarding the extra argument.
*/
%option noyyalloc
%option noyyrealloc
%option noyyfree
%{
#include <ws_diag_control.h>
#include <wiretap/file_wrappers.h>
#include "busmaster_parser.h"
#include "busmaster_priv.h"
#ifndef HAVE_UNISTD_H
#define YY_NO_UNISTD_H
#endif
static int busmaster_yyinput(void *buf, unsigned int length, busmaster_state_t *state)
{
int ret = file_read(buf, length, state->fh);
if (ret < 0)
{
state->err = file_error(state->fh, &state->err_info);
return YY_NULL;
}
return ret;
}
#define YY_INPUT(buf, result, max_size) \
do { (result) = busmaster_yyinput((buf), (max_size), 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->file_bytes_read += yyleng; } while (0);
/*
* Sleazy hack to suppress compiler warnings in yy_fatal_error().
*/
#define YY_EXIT_FAILURE ((void)yyscanner, 2)
/*
* Macros for the allocators, to discard the extra argument.
*/
#define busmaster_alloc(size, yyscanner) (void *)malloc(size)
#define busmaster_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size))
#define busmaster_free(ptr, yyscanner) free((char *)(ptr))
DIAG_OFF_FLEX
%}
SPC [ \t]+
ENDL [\r\n][ \t\r\n]*
INT [0-9]+
NUM (0x)?[0-9A-Fa-f]+
%x HEADER TIME
%x HEADER_CHANNELS HEADER_DB_FILES
%%
<*>{SPC} ;
<INITIAL>{ENDL} { yyterminate(); };
<HEADER,TIME>{ENDL} { YY_FATAL_ERROR("Unterminated header statement"); }
"***" { BEGIN(HEADER); }
<HEADER,TIME>"***"{ENDL}"***" { BEGIN(HEADER); return TOKEN_ENDL; }
<HEADER>"***"{ENDL} { BEGIN(INITIAL); yyterminate(); }
<HEADER>"BUSMASTER" { return TOKEN_HEADER_VER; }
<HEADER>"PROTOCOL CAN" { yyextra->token.v0 = PROTOCOL_CAN; return TOKEN_PROTOCOL_TYPE; }
<HEADER>"PROTOCOL J1939" { yyextra->token.v0 = PROTOCOL_J1939; return TOKEN_PROTOCOL_TYPE; }
<HEADER>"PROTOCOL LIN" { yyextra->token.v0 = PROTOCOL_LIN; return TOKEN_PROTOCOL_TYPE; }
<HEADER>"START DATE AND TIME" { BEGIN(TIME); return TOKEN_START_TIME; }
<HEADER>"END DATE AND TIME" { BEGIN(TIME); return TOKEN_END_TIME; }
<HEADER>"DEC" { yyextra->token.v0 = DATA_MODE_DEC; return TOKEN_DATA_MODE; }
<HEADER>"HEX" { yyextra->token.v0 = DATA_MODE_HEX; return TOKEN_DATA_MODE; }
<HEADER>"ABSOLUTE MODE" { yyextra->token.v0 = TIME_MODE_ABSOLUTE; return TOKEN_TIME_MODE; }
<HEADER>"SYSTEM MODE" { yyextra->token.v0 = TIME_MODE_SYSTEM; return TOKEN_TIME_MODE; }
<HEADER>"RELATIVE MODE" { yyextra->token.v0 = TIME_MODE_RELATIVE; return TOKEN_TIME_MODE; }
<HEADER>"[START LOGGING SESSION]" { return TOKEN_START_SESSION; }
<HEADER>"[STOP LOGGING SESSION]" { return TOKEN_STOP_SESSION; }
<HEADER>"START CHANNEL BAUD RATE***" { BEGIN(HEADER_CHANNELS); }
<HEADER>"START DATABASE FILES (DBF/DBC)***" { BEGIN(HEADER_DB_FILES); }
<HEADER>. { return TOKEN_HEADER_CHAR; }
<HEADER_CHANNELS>"***END CHANNEL BAUD RATE***"{ENDL}"***" { BEGIN(HEADER); }
<HEADER_CHANNELS>.+ ;
<HEADER_CHANNELS>{ENDL} ;
<HEADER_DB_FILES>"***END DATABASE FILES (DBF/DBC)***"{ENDL}"***" { BEGIN(HEADER); }
<HEADER_DB_FILES>"***END OF DATABASE FILES (DBF/DBC)***"{ENDL}"***" { BEGIN(HEADER); }
<HEADER_DB_FILES>.+ ;
<HEADER_DB_FILES>{ENDL} ;
<TIME>{INT} { yyextra->token.v0 = strtoul(yytext, NULL, 10); return TOKEN_INT; }
<TIME>: { return TOKEN_COLON; }
<TIME>. { return TOKEN_INVALID_CHAR; }
<INITIAL>{INT}:{INT}:{INT}:{INT} {
char *endp;
char *strp;
yyextra->token.v0 = strtoul(yytext, &endp, 10);
if (*endp != ':' || endp == yytext)
return TOKEN_INVALID_NUMBER;
strp = endp + 1;
yyextra->token.v1 = strtoul(strp, &endp, 10);
if (*endp != ':' || endp == strp)
return TOKEN_INVALID_NUMBER;
strp = endp + 1;
yyextra->token.v2 = strtoul(strp, &endp, 10);
if (*endp != ':' || endp == strp)
return TOKEN_INVALID_NUMBER;
strp = endp + 1;
yyextra->token.v3 = strtoul(strp, &endp, 10);
if (*endp != '\0' || endp == strp)
return TOKEN_INVALID_NUMBER;
return TOKEN_MSG_TIME;
}
<INITIAL>{NUM} {
char *endp;
if (yyextra->header.data_mode == DATA_MODE_HEX)
yyextra->token.v0 = strtoul(yytext, &endp, 16);
else if (yyextra->header.data_mode == DATA_MODE_DEC)
yyextra->token.v0 = strtoul(yytext, &endp, 10);
else
return TOKEN_INVALID_NUMBER;
if (*endp != '\0' || endp == yytext)
return TOKEN_INVALID_NUMBER;
return TOKEN_INT;
}
<INITIAL>[RT]x { return TOKEN_MSG_DIR; }
<INITIAL>s { yyextra->token.v0 = MSG_TYPE_STD; return TOKEN_MSG_TYPE; }
<INITIAL>sr { yyextra->token.v0 = MSG_TYPE_STD_RTR; return TOKEN_MSG_TYPE; }
<INITIAL>x { yyextra->token.v0 = MSG_TYPE_EXT; return TOKEN_MSG_TYPE; }
<INITIAL>xr { yyextra->token.v0 = MSG_TYPE_EXT_RTR; return TOKEN_MSG_TYPE; }
<INITIAL>s-fd { yyextra->token.v0 = MSG_TYPE_STD_FD; return TOKEN_MSG_TYPE; }
<INITIAL>x-fd { yyextra->token.v0 = MSG_TYPE_EXT_FD; return TOKEN_MSG_TYPE; }
<INITIAL>ERR.* { yyextra->token.v0 = MSG_TYPE_ERR; return TOKEN_ERR_MSG_TYPE; }
<INITIAL>("NONE"|"CMD"|"RQST"|"DATA"|"BROADCAST"|"ACK"|"GRP_FUNC"|"ACL"|"RQST_ACL"|"CA"|"BAM"|"RTS"|"CTS"|"EOM"|"CON_ABORT"|"TPDT") {
return TOKEN_J1939_MSG_TYPE;
}
<INITIAL>. { return TOKEN_INVALID_CHAR; }
%%
DIAG_ON_FLEX