ASN.1
Previous:
Macros Up: Additional Features Next:
Parameterization
To introduce the concept of a table constraint, let's say we have a protocol where message types are identified by a message code and some messages might not be understood or supported by the recipient. Therefore, each message includes a criticality code, telling the recipient how to respond if a message cannot be handled: whether to ignore the message, to send back a rejection message, or to send back a notification message.
In ASN.1, we might define our messages like so:
Message ::= SEQUENCE { code INTEGER(0..255), criticality ENUMERATED {reject, notify, ignore}, data CHOICE { setup Setup, event Event, info Info } }
Now suppose message criticality is not arbitrary but is specified by the protocol. The protocol designers might use the following table to list the various message codes, the criticality, and the data that goes with that type of message:
message code | criticality | message data |
---|---|---|
1 | reject | Setup |
2 | notify | Event |
3 | ignore | Info |
Our goal is to use a table constraint to ensure that messages conform to the information represented by this table - for example, that a message with code 1 is sent with criticality "reject" and that it contains Setup data.
The first step is to specify an information object class,
frequently referred to simply as a "class". The class describes the format
of the table by defining the columns. A CLASS
definition uses a syntax
similar to that of a SEQUENCE
. Here's our class definition:
MESSAGE-CLASS ::= CLASS { &code INTEGER(0..255) UNIQUE, &criticality ENUMERATED {reject, notify, ignore} DEFAULT ignore, &Data } WITH SYNTAX { MESSAGE &Data CODE &code [CRITICALITY &criticality] }A few things to notice in the class definition:
&code
and &criticality
both have types. Fields with a fixed type MUST begin with
a lowercase letter (after the ampersand).
&Data
does not have a type, which means it is an
open type field. Open type fields MUST begin with an uppercase letter
(after the ampersand).Now that we have the format of our table, we need to specify some rows.
An information object is an instance of an information object class,
and it represents a row in the table. The WITH SYNTAX
clause
in our class definition specifies the syntax for defining information objects of
that class. We'll define three information objects, one for each row of
our table:
setupMessage MESSAGE-CLASS ::= { MESSAGE Setup CODE 1 CRITICALITY reject } eventMessage MESSAGE-CLASS ::= { MESSAGE Event CODE 2 CRITICALITY notify } infoMessage MESSAGE-CLASS ::= { MESSAGE Info CODE 3 CRITICALITY ignore }
On the left, the information object definition has the name of the object and the name of its class. On the right, we have the actual object. Note:
&code
and &criticality
), the information object provides
a value of the given type. For class fields that are open type
(such as &Data
), the information object provides a
Type
.
&code
was defined as UNIQUE
,
each information object in a given information object set must have a
unique value for &code
. Here is the definition for our
set:
Messages MESSAGE-CLASS ::= { setupMessage | eventMessage | infoMessage }
The notation for the information object set is similar to the notation for a value set. On the left, we have the set name and the class name; on the right, the elements of the set are listed. The name of an information object set MUST begin with an uppercase letter.
Finally, we can now rewrite Message
to use table constraints:
Message ::= SEQUENCE { code MESSAGE-CLASS.&code ({Messages}), criticality MESSAGE-CLASS.&criticality ({Messages}{@code}), data MESSAGE-CLASS.&Data ({Messages}{@code}) }
First, notice that the type for each of our components is now specified by
reference to a field in class MESSAGE-CLASS
.
The type of the component is the type of the referenced field. Thus,
component code
has type INTEGER(0..255)
and
component data
is open type.
Next, notice that each component has a constraint, specified inside
parentheses as always; each of these constraints is a table constraint. The "table"
of the table constraint is specified as an information object
set inside curly braces. In our case, the "table" is the information object set
Messages
. Messages
therefore essentially gives
us a table that our SEQUENCE
values will have to conform to;
it's the table we saw in the concept section. The constraining information object set for a table constraint
MUST have objects of the class referenced by the constrained component.
Thus, Messages
MUST contain objects of class MESSAGE-CLASS
.
Not only does each component's type depend on which class field is referenced,
but this also establishes the correspondence between the SEQUENCE
components and the columns in the constraining table. For example,
component code
refers to field &code
, so it
is constrained by the table constraint to being one of the values given for
&code
in the information objects in set Messages
.
This means code
is constrained to the values 1, 2, or 3.
As already mentioned, data
is open type. Without the table
constraint, data
could have a value of literally any type, but
the table constraint changes that. Look again at data
's constraint:
data MESSAGE-CLASS.&Data ({Messages}{@code})
Inside the first set of curly braces, we have the constraining information
object set. If we stopped there and omitted the next set of curly braces, then
that would mean data
would be constrained to a value of any of the types
that are specified for &Data
in the set Messages
, i.e.
types Setup
, Event
, or Info
.
That wouldn't be very useful (the exact type would be unknown). So, inside the second set of curly braces,
we have an "at-notation" that refers to another component, namely, code
.
This means that the value of code
and the type of value
must
correspond to the same row in the constraining table, or, in other words, to the
same information object. So, if code
is 1, then data
must be a
value of type Setup
, in accordance with object setupMessage
,
in set Messages
. The same constraint and logic applies to component
criticality
. Thus, if code
is 1, then criticality
must be reject
.
You now know how table constraints work.
A final thing to know is that information object sets can be extensible.
If we wanted Messages
to be extensible, we would have
written:
Messages MESSAGE-CLASS ::= { setupMessage | eventMessage | infoMessage, ... }
When an extensible information object set is used in a table constraint, it
basically means that there are unspecified legal values. In our case, it
means that it is NOT an error if code
does not take
on a value found in the table (i.e. is not equal to the &code
value of some object in the set). However, in that case,
the type for component data
would be unknown. It is not a
problem for an open type to have an unknown type, because open types are
encoded such that a decoder can always locate the end of the open
type data.
Previous: Macros Up: Additional Features Next: Parameterization
This site was developed from: Computer Networks and Open Systems An Application Development Perspective by Lillian N. Cassel Richard H. Austing Jones & Bartlett Publisher ISBN 0-7637-1122-5 |
This site is hosted by: Real World ASN.1 and XML Solutions |