Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/source/pcapkit/foundation/registry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ Link Layer Registries

.. autofunction:: pcapkit.foundation.registry.protocols.register_loopback

.. autofunction:: pcapkit.foundation.registry.protocols.register_arphrd

.. autofunction:: pcapkit.foundation.registry.protocols.register_frad

.. autofunction:: pcapkit.foundation.registry.protocols.register_netlink

Internet Layer Registries
~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions docs/source/pcapkit/protocols/link/frad.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ for SNAP), a 3-octet OUI and a 2-octet PID follow, kept as ``frad.ext_nlpid``,

.. automethod:: read
.. automethod:: make
.. automethod:: register

.. automethod:: __length_hint__
.. automethod:: __index__
Expand Down
9 changes: 7 additions & 2 deletions docs/source/pcapkit/protocols/link/linux_sll.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ validation. It has no registry index, so its ``__index__`` raises.
:show-inheritance:

.. automethod:: id
.. automethod:: register
.. automethod:: __index__
.. automethod:: _import_next_layer

.. autoattribute:: __proto__
:no-value:
.. autoattribute:: __proto_key__
:no-value:

Auxiliary Functions
-------------------

Expand All @@ -38,14 +44,13 @@ Auxiliary Functions
Auxiliary Constants
-------------------

.. autodata:: pcapkit.protocols.link.linux_sll._ARPHRD_NOT_ETHERTYPE
.. autodata:: pcapkit.protocols.link.linux_sll._ETHERTYPE_FIELD
:no-value:

Hardware Types
--------------

The ``arphrd_type`` values in ``_ARPHRD_NOT_ETHERTYPE`` are named by the enumeration below.
The ``arphrd_type`` keys of ``LinuxSLL.__proto__`` are named by the enumeration below.

.. autoclass:: pcapkit.const.linux.arphrd.ARPHRD
:members:
Expand Down
1 change: 1 addition & 0 deletions docs/source/pcapkit/protocols/link/netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ format) and is guessed by :func:`nlmsg_byteorder`; either way it is kept as

.. automethod:: read
.. automethod:: make
.. automethod:: register

.. automethod:: __length_hint__
.. automethod:: __index__
Expand Down
1 change: 1 addition & 0 deletions pcapkit/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
'register_pcap', 'register_pcapng',
'register_ethertype',
'register_loopback',
'register_arphrd', 'register_frad', 'register_netlink',
'register_transtype',
'register_ipx',
'register_icmp_type',
Expand Down
1 change: 1 addition & 0 deletions pcapkit/foundation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
'register_pcap', 'register_pcapng',
'register_ethertype',
'register_loopback',
'register_arphrd', 'register_frad', 'register_netlink',
'register_transtype',
'register_ipx',
'register_icmp_type',
Expand Down
1 change: 1 addition & 0 deletions pcapkit/foundation/registry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

'register_ethertype',
'register_loopback',
'register_arphrd', 'register_frad', 'register_netlink',

'register_transtype',
'register_ipx',
Expand Down
135 changes: 135 additions & 0 deletions pcapkit/foundation/registry/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from pcapkit.const.ipv6.option import Option as IPv6_Option
from pcapkit.const.ipv6.routing import Routing as IPv6_Routing
from pcapkit.const.ipx.packet import Packet as IPX_Packet
from pcapkit.const.linux.arphrd import ARPHRD as Enum_ARPHRD
from pcapkit.const.mh.cga_extension import CGAExtension as MH_CGAExtension
from pcapkit.const.mh.option import Option as MH_Option
from pcapkit.const.mh.packet import Packet as MH_Packet
Expand Down Expand Up @@ -61,8 +62,11 @@
from pcapkit.protocols.internet.ipv6_route import IPv6_Route
from pcapkit.protocols.internet.ipx import IPX
from pcapkit.protocols.internet.mh import MH
from pcapkit.protocols.link.frad import FRAD
from pcapkit.protocols.link.link import Link
from pcapkit.protocols.link.linux_sll import LinuxSLL
from pcapkit.protocols.link.loopback import Loopback
from pcapkit.protocols.link.netlink import Netlink
from pcapkit.protocols.misc.pcap.frame import Frame
from pcapkit.protocols.misc.pcapng import PCAPNG
from pcapkit.protocols.protocol import ProtocolBase
Expand Down Expand Up @@ -149,6 +153,7 @@

'register_ethertype',
'register_loopback',
'register_arphrd', 'register_frad', 'register_netlink',

