1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
%% -*- erlang -*-
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
%% A grammar for dictionary specification.
%%
Nonterminals
application_id avp avp_code avp_def avp_defs avp_flags avp_header
avp_header_tok avp_name avp_names avp_ref avp_spec avp_type
avp_vendor avps bit bits command_def command_id diameter_name
dictionary enum_def enum_defs group_def group_defs header header_tok
ident idents message_defs module qual section sections.
Terminals
avp_types avp_vendor_id codecs custom_types define enum grouped
id inherits messages name prefix vendor
number word
'{' '}' '<' '>' '[' ']' '*' '::=' ':' ',' '-'
code
'answer-message'
'AVP' 'AVP-Header'
'Diameter' 'Diameter-Header' 'Header'
'REQ' 'PXY' 'ERR'.
Rootsymbol dictionary.
Endsymbol '$end'.
%% ===========================================================================
dictionary -> sections : '$1'.
sections -> '$empty' : [].
sections -> section sections : ['$1' | '$2'].
section -> name ident : ['$1', '$2'].
section -> prefix ident : ['$1', '$2'].
section -> id number : ['$1', '$2'].
section -> vendor number ident : ['$1', '$2', '$3'].
section -> inherits module avp_names : ['$1', '$2' | '$3'].
section -> avp_types avp_defs : ['$1' | '$2'].
section -> avp_vendor_id number avp_names : ['$1', '$2' | '$3'].
section -> custom_types module avp_names : ['$1', '$2' | '$3'].
section -> codecs module avp_names : ['$1', '$2' | '$3'].
section -> messages message_defs : ['$1' | '$2'].
section -> grouped group_defs : ['$1' | '$2'].
section -> enum ident enum_defs : ['$1', '$2' | '$3'].
section -> define ident enum_defs : ['$1', '$2' | '$3'].
%% =====================================
module -> ident : '$1'.
avp_names -> idents : '$1'. %% Note: not 'AVP'
avp_defs -> '$empty' : [].
avp_defs -> avp_def avp_defs : ['$1' | '$2'].
avp_def -> ident number avp_type avp_flags : ['$1', '$2', '$3', '$4'].
avp_type -> ident : '$1'.
idents -> '$empty' : [].
idents -> ident idents : ['$1' | '$2'].
avp_flags -> '-' :
{_, Lineno} = '$1',
{word, Lineno, ""}.
avp_flags -> ident :
'$1'.
%% Could support lowercase here if there's a use for distinguishing
%% between Must and Should in the future in deciding whether or not
%% to set a flag.
ident -> word : '$1'.
%% Don't bother mapping reserved words to make these usable in this
%% context. That an AVP can't be named Diameter-Header is probably no
%% great loss, and that it can't be named AVP may even save someone
%% from themselves. (Temporarily at least.)
group_defs -> '$empty' : [].
group_defs -> group_def group_defs : ['$1' | '$2'].
message_defs -> '$empty' : [].
message_defs -> command_def message_defs : ['$1' | '$2'].
enum_defs -> '$empty' : [].
enum_defs -> enum_def enum_defs : ['$1' | '$2'].
enum_def -> ident number : ['$1', '$2'].
%% =====================================
%% 3.2. Command Code ABNF specification
%%
%% Every Command Code defined MUST include a corresponding ABNF
%% specification, which is used to define the AVPs that MUST or MAY be
%% present when sending the message. The following format is used in
%% the definition:
%% command-def = <command-name> "::=" diameter-message
%%
%% command-name = diameter-name
%%
%% diameter-name = ALPHA *(ALPHA / DIGIT / "-")
%%
%% diameter-message = header [ *fixed] [ *required] [ *optional]
%% answer-message is a special case.
command_def -> 'answer-message' '::=' '<' header_tok ':' code
',' 'ERR' '[' 'PXY' ']' '>'
avps
: ['$1', false | '$13'].
command_def -> diameter_name '::=' header avps
: ['$1', '$3' | '$4'].
%% Ensure the order fixed/required/optional by semantic checks rather
%% than grammatically since the latter requires more lookahead: don't
%% know until after a leading qual which of the three it is that's
%% being parsed.
diameter_name -> ident : '$1'.
%% header = "<" "Diameter Header:" command-id
%% [r-bit] [p-bit] [e-bit] [application-id] ">"
%%
%% command-id = 1*DIGIT
%% ; The Command Code assigned to the command
%%
%% r-bit = ", REQ"
%% ; If present, the 'R' bit in the Command
%% ; Flags is set, indicating that the message
%% ; is a request, as opposed to an answer.
%%
%% p-bit = ", PXY"
%% ; If present, the 'P' bit in the Command
%% ; Flags is set, indicating that the message
%% ; is proxiable.
%%
%% e-bit = ", ERR"
%% ; If present, the 'E' bit in the Command
%% ; Flags is set, indicating that the answer
%% ; message contains a Result-Code AVP in
%% ; the "protocol error" class.
%%
%% application-id = 1*DIGIT
header -> '<' header_tok ':' command_id bits application_id '>'
: ['$4', '$5', '$6'].
command_id -> number : '$1'.
%% Accept both the form of the base definition and the typo (fixed in
%% 3588bis) of the grammar.
header_tok -> 'Diameter' 'Header'.
header_tok -> 'Diameter-Header'.
bits -> '$empty' : [].
bits -> ',' bit bits : ['$2' | '$3'].
%% ERR only makes sense for answer-message so don't allow it here
%% (despite 3588).
bit -> 'REQ' : '$1'.
bit -> 'PXY' : '$1'.
application_id -> '$empty' : false.
application_id -> number : '$1'.
%% fixed = [qual] "<" avp-spec ">"
%% ; Defines the fixed position of an AVP
%%
%% required = [qual] "{" avp-spec "}"
%% ; The AVP MUST be present and can appear
%% ; anywhere in the message.
%%
%% optional = [qual] "[" avp-name "]"
%% ; The avp-name in the 'optional' rule cannot
%% ; evaluate to any AVP Name which is included
%% ; in a fixed or required rule. The AVP can
%% ; appear anywhere in the message.
%% ;
%% ; NOTE: "[" and "]" have a slightly different
%% ; meaning than in ABNF (RFC 5234]). These braces
%% ; cannot be used to express optional fixed rules
%% ; (such as an optional ICV at the end). To do this,
%% ; the convention is '0*1fixed'.
avps -> '$empty' : [].
avps -> avp avps : ['$1' | '$2'].
avp -> avp_ref : [false | '$1'].
avp -> qual avp_ref : ['$1' | '$2'].
avp_ref -> '<' avp_spec '>' : [$<, '$2'].
avp_ref -> '{' avp_name '}' : [${, '$2'].
avp_ref -> '[' avp_name ']' : [$[, '$2'].
%% Note that required can be an avp_name, not just avp_spec. 'AVP'
%% is specified as required by Failed-AVP for example.
%% qual = [min] "*" [max]
%% ; See ABNF conventions, RFC 5234 Section 4.
%% ; The absence of any qualifiers depends on
%% ; whether it precedes a fixed, required, or
%% ; optional rule. If a fixed or required rule has
%% ; no qualifier, then exactly one such AVP MUST
%% ; be present. If an optional rule has no
%% ; qualifier, then 0 or 1 such AVP may be
%% ; present. If an optional rule has a qualifier,
%% ; then the value of min MUST be 0 if present.
%%
%% min = 1*DIGIT
%% ; The minimum number of times the element may
%% ; be present. If absent, the default value is zero
%% ; for fixed and optional rules and one for required
%% ; rules. The value MUST be at least one for for
%% ; required rules.
%%
%% max = 1*DIGIT
%% ; The maximum number of times the element may
%% ; be present. If absent, the default value is
%% ; infinity. A value of zero implies the AVP MUST
%% ; NOT be present.
qual -> number '*' number : {'$1', '$3'}.
qual -> number '*' : {'$1', true}.
qual -> '*' number : {true, '$2'}.
qual -> '*' : true.
%% avp-spec = diameter-name
%% ; The avp-spec has to be an AVP Name, defined
%% ; in the base or extended Diameter
%% ; specifications.
avp_spec -> diameter_name : '$1'.
%% avp-name = avp-spec / "AVP"
%% ; The string "AVP" stands for *any* arbitrary AVP
%% ; Name, not otherwise listed in that command code
%% ; definition. Addition this AVP is recommended for
%% ; all command ABNFs to allow for extensibility.
avp_name -> 'AVP' : '$1'.
avp_name -> avp_spec : '$1'.
%% The following is a definition of a fictitious command code:
%%
%% Example-Request ::= < Diameter Header: 9999999, REQ, PXY >
%% { User-Name }
%% * { Origin-Host }
%% * [ AVP ]
%% =====================================
%% 4.4. Grouped AVP Values
%%
%% The Diameter protocol allows AVP values of type 'Grouped'. This
%% implies that the Data field is actually a sequence of AVPs. It is
%% possible to include an AVP with a Grouped type within a Grouped type,
%% that is, to nest them. AVPs within an AVP of type Grouped have the
%% same padding requirements as non-Grouped AVPs, as defined in Section
%% 4.
%%
%% The AVP Code numbering space of all AVPs included in a Grouped AVP is
%% the same as for non-grouped AVPs. Receivers of a Grouped AVP that
%% does not have the 'M' (mandatory) bit set and one or more of the
%% encapsulated AVPs within the group has the 'M' (mandatory) bit set
%% MAY simply be ignored if the Grouped AVP itself is unrecognized. The
%% rule applies even if the encapsulated AVP with its 'M' (mandatory)
%% bit set is further encapsulated within other sub-groups; i.e. other
%% Grouped AVPs embedded within the Grouped AVP.
%%
%% Every Grouped AVP defined MUST include a corresponding grammar, using
%% ABNF [RFC5234] (with modifications), as defined below.
%% grouped-avp-def = <name> "::=" avp
%%
%% name-fmt = ALPHA *(ALPHA / DIGIT / "-")
%%
%% name = name-fmt
%% ; The name has to be the name of an AVP,
%% ; defined in the base or extended Diameter
%% ; specifications.
%%
%% avp = header [ *fixed] [ *required] [ *optional]
group_def -> ident '::=' avp_header avps : ['$1', '$3' | '$4'].
%% header = "<" "AVP-Header:" avpcode [vendor] ">"
%%
%% avpcode = 1*DIGIT
%% ; The AVP Code assigned to the Grouped AVP
%%
%% vendor = 1*DIGIT
%% ; The Vendor-ID assigned to the Grouped AVP.
%% ; If absent, the default value of zero is
%% ; used.
avp_header -> '<' avp_header_tok ':' avp_code avp_vendor '>'
: ['$4', '$5'].
avp_header_tok -> 'AVP-Header'.
avp_header_tok -> 'AVP' 'Header'.
avp_code -> number : '$1'.
avp_vendor -> '$empty' : false.
avp_vendor -> number : '$1'.
|