NGAP - NG Application Protocol¶
Removed in version 1.6.0: pcapkit.protocols.application.ngap._PYCRATE,
pcapkit.protocols.application.ngap._PDU_LOCK,
pcapkit.protocols.application.ngap.load_pycrate,
pcapkit.protocols.application.ngap.PDUKind,
pcapkit.protocols.application.ngap.Criticality,
pcapkit.protocols.application.ngap._convert and
pcapkit.protocols.application.ngap._revert, with no alias: they are in this
module, and pcapkit.protocols.application.ngap exports the protocol class
alone (#2534).
pcapkit.protocols.application.ngap.protocol contains
NGAP,
which implements an extractor for the NG Application Protocol
(NGAP) [*], as specified in 3GPP TS 38.413, and the enumerations its
data models report with:
PDUKind,
Criticality,
ProcedureCode and
ProtocolIE.
NGAP is the control plane between a 5G RAN node (gNB or ng-eNB) and an AMF.
It runs over SCTP and is named by the DATA chunk’s payload protocol
identifier rather than by a port, so NGAP is registered on
SCTP.__proto__ under
PPID 60
(PayloadProtocolIdentifier_3GPP_NG_Application_Protocol)
and PPID 66
(PayloadProtocolIdentifier_3GPP_NGAP_over_DTLS_over_SCTP);
see
pcapkit.foundation.registry.protocols.transport.register_sctp().
An SCTP DATA chunk that names NGAP carries exactly one NGAP-PDU, encoded
in aligned PER (ALIGNED PACKED ENCODING RULES, APER). There is no
header to read and no framing to resolve: the whole payload is the encoding,
and none of its structure is visible until an ASN.1 decoder has run over it.
Decoding needs the optional pycrate dependency
(pip install pypcapkit[NGAP]). Without it pcapkit still works, and an
NGAP payload falls back to Raw as an
unregistered PPID’s does:
_import_next_layer(), which
SCTP inherits, is wrapped in
beholder().
- class pcapkit.protocols.application.ngap.protocol.NGAP(file=None, length=None, **kwargs)[source]¶
Bases:
Application[NGAP,NGAP]This class implements NG Application Protocol.
Changed in version 1.6.0:
procedureandcriticalityofmake()take a member or anintcode, resolved with the enumeration’sget; a name or aboolraisesProtocolError, where a name resolved to its member and aboolwas taken as a code (#2594).- property length: int¶
Header length of current protocol.
NGAP prefixes its payload with nothing and carries no next layer, so the whole
NGAP-PDUis the header and this is its length. That is notself.__length_hint__, which reports the four-octet prefix common to every PDU rather than this PDU’s size.
- read(length=None, **kwargs)[source]¶
Read NG Application Protocol (NGAP).
- Parameters:
- Return type:
- Returns:
Parsed packet data.
- Raises:
ProtocolError – If
pycrateis not installed, if the payload is not a well formed aligned PERNGAP-PDU, or if octets follow theNGAP-PDU. A whole octet left over is not part of it: an SCTP DATA chunk holds one whole message (RFC 9260 §1.3, §3.3.1), and APER pads to the octet (X.691 (02/2021) §11.1.4-5).
- make(kind=PDUKind.INITIATING_MESSAGE, procedure=None, criticality=Criticality.reject, message=None, value=None, data=None, **kwargs)[source]¶
Make (construct) packet data.
- Parameters:
kind (
PDUKind|str) – WhichNGAP-PDUalternative to construct.procedure (
ProcedureCode|int|None) – Procedure code.criticality (
Criticality|int) – Criticality of the procedure.message (
str|None) – Name of the message type, e.g.NGSetupRequest.value (
Any) – Message body, either asSequencefrom a previousread()or as the plain Python valuepycrateexpects.data (
bytes|None) – Pre-encodedNGAP-PDU. When given, it is used verbatim and every other argument is ignored, which is also the only path that does not needpycrate.**kwargs (
Any) – Arbitrary keyword arguments.
- Return type:
- Returns:
Constructed packet data.
- Raises:
ProtocolError – If
datais not given and eitherprocedureormessageis missing, ifprocedure(0..255) orcriticality(two bits) is a name, abool, or a member or code its field cannot carry, ifpycrateis not installed, or if the arguments do not describe a message the specification can encode.
- __length_hint__()[source]¶
Return an estimated length for the object.
Every
NGAP-PDUopens with the same four octets under aligned PER – theCHOICEindex, the procedure code, the criticality, and the first octet of the open type’s length determinant – so four is the fixed prefix NGAP has in place of a header. It is not a minimum PDU length: the smallest completeNGAP-PDUmeasured here, a message whoseprotocolIEslist is empty, is seven octets.- Return type:
Literal[4]
- classmethod __index__()[source]¶
Numeral registry index of the protocol.
- Return type:
- Returns:
Numeral registry index of the protocol in IANA service names and port numbers: SCTP port 38412, the port of
SCTP.ng_controlas anint.SCTP.__proto__dispatches by payload protocol identifier rather than by port, so this value keys no dispatch (The Registry Index).
Decoder Dependency¶
pycrate is used rather than a PER codec of our own. It
ships NGAP already compiled, at pycrate_asn1dir/NGAP.py, so the 3GPP
ASN.1 source does not have to be vendored here and tracked across releases; and
it is pure Python, with no compiled extension to build on any platform.
Decoding costs 0.15 ms per PDU, the same order as pcapkit’s own
per-packet cost, so the generic strategy below is not paying for the
convenience.
Generic Conversion¶
The decoded value tree is mapped into Info
objects structurally, by ASN.1 shape rather than by procedure:
ASN.1 / |
|
|---|---|
|
|
|
|
|
|
|
|
|
That is a deliberate trade: every elementary procedure and protocol IE the
decoder knows is converted, and a new 3GPP release needs no code change here;
what is given up is per-IE typing, so an IE’s value keeps the specification’s
own shape rather than a pcapkit-specific model. The PDU kind, procedure
code, criticality, message type name and IE list are first-class fields on
NGAP regardless.
Known Limitations¶
PPID 66 payloads are not decoded. NGAP over DTLS over SCTP wraps the
NGAP-PDUin a DTLS record, andSCTP.__proto__maps PPID 66 toNGAPrather than throughDTLS, so the bytes reachingNGAP.read()are not an APER encoding. The PPID is registered so that it is named rather than anonymous; the payload itself degrades toRaw.The specification version is that of the installed decoder, not this package’s. The IE and procedure enumerations were generated from
NGAP_Constantsofpycrate0.8.1 (Release-18-era). Apycratethat carries a newer NGAP will decode values thatProcedureCodeandProtocolIEdo not name. Such a value resolves to a non-registering member calledUnassignedrather than failing or adding a member to either enumeration.NGAP over a fragmented SCTP association is not reassembled. A DATA chunk is decoded on its own, so an
NGAP-PDUsplit across chunks by SCTP fragmentation fails to decode rather than being reassembled first.Private IEs (
PrivateMessage) carry no schema. Their contents are vendor defined, so the generic conversion reports whatever ASN.1 shape the encoding declares and cannot name the fields.
Auxiliary Functions¶
- pcapkit.protocols.application.ngap.protocol.load_pycrate()[source]¶
Load the optional
pycrateNGAP-PDUobject.- Return type:
- Returns:
pycrate_asn1dir.NGAP.NGAP_PDU_Descriptions.NGAP_PDU, theCHOICEoverinitiatingMessage/successfulOutcome/unsuccessfulOutcomethat is the entry point of the compiled specification, orNonewhenpycrateis not installed.
Notes
The import is attempted at most once and the outcome is cached. It is not free even when it succeeds –
pycrate_asn1dir.NGAPis a 4.9 MB module – which is the other reason it happens here rather than at module import: neitherimport pcapkitnor the documentation build should pay for it.
- pcapkit.protocols.application.ngap.protocol._convert(value)[source]¶
Convert a
pycratedecoded value intopcapkitdata models.- Parameters:
value (
Any) – A node of the tree returned byNGAP_PDU.get_val().- Return type:
- Returns:
The same tree, with mappings as
Sequence,CHOICEpairs asChoice, andBIT STRINGpairs asBitString.
Notes
The 2-tuple shapes are told apart by their first element, which is unambiguous:
pycratespells aCHOICEas(name, value)with astrname and aBIT STRINGas(bits, length)with twoint. Any other tuple is passed through with its members converted, so an ASN.1 construct not listed above degrades to its own shape rather than being mangled into one of these.
- pcapkit.protocols.application.ngap.protocol._revert(value)[source]¶
Convert
pcapkitdata models back into apycratevalue.- Parameters:
value (
Any) – A node of a tree produced by_convert(), or the equivalent plain Python value.- Return type:
- Returns:
The same tree in the shape
NGAP_PDU.set_val()expects.
Auxiliary Data¶
- class pcapkit.protocols.application.ngap.protocol.PDUKind(*values)[source]¶
Bases:
EnumLookup,StrEnumWhich alternative of the
NGAP-PDUCHOICEa PDU is.The values are spelled as the ASN.1 identifiers, so that a name decoded by
pycrateresolves by value.Built on
EnumLookup, the lookup contract shared by every non-registry enumeration (#877). The class defines neithergetnor_missing_of its own.- INITIATING_MESSAGE = 'initiatingMessage'¶
A procedure’s request, or a class 2 procedure’s only message.
- SUCCESSFUL_OUTCOME = 'successfulOutcome'¶
A class 1 procedure’s successful response.
- UNSUCCESSFUL_OUTCOME = 'unsuccessfulOutcome'¶
A class 1 procedure’s unsuccessful response.
- class pcapkit.protocols.application.ngap.protocol.Criticality(*values)[source]¶
Bases:
EnumLookup,aenum.IntEnum[Criticality] What a receiver must do with an IE it does not understand.
Members are named for the ASN.1 identifiers rather than upper-cased, so that
get()resolves a name decoded bypycratethrough the standard member map. The values are theENUMERATEDindices, which is what goes on the wire.Carries no
getof its own: the inheritedget()is used as is, so an unknown name isKeyError-shaped, exactly asE['nosuch']is on a stdlibEnum(#923), and an unknown value raisesValueError.A
defaultis honoured only when it names a registered value:get('nosuch', Criticality.reject)answersreject, andget('nosuch', 99)raises. A member-valueddefaultresolves through_value2member_map_and never through the constructor, so on this closed ASN.1ENUMERATEDwith no extension marker no path can mint a fourth value; see_missing_(), which refuses one outright.- reject = 0¶
Reject the whole message.
- ignore = 1¶
Ignore the IE and carry on.
- notify = 2¶
Ignore the IE, carry on, and report it.
- classmethod _missing_(value)[source]¶
Lookup function used when value is not found.
- Parameters:
value (
int) – Value to get enum item.- Raises:
ValueError – Always.
Criticalityis anENUMERATEDwith no extension marker, so a fourth value cannot be encoded and a lookup for one is a bug rather than a newer specification.- Return type:
- pcapkit.protocols.application.ngap.protocol._PYCRATE: Any¶
Cached
NGAP-PDUobject; seeload_pycrate().NotImplementedmeans the import has not been attempted yet,Nonethat it was attempted andpycrateis not installed, and anything else is the loaded object. “Not installed” is kept apart from “not attempted” so that a capture full of NGAP packets does not pay for a failing import on every frame.
- pcapkit.protocols.application.ngap.protocol._PDU_LOCK¶
Guards the module-level
NGAP-PDUobject returned byload_pycrate(). That object is stateful:from_aperstores the decoded value on it andget_valhands back the decoder’s own containers rather than copies, so two decodes running concurrently through it would each see the other’s tree. The lock is held across the conversion, not merely across the decode, for that second reason.
Header Schemas¶
Removed in version 1.6.0: pcapkit.protocols.schema.application.ngap, with no alias: the module moved here
(#2534).
- class pcapkit.protocols.application.ngap.schema.NGAP(data=NO_VALUE, *, __packet__=None, **kwargs)[source]¶
Bases:
SchemaHeader schema for NGAP packet.
NGAP has no header of its own: an SCTP DATA chunk whose payload protocol identifier names NGAP carries exactly one aligned-PER-encoded
NGAP-PDUand nothing else, so there is no length field to read and no framing to resolve. The whole payload is the encoding, and its structure only becomes visible once the ASN.1 decoder has run.
Data Models¶
Removed in version 1.6.0: pcapkit.protocols.data.application.ngap, with no alias: the module moved here
(#2534).
- class pcapkit.protocols.application.ngap.data.NGAP(kind, procedure, criticality, message, ies, value)[source]¶
Bases:
ProtocolData model for NGAP protocol.
The three
NGAP-PDUalternatives –initiatingMessage,successfulOutcomeandunsuccessfulOutcome– carry an identical field set and are distinguished bykindrather than by three near-identical models.- procedure: ProcedureCode¶
Procedure code.
- criticality: Criticality¶
Criticality of the procedure.
- class pcapkit.protocols.application.ngap.data.IE(id, criticality, type, value)[source]¶
Bases:
DataData model for one NGAP protocol information element.
- id: ProtocolIE¶
Protocol IE ID.
- criticality: Criticality¶
Criticality, i.e. what a receiver must do when it does not understand
id.
- class pcapkit.protocols.application.ngap.data.Choice(name, value)[source]¶
Bases:
DataData model for an ASN.1
CHOICEalternative or open type.Both the selected alternative’s name and its value are kept, since the name is the only thing that says which of the alternatives was sent – an
NGAP-PDUcarrying('globalGNB-ID', ...)and one carrying('globalNgENB-ID', ...)are otherwise indistinguishable once the value has been converted.
- class pcapkit.protocols.application.ngap.data.BitString(value, length)[source]¶
Bases:
DataData model for an ASN.1
BIT STRING.A bit string is not a whole number of octets, so its length is carried alongside its value rather than being implied by it –
gNB-IDis a 22-to-32-bit field, and(0x000102, 24)and(0x000102, 32)are different identifiers.
- class pcapkit.protocols.application.ngap.data.Sequence(dict_=None, **kwargs)[source]¶
Bases:
DataData model for an ASN.1
SEQUENCE,SETorSEQUENCE OFmember.Fields are whatever the specification names them, so this model carries no fixed annotations: it is populated from the decoded value tree. ASN.1 identifiers are hyphenated where Python identifiers cannot be, e.g.
gNB-ID, so such fields are reachable by subscription (seq['gNB-ID']) rather than by attribute access.
Footnotes