diff --git a/pcapkit/protocols/data/internet/mh.py b/pcapkit/protocols/data/internet/mh.py index d95460ceda..64b83b387a 100644 --- a/pcapkit/protocols/data/internet/mh.py +++ b/pcapkit/protocols/data/internet/mh.py @@ -181,6 +181,9 @@ def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: ' class HomeTestInitMessage(MH): """Data model for MH Home Test Init (HoTI) message type.""" + #: The two reserved octets of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Home init cookie. cookie: 'bytes' #: Mobility options. @@ -188,13 +191,17 @@ class HomeTestInitMessage(MH): if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', - cookie: 'bytes', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... + msg_reserved: 'bytes', cookie: 'bytes', + options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @info_final class CareofTestInitMessage(MH): """Data model for MH Care-of Test Init (CoTI) message type.""" + #: The two reserved octets of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Care-of init cookie. cookie: 'bytes' #: Mobility options. @@ -202,7 +209,8 @@ class CareofTestInitMessage(MH): if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', - cookie: 'bytes', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... + msg_reserved: 'bytes', cookie: 'bytes', + options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @info_final @@ -332,6 +340,9 @@ class BindingErrorMessage(MH): #: Status. status: 'Enum_BindingError' + #: The reserved octet of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Home address. home: 'IPv6Address' #: Mobility options. @@ -339,7 +350,7 @@ class BindingErrorMessage(MH): if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', - status: 'Enum_BindingError', home: 'IPv6Address', + status: 'Enum_BindingError', msg_reserved: 'bytes', home: 'IPv6Address', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @@ -406,12 +417,15 @@ def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: ' class FastNeighborAdvertisementMessage(MH): """Data model for MH Fast Neighbor Advertisement (FNA) message type.""" + #: The two reserved octets of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Mobility options. options: 'OrderedMultiDict[Enum_Option, Option]' if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', - options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... + msg_reserved: 'bytes', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @info_final @@ -507,6 +521,9 @@ def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: ' class HomeAgentSwitchMessage(MH): """Data model for MH Home Agent Switch message type.""" + #: The reserved octet of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Alternate home agent addresses. An empty tuple asks the mobile node to #: run home agent discovery instead. addresses: 'tuple[IPv6Address, ...]' @@ -515,7 +532,7 @@ class HomeAgentSwitchMessage(MH): if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', - addresses: 'tuple[IPv6Address, ...]', + msg_reserved: 'bytes', addresses: 'tuple[IPv6Address, ...]', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @@ -562,6 +579,9 @@ class LocalizedRoutingInitiationMessage(MH): #: Sequence number. seq: 'int' + #: The two reserved octets of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Lifetime. :rfc:`6705#section-10.1` counts this in seconds rather than in #: the units of 4 seconds the binding messages use. lifetime: 'timedelta' @@ -570,7 +590,7 @@ class LocalizedRoutingInitiationMessage(MH): if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', - seq: 'int', lifetime: 'timedelta', + seq: 'int', msg_reserved: 'bytes', lifetime: 'timedelta', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @@ -633,13 +653,16 @@ class UpdateNotificationAcknowledgementMessage(MH): seq: 'int' #: Status. status: 'Enum_UpdateNotificationACKStatus' + #: The three reserved octets of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Mobility options. options: 'OrderedMultiDict[Enum_Option, Option]' if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', seq: 'int', status: 'Enum_UpdateNotificationACKStatus', - options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... + msg_reserved: 'bytes', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @info_final @@ -680,13 +703,16 @@ class SubscriptionQueryMessage(MH): #: Sequence number, counted modulo 256. seq: 'int' + #: The reserved octet of the message body, as captured. Named apart + #: from :attr:`MH.reserved`, the reserved octet of the fixed header. + msg_reserved: 'bytes' #: Mobility options. options: 'OrderedMultiDict[Enum_Option, Option]' if TYPE_CHECKING: def __init__(self, next: 'TransType', length: 'int', type: 'Packet', reserved: 'int', chksum: 'bytes', seq: 'int', - options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... + msg_reserved: 'bytes', options: 'OrderedMultiDict[Enum_Option, Option]') -> 'None': ... @info_final @@ -795,11 +821,13 @@ def __init__(self, type: 'Enum_Option', length: 'int', data: 'bytes') -> 'None': class MobileNetworkPrefixOption(Option): """Data model for Mobile Network Prefix option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Mobile Network Prefix. prefix: 'IPv6Network' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix: 'IPv6Network') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix: 'IPv6Network') -> 'None': ... @info_final @@ -1038,6 +1066,8 @@ def __init__(self, type: 'Enum_Option', length: 'int', code: 'IPv6AddressPrefixC class HomeNetworkPrefixOption(Option): """Data model for MH Home Network Prefix option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Prefix length. prefix_length: 'int' #: Home network prefix. Kept apart from :attr:`prefix_length` rather than @@ -1049,7 +1079,7 @@ class HomeNetworkPrefixOption(Option): prefix: 'IPv6Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address') -> 'None': ... @@ -1070,22 +1100,26 @@ def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'int', hi: 'Enu class AccessTechnologyTypeOption(Option): """Data model for MH Access Technology Type option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Access technology type. att: 'Enum_AccessType' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', att: 'Enum_AccessType') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', att: 'Enum_AccessType') -> 'None': ... @info_final class MNLLIdentifierOption(Option): """Data model for MH Mobile Node Link-layer Identifier option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Link-layer identifier. lli: 'bytes' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', lli: 'bytes') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', lli: 'bytes') -> 'None': ... @info_final @@ -1238,24 +1272,28 @@ def __init__(self, type: 'Enum_Option', length: 'int', force: 'bool', reserved: class IPv4CareofAddressOption(Option): """Data model for MH IPv4 Care-of Address option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: IPv4 care-of address. address: 'IPv4Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', address: 'IPv4Address') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', address: 'IPv4Address') -> 'None': ... @info_final class GREKeyOption(Option): """Data model for MH GRE Key option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: GRE key identifier, or :obj:`None` when the option carries none -- which #: :rfc:`5845#section-6.1` signals by an option length of 2 rather than 6. key: 'Optional[int]' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - key: 'Optional[int]') -> 'None': ... + reserved: 'bytes', key: 'Optional[int]') -> 'None': ... @info_final @@ -1320,11 +1358,13 @@ def __init__(self, type: 'Enum_Option', length: 'int', status: 'Enum_HomeAddress class IPv4DefaultRouterAddressOption(Option): """Data model for MH IPv4 Default-Router Address option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: IPv4 default-router address. address: 'IPv4Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', address: 'IPv4Address') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', address: 'IPv4Address') -> 'None': ... @info_final @@ -1361,12 +1401,14 @@ def __init__(self, type: 'Enum_Option', length: 'int', value: 'bytes') -> 'None' class ContextRequestOption(Option): """Data model for MH Context Request option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Requested contexts. requests: 'tuple[ContextRequest, ...]' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - requests: 'tuple[ContextRequest, ...]') -> 'None': ... + reserved: 'bytes', requests: 'tuple[ContextRequest, ...]') -> 'None': ... @info_final @@ -1377,23 +1419,27 @@ class LMAAddressOption(Option): #: by the RFC with no IANA registry behind them, so this field carries the #: module-local :class:`~pcapkit.protocols.internet.mh.LMAAddressCode`. code: 'LMAAddressCode' + #: The reserved octet, as captured. + reserved: 'bytes' #: Local mobility anchor address. address: 'IPv4Address | IPv6Address | bytes' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', code: 'LMAAddressCode', - address: 'IPv4Address | IPv6Address | bytes') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | IPv6Address | bytes') -> 'None': ... @info_final class MNLLAIIDOption(Option): """Data model for MH Mobile Node Link-local Address Interface Identifier option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Interface identifier. iid: 'bytes' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', iid: 'bytes') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', iid: 'bytes') -> 'None': ... @info_final @@ -1476,37 +1522,43 @@ class TrafficSelectorSuboption(FlowIdentificationSuboption): #: Traffic selector format. ts_format: 'Enum_TrafficSelector' + #: The reserved octet, as captured. + reserved: 'bytes' #: Traffic selector. Its interior is :rfc:`6088` territory and belongs to the #: separate traffic selector format registry, so it is kept opaque. selector: 'bytes' if TYPE_CHECKING: def __init__(self, type: 'Enum_FlowIDSuboption', length: 'int', - ts_format: 'Enum_TrafficSelector', selector: 'bytes') -> 'None': ... + ts_format: 'Enum_TrafficSelector', reserved: 'bytes', selector: 'bytes') -> 'None': ... @info_final class FlowBindingActionSuboption(FlowIdentificationSuboption): """Data model for MH Flow Identification Flow Binding Action sub-option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Flow binding action. action: 'Enum_FlowBindingAction' if TYPE_CHECKING: def __init__(self, type: 'Enum_FlowIDSuboption', length: 'int', - action: 'Enum_FlowBindingAction') -> 'None': ... + reserved: 'bytes', action: 'Enum_FlowBindingAction') -> 'None': ... @info_final class TargetCareofAddressSuboption(FlowIdentificationSuboption): """Data model for MH Flow Identification Target Care-of Address sub-option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Target care-of address. address: 'IPv4Address | IPv6Address | bytes' if TYPE_CHECKING: def __init__(self, type: 'Enum_FlowIDSuboption', length: 'int', - address: 'IPv4Address | IPv6Address | bytes') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | IPv6Address | bytes') -> 'None': ... @info_final @@ -1517,6 +1569,8 @@ class FlowIdentificationOption(Option): fid: 'int' #: Flow priority. fid_pri: 'int' + #: The reserved octet, as captured. + reserved: 'bytes' #: Status. status: 'Enum_FlowIDStatus' #: Sub-options. @@ -1524,7 +1578,7 @@ class FlowIdentificationOption(Option): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', fid: 'int', fid_pri: 'int', - status: 'Enum_FlowIDStatus', + reserved: 'bytes', status: 'Enum_FlowIDStatus', suboptions: 'OrderedMultiDict[Enum_FlowIDSuboption, FlowIdentificationSuboption]') -> 'None': ... @@ -1532,8 +1586,11 @@ def __init__(self, type: 'Enum_Option', length: 'int', fid: 'int', fid_pri: 'int class RedirectCapabilityOption(Option): """Data model for MH Redirect-Capability mobility option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' + if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes') -> 'None': ... @info_final @@ -1590,25 +1647,29 @@ class MNGroupIdentifierOption(Option): #: Sub-type. subtype: 'Enum_MNGroupID' + #: The reserved octet, as captured. + reserved: 'bytes' #: Mobile node group identifier. ``1`` is the default "all sessions" group. group_id: 'int' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', subtype: 'Enum_MNGroupID', - group_id: 'int') -> 'None': ... + reserved: 'bytes', group_id: 'int') -> 'None': ... @info_final class MAGIPv6AddressOption(Option): """Data model for MH MAG IPv6 Address option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Address length, in bits; always 128. address_length: 'int' #: MAG IPv6 address. address: 'IPv6Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', address_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', address_length: 'int', address: 'IPv6Address') -> 'None': ... @@ -1691,12 +1752,14 @@ class ANICivicLocationSuboption(ANISuboption): #: Encoding format; only ``0``, the binary encoding of #: :rfc:`4776#section-3.1`, is defined. format: 'int' + #: The reserved octet, as captured. + reserved: 'bytes' #: Civic location. location: 'bytes' if TYPE_CHECKING: def __init__(self, type: 'Enum_ANISuboption', length: 'int', format: 'int', - location: 'bytes') -> 'None': ... + reserved: 'bytes', location: 'bytes') -> 'None': ... @info_final @@ -1847,11 +1910,13 @@ def __init__(self, type: 'Enum_QoSAttribute', length: 'int', data: 'bytes') -> ' class BitRateAttribute(QoSAttribute): """Data model for the MH Quality-of-Service attributes carrying a bare bit rate.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Bit rate, in **bits** per second. rate: 'int' if TYPE_CHECKING: - def __init__(self, type: 'Enum_QoSAttribute', length: 'int', rate: 'int') -> 'None': ... + def __init__(self, type: 'Enum_QoSAttribute', length: 'int', reserved: 'bytes', rate: 'int') -> 'None': ... @info_final @@ -1876,6 +1941,8 @@ def __init__(self, type: 'Enum_QoSAttribute', length: 'int', service: 'bool', class AllocationRetentionPriorityAttribute(QoSAttribute): """Data model for the MH Allocation-Retention-Priority attribute.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Priority level, 1 through 15, where 1 is the highest. priority_level: 'int' #: Pre-emption capability; ``0`` enabled, ``1`` disabled. @@ -1884,7 +1951,7 @@ class AllocationRetentionPriorityAttribute(QoSAttribute): preemption_vulnerability: 'int' if TYPE_CHECKING: - def __init__(self, type: 'Enum_QoSAttribute', length: 'int', priority_level: 'int', + def __init__(self, type: 'Enum_QoSAttribute', length: 'int', reserved: 'bytes', priority_level: 'int', preemption_capability: 'int', preemption_vulnerability: 'int') -> 'None': ... @@ -1893,6 +1960,8 @@ def __init__(self, type: 'Enum_QoSAttribute', length: 'int', priority_level: 'in class QoSTrafficSelectorAttribute(QoSAttribute): """Data model for the MH QoS-Traffic-Selector attribute.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Traffic selector format. ts_format: 'Enum_TrafficSelector' #: Traffic selector, kept opaque as for @@ -1901,13 +1970,15 @@ class QoSTrafficSelectorAttribute(QoSAttribute): if TYPE_CHECKING: def __init__(self, type: 'Enum_QoSAttribute', length: 'int', - ts_format: 'Enum_TrafficSelector', selector: 'bytes') -> 'None': ... + reserved: 'bytes', ts_format: 'Enum_TrafficSelector', selector: 'bytes') -> 'None': ... @info_final class QoSVendorSpecificAttribute(QoSAttribute): """Data model for the MH QoS-Vendor-Specific attribute.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Vendor ID, an SMI Network Management Private Enterprise Number. vendor: 'int' #: Vendor-administered sub-type. @@ -1916,7 +1987,7 @@ class QoSVendorSpecificAttribute(QoSAttribute): data: 'bytes' if TYPE_CHECKING: - def __init__(self, type: 'Enum_QoSAttribute', length: 'int', vendor: 'int', + def __init__(self, type: 'Enum_QoSAttribute', length: 'int', reserved: 'bytes', vendor: 'int', subtype: 'int', data: 'bytes') -> 'None': ... @@ -1932,19 +2003,23 @@ class QualityOfServiceOption(Option): #: Operational code: ``0`` response, ``1`` allocate, ``2`` de-allocate, #: ``3`` modify, ``4`` query, ``5`` negotiate. oc: 'int' + #: The three reserved octets, as captured. + reserved: 'bytes' #: Quality-of-service attributes. attributes: 'OrderedMultiDict[Enum_QoSAttribute, QoSAttribute]' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', sr_id: 'int', dscp: 'int', oc: 'int', - attributes: 'OrderedMultiDict[Enum_QoSAttribute, QoSAttribute]') -> 'None': ... + reserved: 'bytes', attributes: 'OrderedMultiDict[Enum_QoSAttribute, QoSAttribute]') -> 'None': ... @info_final class LMAUserPlaneAddressOption(Option): """Data model for MH LMA User-Plane Address option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: LMA user-plane address, or :obj:`None` when the option carries none -- #: which is how a mobile access gateway asks for a transport without naming #: an address. @@ -1952,7 +2027,7 @@ class LMAUserPlaneAddressOption(Option): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - address: 'Optional[IPv4Address | IPv6Address]') -> 'None': ... + reserved: 'bytes', address: 'Optional[IPv4Address | IPv6Address]') -> 'None': ... @info_final @@ -1962,12 +2037,14 @@ class MulticastMobilityOption(Option): #: Option code: ``1`` IGMPv3, ``2`` MLDv2, ``3`` IGMPv3 in IGMPv2 #: compatibility mode, ``4`` MLDv2 in MLDv1 compatibility mode. code: 'int' + #: The reserved octet, as captured. + reserved: 'bytes' #: MLD or IGMP report payload, kept opaque. data: 'bytes' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', code: 'int', - data: 'bytes') -> 'None': ... + reserved: 'bytes', data: 'bytes') -> 'None': ... @info_final @@ -2084,18 +2161,22 @@ class MAGIdentifierOption(Option): #: Sub-type, drawn from the mobile node identifier subtype registry. subtype: 'Enum_MNIDSubtype' + #: The reserved octet, as captured. + reserved: 'bytes' #: Identifier, in the form named by :attr:`subtype`. identifier: 'bytes' if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', subtype: 'Enum_MNIDSubtype', - identifier: 'bytes') -> 'None': ... + reserved: 'bytes', identifier: 'bytes') -> 'None': ... @info_final class AnchoredPrefixOption(Option): """Data model for MH Anchored Prefix option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Prefix length. prefix_length: 'int' #: Anchored prefix. Kept apart from :attr:`prefix_length` so that the bits @@ -2104,7 +2185,7 @@ class AnchoredPrefixOption(Option): prefix: 'IPv6Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address') -> 'None': ... @@ -2112,13 +2193,15 @@ def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', class LocalPrefixOption(Option): """Data model for MH Local Prefix option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Prefix length. prefix_length: 'int' #: Local prefix. prefix: 'IPv6Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address') -> 'None': ... @@ -2126,6 +2209,8 @@ def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', class PreviousMAAROption(Option): """Data model for MH Previous MAAR option.""" + #: The reserved octet, as captured. + reserved: 'bytes' #: Prefix length of :attr:`prefix`. prefix_length: 'int' #: Previous MAAR's global address. A full address rather than a prefix, so @@ -2135,7 +2220,7 @@ class PreviousMAAROption(Option): prefix: 'IPv6Address' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', maar: 'IPv6Address', prefix: 'IPv6Address') -> 'None': ... @@ -2165,11 +2250,13 @@ def __init__(self, type: 'Enum_Option', length: 'int', address: 'IPv6Address') - class DLIFLinkLayerAddressOption(Option): """Data model for MH DLIF Link-Layer Address option.""" + #: The two reserved octets, as captured. + reserved: 'bytes' #: Distributed logical interface's link-layer address. lla: 'bytes' if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', lla: 'bytes') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', lla: 'bytes') -> 'None': ... # TODO: Implement other options. diff --git a/pcapkit/protocols/internet/mh.py b/pcapkit/protocols/internet/mh.py index db8750d46a..4c5a6c2059 100644 --- a/pcapkit/protocols/internet/mh.py +++ b/pcapkit/protocols/internet/mh.py @@ -1752,6 +1752,7 @@ def _read_msg_hoti(self, schema: 'Schema_HomeTestInitMessage', *, type=header.type, reserved=header.reserved, chksum=header.chksum, + msg_reserved=schema.reserved, cookie=schema.cookie, options=self._read_mh_options(schema.options) ) @@ -1793,6 +1794,7 @@ def _read_msg_coti(self, schema: 'Schema_CareofTestInitMessage', *, type=header.type, reserved=header.reserved, chksum=header.chksum, + msg_reserved=schema.reserved, cookie=schema.cookie, options=self._read_mh_options(schema.options) ) @@ -2042,6 +2044,7 @@ def _read_msg_be(self, schema: 'Schema_BindingErrorMessage', *, reserved=header.reserved, chksum=header.chksum, status=schema.status, + msg_reserved=schema.reserved, home=schema.home, options=self._read_mh_options(schema.options), ) @@ -2195,6 +2198,7 @@ def _read_msg_fna(self, schema: 'Schema_FastNeighborAdvertisementMessage', *, type=header.type, reserved=header.reserved, chksum=header.chksum, + msg_reserved=schema.reserved, options=self._read_mh_options(schema.options), ) return data @@ -2397,6 +2401,7 @@ def _read_msg_has(self, schema: 'Schema_HomeAgentSwitchMessage', *, type=header.type, reserved=header.reserved, chksum=header.chksum, + msg_reserved=schema.reserved, addresses=tuple(schema.addresses), options=self._read_mh_options(schema.options), ) @@ -2563,6 +2568,7 @@ def _read_msg_lri(self, schema: 'Schema_LocalizedRoutingInitiationMessage', *, reserved=header.reserved, chksum=header.chksum, seq=schema.seq, + msg_reserved=schema.reserved, lifetime=datetime.timedelta(seconds=schema.lifetime), options=self._read_mh_options(schema.options), ) @@ -2702,6 +2708,7 @@ def _read_msg_upa(self, schema: 'Schema_UpdateNotificationAcknowledgementMessage chksum=header.chksum, seq=schema.seq, status=schema.status, + msg_reserved=schema.reserved, options=self._read_mh_options(schema.options), ) return data @@ -2810,6 +2817,7 @@ def _read_msg_sq(self, schema: 'Schema_SubscriptionQueryMessage', *, reserved=header.reserved, chksum=header.chksum, seq=schema.seq, + msg_reserved=schema.reserved, options=self._read_mh_options(schema.options), ) return data @@ -3208,6 +3216,7 @@ def _read_opt_mnp(self, schema: 'Schema_MobileNetworkPrefixOption', *, data = Data_MobileNetworkPrefixOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, prefix=prefix, ) return data @@ -3877,6 +3886,7 @@ def _read_opt_hnp(self, schema: 'Schema_HomeNetworkPrefixOption', *, data = Data_HomeNetworkPrefixOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, prefix_length=schema.prefix_length, prefix=schema.prefix, ) @@ -3949,6 +3959,7 @@ def _read_opt_att(self, schema: 'Schema_AccessTechnologyTypeOption', *, data = Data_AccessTechnologyTypeOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, att=schema.att, ) return data @@ -3994,6 +4005,7 @@ def _read_opt_mn_lli(self, schema: 'Schema_MNLLIdentifierOption', *, data = Data_MNLLIdentifierOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, lli=schema.lli, ) return data @@ -4304,6 +4316,7 @@ def _read_opt_ipv4_coa(self, schema: 'Schema_IPv4CareofAddressOption', *, data = Data_IPv4CareofAddressOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, address=schema.address, ) return data @@ -4344,6 +4357,7 @@ def _read_opt_gre(self, schema: 'Schema_GREKeyOption', *, data = Data_GREKeyOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, key=schema.key if schema.length == 6 else None, ) return data @@ -4518,6 +4532,7 @@ def _read_opt_ipv4_router(self, schema: 'Schema_IPv4DefaultRouterAddressOption', data = Data_IPv4DefaultRouterAddressOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, address=schema.address, ) return data @@ -4620,6 +4635,7 @@ def _read_opt_cr(self, schema: 'Schema_ContextRequestOption', *, data = Data_ContextRequestOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, requests=tuple(requests), ) return data @@ -4661,6 +4677,7 @@ def _read_opt_lmaa(self, schema: 'Schema_LMAAddressOption', *, type=schema.type, length=self._mh_option_length(schema.length), code=LMAAddressCode(schema.code), + reserved=schema.reserved, address=schema.address, ) return data @@ -4698,6 +4715,7 @@ def _read_opt_mn_lla_iid(self, schema: 'Schema_MNLLAIIDOption', *, data = Data_MNLLAIIDOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, iid=schema.iid, ) return data @@ -4868,6 +4886,7 @@ def _read_fid_suboptions( type=code, length=self._mh_option_length(selector.length), ts_format=selector.ts_format, + reserved=selector.reserved, selector=selector.selector, ) elif code == Enum_FlowIDSuboption.Flow_Binding_Action: @@ -4875,6 +4894,7 @@ def _read_fid_suboptions( data = Data_FlowBindingActionSuboption( type=code, length=self._mh_option_length(action.length), + reserved=action.reserved, action=action.action, ) elif code == Enum_FlowIDSuboption.Target_Care_of_Address: @@ -4882,6 +4902,7 @@ def _read_fid_suboptions( data = Data_TargetCareofAddressSuboption( type=code, length=self._mh_option_length(target.length), + reserved=target.reserved, address=target.address, ) else: @@ -4937,6 +4958,7 @@ def _read_opt_fid(self, schema: 'Schema_FlowIdentificationOption', *, length=self._mh_option_length(schema.length), fid=schema.fid, fid_pri=schema.fid_pri, + reserved=schema.reserved, status=schema.status, suboptions=self._read_fid_suboptions(schema.suboptions), ) @@ -4971,6 +4993,7 @@ def _read_opt_rc(self, schema: 'Schema_RedirectCapabilityOption', *, data = Data_RedirectCapabilityOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, ) return data @@ -5142,6 +5165,7 @@ def _read_opt_mn_group(self, schema: 'Schema_MNGroupIdentifierOption', *, type=schema.type, length=self._mh_option_length(schema.length), subtype=schema.subtype, + reserved=schema.reserved, group_id=schema.group_id, ) return data @@ -5187,6 +5211,7 @@ def _read_opt_mag_addr(self, schema: 'Schema_MAGIPv6AddressOption', *, data = Data_MAGIPv6AddressOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, address_length=schema.address_length, address=schema.address, ) @@ -5268,6 +5293,7 @@ def _read_ani_suboptions( type=code, length=self._mh_option_length(civic.length), format=civic.format, + reserved=civic.reserved, location=civic.location, ) elif code == Enum_ANISuboption.MAG_Group_Identifier: @@ -5663,6 +5689,7 @@ def _read_qos_attributes( data = Data_BitRateAttribute( type=code, length=self._mh_option_length(rate.length), + reserved=rate.reserved, rate=rate.rate, ) elif code == Enum_QoSAttribute.Allocation_Retention_Priority: @@ -5670,6 +5697,7 @@ def _read_qos_attributes( data = Data_AllocationRetentionPriorityAttribute( type=code, length=self._mh_option_length(arp.length), + reserved=arp.reserved, priority_level=arp.priority['PL'], preemption_capability=arp.priority['PC'], preemption_vulnerability=arp.priority['PV'], @@ -5679,6 +5707,7 @@ def _read_qos_attributes( data = Data_QoSTrafficSelectorAttribute( type=code, length=self._mh_option_length(selector.length), + reserved=selector.reserved, ts_format=selector.ts_format, selector=selector.selector, ) @@ -5687,6 +5716,7 @@ def _read_qos_attributes( data = Data_QoSVendorSpecificAttribute( type=code, length=self._mh_option_length(vendor.length), + reserved=vendor.reserved, vendor=vendor.vendor, subtype=vendor.subtype, data=vendor.data, @@ -5743,6 +5773,7 @@ def _read_opt_qos(self, schema: 'Schema_QualityOfServiceOption', *, sr_id=schema.sr_id, dscp=schema.tc >> 2, oc=schema.oc, + reserved=schema.reserved, attributes=self._read_qos_attributes(schema.attributes), ) return data @@ -5790,6 +5821,7 @@ def _read_opt_lma_up(self, schema: 'Schema_LMAUserPlaneAddressOption', *, data = Data_LMAUserPlaneAddressOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, address=cast('Optional[IPv4Address | IPv6Address]', schema.address if schema.length != 2 else None), ) @@ -5838,6 +5870,7 @@ def _read_opt_mcast(self, schema: 'Schema_MulticastMobilityOption', *, type=schema.type, length=schema.length * 4 + 4, code=schema.code, + reserved=schema.reserved, data=schema.data, ) return data @@ -6079,6 +6112,7 @@ def _read_opt_mag_id(self, schema: 'Schema_MAGIdentifierOption', *, type=schema.type, length=self._mh_option_length(schema.length), subtype=schema.subtype, + reserved=schema.reserved, identifier=schema.identifier, ) return data @@ -6121,6 +6155,7 @@ def _read_opt_anchored(self, schema: 'Schema_AnchoredPrefixOption', *, data = Data_AnchoredPrefixOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, prefix_length=schema.prefix_length, prefix=schema.prefix, ) @@ -6164,6 +6199,7 @@ def _read_opt_local_prefix(self, schema: 'Schema_LocalPrefixOption', *, data = Data_LocalPrefixOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, prefix_length=schema.prefix_length, prefix=schema.prefix, ) @@ -6220,6 +6256,7 @@ def _read_opt_prev_maar(self, schema: 'Schema_PreviousMAAROption', *, data = Data_PreviousMAAROption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, prefix_length=schema.prefix_length, maar=schema.maar, prefix=schema.prefix, @@ -6350,6 +6387,7 @@ def _read_opt_dlif_lladdr(self, schema: 'Schema_DLIFLinkLayerAddressOption', *, data = Data_DLIFLinkLayerAddressOption( type=schema.type, length=self._mh_option_length(schema.length), + reserved=schema.reserved, lla=schema.lla, ) return data @@ -6593,6 +6631,7 @@ def _make_msg_brr(self, message: 'Optional[Data_BindingRefreshRequestMessage]' = def _make_msg_hoti(self, message: 'Optional[Data_HomeTestInitMessage]' = None, *, cookie: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00', options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_HomeTestInitMessage': """Make MH home test init (HoTI) message type. @@ -6600,6 +6639,8 @@ def _make_msg_hoti(self, message: 'Optional[Data_HomeTestInitMessage]' = None, * message: Message data model. cookie: Home test cookie. options: Mobility options. + msg_reserved: The two reserved octets of the message body as captured, + truncated or zero-filled to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -6607,12 +6648,14 @@ def _make_msg_hoti(self, message: 'Optional[Data_HomeTestInitMessage]' = None, * """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00\x00') cookie = message.cookie options = message.options else: options = options or [] return Schema_HomeTestInitMessage( + reserved=msg_reserved, cookie=cookie, options=self._make_mh_options(options), ) @@ -6620,6 +6663,7 @@ def _make_msg_hoti(self, message: 'Optional[Data_HomeTestInitMessage]' = None, * def _make_msg_coti(self, message: 'Optional[Data_CareofTestInitMessage]' = None, *, cookie: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00', options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_CareofTestInitMessage': """Make MH care-of test init (CoTI) message type. @@ -6627,6 +6671,8 @@ def _make_msg_coti(self, message: 'Optional[Data_CareofTestInitMessage]' = None, message: Message data model. cookie: Care-of test cookie. options: Mobility options. + msg_reserved: The two reserved octets of the message body as captured, + truncated or zero-filled to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -6634,12 +6680,14 @@ def _make_msg_coti(self, message: 'Optional[Data_CareofTestInitMessage]' = None, """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00\x00') cookie = message.cookie options = message.options else: options = options or [] return Schema_CareofTestInitMessage( + reserved=msg_reserved, cookie=cookie, options=self._make_mh_options(options), ) @@ -6887,6 +6935,7 @@ def _make_msg_be(self, message: 'Optional[Data_BindingErrorMessage]' = None, *, status_reversed: 'bool' = False, home: 'IPv6Address | int | str | bytes' = '::', options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_BindingErrorMessage': """Make MH binding error (BE) message type. @@ -6898,6 +6947,8 @@ def _make_msg_be(self, message: 'Optional[Data_BindingErrorMessage]' = None, *, status_reversed: Reverse status code namespace. home: Home address. options: Mobility options. + msg_reserved: The reserved octet of the message body as captured, + truncated or zero-filled to 1 octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -6905,6 +6956,7 @@ def _make_msg_be(self, message: 'Optional[Data_BindingErrorMessage]' = None, *, """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00') status_val = message.status home = message.home options = message.options @@ -6915,6 +6967,7 @@ def _make_msg_be(self, message: 'Optional[Data_BindingErrorMessage]' = None, *, return Schema_BindingErrorMessage( status=status_val, + reserved=msg_reserved, home=home, options=self._make_mh_options(options), ) @@ -7036,12 +7089,15 @@ def _make_msg_fback(self, message: 'Optional[Data_FastBindingAcknowledgmentMessa def _make_msg_fna(self, message: 'Optional[Data_FastNeighborAdvertisementMessage]' = None, *, options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_FastNeighborAdvertisementMessage': """Make MH fast neighbor advertisement (FNA) message type. Args: message: Message data model. options: Mobility options. + msg_reserved: The two reserved octets of the message body as captured, + truncated or zero-filled to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -7049,11 +7105,13 @@ def _make_msg_fna(self, message: 'Optional[Data_FastNeighborAdvertisementMessage """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00\x00') options = message.options else: options = options or [] return Schema_FastNeighborAdvertisementMessage( + reserved=msg_reserved, options=self._make_mh_options(options), ) @@ -7199,6 +7257,7 @@ def _make_msg_hack(self, message: 'Optional[Data_HandoverAcknowledgeMessage]' = def _make_msg_has(self, message: 'Optional[Data_HomeAgentSwitchMessage]' = None, *, addresses: 'Optional[list[IPv6Address | bytes | str | int]]' = None, options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_HomeAgentSwitchMessage': """Make MH home agent switch (HAS) message type. @@ -7207,6 +7266,8 @@ def _make_msg_has(self, message: 'Optional[Data_HomeAgentSwitchMessage]' = None, addresses: Alternate home agent addresses. An empty list is valid and asks the mobile node to run home agent discovery. options: Mobility options. + msg_reserved: The reserved octet of the message body as captured, + truncated or zero-filled to 1 octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -7214,6 +7275,7 @@ def _make_msg_has(self, message: 'Optional[Data_HomeAgentSwitchMessage]' = None, """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00') addresses = cast('list[IPv6Address | bytes | str | int]', list(message.addresses)) options = message.options else: @@ -7222,6 +7284,7 @@ def _make_msg_has(self, message: 'Optional[Data_HomeAgentSwitchMessage]' = None, return Schema_HomeAgentSwitchMessage( count=len(addresses), + reserved=msg_reserved, addresses=addresses, options=self._make_mh_options(options), ) @@ -7342,6 +7405,7 @@ def _make_msg_lri(self, message: 'Optional[Data_LocalizedRoutingInitiationMessag seq: 'int' = 0, lifetime: 'int | timedelta' = 0, options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_LocalizedRoutingInitiationMessage': """Make MH localized routing initiation (LRI) message type. @@ -7353,6 +7417,8 @@ def _make_msg_lri(self, message: 'Optional[Data_LocalizedRoutingInitiationMessag one counts seconds rather than units of 4 seconds, so the value is not scaled. options: Mobility options. + msg_reserved: The two reserved octets of the message body as captured, + truncated or zero-filled to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -7360,6 +7426,7 @@ def _make_msg_lri(self, message: 'Optional[Data_LocalizedRoutingInitiationMessag """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00\x00') seq = message.seq lifetime_val = math.ceil(message.lifetime.total_seconds()) options = message.options @@ -7369,6 +7436,7 @@ def _make_msg_lri(self, message: 'Optional[Data_LocalizedRoutingInitiationMessag return Schema_LocalizedRoutingInitiationMessage( seq=seq, + reserved=msg_reserved, lifetime=lifetime_val, options=self._make_mh_options(options), ) @@ -7489,6 +7557,7 @@ def _make_msg_upa(self, message: 'Optional[Data_UpdateNotificationAcknowledgemen status_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long status_reversed: 'bool' = False, options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00\x00\x00', **kwargs: 'Any') -> 'Schema_UpdateNotificationAcknowledgementMessage': """Make MH update notification acknowledgement (UPA) message type. @@ -7500,6 +7569,8 @@ def _make_msg_upa(self, message: 'Optional[Data_UpdateNotificationAcknowledgemen status_namespace: Status namespace. status_reversed: Reverse status namespace. options: Mobility options. + msg_reserved: The three reserved octets of the message body as captured, + truncated or zero-filled to 3 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -7507,6 +7578,7 @@ def _make_msg_upa(self, message: 'Optional[Data_UpdateNotificationAcknowledgemen """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00\x00\x00') seq = message.seq status_val = message.status # type: Enum_UpdateNotificationACKStatus options = message.options @@ -7518,6 +7590,7 @@ def _make_msg_upa(self, message: 'Optional[Data_UpdateNotificationAcknowledgemen return Schema_UpdateNotificationAcknowledgementMessage( seq=seq, status=status_val, + reserved=msg_reserved, options=self._make_mh_options(options), ) @@ -7587,6 +7660,7 @@ def _make_msg_fbm(self, message: 'Optional[Data_FlowBindingMessage]' = None, *, def _make_msg_sq(self, message: 'Optional[Data_SubscriptionQueryMessage]' = None, *, seq: 'int' = 0, options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None, + msg_reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_SubscriptionQueryMessage': """Make MH subscription query (SQ) message type. @@ -7594,6 +7668,8 @@ def _make_msg_sq(self, message: 'Optional[Data_SubscriptionQueryMessage]' = None message: Message data model. seq: Sequence number, counted modulo 256. options: Mobility options. + msg_reserved: The reserved octet of the message body as captured, + truncated or zero-filled to 1 octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -7601,6 +7677,7 @@ def _make_msg_sq(self, message: 'Optional[Data_SubscriptionQueryMessage]' = None """ if message is not None: + msg_reserved = getattr(message, 'msg_reserved', b'\x00') seq = message.seq options = message.options else: @@ -7608,6 +7685,7 @@ def _make_msg_sq(self, message: 'Optional[Data_SubscriptionQueryMessage]' = None return Schema_SubscriptionQueryMessage( seq=seq, + reserved=msg_reserved, options=self._make_mh_options(options), ) @@ -7979,6 +8057,7 @@ def _make_opt_bad(self, type: 'Enum_Option', option: 'Optional[Data_Authorizatio def _make_opt_mnp(self, type: 'Enum_Option', option: 'Optional[Data_MobileNetworkPrefixOption]' = None, *, prefix: 'bytes | str | IPv6Network' = '::/0', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_MobileNetworkPrefixOption': """Make MH mobile network prefix option. @@ -7986,6 +8065,8 @@ def _make_opt_mnp(self, type: 'Enum_Option', option: 'Optional[Data_MobileNetwor type: Option type. option: Option data model. prefix: Mobile network prefix. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -7993,6 +8074,7 @@ def _make_opt_mnp(self, type: 'Enum_Option', option: 'Optional[Data_MobileNetwor """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') prefix = option.prefix prefix_val = ipaddress.ip_network(prefix) @@ -8004,6 +8086,7 @@ def _make_opt_mnp(self, type: 'Enum_Option', option: 'Optional[Data_MobileNetwor return Schema_MobileNetworkPrefixOption( type=type, length=18, + reserved=reserved, prefix_length=prefix_length, prefix=prefix_addr, ) @@ -8719,6 +8802,7 @@ def _make_opt_service(self, type: 'Enum_Option', option: 'Optional[Data_ServiceS def _make_opt_hnp(self, type: 'Enum_Option', option: 'Optional[Data_HomeNetworkPrefixOption]' = None, *, prefix_length: 'int' = 64, prefix: 'bytes | str | int | IPv6Address' = '::', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_HomeNetworkPrefixOption': """Make MH home network prefix option. @@ -8727,6 +8811,8 @@ def _make_opt_hnp(self, type: 'Enum_Option', option: 'Optional[Data_HomeNetworkP option: Option data model. prefix_length: Prefix length. prefix: Home network prefix. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -8734,6 +8820,7 @@ def _make_opt_hnp(self, type: 'Enum_Option', option: 'Optional[Data_HomeNetworkP """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') prefix_length = option.prefix_length prefix = option.prefix @@ -8743,6 +8830,7 @@ def _make_opt_hnp(self, type: 'Enum_Option', option: 'Optional[Data_HomeNetworkP return Schema_HomeNetworkPrefixOption( type=type, length=18, + reserved=reserved, prefix_length=prefix_length, prefix=prefix, ) @@ -8789,6 +8877,7 @@ def _make_opt_att(self, type: 'Enum_Option', option: 'Optional[Data_AccessTechno att_default: 'Optional[int]' = None, att_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long att_reversed: 'bool' = False, + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_AccessTechnologyTypeOption': """Make MH access technology type option. @@ -8799,6 +8888,8 @@ def _make_opt_att(self, type: 'Enum_Option', option: 'Optional[Data_AccessTechno att_default: Default access technology type. att_namespace: Access technology type namespace. att_reversed: Reverse access technology type namespace. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -8806,6 +8897,7 @@ def _make_opt_att(self, type: 'Enum_Option', option: 'Optional[Data_AccessTechno """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') att_val = option.att # type: Enum_AccessType else: att_val = self._make_index(att, att_default, namespace=att_namespace, # type: ignore[assignment] @@ -8814,11 +8906,13 @@ def _make_opt_att(self, type: 'Enum_Option', option: 'Optional[Data_AccessTechno return Schema_AccessTechnologyTypeOption( type=type, length=2, + reserved=reserved, att=att_val, ) def _make_opt_mn_lli(self, type: 'Enum_Option', option: 'Optional[Data_MNLLIdentifierOption]' = None, *, lli: 'bytes' = b'', + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_MNLLIdentifierOption': """Make MH mobile node link-layer identifier option. @@ -8826,6 +8920,8 @@ def _make_opt_mn_lli(self, type: 'Enum_Option', option: 'Optional[Data_MNLLIdent type: Option type. option: Option data model. lli: Link-layer identifier. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -8833,11 +8929,13 @@ def _make_opt_mn_lli(self, type: 'Enum_Option', option: 'Optional[Data_MNLLIdent """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') lli = option.lli return Schema_MNLLIdentifierOption( type=type, length=2 + len(lli), + reserved=reserved, lli=lli, ) @@ -9056,6 +9154,7 @@ def _make_opt_nat(self, type: 'Enum_Option', option: 'Optional[Data_NATDetection def _make_opt_ipv4_coa(self, type: 'Enum_Option', option: 'Optional[Data_IPv4CareofAddressOption]' = None, *, address: 'bytes | str | int | IPv4Address' = '0.0.0.0', + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_IPv4CareofAddressOption': """Make MH IPv4 care-of address option. @@ -9063,6 +9162,8 @@ def _make_opt_ipv4_coa(self, type: 'Enum_Option', option: 'Optional[Data_IPv4Car type: Option type. option: Option data model. address: IPv4 care-of address. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -9070,16 +9171,19 @@ def _make_opt_ipv4_coa(self, type: 'Enum_Option', option: 'Optional[Data_IPv4Car """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') address = option.address return Schema_IPv4CareofAddressOption( type=type, length=6, + reserved=reserved, address=address, ) def _make_opt_gre(self, type: 'Enum_Option', option: 'Optional[Data_GREKeyOption]' = None, *, key: 'Optional[int]' = None, + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_GREKeyOption': """Make MH GRE key option. @@ -9088,6 +9192,8 @@ def _make_opt_gre(self, type: 'Enum_Option', option: 'Optional[Data_GREKeyOption option: Option data model. key: GRE key identifier, or :obj:`None` to omit it -- which is what an option length of 2 means on the wire. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -9095,11 +9201,13 @@ def _make_opt_gre(self, type: 'Enum_Option', option: 'Optional[Data_GREKeyOption """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') key = option.key return Schema_GREKeyOption( type=type, length=2 if key is None else 6, + reserved=reserved, key=key, ) @@ -9263,6 +9371,7 @@ def _make_opt_ipv4_hoa_rep(self, type: 'Enum_Option', option: 'Optional[Data_IPv def _make_opt_ipv4_router(self, type: 'Enum_Option', option: 'Optional[Data_IPv4DefaultRouterAddressOption]' = None, *, address: 'bytes | str | int | IPv4Address' = '0.0.0.0', + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_IPv4DefaultRouterAddressOption': """Make MH IPv4 default-router address option. @@ -9270,6 +9379,8 @@ def _make_opt_ipv4_router(self, type: 'Enum_Option', type: Option type. option: Option data model. address: IPv4 default-router address. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -9277,11 +9388,13 @@ def _make_opt_ipv4_router(self, type: 'Enum_Option', """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') address = option.address return Schema_IPv4DefaultRouterAddressOption( type=type, length=6, + reserved=reserved, address=address, ) @@ -9326,6 +9439,7 @@ def _make_opt_ipv4_dhcp(self, type: 'Enum_Option', option: 'Optional[Data_IPv4DH def _make_opt_cr(self, type: 'Enum_Option', option: 'Optional[Data_ContextRequestOption]' = None, *, requests: 'Optional[list[Data_ContextRequest | tuple[Enum_Option | int, bytes]]]' = None, + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_ContextRequestOption': """Make MH context request option. @@ -9334,6 +9448,8 @@ def _make_opt_cr(self, type: 'Enum_Option', option: 'Optional[Data_ContextReques option: Option data model. requests: Requested contexts, each either a data model or a ``(mobility option type, extra data)`` pair. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -9341,6 +9457,7 @@ def _make_opt_cr(self, type: 'Enum_Option', option: 'Optional[Data_ContextReques """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') requests = cast('list[Data_ContextRequest | tuple[Enum_Option | int, bytes]]', list(option.requests)) else: @@ -9365,6 +9482,7 @@ def _make_opt_cr(self, type: 'Enum_Option', option: 'Optional[Data_ContextReques return Schema_ContextRequestOption( type=type, length=2 + len(buffer), + reserved=reserved, requests=bytes(buffer), ) @@ -9374,6 +9492,7 @@ def _make_opt_lmaa(self, type: 'Enum_Option', option: 'Optional[Data_LMAAddressO code_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long code_reversed: 'bool' = False, address: 'bytes | str | int | IPv4Address | IPv6Address' = '::', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_LMAAddressOption': """Make MH local mobility anchor address option. @@ -9386,6 +9505,8 @@ def _make_opt_lmaa(self, type: 'Enum_Option', option: 'Optional[Data_LMAAddressO code_namespace: Option code namespace. code_reversed: Reverse option code namespace. address: Local mobility anchor address. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -9397,6 +9518,7 @@ def _make_opt_lmaa(self, type: 'Enum_Option', option: 'Optional[Data_LMAAddressO """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') code_val = int(option.code) address = option.address else: @@ -9421,11 +9543,13 @@ def _make_opt_lmaa(self, type: 'Enum_Option', option: 'Optional[Data_LMAAddressO type=type, length=6 if addr.version == 4 else 18, code=code_val, + reserved=reserved, address=addr, ) def _make_opt_mn_lla_iid(self, type: 'Enum_Option', option: 'Optional[Data_MNLLAIIDOption]' = None, *, iid: 'bytes' = b'\x00' * 8, + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_MNLLAIIDOption': """Make MH mobile node link-local address interface identifier option. @@ -9433,6 +9557,8 @@ def _make_opt_mn_lla_iid(self, type: 'Enum_Option', option: 'Optional[Data_MNLLA type: Option type. option: Option data model. iid: Interface identifier; exactly 8 octets. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -9440,6 +9566,7 @@ def _make_opt_mn_lla_iid(self, type: 'Enum_Option', option: 'Optional[Data_MNLLA """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') iid = option.iid if len(iid) != 8: @@ -9448,6 +9575,7 @@ def _make_opt_mn_lla_iid(self, type: 'Enum_Option', option: 'Optional[Data_MNLLA return Schema_MNLLAIIDOption( type=type, length=10, + reserved=reserved, iid=iid, ) @@ -9594,30 +9722,38 @@ def _make_fid_suboption(self, code: 'Enum_FlowIDSuboption', selector_opt = cast('Data_TrafficSelectorSuboption', option) ts_format = selector_opt.ts_format # type: Enum_TrafficSelector | int selector = selector_opt.selector + reserved = getattr(selector_opt, 'reserved', b'\x00') else: ts_format = cast('Enum_TrafficSelector | int', kwargs.get('ts_format', Enum_TrafficSelector.IPv6_Binary_Traffic_Selector)) selector = cast('bytes', kwargs.get('selector', b'')) + reserved = cast('bytes', kwargs.get('reserved', b'\x00')) return Schema_TrafficSelectorSuboption( type=code, length=2 + len(selector), - ts_format=cast('Enum_TrafficSelector', ts_format), selector=selector) + ts_format=cast('Enum_TrafficSelector', ts_format), reserved=reserved, + selector=selector) if code == Enum_FlowIDSuboption.Flow_Binding_Action: if option is not None: action = cast('Data_FlowBindingActionSuboption', option).action # type: Enum_FlowBindingAction | int + reserved = getattr(option, 'reserved', b'\x00') else: action = cast('Enum_FlowBindingAction | int', kwargs.get('action', Enum_FlowBindingAction.Add)) + reserved = cast('bytes', kwargs.get('reserved', b'\x00')) return Schema_FlowBindingActionSuboption( - type=code, length=2, action=cast('Enum_FlowBindingAction', action)) + type=code, length=2, reserved=reserved, + action=cast('Enum_FlowBindingAction', action)) if code == Enum_FlowIDSuboption.Target_Care_of_Address: if option is not None: address = cast('Data_TargetCareofAddressSuboption', option).address # type: Any + reserved = getattr(option, 'reserved', b'\x00\x00') else: address = kwargs.get('address', '::') + reserved = cast('bytes', kwargs.get('reserved', b'\x00\x00')) # NOTE: Through ``parse_ip_address`` because the sub-option length # below is derived from the family here, ahead of the schema, so a # bare ``ipaddress.ip_address`` would launder a ``bool`` past the @@ -9625,7 +9761,8 @@ def _make_fid_suboption(self, code: 'Enum_FlowIDSuboption', addr = parse_ip_address( address, f'{self.alias}: [OptNo {code}] invalid target care-of address') return Schema_TargetCareofAddressSuboption( - type=code, length=6 if addr.version == 4 else 18, address=addr) + type=code, length=6 if addr.version == 4 else 18, reserved=reserved, + address=addr) if option is not None: payload = cast('Data_UnassignedFlowIdentificationSuboption', option).data @@ -9642,6 +9779,7 @@ def _make_opt_fid(self, type: 'Enum_Option', option: 'Optional[Data_FlowIdentifi status_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long status_reversed: 'bool' = False, suboptions: 'Optional[FlowIDSuboption | list[Schema_FlowIdentificationSuboption | tuple[Enum_FlowIDSuboption, dict[str, Any]] | bytes]]' = None, + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_FlowIdentificationOption': """Make MH flow identification mobility option. @@ -9655,6 +9793,8 @@ def _make_opt_fid(self, type: 'Enum_Option', option: 'Optional[Data_FlowIdentifi status_namespace: Status namespace. status_reversed: Reverse status namespace. suboptions: Sub-options. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -9662,6 +9802,7 @@ def _make_opt_fid(self, type: 'Enum_Option', option: 'Optional[Data_FlowIdentifi """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') fid = option.fid fid_pri = option.fid_pri status_val = option.status # type: Enum_FlowIDStatus @@ -9680,26 +9821,34 @@ def _make_opt_fid(self, type: 'Enum_Option', option: 'Optional[Data_FlowIdentifi length=length, fid=fid, fid_pri=fid_pri, + reserved=reserved, status=status_val, suboptions=entries, ) - def _make_opt_rc(self, type: 'Enum_Option', option: 'Optional[Data_RedirectCapabilityOption]' = None, + def _make_opt_rc(self, type: 'Enum_Option', option: 'Optional[Data_RedirectCapabilityOption]' = None, *, + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_RedirectCapabilityOption': """Make MH redirect-capability mobility option. Args: type: Option type. option: Option data model. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: Constructed option schema. """ + if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') + return Schema_RedirectCapabilityOption( type=type, length=2, + reserved=reserved, ) def _make_opt_redirect(self, type: 'Enum_Option', option: 'Optional[Data_RedirectOption]' = None, *, @@ -9817,6 +9966,7 @@ def _make_opt_mn_group(self, type: 'Enum_Option', option: 'Optional[Data_MNGroup subtype_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long subtype_reversed: 'bool' = False, group_id: 'int' = 1, + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_MNGroupIdentifierOption': """Make MH mobile node group identifier option. @@ -9828,6 +9978,8 @@ def _make_opt_mn_group(self, type: 'Enum_Option', option: 'Optional[Data_MNGroup subtype_namespace: Sub-type namespace. subtype_reversed: Reverse sub-type namespace. group_id: Mobile node group identifier. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -9835,6 +9987,7 @@ def _make_opt_mn_group(self, type: 'Enum_Option', option: 'Optional[Data_MNGroup """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') subtype_val = option.subtype # type: Enum_MNGroupID group_id = option.group_id else: @@ -9845,12 +9998,14 @@ def _make_opt_mn_group(self, type: 'Enum_Option', option: 'Optional[Data_MNGroup type=type, length=6, subtype=subtype_val, + reserved=reserved, group_id=group_id, ) def _make_opt_mag_addr(self, type: 'Enum_Option', option: 'Optional[Data_MAGIPv6AddressOption]' = None, *, address_length: 'int' = 128, address: 'bytes | str | int | IPv6Address' = '::', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_MAGIPv6AddressOption': """Make MH MAG IPv6 address option. @@ -9860,6 +10015,8 @@ def _make_opt_mag_addr(self, type: 'Enum_Option', option: 'Optional[Data_MAGIPv6 address_length: Address length, in bits; :rfc:`6705#section-11.1` requires 128. address: MAG IPv6 address. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -9867,12 +10024,14 @@ def _make_opt_mag_addr(self, type: 'Enum_Option', option: 'Optional[Data_MAGIPv6 """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') address_length = option.address_length address = option.address return Schema_MAGIPv6AddressOption( type=type, length=18, + reserved=reserved, address_length=address_length, address=address, ) @@ -9974,11 +10133,14 @@ def _make_ani_suboption(self, code: 'Enum_ANISuboption', if option is not None: civic = cast('Data_ANICivicLocationSuboption', option) fmt, location = civic.format, civic.location + octets = getattr(civic, 'reserved', b'\x00') else: fmt = cast('int', kwargs.get('format', 0)) location = cast('bytes', kwargs.get('location', b'')) + octets = cast('bytes', kwargs.get('reserved', b'\x00')) return Schema_ANICivicLocationSuboption( - type=code, length=2 + len(location), format=fmt, location=location) + type=code, length=2 + len(location), format=fmt, reserved=octets, + location=location) if code == Enum_ANISuboption.MAG_Group_Identifier: if option is not None: @@ -10299,9 +10461,11 @@ def _make_qos_attribute(self, code: 'Enum_QoSAttribute', Enum_QoSAttribute.Guaranteed_UL_Bit_Rate): if option is not None: rate = cast('Data_BitRateAttribute', option).rate + octets = getattr(option, 'reserved', b'\x00\x00') else: rate = cast('int', kwargs.get('rate', 0)) - return Schema_BitRateAttribute(type=code, length=6, rate=rate) + octets = cast('bytes', kwargs.get('reserved', b'\x00\x00')) + return Schema_BitRateAttribute(type=code, length=6, reserved=octets, rate=rate) if code == Enum_QoSAttribute.Allocation_Retention_Priority: if option is not None: @@ -10309,12 +10473,14 @@ def _make_qos_attribute(self, code: 'Enum_QoSAttribute', level = arp.priority_level capability = arp.preemption_capability vulnerability = arp.preemption_vulnerability + octets = getattr(arp, 'reserved', b'\x00') else: level = cast('int', kwargs.get('priority_level', 1)) capability = cast('int', kwargs.get('preemption_capability', 0)) vulnerability = cast('int', kwargs.get('preemption_vulnerability', 0)) + octets = cast('bytes', kwargs.get('reserved', b'\x00')) return Schema_AllocationRetentionPriorityAttribute( - type=code, length=2, + type=code, length=2, reserved=octets, priority={'PL': level, 'PC': capability, 'PV': vulnerability}) if code == Enum_QoSAttribute.QoS_Traffic_Selector: @@ -10322,13 +10488,15 @@ def _make_qos_attribute(self, code: 'Enum_QoSAttribute', ts_attr = cast('Data_QoSTrafficSelectorAttribute', option) ts_format = ts_attr.ts_format # type: Enum_TrafficSelector | int selector = ts_attr.selector + octets = getattr(ts_attr, 'reserved', b'\x00') else: ts_format = cast('Enum_TrafficSelector | int', kwargs.get('ts_format', Enum_TrafficSelector.IPv6_Binary_Traffic_Selector)) selector = cast('bytes', kwargs.get('selector', b'')) + octets = cast('bytes', kwargs.get('reserved', b'\x00')) return Schema_QoSTrafficSelectorAttribute( - type=code, length=2 + len(selector), + type=code, length=2 + len(selector), reserved=octets, ts_format=cast('Enum_TrafficSelector', ts_format), selector=selector) if code == Enum_QoSAttribute.QoS_Vendor_Specific_Attribute: @@ -10336,13 +10504,15 @@ def _make_qos_attribute(self, code: 'Enum_QoSAttribute', vendor_attr = cast('Data_QoSVendorSpecificAttribute', option) vendor, subtype, payload = (vendor_attr.vendor, vendor_attr.subtype, vendor_attr.data) + octets = getattr(vendor_attr, 'reserved', b'\x00\x00') else: vendor = cast('int', kwargs.get('vendor', 0)) subtype = cast('int', kwargs.get('subtype', 0)) payload = cast('bytes', kwargs.get('data', b'')) + octets = cast('bytes', kwargs.get('reserved', b'\x00\x00')) return Schema_QoSVendorSpecificAttribute( - type=code, length=7 + len(payload), vendor=vendor, subtype=subtype, - data=payload) + type=code, length=7 + len(payload), reserved=octets, vendor=vendor, + subtype=subtype, data=payload) if option is not None: payload = cast('Data_UnassignedQoSAttribute', option).data @@ -10355,6 +10525,7 @@ def _make_opt_qos(self, type: 'Enum_Option', option: 'Optional[Data_QualityOfSer dscp: 'int' = 0, oc: 'int' = 0, attributes: 'Optional[QoSAttribute | list[Schema_QoSAttribute | tuple[Enum_QoSAttribute, dict[str, Any]] | bytes]]' = None, + reserved: 'bytes' = b'\x00\x00\x00', **kwargs: 'Any') -> 'Schema_QualityOfServiceOption': """Make MH quality-of-service option. @@ -10365,6 +10536,8 @@ def _make_opt_qos(self, type: 'Enum_Option', option: 'Optional[Data_QualityOfSer dscp: Differentiated services code point, 6 bits. oc: Operational code. attributes: Quality-of-service attributes. + reserved: The three reserved octets as captured, truncated or zero- + filled to 3 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -10372,6 +10545,7 @@ def _make_opt_qos(self, type: 'Enum_Option', option: 'Optional[Data_QualityOfSer """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00\x00') sr_id = option.sr_id dscp = option.dscp oc = option.oc @@ -10392,11 +10566,13 @@ def _make_opt_qos(self, type: 'Enum_Option', option: 'Optional[Data_QualityOfSer sr_id=sr_id, tc=dscp << 2, oc=oc, + reserved=reserved, attributes=entries, ) def _make_opt_lma_up(self, type: 'Enum_Option', option: 'Optional[Data_LMAUserPlaneAddressOption]' = None, *, address: 'Optional[bytes | str | int | IPv4Address | IPv6Address]' = None, + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_LMAUserPlaneAddressOption': """Make MH LMA user-plane address option. @@ -10406,6 +10582,8 @@ def _make_opt_lma_up(self, type: 'Enum_Option', option: 'Optional[Data_LMAUserPl address: LMA user-plane address, or :obj:`None` to omit it -- which is how a mobile access gateway asks for a transport without naming an address. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -10413,10 +10591,11 @@ def _make_opt_lma_up(self, type: 'Enum_Option', option: 'Optional[Data_LMAUserPl """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') address = option.address if address is None: - return Schema_LMAUserPlaneAddressOption(type=type, length=2, address=b'') + return Schema_LMAUserPlaneAddressOption(type=type, length=2, reserved=reserved, address=b'') # NOTE: Through ``parse_ip_address`` because the option length below is # derived from the family here, ahead of the schema, so a bare @@ -10430,12 +10609,14 @@ def _make_opt_lma_up(self, type: 'Enum_Option', option: 'Optional[Data_LMAUserPl return Schema_LMAUserPlaneAddressOption( type=type, length=6 if addr.version == 4 else 18, + reserved=reserved, address=addr, ) def _make_opt_mcast(self, type: 'Enum_Option', option: 'Optional[Data_MulticastMobilityOption]' = None, *, code: 'int' = 2, data: 'bytes' = b'', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_MulticastMobilityOption': """Make MH multicast mobility option. @@ -10444,6 +10625,8 @@ def _make_opt_mcast(self, type: 'Enum_Option', option: 'Optional[Data_MulticastM option: Option data model. code: Option code. data: MLD or IGMP report payload, opaque to this module. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -10457,6 +10640,7 @@ def _make_opt_mcast(self, type: 'Enum_Option', option: 'Optional[Data_MulticastM """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') code = option.code data = option.data @@ -10468,6 +10652,7 @@ def _make_opt_mcast(self, type: 'Enum_Option', option: 'Optional[Data_MulticastM type=type, length=len(data) // 4, code=code, + reserved=reserved, data=data, ) @@ -10714,6 +10899,7 @@ def _make_opt_mag_id(self, type: 'Enum_Option', option: 'Optional[Data_MAGIdenti subtype_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long subtype_reversed: 'bool' = False, identifier: 'bytes' = b'', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_MAGIdentifierOption': """Make MH MAG identifier option. @@ -10725,6 +10911,8 @@ def _make_opt_mag_id(self, type: 'Enum_Option', option: 'Optional[Data_MAGIdenti subtype_namespace: Sub-type namespace. subtype_reversed: Reverse sub-type namespace. identifier: Identifier. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -10732,6 +10920,7 @@ def _make_opt_mag_id(self, type: 'Enum_Option', option: 'Optional[Data_MAGIdenti """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') subtype_val = option.subtype # type: Enum_MNIDSubtype identifier = option.identifier else: @@ -10742,12 +10931,14 @@ def _make_opt_mag_id(self, type: 'Enum_Option', option: 'Optional[Data_MAGIdenti type=type, length=2 + len(identifier), subtype=subtype_val, + reserved=reserved, identifier=identifier, ) def _make_opt_anchored(self, type: 'Enum_Option', option: 'Optional[Data_AnchoredPrefixOption]' = None, *, prefix_length: 'int' = 64, prefix: 'bytes | str | int | IPv6Address' = '::', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_AnchoredPrefixOption': """Make MH anchored prefix option. @@ -10756,6 +10947,8 @@ def _make_opt_anchored(self, type: 'Enum_Option', option: 'Optional[Data_Anchore option: Option data model. prefix_length: Prefix length. prefix: Anchored prefix. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -10763,6 +10956,7 @@ def _make_opt_anchored(self, type: 'Enum_Option', option: 'Optional[Data_Anchore """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') prefix_length = option.prefix_length prefix = option.prefix @@ -10772,6 +10966,7 @@ def _make_opt_anchored(self, type: 'Enum_Option', option: 'Optional[Data_Anchore return Schema_AnchoredPrefixOption( type=type, length=18, + reserved=reserved, prefix_length=prefix_length, prefix=prefix, ) @@ -10779,6 +10974,7 @@ def _make_opt_anchored(self, type: 'Enum_Option', option: 'Optional[Data_Anchore def _make_opt_local_prefix(self, type: 'Enum_Option', option: 'Optional[Data_LocalPrefixOption]' = None, *, prefix_length: 'int' = 64, prefix: 'bytes | str | int | IPv6Address' = '::', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_LocalPrefixOption': """Make MH local prefix option. @@ -10787,6 +10983,8 @@ def _make_opt_local_prefix(self, type: 'Enum_Option', option: 'Optional[Data_Loc option: Option data model. prefix_length: Prefix length. prefix: Local prefix. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -10794,6 +10992,7 @@ def _make_opt_local_prefix(self, type: 'Enum_Option', option: 'Optional[Data_Loc """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') prefix_length = option.prefix_length prefix = option.prefix @@ -10803,6 +11002,7 @@ def _make_opt_local_prefix(self, type: 'Enum_Option', option: 'Optional[Data_Loc return Schema_LocalPrefixOption( type=type, length=18, + reserved=reserved, prefix_length=prefix_length, prefix=prefix, ) @@ -10811,6 +11011,7 @@ def _make_opt_prev_maar(self, type: 'Enum_Option', option: 'Optional[Data_Previo prefix_length: 'int' = 64, maar: 'bytes | str | int | IPv6Address' = '::', prefix: 'bytes | str | int | IPv6Address' = '::', + reserved: 'bytes' = b'\x00', **kwargs: 'Any') -> 'Schema_PreviousMAAROption': """Make MH previous MAAR option. @@ -10820,6 +11021,8 @@ def _make_opt_prev_maar(self, type: 'Enum_Option', option: 'Optional[Data_Previo prefix_length: Prefix length of ``prefix``. maar: Previous MAAR's global address. prefix: Mobile node's home network prefix. + reserved: The reserved octet as captured, truncated or zero-filled to 1 + octet. **kwargs: Arbitrary keyword arguments. Returns: @@ -10827,6 +11030,7 @@ def _make_opt_prev_maar(self, type: 'Enum_Option', option: 'Optional[Data_Previo """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00') prefix_length = option.prefix_length maar = option.maar prefix = option.prefix @@ -10837,6 +11041,7 @@ def _make_opt_prev_maar(self, type: 'Enum_Option', option: 'Optional[Data_Previo return Schema_PreviousMAAROption( type=type, length=34, + reserved=reserved, prefix_length=prefix_length, maar=maar, prefix=prefix, @@ -10892,6 +11097,7 @@ def _make_opt_dlif_lla(self, type: 'Enum_Option', option: 'Optional[Data_DLIFLin def _make_opt_dlif_lladdr(self, type: 'Enum_Option', option: 'Optional[Data_DLIFLinkLayerAddressOption]' = None, *, lla: 'bytes' = b'', + reserved: 'bytes' = b'\x00\x00', **kwargs: 'Any') -> 'Schema_DLIFLinkLayerAddressOption': """Make MH DLIF link-layer address option. @@ -10899,6 +11105,8 @@ def _make_opt_dlif_lladdr(self, type: 'Enum_Option', option: 'Optional[Data_DLIF type: Option type. option: Option data model. lla: Distributed logical interface's link-layer address. + reserved: The two reserved octets as captured, truncated or zero-filled + to 2 octets. **kwargs: Arbitrary keyword arguments. Returns: @@ -10906,11 +11114,13 @@ def _make_opt_dlif_lladdr(self, type: 'Enum_Option', option: 'Optional[Data_DLIF """ if option is not None: + reserved = getattr(option, 'reserved', b'\x00\x00') lla = option.lla return Schema_DLIFLinkLayerAddressOption( type=type, length=2 + len(lla), + reserved=reserved, lla=lla, ) diff --git a/pcapkit/protocols/schema/internet/mh.py b/pcapkit/protocols/schema/internet/mh.py index f6b93a304b..9040a12fcb 100644 --- a/pcapkit/protocols/schema/internet/mh.py +++ b/pcapkit/protocols/schema/internet/mh.py @@ -736,7 +736,7 @@ class MobileNetworkPrefixOption(Option, code=Enum_Option.Mobile_Network_Prefix_O prefix: 'IPv6Address' = IPv6AddressField() if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', prefix: 'IPv6Address | int | bytes | str') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address | int | bytes | str') -> 'None': ... @schema_final @@ -1117,7 +1117,7 @@ class HomeNetworkPrefixOption(Option, code=Enum_Option.Home_Network_Prefix_Optio prefix: 'IPv6Address' = IPv6AddressField() if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address | int | bytes | str') -> 'None': ... @@ -1144,7 +1144,7 @@ class AccessTechnologyTypeOption(Option, code=Enum_Option.Access_Technology_Type att: 'Enum_AccessType' = EnumField(length=1, namespace=Enum_AccessType) if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', att: 'Enum_AccessType') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', att: 'Enum_AccessType') -> 'None': ... @schema_final @@ -1157,7 +1157,7 @@ class MNLLIdentifierOption(Option, code=Enum_Option.Mobile_Node_Link_layer_Ident lli: 'bytes' = BytesField(length=lambda pkt: pkt['length'] - 2) if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', lli: 'bytes') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', lli: 'bytes') -> 'None': ... @schema_final @@ -1279,7 +1279,7 @@ class IPv4CareofAddressOption(Option, code=Enum_Option.IPv4_Care_of_Address): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - address: 'IPv4Address | int | bytes | str') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | int | bytes | str') -> 'None': ... @schema_final @@ -1304,7 +1304,7 @@ class GREKeyOption(Option, code=Enum_Option.GRE_Key_Option): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - key: 'Optional[int]') -> 'None': ... + reserved: 'bytes', key: 'Optional[int]') -> 'None': ... @schema_final @@ -1392,7 +1392,7 @@ class IPv4DefaultRouterAddressOption(Option, code=Enum_Option.IPv4_Default_Route if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - address: 'IPv4Address | int | bytes | str') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | int | bytes | str') -> 'None': ... @schema_final @@ -1439,7 +1439,7 @@ class ContextRequestOption(Option, code=Enum_Option.Context_Request_Option): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - requests: 'bytes') -> 'None': ... + reserved: 'bytes', requests: 'bytes') -> 'None': ... @schema_final @@ -1467,7 +1467,7 @@ class LMAAddressOption(Option, code=Enum_Option.Local_Mobility_Anchor_Address_Op if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', code: 'int', - address: 'IPv4Address | IPv6Address | bytes | int | str') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | IPv6Address | bytes | int | str') -> 'None': ... @schema_final @@ -1481,7 +1481,7 @@ class MNLLAIIDOption(Option, iid: 'bytes' = BytesField(length=8) if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', iid: 'bytes') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', iid: 'bytes') -> 'None': ... @schema_final @@ -1613,7 +1613,7 @@ class TrafficSelectorSuboption(FlowIdentificationSuboption, if TYPE_CHECKING: def __init__(self, type: 'Enum_FlowIDSuboption', length: 'int', - ts_format: 'Enum_TrafficSelector', selector: 'bytes') -> 'None': ... + ts_format: 'Enum_TrafficSelector', reserved: 'bytes', selector: 'bytes') -> 'None': ... @schema_final @@ -1628,7 +1628,7 @@ class FlowBindingActionSuboption(FlowIdentificationSuboption, if TYPE_CHECKING: def __init__(self, type: 'Enum_FlowIDSuboption', length: 'int', - action: 'Enum_FlowBindingAction') -> 'None': ... + reserved: 'bytes', action: 'Enum_FlowBindingAction') -> 'None': ... @schema_final @@ -1651,7 +1651,7 @@ class TargetCareofAddressSuboption(FlowIdentificationSuboption, if TYPE_CHECKING: def __init__(self, type: 'Enum_FlowIDSuboption', length: 'int', - address: 'IPv4Address | IPv6Address | bytes | int | str') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | IPv6Address | bytes | int | str') -> 'None': ... @schema_final @@ -1677,7 +1677,7 @@ class FlowIdentificationOption(Option, code=Enum_Option.Flow_Identification_Mobi if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', fid: 'int', fid_pri: 'int', - status: 'Enum_FlowIDStatus', + reserved: 'bytes', status: 'Enum_FlowIDStatus', suboptions: 'list[FlowIdentificationSuboption | bytes]') -> 'None': ... @@ -1689,7 +1689,7 @@ class RedirectCapabilityOption(Option, code=Enum_Option.Redirect_Capability_Mobi reserved: 'bytes' = PaddingField(length=2) if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes') -> 'None': ... @schema_final @@ -1773,7 +1773,7 @@ class MNGroupIdentifierOption(Option, code=Enum_Option.Mobile_Node_Group_Identif if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', subtype: 'Enum_MNGroupID', - group_id: 'int') -> 'None': ... + reserved: 'bytes', group_id: 'int') -> 'None': ... @schema_final @@ -1788,7 +1788,7 @@ class MAGIPv6AddressOption(Option, code=Enum_Option.MAG_IPv6_Address): address: 'IPv6Address' = IPv6AddressField() if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', address_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', address_length: 'int', address: 'IPv6Address | int | bytes | str') -> 'None': ... @@ -1893,7 +1893,7 @@ class ANICivicLocationSuboption(ANISuboption, code=Enum_ANISuboption.Civic_Locat if TYPE_CHECKING: def __init__(self, type: 'Enum_ANISuboption', length: 'int', format: 'int', - location: 'bytes') -> 'None': ... + reserved: 'bytes', location: 'bytes') -> 'None': ... @schema_final @@ -2129,7 +2129,7 @@ class BitRateAttribute(QoSAttribute, code=[Enum_QoSAttribute.Per_MN_Agg_Max_DL_B rate: 'int' = UInt32Field() if TYPE_CHECKING: - def __init__(self, type: 'Enum_QoSAttribute', length: 'int', rate: 'int') -> 'None': ... + def __init__(self, type: 'Enum_QoSAttribute', length: 'int', reserved: 'bytes', rate: 'int') -> 'None': ... @schema_final @@ -2171,7 +2171,7 @@ class AllocationRetentionPriorityAttribute( if TYPE_CHECKING: def __init__(self, type: 'Enum_QoSAttribute', length: 'int', - priority: 'AllocationRetentionPriorityFields') -> 'None': ... + reserved: 'bytes', priority: 'AllocationRetentionPriorityFields') -> 'None': ... @schema_final @@ -2195,7 +2195,7 @@ class QoSTrafficSelectorAttribute(QoSAttribute, code=Enum_QoSAttribute.QoS_Traff if TYPE_CHECKING: def __init__(self, type: 'Enum_QoSAttribute', length: 'int', - ts_format: 'Enum_TrafficSelector', selector: 'bytes') -> 'None': ... + reserved: 'bytes', ts_format: 'Enum_TrafficSelector', selector: 'bytes') -> 'None': ... @schema_final @@ -2214,7 +2214,7 @@ class QoSVendorSpecificAttribute( data: 'bytes' = BytesField(length=lambda pkt: pkt['length'] - 7) if TYPE_CHECKING: - def __init__(self, type: 'Enum_QoSAttribute', length: 'int', vendor: 'int', + def __init__(self, type: 'Enum_QoSAttribute', length: 'int', reserved: 'bytes', vendor: 'int', subtype: 'int', data: 'bytes') -> 'None': ... @@ -2241,7 +2241,7 @@ class QualityOfServiceOption(Option, code=Enum_Option.Quality_of_Service): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', sr_id: 'int', tc: 'int', - oc: 'int', attributes: 'list[QoSAttribute | bytes]') -> 'None': ... + oc: 'int', reserved: 'bytes', attributes: 'list[QoSAttribute | bytes]') -> 'None': ... @schema_final @@ -2255,7 +2255,7 @@ class LMAUserPlaneAddressOption(Option, code=Enum_Option.LMA_User_Plane_Address) if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', - address: 'IPv4Address | IPv6Address | bytes | int | str') -> 'None': ... + reserved: 'bytes', address: 'IPv4Address | IPv6Address | bytes | int | str') -> 'None': ... @schema_final @@ -2282,7 +2282,7 @@ class MulticastMobilityOption(Option, code=Enum_Option.Multicast_Mobility_Option if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', code: 'int', - data: 'bytes') -> 'None': ... + reserved: 'bytes', data: 'bytes') -> 'None': ... @schema_final @@ -2434,7 +2434,7 @@ class MAGIdentifierOption(Option, code=Enum_Option.MAG_Identifier): if TYPE_CHECKING: def __init__(self, type: 'Enum_Option', length: 'int', subtype: 'Enum_MNIDSubtype', - identifier: 'bytes') -> 'None': ... + reserved: 'bytes', identifier: 'bytes') -> 'None': ... @schema_final @@ -2449,7 +2449,7 @@ class AnchoredPrefixOption(Option, code=Enum_Option.Anchored_Prefix): prefix: 'IPv6Address' = IPv6AddressField() if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address | int | bytes | str') -> 'None': ... @@ -2465,7 +2465,7 @@ class LocalPrefixOption(Option, code=Enum_Option.Local_Prefix): prefix: 'IPv6Address' = IPv6AddressField() if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', prefix: 'IPv6Address | int | bytes | str') -> 'None': ... @@ -2483,7 +2483,7 @@ class PreviousMAAROption(Option, code=Enum_Option.Previous_MAAR): prefix: 'IPv6Address' = IPv6AddressField() if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', prefix_length: 'int', + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', prefix_length: 'int', maar: 'IPv6Address | int | bytes | str', prefix: 'IPv6Address | int | bytes | str') -> 'None': ... @@ -2523,7 +2523,7 @@ class DLIFLinkLayerAddressOption(Option, code=Enum_Option.DLIF_Link_Layer_Addres lla: 'bytes' = BytesField(length=lambda pkt: pkt['length'] - 2) if TYPE_CHECKING: - def __init__(self, type: 'Enum_Option', length: 'int', lla: 'bytes') -> 'None': ... + def __init__(self, type: 'Enum_Option', length: 'int', reserved: 'bytes', lla: 'bytes') -> 'None': ... # TODO: Implement other options. @@ -2583,7 +2583,7 @@ class HomeTestInitMessage(Packet, code=Enum_Packet.Home_Test_Init): ) if TYPE_CHECKING: - def __init__(self, cookie: 'bytes', options: 'list[Option | bytes]') -> 'None': ... + def __init__(self, reserved: 'bytes', cookie: 'bytes', options: 'list[Option | bytes]') -> 'None': ... @schema_final @@ -2604,7 +2604,7 @@ class CareofTestInitMessage(Packet, code=Enum_Packet.Care_of_Test_Init): ) if TYPE_CHECKING: - def __init__(self, cookie: 'bytes', options: 'list[Option | bytes]') -> 'None': ... + def __init__(self, reserved: 'bytes', cookie: 'bytes', options: 'list[Option | bytes]') -> 'None': ... @schema_final @@ -2750,7 +2750,7 @@ class BindingErrorMessage(Packet, code=Enum_Packet.Binding_Error): ) if TYPE_CHECKING: - def __init__(self, status: 'Enum_BindingError', home: 'IPv6Address | str | int | bytes', + def __init__(self, status: 'Enum_BindingError', reserved: 'bytes', home: 'IPv6Address | str | int | bytes', options: 'list[Option | bytes]') -> 'None': ... @@ -2843,7 +2843,7 @@ class FastNeighborAdvertisementMessage(Packet, code=Enum_Packet.Fast_Neighbor_Ad ) if TYPE_CHECKING: - def __init__(self, options: 'list[Option | bytes]') -> 'None': ... + def __init__(self, reserved: 'bytes', options: 'list[Option | bytes]') -> 'None': ... @schema_final @@ -2965,7 +2965,7 @@ class HomeAgentSwitchMessage(Packet, code=Enum_Packet.Home_Agent_Switch_Message) ) if TYPE_CHECKING: - def __init__(self, count: 'int', addresses: 'list[IPv6Address | int | bytes | str]', + def __init__(self, count: 'int', reserved: 'bytes', addresses: 'list[IPv6Address | int | bytes | str]', options: 'list[Option | bytes]') -> 'None': ... @@ -3035,7 +3035,7 @@ class LocalizedRoutingInitiationMessage(Packet, code=Enum_Packet.Localized_Routi ) if TYPE_CHECKING: - def __init__(self, seq: 'int', lifetime: 'int', + def __init__(self, seq: 'int', reserved: 'bytes', lifetime: 'int', options: 'list[Option | bytes]') -> 'None': ... @@ -3136,7 +3136,7 @@ class UpdateNotificationAcknowledgementMessage( if TYPE_CHECKING: def __init__(self, seq: 'int', status: 'Enum_UpdateNotificationACKStatus', - options: 'list[Option | bytes]') -> 'None': ... + reserved: 'bytes', options: 'list[Option | bytes]') -> 'None': ... @schema_final @@ -3208,7 +3208,7 @@ class SubscriptionQueryMessage(Packet, code=Enum_Packet.Subscription_Query): ) if TYPE_CHECKING: - def __init__(self, seq: 'int', options: 'list[Option | bytes]') -> 'None': ... + def __init__(self, seq: 'int', reserved: 'bytes', options: 'list[Option | bytes]') -> 'None': ... @schema_final diff --git a/tests/protocols/internet/test_mh_reserved_padding_unit.py b/tests/protocols/internet/test_mh_reserved_padding_unit.py new file mode 100644 index 0000000000..89f63f8076 --- /dev/null +++ b/tests/protocols/internet/test_mh_reserved_padding_unit.py @@ -0,0 +1,249 @@ +# -*- coding: utf-8 -*- +"""MH reserved octets rebuild as captured. + +GitHub issue #1437, part A: every reserved field of the Mobility Header that a +:class:`~pcapkit.corekit.fields.strings.PaddingField` holds -- in a message +body, an option, a Flow Identification sub-option, an ANI sub-option or a QoS +attribute -- was dropped by its reader, so a rebuild wrote zeros: Home Test Init +reserved ``aabb`` came back as ``0000``. #1436 made the field pack the octets it +is given; the readers now keep them on the data model (``msg_reserved`` on a +message, ``reserved`` elsewhere) and the makers write them back. A fresh build +still writes zeros. + +Each case is one Mobility Header carrying the site under test, with its +reserved octets set to ``aa``, ``aabb`` or ``aabbcc``, next to the same header +as a fresh build writes it. Messages travel bare; options travel in a Binding +Refresh Request; sub-options and attributes travel in their container option. +Every case builds its own octets in memory and reads no capture. :class:`MH` is +imported inside each test, after :func:`~tests._support.reimport_once_per_class`. + +""" + +import io +import unittest + +from tests._support import reimport_once_per_class + +#: ``(schema class, carrier, code name, captured octets, fresh-build octets)``. +#: The two octet strings differ only in the reserved field. +CASES = ( + ('ANICivicLocationSuboption', 'ani', 'Civic_Location', + '3b010000000000003406040400aa0102', + '3b010000000000003406040400000102'), + ('AccessTechnologyTypeOption', 'opt', 'Access_Technology_Type_Option', + '3b010000000000001802aa0101020000', + '3b010000000000001802000101020000'), + ('AllocationRetentionPriorityAttribute', 'qos', 'Allocation_Retention_Priority', + '3b020000000000003a0a0000000000000502aa1001020000', + '3b020000000000003a0a0000000000000502001001020000'), + ('AnchoredPrefixOption', 'opt', 'Anchored_Prefix', + '3b030000000000004112aa400000000000000000000000000000000001020000', + '3b03000000000000411200400000000000000000000000000000000001020000'), + ('BindingErrorMessage', 'msg', 'Binding_Error', + '3b020700000000aa00000000000000000000000000000000', + '3b0207000000000000000000000000000000000000000000'), + ('BitRateAttribute', 'qos', 'Per_MN_Agg_Max_DL_Bit_Rate', + '3b020000000000003a0e0000000000000106aabb00000000', + '3b020000000000003a0e0000000000000106000000000000'), + ('CareofTestInitMessage', 'msg', 'Care_of_Test_Init', + '3b0102000000aabb0000000000000000', + '3b010200000000000000000000000000'), + ('ContextRequestOption', 'opt', 'Context_Request_Option', + '3b010000000000002802aabb01020000', + '3b010000000000002802000001020000'), + ('DLIFLinkLayerAddressOption', 'opt', 'DLIF_Link_Layer_Address', + '3b010000000000004602aabb01020000', + '3b010000000000004602000001020000'), + ('FastNeighborAdvertisementMessage', 'msg', 'Fast_Neighbor_Advertisement', + '3b000a000000aabb', + '3b000a0000000000'), + ('FlowBindingActionSuboption', 'fid', 'Flow_Binding_Action', + '3b020000000000002d0a0001000100000402aa0b01020000', + '3b020000000000002d0a0001000100000402000b01020000'), + ('FlowIdentificationOption', 'opt', 'Flow_Identification_Mobility_Option', + '3b010000000000002d0600010001aa00', + '3b010000000000002d06000100010000'), + ('GREKeyOption', 'opt', 'GRE_Key_Option', + '3b010000000000002102aabb01020000', + '3b010000000000002102000001020000'), + ('HomeAgentSwitchMessage', 'msg', 'Home_Agent_Switch_Message', + '3b000c00000000aa', + '3b000c0000000000'), + ('HomeNetworkPrefixOption', 'opt', 'Home_Network_Prefix_Option', + '3b030000000000001612aa400000000000000000000000000000000001020000', + '3b03000000000000161200400000000000000000000000000000000001020000'), + ('HomeTestInitMessage', 'msg', 'Home_Test_Init', + '3b0101000000aabb0000000000000000', + '3b010100000000000000000000000000'), + ('IPv4CareofAddressOption', 'opt', 'IPv4_Care_of_Address', + '3b010000000000002006aabb00000000', + '3b010000000000002006000000000000'), + ('IPv4DefaultRouterAddressOption', 'opt', 'IPv4_Default_Router_Address', + '3b010000000000002606aabb00000000', + '3b010000000000002606000000000000'), + ('LMAAddressOption', 'opt', 'Local_Mobility_Anchor_Address_Option', + '3b03000000000000291201aa0000000000000000000000000000000001020000', + '3b03000000000000291201000000000000000000000000000000000001020000'), + ('LMAUserPlaneAddressOption', 'opt', 'LMA_User_Plane_Address', + '3b010000000000003b02aabb01020000', + '3b010000000000003b02000001020000'), + ('LocalPrefixOption', 'opt', 'Local_Prefix', + '3b030000000000004212aa400000000000000000000000000000000001020000', + '3b03000000000000421200400000000000000000000000000000000001020000'), + ('LocalizedRoutingInitiationMessage', 'msg', 'Localized_Routing_Initiation', + '3b01110000000000aabb000001020000', + '3b011100000000000000000001020000'), + ('MAGIPv6AddressOption', 'opt', 'MAG_IPv6_Address', + '3b030000000000003312aa800000000000000000000000000000000001020000', + '3b03000000000000331200800000000000000000000000000000000001020000'), + ('MAGIdentifierOption', 'opt', 'MAG_Identifier', + '3b01000000000000400201aa01020000', + '3b010000000000004002010001020000'), + ('MNGroupIdentifierOption', 'opt', 'Mobile_Node_Group_Identifier', + '3b01000000000000320601aa00000001', + '3b010000000000003206010000000001'), + ('MNLLAIIDOption', 'opt', 'Mobile_Node_Link_local_Address_Interface_Identifier_Option', + '3b020000000000002a0aaabb000000000000000001020000', + '3b020000000000002a0a0000000000000000000001020000'), + ('MNLLIdentifierOption', 'opt', 'Mobile_Node_Link_layer_Identifier_Option', + '3b010000000000001902aabb01020000', + '3b010000000000001902000001020000'), + ('MobileNetworkPrefixOption', 'opt', 'Mobile_Network_Prefix_Option', + '3b030000000000000612aa000000000000000000000000000000000001020000', + '3b03000000000000061200000000000000000000000000000000000001020000'), + ('MulticastMobilityOption', 'opt', 'Multicast_Mobility_Option', + '3b010000000000003c0002aa01020000', + '3b010000000000003c00020001020000'), + ('PreviousMAAROption', 'opt', 'Previous_MAAR', + '3b050000000000004322aa4000000000000000000000000000000000' + '0000000000000000000000000000000001020000', + '3b05000000000000432200400000000000000000000000000000000000' + '00000000000000000000000000000001020000'), + ('QoSTrafficSelectorAttribute', 'qos', 'QoS_Traffic_Selector', + '3b020000000000003a0a0000000000000a02aa0201020000', + '3b020000000000003a0a0000000000000a02000201020000'), + ('QoSVendorSpecificAttribute', 'qos', 'QoS_Vendor_Specific_Attribute', + '3b030000000000003a0f0000000000000b07aabb000000000001050000000000', + '3b030000000000003a0f0000000000000b070000000000000001050000000000'), + ('QualityOfServiceOption', 'opt', 'Quality_of_Service', + '3b010000000000003a06000000aabbcc', + '3b010000000000003a06000000000000'), + ('RedirectCapabilityOption', 'opt', 'Redirect_Capability_Mobility_Option', + '3b010000000000002e02aabb01020000', + '3b010000000000002e02000001020000'), + ('SubscriptionQueryMessage', 'msg', 'Subscription_Query', + '3b001600000000aa', + '3b00160000000000'), + ('TargetCareofAddressSuboption', 'fid', 'Target_Care_of_Address', + '3b040000000000002d1a0001000100000512aabb0000000000000000000000000000000001020000', + '3b040000000000002d1a000100010000051200000000000000000000000000000000000001020000'), + ('TrafficSelectorSuboption', 'fid', 'Traffic_Selector', + '3b020000000000002d0a000100010000030202aa01020000', + '3b020000000000002d0a0001000100000302020001020000'), + ('UpdateNotificationAcknowledgementMessage', 'msg', 'Update_Notification_Acknowledgement', + '3b0114000000000000aabbcc01020000', + '3b011400000000000000000001020000'),) + +#: Where the code name of each carrier is looked up. +ENUMS = { + 'msg': ('pcapkit.const.mh.packet', 'Packet'), + 'opt': ('pcapkit.const.mh.option', 'Option'), + 'fid': ('pcapkit.const.mh.flow_id_suboption', 'FlowIDSuboption'), + 'ani': ('pcapkit.const.mh.ani_suboption', 'ANISuboption'), + 'qos': ('pcapkit.const.mh.qos_attribute', 'QoSAttribute'), +} + + +class TestMHReservedPadding(unittest.TestCase): + """Pin the wire form of every MH ``PaddingField`` reserved site.""" + + def setUp(self) -> None: + reimport_once_per_class(self) + + @staticmethod + def fresh(carrier: 'str', name: 'str') -> 'bytes': + """Build the case's header from keyword arguments alone.""" + import importlib + + from pcapkit.const.mh.option import Option + from pcapkit.const.mh.packet import Packet + from pcapkit.protocols.internet.mh import MH + + module, enum = ENUMS[carrier] + code = getattr(getattr(importlib.import_module(module), enum), name) + base = {'next': 59, 'chksum': b'\x00\x00', 'payload': b''} + if carrier == 'msg': + return bytes(MH(type=code, data={}, **base)) + if carrier == 'opt': + option = (code, {}) + elif carrier == 'fid': + option = (Option.Flow_Identification_Mobility_Option, {'suboptions': [(code, {})]}) + elif carrier == 'qos': + option = (Option.Quality_of_Service, {'attributes': [(code, {})]}) + else: + option = (Option.Access_Network_Identifier, + {'suboptions': [(code, {'location': b'\x01\x02'})]}) + return bytes(MH(type=Packet.Binding_Refresh_Request, data={'options': [option]}, **base)) + + def test_reserved_octets_rebuild_as_captured(self) -> None: + from pcapkit.protocols.internet.mh import MH + + for site, _, _, raw_hex, zero_hex in CASES: + raw = bytes.fromhex(raw_hex) + with self.subTest(site=site): + self.assertNotEqual(raw_hex, zero_hex) + parsed = MH(io.BytesIO(raw), len(raw), extension=True).info + rebuilt = bytes(MH(next=parsed.next, type=parsed.type, chksum=parsed.chksum, + data=parsed, payload=b'')) + self.assertEqual(rebuilt.hex(), raw_hex) + + def test_fresh_build_writes_zeros(self) -> None: + from pcapkit.protocols.internet.mh import MH + + for site, carrier, name, _, zero_hex in CASES: + with self.subTest(site=site): + self.assertEqual(self.fresh(carrier, name).hex(), zero_hex) + zero = bytes.fromhex(zero_hex) + parsed = MH(io.BytesIO(zero), len(zero), extension=True).info + rebuilt = bytes(MH(next=parsed.next, type=parsed.type, chksum=parsed.chksum, + data=parsed, payload=b'')) + self.assertEqual(rebuilt.hex(), zero_hex) + + def test_every_padding_site_has_a_case(self) -> None: + from pcapkit.corekit.fields.strings import PaddingField + from pcapkit.protocols.schema.internet import mh as schema + + # ``PadOption`` and ``PadFlowIdentificationSuboption`` carry padding + # rather than a reserved field, and are pinned by + # ``test_mh_padn_contents_unit``. + sites = { + name for name, cls in vars(schema).items() + if isinstance(cls, type) and cls.__module__ == schema.__name__ + and any(isinstance(field, PaddingField) for field in getattr(cls, '__fields__', {}).values()) + } - {'PadOption', 'PadFlowIdentificationSuboption'} + self.assertEqual(sites, {case[0] for case in CASES}) + + def test_data_model_keeps_the_octets(self) -> None: + from pcapkit.protocols.internet.mh import MH + + hoti = bytes.fromhex(dict((case[0], case[3]) for case in CASES)['HomeTestInitMessage']) + info = MH(io.BytesIO(hoti), len(hoti), extension=True).info + self.assertEqual(info.msg_reserved, b'\xaa\xbb') + self.assertEqual(info.reserved, 0) # the fixed header's own octet + + gre = bytes.fromhex(dict((case[0], case[3]) for case in CASES)['GREKeyOption']) + option = next(iter(MH(io.BytesIO(gre), len(gre), extension=True).info.options.values())) + self.assertEqual(option.reserved, b'\xaa\xbb') + + def test_maker_takes_reserved_keyword(self) -> None: + from pcapkit.const.mh.option import Option + from pcapkit.protocols.internet.mh import MH + + proto = object.__new__(MH) + self.assertEqual(bytes(proto._make_msg_hoti(msg_reserved=b'\xaa\xbb').pack())[:2], b'\xaa\xbb') + self.assertEqual(bytes(proto._make_opt_gre(Option.GRE_Key_Option, reserved=b'\xaa\xbb').pack()).hex(), + '2102aabb') + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/protocols/internet/test_mh_unit.py b/tests/protocols/internet/test_mh_unit.py index ddf9e9492c..34d0f812e1 100644 --- a/tests/protocols/internet/test_mh_unit.py +++ b/tests/protocols/internet/test_mh_unit.py @@ -218,9 +218,9 @@ def header(type_: Packet) -> SimpleNamespace: self.assertEqual(unknown.data, b'raw') self.assertEqual(proto._read_msg_brr(SimpleNamespace(reserved=0, options=[]), header=header(Packet.Binding_Refresh_Request)).options, 'opts') - self.assertEqual(proto._read_msg_hoti(SimpleNamespace(cookie=b'12345678', options=[]), + self.assertEqual(proto._read_msg_hoti(SimpleNamespace(reserved=b'\x00\x00', cookie=b'12345678', options=[]), header=header(Packet.Home_Test_Init)).cookie, b'12345678') - self.assertEqual(proto._read_msg_coti(SimpleNamespace(cookie=b'abcdefgh', options=[]), + self.assertEqual(proto._read_msg_coti(SimpleNamespace(reserved=b'\x00\x00', cookie=b'abcdefgh', options=[]), header=header(Packet.Care_of_Test_Init)).cookie, b'abcdefgh') hot = proto._read_msg_hot(SimpleNamespace(nonce_index=1, cookie=b'12345678', token=b'abcdefgh', options=[]), @@ -246,6 +246,7 @@ def header(type_: Packet) -> SimpleNamespace: self.assertTrue(ba.key_mngt) self.assertEqual(ba.lifetime, datetime.timedelta(seconds=20)) be = proto._read_msg_be(SimpleNamespace(status=BindingError.Unrecognized_MH_Type_value, + reserved=b'\x00', home=ip_address('2001:db8::1'), options=[]), header=header(Packet.Binding_Error)) @@ -791,7 +792,7 @@ def make_extension(code: CGAExtension, extension: data.UnknownExtension | None = self.assertEqual(proto._make_opt_mnp( Option.Mobile_Network_Prefix_Option, data.MobileNetworkPrefixOption(type=Option.Mobile_Network_Prefix_Option, - length=18, + length=18, reserved=b'\x00', prefix=ip_network('2001:db8:1::/64')), ).prefix_length, 64) self.assertEqual(proto._make_opt_lla( @@ -956,7 +957,7 @@ def header(type_: Packet) -> SimpleNamespace: self.assertEqual(fback.lifetime, datetime.timedelta(seconds=10)) # RFC 4068, section 6.3.3 -- two reserved octets, then mobility options. - fna = proto._read_msg_fna(SimpleNamespace(options=[]), + fna = proto._read_msg_fna(SimpleNamespace(reserved=b'\x00\x00', options=[]), header=header(Packet.Fast_Neighbor_Advertisement)) self.assertEqual(fna.options, 'opts') self.assertEqual(fna.type, Packet.Fast_Neighbor_Advertisement)