'register_transtype',
'register_ipx',
Expand Down Expand Up @@ -888,6 +893,136 @@ def register_loopback(code: 'int', module: 'str | ModuleDescriptor[ProtocolBase]
_register_name(module, (Loopback, code))


@overload
def register_arphrd(code: 'Enum_ARPHRD', module: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None': ...
@overload
def register_arphrd(code: 'Enum_ARPHRD', module: 'str', class_: 'str') -> 'None': ...


# NOTE: pcapkit.protocols.link.linux_sll.LinuxSLL.__proto__
def register_arphrd(code: 'Enum_ARPHRD', module: 'str | ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]',
class_: 'str | NullType' = NULL) -> 'None':
r"""Register a new protocol class.

Notes:
The fully qualified class name of the new protocol class
should be ``{module}.{class_}``.

The function will register the given protocol class to the
:data:`pcapkit.protocols.link.linux_sll.LinuxSLL.__proto__` registry, so
that a Linux "cooked" capture on that ``arphrd_type`` dispatches to it
instead of reading ``protocol_type`` as an EtherType.

Arguments:
code: ARP hardware type as in :class:`~pcapkit.const.linux.arphrd.ARPHRD`
module: module name or module descriptor or a
:class:`~pcapkit.protocols.protocol.ProtocolBase` subclass
class\_: class name

Raises:
RegistryError: If ``code`` is not a :class:`~pcapkit.const.linux.arphrd.ARPHRD`
member, e.g. a member of another enum, or ``module``
is not a :class:`~pcapkit.protocols.protocol.ProtocolBase`
subclass.

"""
_check_code(code, Enum_ARPHRD, LinuxSLL) # type: ignore[type-abstract]
if isinstance(module, str):
module = cast('ModuleDescriptor[ProtocolBase]', ModuleDescriptor(module, class_))

LinuxSLL.register(code, module)
logger.debug('registered ARPHRD protocol: %s', code.name)

# register protocol to protocol registry
if isinstance(module, ModuleDescriptor):
module = module.klass
_register_name(module, (LinuxSLL, code))


@overload
def register_frad(code: 'int', module: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None': ...
@overload
def register_frad(code: 'int', module: 'str', class_: 'str') -> 'None': ...


# NOTE: pcapkit.protocols.link.frad.FRAD.__proto__
def register_frad(code: 'int', module: 'str | ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]',
class_: 'str | NullType' = NULL) -> 'None':
r"""Register a new protocol class.

Notes:
The fully qualified class name of the new protocol class
should be ``{module}.{class_}``.

The function will register the given protocol class to the
:data:`pcapkit.protocols.link.frad.FRAD.__proto__` registry.

Arguments:
code: NLPID, after resolving the ``0x00`` pad ahead of a SNAP header
module: module name or module descriptor or a
:class:`~pcapkit.protocols.protocol.ProtocolBase` subclass
class\_: class name

Raises:
RegistryError: If ``code`` is not an :class:`int` (a :class:`bool` is
not accepted, even though it is one), or is a member of an enum.

"""
_check_code(code, None, FRAD)
if isinstance(module, str):
module = cast('ModuleDescriptor[ProtocolBase]', ModuleDescriptor(module, class_))

FRAD.register(code, module)
logger.debug('registered FRAD NLPID: %s', code)

# register protocol to protocol registry
if isinstance(module, ModuleDescriptor):
module = module.klass
_register_name(module, (FRAD, code))


@overload
def register_netlink(code: 'int', module: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None': ...
@overload
def register_netlink(code: 'int', module: 'str', class_: 'str') -> 'None': ...


# NOTE: pcapkit.protocols.link.netlink.Netlink.__proto__
def register_netlink(code: 'int', module: 'str | ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]',
class_: 'str | NullType' = NULL) -> 'None':
r"""Register a new protocol class.

Notes:
The fully qualified class name of the new protocol class
should be ``{module}.{class_}``.

The function will register the given protocol class to the
:data:`pcapkit.protocols.link.netlink.Netlink.__proto__` registry.

Arguments:
code: ``nlmsg_type`` of the dissected message
module: module name or module descriptor or a
:class:`~pcapkit.protocols.protocol.ProtocolBase` subclass
class\_: class name

Raises:
RegistryError: If ``code`` is not an :class:`int` (a :class:`bool` is
not accepted, even though it is one), or is a member of an enum.

"""
_check_code(code, None, Netlink)
if isinstance(module, str):
module = cast('ModuleDescriptor[ProtocolBase]', ModuleDescriptor(module, class_))

Netlink.register(code, module)
logger.debug('registered Netlink message type: %s', code)

# register protocol to protocol registry
if isinstance(module, ModuleDescriptor):
module = module.klass
_register_name(module, (Netlink, code))


###############################################################################
# Internet Layer Registries
###############################################################################
Expand Down
62 changes: 52 additions & 10 deletions pcapkit/protocols/link/frad.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
is ``ARPHRD_FRAD`` -- :class:`~pcapkit.protocols.link.linux_sll.LinuxSLL`
dispatches here instead of falling back to
:class:`~pcapkit.protocols.misc.raw.Raw` for that one case; see
:data:`~pcapkit.protocols.link.linux_sll._ARPHRD_NOT_ETHERTYPE`. Its
:attr:`LinuxSLL.__proto__ <pcapkit.protocols.link.linux_sll.LinuxSLL.__proto__>`. Its
structure is the Q.922 LAPF address onward, with no trailing FCS: a 2-octet
``frad.addr``, a 1-octet ``frad.control`` (``0x03``, UI, for ordinary data
traffic), then a 1-octet ``frad.nlpid`` -- or, when SNAP-encapsulated, the
Expand All @@ -29,15 +29,17 @@
import collections
from typing import TYPE_CHECKING

from pcapkit.const.linux.arphrd import ARPHRD as Enum_ARPHRD
from pcapkit.corekit.decorators import beholder
from pcapkit.corekit.module import ModuleDescriptor
from pcapkit.protocols.data.link.frad import FRAD as Data_FRAD
from pcapkit.protocols.link.link import Link
from pcapkit.protocols.schema.link.frad import FRAD as Schema_FRAD
from pcapkit.utilities.exceptions import ProtocolError, UnsupportedCall
from pcapkit.utilities.exceptions import ProtocolError
from pcapkit.utilities.warnings import RegistryWarning, warn

if TYPE_CHECKING:
from typing import Any, DefaultDict, NoReturn, Optional, Type
from typing import Any, DefaultDict, Optional, Type

from typing_extensions import Literal

Expand Down Expand Up @@ -286,6 +288,46 @@ def make(self,
payload=payload,
)

@classmethod
def register(cls, code: 'int', protocol: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None':
r"""Register a new protocol class for an NLPID.

Notes:
The fully qualified class name of the new protocol class
should be ``{protocol.module}.{protocol.name}``.

Arguments:
code: NLPID, after resolving the ``0x00`` pad ahead of a SNAP header
protocol: module descriptor or a
:class:`~pcapkit.protocols.protocol.ProtocolBase` subclass

Important:
This overrides :meth:`Link.register
<pcapkit.protocols.link.link.Link.register>` because
:attr:`self.__proto__ <FRAD.__proto__>` is keyed by NLPID rather
than by EtherType.

Raises:
pcapkit.utilities.exceptions.RegistryError: If ``protocol`` is not a
class, or not a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass.

Warns:
pcapkit.utilities.warnings.RegistryWarning: If this NLPID is already
registered and the incumbent differs from the replacement; see
:meth:`Protocol.register <pcapkit.protocols.protocol.Protocol.register>`
for the guard, and for the shipped descriptor a restore puts
back (:issue:`1504`).

"""
incumbent = cls.__proto__.get(code)
entry = cls._next_layer_entry(code, protocol)
if entry is None:
return
if incumbent is not None and incumbent is not entry:
warn(f'NLPID {code} already registered, overwriting '
f'{incumbent!r} with {entry!r}', RegistryWarning)
cls.__proto__[code] = entry

##########################################################################
# Data models.
##########################################################################
Expand All @@ -303,17 +345,17 @@ def __length_hint__(self) -> 'Literal[10]':
return 10

@classmethod
def __index__(cls) -> 'NoReturn': # pylint: disable=invalid-index-returned
def __index__(cls) -> 'Enum_ARPHRD': # pylint: disable=invalid-index-returned
"""Numeral registry index of the protocol.

Raises:
UnsupportedCall: This protocol is reached only through
:class:`~pcapkit.protocols.link.linux_sll.LinuxSLL`'s
``arphrd_type`` dispatch, not through a link-layer header
type of its own.
Returns:
Numeral registry index of the protocol in Linux ARP hardware
types, the ``arphrd_type`` that
:attr:`LinuxSLL.__proto__ <pcapkit.protocols.link.linux_sll.LinuxSLL.__proto__>`
dispatches here.

"""
raise UnsupportedCall(f'{cls.__name__!r} object cannot be interpreted as an integer')
return Enum_ARPHRD.FRAD # type: ignore[return-value]

##########################################################################
# Utilities.
Expand Down
Loading
Loading