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