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