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
1 change: 1 addition & 0 deletions docs/source/pcapkit/protocols/internet/hip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Octets Bits Name Description
.. automethod:: _read_param_relay_hmac

.. automethod:: _make_hip_param
.. automethod:: _make_hip_param_data
.. automethod:: _make_param_unassigned
.. automethod:: _make_param_esp_info
.. automethod:: _make_param_r1_counter
Expand Down
61 changes: 51 additions & 10 deletions pcapkit/protocols/internet/hip.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
from pcapkit.protocols.data.internet.hip import NotificationParameter as Data_NotificationParameter
from pcapkit.protocols.data.internet.hip import OverlayIDParameter as Data_OverlayIDParameter
from pcapkit.protocols.data.internet.hip import OverlayTTLParameter as Data_OverlayTTLParameter
from pcapkit.protocols.data.internet.hip import Parameter as Data_Parameter
from pcapkit.protocols.data.internet.hip import PayloadMICParameter as Data_PayloadMICParameter
from pcapkit.protocols.data.internet.hip import PuzzleParameter as Data_PuzzleParameter
from pcapkit.protocols.data.internet.hip import R1CounterParameter as Data_R1CounterParameter
Expand Down Expand Up @@ -221,7 +222,6 @@
from pcapkit.const.hip.suite import Suite as Enum_Suite
from pcapkit.const.hip.transport import Transport as Enum_Transport
from pcapkit.corekit.protochain import ProtoChain
from pcapkit.protocols.data.internet.hip import Parameter as Data_Parameter
from pcapkit.protocols.protocol import ProtocolBase
from pcapkit.protocols.schema.internet.hip import Parameter as Schema_Parameter

Expand Down Expand Up @@ -409,6 +409,9 @@ class HIP(IPv6_Ext[Data_HIP, Schema_HIP], Internet[Data_HIP, Schema_HIP],
and the two fixed header bits (:issue:`1313`, :issue:`1314`,
:issue:`1323`, :issue:`1328`, :issue:`1365`, :issue:`1417`,
:issue:`1459`).
* A ``(code, data)`` pair rebuilds from the parsed data model rather
than from its fields as keyword arguments, which dropped every field
whose constructor keyword is spelled differently (:issue:`2352`).

"""

Expand Down Expand Up @@ -639,7 +642,7 @@ def make(self,
controls_reserved: 'int' = 0,
shit: 'int' = 0,
rhit: 'int' = 0,
parameters: 'Optional[list[Schema_Parameter | tuple[Enum_Parameter, dict[str, Any]] | bytes] | Parameter]' = None, # pylint: disable=line-too-long
parameters: 'Optional[list[Schema_Parameter | tuple[Enum_Parameter, Data_Parameter | dict[str, Any]] | bytes] | Parameter]' = None, # pylint: disable=line-too-long
payload: 'bytes | ProtocolBase | Schema' = b'',
**kwargs: 'Any') -> 'Schema_HIP':
"""Make (construct) packet data.
Expand Down Expand Up @@ -3056,10 +3059,17 @@ def _read_param_relay_hmac(self, schema: 'Schema_RelayHMACParameter', version: '
)
return relay_hmac

def _make_hip_param(self, parameters: 'list[Schema_Parameter | tuple[Enum_Parameter, dict[str, Any]] | bytes] | Parameter', *,
def _make_hip_param(self, parameters: 'list[Schema_Parameter | tuple[Enum_Parameter, Data_Parameter | dict[str, Any]] | bytes] | Parameter', *, # pylint: disable=line-too-long
version: 'int') -> 'tuple[list[Schema_Parameter | bytes], int]':
"""Make HIP parameter.

A ``(code, value)`` pair carries either a mapping of keyword arguments
for the parameter's constructor, or a parsed
:class:`~pcapkit.protocols.data.internet.hip.Parameter` data model,
which goes to the constructor positionally through
:meth:`_make_hip_param_data` rather than expanded as keyword arguments
(:issue:`2352`).

Args:
parameters: HIP parameters
version: HIP protocol version
Expand All @@ -3085,7 +3095,8 @@ def _make_hip_param(self, parameters: 'list[Schema_Parameter | tuple[Enum_Parame
parameters_list.append(schema_packed)
total_length += len(schema_packed)
else:
code, args = cast('tuple[Enum_Parameter, dict[str, Any]]', schema)
code, args = cast('tuple[Enum_Parameter, Data_Parameter | dict[str, Any]]',
schema)
name = self._lookup_registry(self.__parameter__, code)
if isinstance(name, str):
meth_name = f'_make_param_{name}'
Expand All @@ -3094,7 +3105,11 @@ def _make_hip_param(self, parameters: 'list[Schema_Parameter | tuple[Enum_Parame
else:
meth = name[1]

data = meth(code, version=version, **args) # type: Schema_Parameter
if isinstance(args, Data_Parameter):
data = self._make_hip_param_data(meth, code, args,
version=version) # type: Schema_Parameter
else:
data = meth(code, version=version, **args)
data_packed = data.pack()

parameters_list.append(data)
Expand All @@ -3111,17 +3126,43 @@ def _make_hip_param(self, parameters: 'list[Schema_Parameter | tuple[Enum_Parame
else:
meth = name[1]

data = meth(code, param, version=version)
# NOTE: The trailing padding :meth:`_read_hip_param` kept, if any.
padding = getattr(param, 'padding', None)
if isinstance(padding, bytes) and 'padding' in data.__fields__:
data.padding = padding
data = self._make_hip_param_data(meth, code, param, version=version)
data_packed = data.pack()

parameters_list.append(data)
total_length += len(data_packed)
return parameters_list, total_length

def _make_hip_param_data(self, meth: 'ParameterConstructor', code: 'Enum_Parameter',
param: 'Data_Parameter', *,
version: 'int') -> 'Schema_Parameter':
"""Make a HIP parameter from the data model its reader produced.

The parsed parameter goes to ``meth`` **positionally**. Expanding it as
keyword arguments instead would drop every field whose constructor
keyword is spelled differently -- ``HIP_TRANSFORM`` keeps its suites in
``suite_id`` and :meth:`_make_param_hip_transform` takes them as
``suites``, so ``**param`` left the parameter empty (:issue:`2352`).

Args:
meth: Parameter constructor.
code: Parameter code.
param: Parsed parameter data model.
version: HIP protocol version.

Returns:
HIP parameter schema.

.. versionadded:: 1.5.0

"""
data = meth(code, param, version=version)
# NOTE: The trailing padding :meth:`_read_hip_param` kept, if any.
padding = getattr(param, 'padding', None)
if isinstance(padding, bytes) and 'padding' in data.__fields__:
data.padding = padding
return data

def _make_param_unassigned(self, code: 'Enum_Parameter', param: 'Optional[Data_UnassignedParameter]' = None, *, # pylint: disable=unused-argument
version: 'int',
contents: 'bytes' = b'',
Expand Down
Loading
Loading