forked from osmocom/wireshark
d2d1f793f8
Change-Id: I8155573933daeb69c6e4c95c6702bdd6fc1fa89b Reviewed-on: https://code.wireshark.org/review/25707 Petri-Dish: Dario Lombardo <lomato@gmail.com> Reviewed-by: Anders Broman <a.broman58@gmail.com>
721 lines
21 KiB
Text
721 lines
21 KiB
Text
%include {
|
|
|
|
/* mate_grammar.lemon
|
|
* MATE's configuration language grammar
|
|
*
|
|
* Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
/*
|
|
* XXX - there's a Lemon bug where this grammar produces a parser that
|
|
* fails assertions; to work around it, we disable assert() failures.
|
|
*/
|
|
#ifndef NDEBUG
|
|
#define NDEBUG
|
|
#endif
|
|
|
|
#include "mate.h"
|
|
#include "mate_grammar.h"
|
|
#include <wsutil/file_util.h>
|
|
|
|
#define DUMMY void*
|
|
|
|
typedef struct _extraction {
|
|
gchar* as;
|
|
header_field_info* hfi;
|
|
struct _extraction* next;
|
|
struct _extraction* last;
|
|
} extraction_t;
|
|
|
|
typedef struct _pdu_criteria_t {
|
|
AVPL* criterium_avpl;
|
|
avpl_match_mode criterium_match_mode;
|
|
accept_mode_t criterium_accept_mode;
|
|
} pdu_criteria_t;
|
|
|
|
typedef struct _gop_options {
|
|
gop_tree_mode_t pdu_tree_mode;
|
|
gboolean drop_unassigned;
|
|
gboolean show_times;
|
|
float expiration;
|
|
float idle_timeout;
|
|
float lifetime;
|
|
AVPL* start;
|
|
AVPL* stop;
|
|
AVPL* extras;
|
|
} gop_options_t;
|
|
|
|
typedef struct _gog_statements {
|
|
float expiration;
|
|
gop_tree_mode_t gop_tree_mode;
|
|
GPtrArray* transform_list;
|
|
AVPL* extras;
|
|
LoAL* current_gogkeys;
|
|
} gog_statement_t;
|
|
|
|
typedef struct _transf_match_t {
|
|
avpl_match_mode match_mode;
|
|
AVPL* avpl;
|
|
} transf_match_t;
|
|
|
|
typedef struct _transf_action_t {
|
|
avpl_replace_mode replace_mode;
|
|
AVPL* avpl;
|
|
} transf_action_t;
|
|
|
|
static void configuration_error(mate_config* mc, const gchar* fmt, ...) {
|
|
static gchar error_buffer[256];
|
|
const gchar* incl;
|
|
gint i;
|
|
mate_config_frame* current_frame;
|
|
va_list list;
|
|
|
|
va_start( list, fmt );
|
|
g_vsnprintf(error_buffer,sizeof(error_buffer),fmt,list);
|
|
va_end( list );
|
|
|
|
i = (gint) mc->config_stack->len;
|
|
|
|
while (i--) {
|
|
|
|
if (i>0) {
|
|
incl = "\n included from: ";
|
|
} else {
|
|
incl = " ";
|
|
}
|
|
|
|
current_frame = (mate_config_frame *)g_ptr_array_index(mc->config_stack,(guint)i);
|
|
|
|
g_string_append_printf(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum);
|
|
}
|
|
|
|
g_string_append_printf(mc->config_error,": %s\n",error_buffer);
|
|
|
|
THROW(MateConfigError);
|
|
|
|
}
|
|
|
|
static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
|
|
AVPL_Transf* t = (AVPL_Transf *)g_malloc(sizeof(AVPL_Transf));
|
|
|
|
t->name = NULL;
|
|
t->match = match;
|
|
t->replace = replace;
|
|
t->match_mode = match_mode;
|
|
t->replace_mode = replace_mode;
|
|
|
|
t->map = NULL;
|
|
t->next = NULL;
|
|
|
|
return t;
|
|
}
|
|
|
|
static gchar* recolonize(mate_config* mc, gchar* s) {
|
|
GString* str = g_string_new("");
|
|
gchar** vec;
|
|
gchar* r;
|
|
guint i,v;
|
|
gchar c;
|
|
|
|
vec = g_strsplit(s,":",0);
|
|
|
|
for (i = 0; vec[i]; i++) {
|
|
g_ascii_strdown(vec[i], -1);
|
|
|
|
v = 0;
|
|
switch ( strlen(vec[i]) ) {
|
|
case 2:
|
|
c = vec[i][1];
|
|
vec[i][1] = vec[i][0];
|
|
vec[i][0] = c;
|
|
if (vec[i][0] >= '0' && vec[i][0] <= '9') {
|
|
v += (vec[i][1] - '0' )*16;
|
|
} else {
|
|
v += (vec[i][1] - 'a' + 10)*16;
|
|
}
|
|
/* FALL THROUGH */
|
|
case 1:
|
|
if (vec[i][0] >= '0' && vec[i][0] <= '9') {
|
|
v += (vec[i][0] - '0' );
|
|
} else {
|
|
v += (vec[i][0] - 'a' + 10);
|
|
}
|
|
case 0:
|
|
break;
|
|
default:
|
|
configuration_error(mc,"bad token %s",s);
|
|
}
|
|
|
|
g_string_append_printf(str,":%.2X",v);
|
|
}
|
|
|
|
g_strfreev(vec);
|
|
|
|
g_string_erase(str,0,1);
|
|
|
|
r = str->str;
|
|
|
|
g_string_free(str,FALSE);
|
|
|
|
return r;
|
|
}
|
|
|
|
}
|
|
|
|
%name MateParser
|
|
|
|
%token_prefix TOKEN_
|
|
|
|
%token_type { gchar* }
|
|
%token_destructor {
|
|
(void) mc; /* Mark unused, similar to Q_UNUSED */
|
|
g_free($$);
|
|
}
|
|
|
|
%extra_argument { mate_config* mc }
|
|
|
|
%syntax_error {
|
|
configuration_error(mc,"Syntax Error before %s",yyminor);
|
|
}
|
|
|
|
%parse_failure {
|
|
configuration_error(mc,"Parse Error");
|
|
}
|
|
|
|
%type transform_decl { AVPL_Transf* }
|
|
%type transform_body { AVPL_Transf* }
|
|
%type transform_statements { AVPL_Transf* }
|
|
%type transform_statement { AVPL_Transf* }
|
|
%type transform_match { transf_match_t* }
|
|
%type transform_action { transf_action_t* }
|
|
%type match_mode { avpl_match_mode }
|
|
%type action_mode { avpl_replace_mode }
|
|
|
|
%type gop_name { gchar* }
|
|
%type time_value { float }
|
|
%type pdu_name { gchar* }
|
|
%type gop_tree_mode { gop_tree_mode_t }
|
|
%type true_false { gboolean }
|
|
|
|
%type criteria_statement { pdu_criteria_t* }
|
|
%type accept_mode { accept_mode_t }
|
|
%type pdu_drop_unassigned_statement { gboolean }
|
|
%type discard_pdu_data_statement { gboolean }
|
|
%type last_extracted_statement { gboolean }
|
|
|
|
%type extraction_statement {extraction_t*}
|
|
%type extraction_statements {extraction_t*}
|
|
|
|
%type gop_options { gop_options_t* }
|
|
|
|
%type gop_start_statement { AVPL* }
|
|
%type gop_stop_statement { AVPL* }
|
|
%type extra_statement { AVPL* }
|
|
%type gop_drop_unassigned_statement { gboolean }
|
|
%type show_goptree_statement { gop_tree_mode_t }
|
|
%type show_times_statement { gboolean }
|
|
%type gop_expiration_statement { float }
|
|
%type idle_timeout_statement { float }
|
|
%type lifetime_statement { float }
|
|
|
|
%type gog_statements { gog_statement_t* }
|
|
%type gog_expiration_statement { float }
|
|
%type gog_goptree_statement { gop_tree_mode_t }
|
|
%type gog_key_statements { LoAL* }
|
|
%type gog_key_statement { AVPL* }
|
|
%type transform_list_statement { GPtrArray* }
|
|
%type transform { AVPL_Transf* }
|
|
%type gop_tree_type { gop_tree_mode_t }
|
|
|
|
%type payload_statement { GPtrArray* }
|
|
%type proto_stack { GPtrArray* }
|
|
%type field { header_field_info* }
|
|
%type transform_list { GPtrArray* }
|
|
%type avpl { AVPL* }
|
|
%type avps { AVPL* }
|
|
%type avp { AVP* }
|
|
%type value { gchar* }
|
|
%type avp_oneoff { gchar* }
|
|
|
|
|
|
mate_config ::= decls.
|
|
|
|
decls ::= decls decl.
|
|
decls ::= .
|
|
|
|
decl ::= pdu_decl.
|
|
decl ::= gop_decl.
|
|
decl ::= gog_decl.
|
|
decl ::= transform_decl.
|
|
decl ::= defaults_decl.
|
|
decl ::= debug_decl.
|
|
decl ::= DONE_KW SEMICOLON.
|
|
|
|
/************* DEBUG
|
|
*/
|
|
|
|
debug_decl ::= DEBUG_KW OPEN_BRACE dbgfile_default dbglevel_default pdu_dbglevel_default gop_dbglevel_default gog_dbglevel_default CLOSE_BRACE SEMICOLON.
|
|
|
|
dbgfile_default ::= FILENAME_KW QUOTED(Filename) SEMICOLON. { mc->dbg_facility = ws_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
|
|
dbgfile_default ::= FILENAME_KW NAME(Filename) SEMICOLON. { mc->dbg_facility = ws_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
|
|
dbgfile_default ::= .
|
|
|
|
dbglevel_default ::= LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_lvl = (int) strtol(LevelString,NULL,10); }
|
|
dbglevel_default ::= .
|
|
|
|
pdu_dbglevel_default ::= PDU_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_pdu_lvl = (int) strtol(LevelString,NULL,10); }
|
|
pdu_dbglevel_default ::= .
|
|
|
|
gop_dbglevel_default ::= GOP_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gop_lvl = (int) strtol(LevelString,NULL,10); }
|
|
gop_dbglevel_default ::= .
|
|
|
|
gog_dbglevel_default ::= GOG_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gog_lvl = (int) strtol(LevelString,NULL,10); }
|
|
gog_dbglevel_default ::= .
|
|
|
|
|
|
/************* DEFAULTS
|
|
*/
|
|
|
|
defaults_decl ::= DEFAULT_KW OPEN_BRACE pdu_defaults gop_defaults gog_defaults CLOSE_BRACE SEMICOLON.
|
|
|
|
pdu_defaults ::= PDU_KW OPEN_BRACE pdu_last_extracted_default pdu_drop_unassigned_default pdu_discard_default CLOSE_BRACE SEMICOLON.
|
|
pdu_defaults ::= .
|
|
|
|
pdu_last_extracted_default ::= LAST_EXTRACTED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.last_extracted = Flag; }
|
|
pdu_last_extracted_default ::= .
|
|
|
|
pdu_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.drop_unassigned = Flag; }
|
|
pdu_drop_unassigned_default ::= .
|
|
|
|
pdu_discard_default ::= DISCARD_PDU_DATA_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.discard = Flag; }
|
|
pdu_discard_default ::= .
|
|
|
|
gop_defaults ::= GOP_KW OPEN_BRACE gop_expiration_default gop_idle_timeout_default gop_lifetime_default gop_drop_unassigned_default gop_tree_mode_default gop_show_times_default CLOSE_BRACE SEMICOLON.
|
|
gop_defaults ::= .
|
|
|
|
gop_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
|
|
gop_expiration_default ::= .
|
|
|
|
gop_idle_timeout_default ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { mc->defaults.gop.idle_timeout = B; }
|
|
gop_idle_timeout_default ::= .
|
|
|
|
gop_lifetime_default ::= LIFETIME_KW time_value(B) SEMICOLON. { mc->defaults.gop.lifetime = B; }
|
|
gop_lifetime_default ::= .
|
|
|
|
gop_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { mc->defaults.gop.drop_unassigned = B; }
|
|
gop_drop_unassigned_default ::= .
|
|
|
|
gop_tree_mode_default ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { mc->defaults.gop.pdu_tree_mode = (gop_pdu_tree_t)B; }
|
|
gop_tree_mode_default ::= .
|
|
|
|
gop_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gop.show_times = B; }
|
|
gop_show_times_default ::= .
|
|
|
|
gog_defaults ::= GOG_KW OPEN_BRACE gog_expiration_default gop_tree_mode_default gog_goptree_default gog_show_times_default CLOSE_BRACE SEMICOLON.
|
|
gog_defaults ::= .
|
|
|
|
gog_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
|
|
gog_expiration_default ::= .
|
|
|
|
gog_goptree_default ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { mc->defaults.gog.gop_tree_mode = B; }
|
|
gog_goptree_default ::= .
|
|
|
|
gog_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gog.show_times = B; }
|
|
gog_show_times_default ::= .
|
|
|
|
|
|
/******************************************* TRANSFORM
|
|
*/
|
|
|
|
transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. {
|
|
AVPL_Transf* c;
|
|
|
|
if ( g_hash_table_lookup(mc->transfs,B) ) {
|
|
configuration_error(mc,"A transformation called '%s' exists already",B);
|
|
}
|
|
|
|
for ( c = C; c; c = c->next )
|
|
c->name = g_strdup(B);
|
|
|
|
g_hash_table_insert(mc->transfs,C->name,C);
|
|
|
|
A = NULL;
|
|
}
|
|
|
|
transform_body(A) ::= OPEN_BRACE transform_statements(B) CLOSE_BRACE. { A = B; }
|
|
|
|
transform_statements(A) ::= transform_statements(C) transform_statement(B). {
|
|
AVPL_Transf* c;
|
|
|
|
for ( c = C; c->next; c = c->next ) ;
|
|
c->next = B;
|
|
A = C;
|
|
}
|
|
|
|
transform_statements(A) ::= transform_statement(B). { A = B; }
|
|
|
|
transform_statement(A) ::= transform_match(Match) transform_action(Action) SEMICOLON. {
|
|
A = new_transform_elem(Match->avpl,Action->avpl,Match->match_mode,Action->replace_mode);
|
|
}
|
|
|
|
transform_match(A) ::= MATCH_KW match_mode(Mode) avpl(Avpl). {
|
|
A = (transf_match_t *)g_malloc(sizeof(transf_match_t));
|
|
A->match_mode = Mode;
|
|
A->avpl = Avpl;
|
|
}
|
|
|
|
transform_match(A) ::= . {
|
|
A = (transf_match_t *)g_malloc(sizeof(transf_match_t));
|
|
A->match_mode = AVPL_STRICT;
|
|
A->avpl = new_avpl("");
|
|
|
|
}
|
|
|
|
transform_action(A) ::= . {
|
|
A = (transf_action_t *)g_malloc(sizeof(transf_action_t));
|
|
A->replace_mode = AVPL_INSERT;
|
|
A->avpl = new_avpl("");
|
|
}
|
|
transform_action(A) ::= action_mode(Mode) avpl(Avpl). {
|
|
A = (transf_action_t *)g_malloc(sizeof(transf_action_t));
|
|
A->replace_mode = Mode;
|
|
A->avpl = Avpl;
|
|
}
|
|
|
|
match_mode(A) ::= . { A = AVPL_STRICT; }
|
|
match_mode(A) ::= STRICT_KW. { A = AVPL_STRICT; }
|
|
match_mode(A) ::= EVERY_KW. { A = AVPL_EVERY; }
|
|
match_mode(A) ::= LOOSE_KW. { A = AVPL_LOOSE; }
|
|
|
|
action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; }
|
|
action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; }
|
|
action_mode(A) ::= . { A = AVPL_INSERT; }
|
|
|
|
/******************************************* PDU
|
|
*/
|
|
|
|
pdu_decl ::=
|
|
PDU_KW NAME(Name) PROTO_KW field(Field) TRANSPORT_KW proto_stack(Stack)
|
|
OPEN_BRACE
|
|
payload_statement(Payload)
|
|
extraction_statements(Extraction)
|
|
transform_list_statement(Transform)
|
|
criteria_statement(Criteria)
|
|
pdu_drop_unassigned_statement(DropUnassigned)
|
|
discard_pdu_data_statement(DistcardPduData)
|
|
last_extracted_statement(LastExtracted)
|
|
CLOSE_BRACE SEMICOLON.
|
|
{
|
|
|
|
mate_cfg_pdu* cfg = new_pducfg(mc, Name);
|
|
extraction_t *extraction, *next_extraction;
|
|
GPtrArray* transport_stack = g_ptr_array_new();
|
|
int i;
|
|
|
|
if (! cfg ) configuration_error(mc,"could not create Pdu %s.",Name);
|
|
|
|
cfg->hfid_proto = Field->id;
|
|
|
|
cfg->last_extracted = LastExtracted;
|
|
cfg->discard = DistcardPduData;
|
|
cfg->drop_unassigned = DropUnassigned;
|
|
|
|
/*
|
|
* Add this protocol to our table of wanted hfids.
|
|
*/
|
|
mc->wanted_hfids = g_array_append_val(mc->wanted_hfids, Field->id);
|
|
|
|
/* flip the transport_stack */
|
|
for (i = Stack->len - 1; Stack->len; i--) {
|
|
g_ptr_array_add(transport_stack,g_ptr_array_remove_index(Stack,i));
|
|
}
|
|
|
|
g_ptr_array_free(Stack,FALSE);
|
|
|
|
cfg->transport_ranges = transport_stack;
|
|
cfg->payload_ranges = Payload;
|
|
|
|
if (Criteria) {
|
|
cfg->criterium = Criteria->criterium_avpl;
|
|
cfg->criterium_match_mode = Criteria->criterium_match_mode;
|
|
cfg->criterium_accept_mode = Criteria->criterium_accept_mode;
|
|
}
|
|
|
|
cfg->transforms = Transform;
|
|
|
|
for (extraction = Extraction; extraction; extraction = next_extraction) {
|
|
next_extraction = extraction->next;
|
|
|
|
if ( ! add_hfid(mc, extraction->hfi, extraction->as, cfg->hfids_attr) ) {
|
|
configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as);
|
|
}
|
|
|
|
g_free(extraction);
|
|
}
|
|
}
|
|
|
|
payload_statement(A) ::= . { A = NULL; }
|
|
payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; }
|
|
|
|
criteria_statement(A) ::= . { A = NULL; }
|
|
criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. {
|
|
A = (pdu_criteria_t *)g_malloc(sizeof(pdu_criteria_t));
|
|
A->criterium_avpl = D;
|
|
A->criterium_match_mode = C;
|
|
A->criterium_accept_mode = B;
|
|
}
|
|
|
|
accept_mode(A) ::= . { A = ACCEPT_MODE; }
|
|
accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; }
|
|
accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; }
|
|
|
|
extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last = A->last->next = C; }
|
|
extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; }
|
|
|
|
extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. {
|
|
A = (extraction_t *)g_malloc(sizeof(extraction_t));
|
|
A->as = NAME;
|
|
A->hfi = FIELD;
|
|
A->next = A->last = NULL;
|
|
}
|
|
|
|
|
|
pdu_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
|
|
pdu_drop_unassigned_statement(A) ::= . { A = mc->defaults.pdu.drop_unassigned; }
|
|
|
|
discard_pdu_data_statement(A) ::= DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; }
|
|
discard_pdu_data_statement(A) ::= . { A = mc->defaults.pdu.discard; }
|
|
|
|
last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; }
|
|
last_extracted_statement(A) ::= . { A = mc->defaults.pdu.last_extracted; }
|
|
|
|
proto_stack(A) ::= proto_stack(B) SLASH field(C). {
|
|
int* hfidp = (int *)g_malloc(sizeof(int));
|
|
|
|
*hfidp = C->id;
|
|
g_ptr_array_add(B,hfidp);
|
|
A = B;
|
|
}
|
|
|
|
proto_stack(A) ::= field(B). {
|
|
int* hfidp = (int *)g_malloc(sizeof(int));
|
|
*hfidp = B->id;
|
|
|
|
A = g_ptr_array_new();
|
|
g_ptr_array_add(A,hfidp);
|
|
}
|
|
|
|
field(A) ::= NAME(B). {
|
|
A = proto_registrar_get_byname(B);
|
|
}
|
|
|
|
/******************************************* GOP
|
|
*/
|
|
|
|
gop_decl(A) ::= GOP_KW NAME(Name) ON_KW pdu_name(PduName) MATCH_KW avpl(Key) OPEN_BRACE
|
|
gop_start_statement(Start)
|
|
gop_stop_statement(Stop)
|
|
extra_statement(Extra)
|
|
transform_list_statement(Transform)
|
|
gop_expiration_statement(Expiration)
|
|
idle_timeout_statement(IdleTimeout)
|
|
lifetime_statement(Lifetime)
|
|
gop_drop_unassigned_statement(DropUnassigned)
|
|
show_goptree_statement(TreeMode)
|
|
show_times_statement(ShowTimes)
|
|
CLOSE_BRACE SEMICOLON. {
|
|
mate_cfg_gop* cfg;
|
|
|
|
if (g_hash_table_lookup(mc->gopcfgs,Name)) configuration_error(mc,"A Gop Named '%s' exists already.",Name);
|
|
if (g_hash_table_lookup(mc->gops_by_pduname,PduName) ) configuration_error(mc,"Gop for Pdu '%s' exists already",PduName);
|
|
|
|
cfg = new_gopcfg(mc, Name);
|
|
g_hash_table_insert(mc->gops_by_pduname,PduName,cfg);
|
|
g_hash_table_insert(mc->gopcfgs,cfg->name,cfg);
|
|
|
|
cfg->on_pdu = PduName;
|
|
cfg->key = Key;
|
|
cfg->drop_unassigned = DropUnassigned;
|
|
cfg->show_times = ShowTimes;
|
|
cfg->pdu_tree_mode = (gop_pdu_tree_t)TreeMode;
|
|
cfg->expiration = Expiration;
|
|
cfg->idle_timeout = IdleTimeout;
|
|
cfg->lifetime = Lifetime;
|
|
cfg->start = Start;
|
|
cfg->stop = Stop;
|
|
cfg->transforms = Transform;
|
|
|
|
merge_avpl(cfg->extra,Extra,TRUE);
|
|
delete_avpl(Extra,TRUE);
|
|
}
|
|
|
|
gop_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
|
|
gop_drop_unassigned_statement(A) ::= . { A = mc->defaults.gop.drop_unassigned; }
|
|
|
|
gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; }
|
|
gop_start_statement(A) ::= . { A = NULL; }
|
|
|
|
gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; }
|
|
gop_stop_statement(A) ::= . { A = NULL; }
|
|
|
|
show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; }
|
|
show_goptree_statement(A) ::= . { A = (gop_tree_mode_t)mc->defaults.gop.pdu_tree_mode; }
|
|
|
|
show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; }
|
|
show_times_statement(A) ::= . { A = mc->defaults.gop.show_times; }
|
|
|
|
gop_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
|
|
gop_expiration_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
|
|
|
|
idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; }
|
|
idle_timeout_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
|
|
|
|
lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; }
|
|
lifetime_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
|
|
|
|
gop_tree_mode(A) ::= NO_TREE_KW. { A = (gop_tree_mode_t)GOP_NO_TREE; }
|
|
gop_tree_mode(A) ::= PDU_TREE_KW. { A = (gop_tree_mode_t)GOP_PDU_TREE; }
|
|
gop_tree_mode(A) ::= FRAME_TREE_KW. { A = (gop_tree_mode_t)GOP_FRAME_TREE; }
|
|
gop_tree_mode(A) ::= BASIC_TREE_KW. { A = (gop_tree_mode_t)GOP_BASIC_PDU_TREE; }
|
|
|
|
true_false(A) ::= TRUE_KW. { A = TRUE; }
|
|
true_false(A) ::= FALSE_KW. { A = FALSE; }
|
|
|
|
pdu_name(A) ::= NAME(B). {
|
|
mate_cfg_pdu* c;
|
|
if (( c = (mate_cfg_pdu *)g_hash_table_lookup(mc->pducfgs,B) )) {
|
|
A = c->name;
|
|
} else {
|
|
configuration_error(mc,"No such Pdu: '%s'",B);
|
|
}
|
|
}
|
|
|
|
|
|
time_value(A) ::= FLOATING(B). {
|
|
A = (float) g_ascii_strtod(B,NULL);
|
|
}
|
|
|
|
time_value(A) ::= INTEGER(B). {
|
|
A = (float) g_ascii_strtod(B,NULL);
|
|
}
|
|
|
|
/************* GOG
|
|
*/
|
|
|
|
gog_decl ::= GOG_KW NAME(Name) OPEN_BRACE
|
|
gog_key_statements(Keys)
|
|
extra_statement(Extra)
|
|
transform_list_statement(Transforms)
|
|
gog_expiration_statement(Expiration)
|
|
gog_goptree_statement(Tree)
|
|
show_times_statement(ShowTimes)
|
|
CLOSE_BRACE SEMICOLON. {
|
|
mate_cfg_gog* cfg = NULL;
|
|
|
|
if ( g_hash_table_lookup(mc->gogcfgs,Name) ) {
|
|
configuration_error(mc,"Gog '%s' exists already ",Name);
|
|
}
|
|
|
|
cfg = new_gogcfg(mc, Name);
|
|
|
|
cfg->expiration = Expiration;
|
|
cfg->gop_tree_mode = Tree;
|
|
cfg->transforms = Transforms;
|
|
cfg->keys = Keys;
|
|
cfg->show_times = ShowTimes;
|
|
|
|
merge_avpl(cfg->extra,Extra,TRUE);
|
|
delete_avpl(Extra,TRUE);
|
|
}
|
|
|
|
gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; }
|
|
gog_goptree_statement(A) ::= . { A = mc->defaults.gog.gop_tree_mode; }
|
|
|
|
gog_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
|
|
gog_expiration_statement(A) ::= . { A = mc->defaults.gog.expiration; }
|
|
|
|
gop_tree_type(A) ::= NULL_TREE_KW. { A = GOP_NULL_TREE; }
|
|
gop_tree_type(A) ::= FULL_TREE_KW. { A = GOP_FULL_TREE; }
|
|
gop_tree_type(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_TREE; }
|
|
|
|
gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). {
|
|
loal_append(B,C);
|
|
A = B;
|
|
}
|
|
|
|
gog_key_statements(A) ::= gog_key_statement(B). {
|
|
A = new_loal("");
|
|
loal_append(A,B);
|
|
}
|
|
|
|
|
|
gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. {
|
|
rename_avpl(C,B);
|
|
A = C;
|
|
}
|
|
|
|
gop_name(A) ::= NAME(B). {
|
|
mate_cfg_gop* c;
|
|
if (( c = (mate_cfg_gop *)g_hash_table_lookup(mc->gopcfgs,B) )) {
|
|
A = c->name;
|
|
} else {
|
|
configuration_error(mc,"No Gop called '%s' has been already declared",B);
|
|
}
|
|
}
|
|
/******************************************** GENERAL
|
|
*/
|
|
|
|
|
|
extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; }
|
|
extra_statement(A) ::= . { A = new_avpl(""); }
|
|
|
|
transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; }
|
|
transform_list_statement(A) ::= . { A = g_ptr_array_new(); }
|
|
|
|
transform_list(A) ::= transform_list(B) COMMA transform(C). {
|
|
A = B;
|
|
g_ptr_array_add(B,C);
|
|
}
|
|
|
|
transform_list(A) ::= transform(B). {
|
|
A = g_ptr_array_new();
|
|
g_ptr_array_add(A,B);
|
|
}
|
|
|
|
transform(A) ::= NAME(B). {
|
|
AVPL_Transf* t;
|
|
|
|
if (( t = (AVPL_Transf *)g_hash_table_lookup(mc->transfs,B) )) {
|
|
A = t;
|
|
} else {
|
|
configuration_error(mc,"There's no such Transformation: %s",B);
|
|
}
|
|
}
|
|
|
|
avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; }
|
|
avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); }
|
|
|
|
avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); }
|
|
avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); }
|
|
|
|
avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); }
|
|
avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); }
|
|
avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); }
|
|
|
|
avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = g_strdup_printf("%s|%s",B,C); }
|
|
avp_oneoff(A) ::= value(B). { A = g_strdup(B); }
|
|
|
|
value(A) ::= QUOTED(B). { A = g_strdup(B); }
|
|
value(A) ::= NAME(B). { A = g_strdup(B); }
|
|
value(A) ::= FLOATING(B). { A = g_strdup(B); }
|
|
value(A) ::= INTEGER(B). { A = g_strdup(B); }
|
|
value(A) ::= DOTED_IP(B). { A = g_strdup(B); }
|
|
value(A) ::= COLONIZED(B). { A = recolonize(mc,B); }
|
|
|