Source code for pcapkit.protocols.schema.link.ethernet
# -*- coding: utf-8 -*-
# mypy: disable-error-code=assignment
"""header schema for ethernet protocol"""
from typing import TYPE_CHECKING
from pcapkit.const.reg.ethertype import EtherType as Enum_EtherType
from pcapkit.corekit.fields.misc import PayloadField
from pcapkit.corekit.fields.numbers import EnumField
from pcapkit.corekit.fields.strings import BytesField
from pcapkit.protocols.schema.schema import Schema, schema_final
__all__ = ['Ethernet']
if TYPE_CHECKING:
from typing import Any
from pcapkit.protocols.protocol import ProtocolBase
[docs]
def callback_payload(self: 'PayloadField', packet: 'dict[str, Any]') -> 'None':
"""Callback function for :attr:`Ethernet.payload`.
Args:
self: Payload field to resolve.
packet: Packet data, whose ``type`` names the next layer.
Returns:
:obj:`None`; the resolved class is assigned to ``self.protocol``.
Important:
The lookup goes through :meth:`ProtocolBase._lookup_next_layer
<pcapkit.protocols.protocol.Protocol._lookup_next_layer>` rather than
subscripting the registry. :attr:`Ethernet.__proto__
<pcapkit.protocols.link.link.Link.__proto__>` *is*
:attr:`Link.__proto__ <pcapkit.protocols.link.link.Link.__proto__>`, a
class-level :class:`collections.defaultdict`, so reading a missing key
inserted it -- every unregistered EtherType a parse saw was recorded as
though somebody had registered it, and
:meth:`Link.register <pcapkit.protocols.link.link.Link.register>`
afterwards reported it as an overwrite. The helper reads the fallback
without recording it, and memoises a
:class:`~pcapkit.corekit.module.ModuleDescriptor` for a code that really
is registered, which this did not.
"""
from pcapkit.protocols.link.ethernet import Ethernet # pylint: disable=import-outside-toplevel
self.protocol = Ethernet._lookup_next_layer( # pylint: disable=protected-access
Ethernet.__proto__, packet['type'])
[docs]
@schema_final
class Ethernet(Schema):
"""Header schema for ethernet packet."""
#: Destination MAC address.
dst: 'bytes' = BytesField(length=6)
#: Source MAC address.
src: 'bytes' = BytesField(length=6)
#: Protocol (internet layer).
type: 'Enum_EtherType' = EnumField(length=2, namespace=Enum_EtherType)
#: Payload.
payload: 'bytes' = PayloadField(
length=lambda pkt: pkt['__length__'],
callback=callback_payload,
)
if TYPE_CHECKING:
def __init__(self, dst: 'bytes', src: 'bytes', type: 'Enum_EtherType',
payload: 'bytes | ProtocolBase | Schema') -> 'None': ...