Skip to content

Commit 2ebca5e

Browse files
committed
working on MH protocol impl (message types)
1 parent 373b651 commit 2ebca5e

File tree

5 files changed

+166
-44
lines changed

5 files changed

+166
-44
lines changed

pcapkit/protocols/data/internet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@
195195
from pcapkit.protocols.data.internet.mh import PermanentHomeKeygenTokenOption as MH_PermanentHomeKeygenTokenOption
196196
from pcapkit.protocols.data.internet.mh import CareofTestInitOption as MH_CareofTestInitOption
197197
from pcapkit.protocols.data.internet.mh import CareofTestOption as MH_CareofTestOption
198+
from pcapkit.protocols.data.internet.mh import UnknownMessage as MH_UnknownMessage
198199

199200
__all__ = [
200201
# Authentication Header

pcapkit/protocols/data/internet/mh.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464

6565
__all__ = [
6666
'MH',
67+
'UnknownMessage',
6768

6869
'Option',
6970
'UnassignedOption', 'PadOption', 'BindRefreshAdviceOption', 'AlternateCareofAddressOption',
@@ -79,7 +80,6 @@
7980
]
8081

8182

82-
@info_final
8383
class MH(Data):
8484
"""Data model for MH protocol."""
8585

@@ -91,6 +91,12 @@ class MH(Data):
9191
type: 'Packet'
9292
#: Checksum.
9393
chksum: 'bytes'
94+
95+
96+
@info_final
97+
class UnknownMessage(MH):
98+
"""Data model for MH unknown message type."""
99+
94100
#: Message data.
95101
data: 'bytes'
96102

pcapkit/protocols/internet/mh.py

Lines changed: 99 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@
133133
from pcapkit.protocols.schema.internet.mh import CareofTestOption as Schema_CareofTestOption
134134
from pcapkit.protocols.data.internet.mh import CareofTestOption as Data_CareofTestOption
135135

136+
from pcapkit.protocols.schema.internet.mh import UnknownMessage as Schema_UnknownMessage
137+
from pcapkit.protocols.data.internet.mh import UnknownMessage as Data_UnknownMessage
138+
139+
136140
if TYPE_CHECKING:
137141
from datetime import datetime as dt_type
138142
from enum import IntEnum as StdlibEnum
@@ -155,7 +159,7 @@
155159
Extension = OrderedMultiDict[Enum_CGAExtension, Data_CGAExtension]
156160

157161
PacketParser = Callable[[Schema_Packet, NamedArg(Schema_MH, 'header')], Data_MH]
158-
PacketConstructor = Callable[[Enum_Packet, DefaultArg(Optional[Data_MH]),
162+
PacketConstructor = Callable[[DefaultArg(Optional[Data_MH]),
159163
KwArg(Any)], Schema_Packet]
160164

161165
OptionParser = Callable[[Schema_Option, NamedArg(Option, 'options')], Data_Option]
@@ -182,10 +186,10 @@ class MH(Internet[Data_MH, Schema_MH],
182186

183187
#: DefaultDict[Enum_Packet, str | tuple[PacketParser, PacketConstructor]]:
184188
#: Message type to method mapping. Method names are expected to be referred
185-
#: to the class by ``_read_packet_${name}`` and/or ``_make_packet_${name}``,
189+
#: to the class by ``_read_msg_${name}`` and/or ``_make_msg_${name}``,
186190
#: and if such name not found, the value should then be a method that can
187-
#: parse the packet by itself.
188-
__packet__ = collections.defaultdict(
191+
#: parse the message type by itself.
192+
__message__ = collections.defaultdict(
189193
lambda: 'unknown',
190194
{
191195

@@ -320,13 +324,14 @@ def read(self, length: 'Optional[int]' = None, *, version: 'Literal[4, 6]' = 4,
320324
length = len(self)
321325
schema = self.__header__
322326

323-
mh = Data_MH(
324-
next=schema.next,
325-
length=(schema.length + 1) * 8,
326-
type=schema.type,
327-
chksum=schema.chksum,
328-
data=schema.data,
329-
)
327+
name = self.__message__[schema.type]
328+
if isinstance(name, str):
329+
meth_name = f'_read_msg_{name}'
330+
meth = cast('PacketParser',
331+
getattr(self, meth_name, self._read_msg_unknown))
332+
else:
333+
meth = name[0]
334+
mh = meth(schema.data, header=schema)
330335

331336
if extension:
332337
return mh
@@ -342,12 +347,23 @@ def make(self,
342347
type_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
343348
type_reversed: 'bool' = False,
344349
chksum: 'bytes' = b'',
345-
data: 'bytes' = b'\x00\x00', # minimum length
350+
data: 'bytes | Data_MH | Schema_Packet | dict[str, Any]' = b'\x00\x00', # minimum length
346351
payload: 'Protocol | Schema | bytes' = b'',
347352
**kwargs: 'Any') -> 'Schema_MH':
348353
"""Make (construct) packet data.
349354
350355
Args:
356+
next: Next header type.
357+
next_default: Default value for next header type field.
358+
next_namespace: Namespace of next header type field.
359+
next_reversed: Whether the bits of next header type field is reversed.
360+
type: Mobility Header type.
361+
type_default: Default value for Mobility Header type field.
362+
type_namespace: Namespace of Mobility Header type field.
363+
type_reversed: Whether the bits of Mobility Header type field is reversed.
364+
chksum: Checksum.
365+
data: Message data.
366+
payload: Payload of next layer protocol.
351367
**kwargs: Arbitrary keyword arguments.
352368
353369
Returns:
@@ -359,12 +375,32 @@ def make(self,
359375
type_val = self._make_index(type, type_default, namespace=type_namespace, # type: ignore[call-overload]
360376
reversed=type_reversed, pack=False)
361377

378+
if isinstance(data, bytes):
379+
data_val = data # type: bytes | Schema_Packet
380+
elif isinstance(data, (dict, Data_MH)):
381+
name = self.__message__[type_val]
382+
if isinstance(name, str):
383+
meth_name = f'_make_msg_{name}'
384+
meth = cast('PacketConstructor',
385+
getattr(self, meth_name, self._make_msg_unknown))
386+
else:
387+
meth = name[1]
388+
389+
if isinstance(data, dict):
390+
data_val = meth(**data)
391+
else:
392+
data_val = meth(data)
393+
elif isinstance(data, Schema_Packet):
394+
data_val = data
395+
else:
396+
raise ProtocolError(f'MH: [Type {type_val}] invalid format')
397+
362398
return Schema_MH(
363399
next=next_val,
364-
length=math.ceil((len(data) + 6) / 8) - 1,
400+
length=math.ceil((len(data_val) + 6) / 8) - 1,
365401
type=type_val,
366402
chksum=chksum,
367-
data=data,
403+
data=data_val,
368404
payload=payload,
369405
)
370406

@@ -434,10 +470,34 @@ def _make_data(cls, data: 'Data_MH') -> 'dict[str, Any]': # type: ignore[overri
434470
'next': data.next,
435471
'type': data.type,
436472
'chksum': data.chksum,
437-
'data': data.data,
473+
'data': data,
438474
'payload': cls._make_payload(data),
439475
}
440476

477+
def _read_msg_unknown(self, schema: 'Schema_UnknownMessage', *,
478+
header: 'Schema_MH') -> 'Data_UnknownMessage':
479+
"""Read unknown MH message type.
480+
481+
Args:
482+
schema: Parsed message type schema.
483+
header: Parsed MH header schema.
484+
485+
Returns:
486+
Parsed message type data.
487+
488+
"""
489+
data = Data_UnknownMessage(
490+
next=header.next,
491+
length=(header.length + 1) * 8,
492+
type=header.type,
493+
chksum=header.chksum,
494+
data=schema.data,
495+
)
496+
return data
497+
498+
499+
500+
441501
def _read_mh_options(self, options_schema: 'list[Schema_Option]') -> 'Option':
442502
"""Read MH options.
443503
@@ -1210,6 +1270,30 @@ def _read_ext_multiprefix(self, schema: 'Schema_MultiPrefixExtension', *,
12101270

12111271

12121272

1273+
1274+
def _make_msg_unknown(self, message: 'Optional[Data_UnknownMessage]', *,
1275+
data: 'bytes' = b'',
1276+
**kwargs: 'Any') -> 'Schema_UnknownMessage':
1277+
"""Make MH unknown message type.
1278+
1279+
Args:
1280+
message: Message data model.
1281+
data: Raw message data.
1282+
**kwargs: Arbitrary keyword arguments.
1283+
1284+
Returns:
1285+
Constructed message type.
1286+
1287+
"""
1288+
if message is not None:
1289+
data = message.data
1290+
1291+
return Schema_UnknownMessage(
1292+
data=data,
1293+
)
1294+
1295+
1296+
12131297
def _make_mh_options(self, options: 'Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]') -> 'tuple[list[Schema_Option | bytes], int]':
12141298
"""Make options for MH.
12151299

pcapkit/protocols/schema/internet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@
193193
from pcapkit.protocols.schema.internet.mh import PermanentHomeKeygenTokenOption as MH_PermanentHomeKeygenTokenOption
194194
from pcapkit.protocols.schema.internet.mh import CareofTestInitOption as MH_CareofTestInitOption
195195
from pcapkit.protocols.schema.internet.mh import CareofTestOption as MH_CareofTestOption
196+
from pcapkit.protocols.schema.internet.mh import UnknownMessage as MH_UnknownMessage
196197

197198
__all__ = [
198199
# Authentication Header

pcapkit/protocols/schema/internet/mh.py

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
'MH',
6767

6868
'Packet',
69+
'UnknownMessage',
6970

7071
'Option',
7172
'UnassignedOption', 'PadOption', 'BindRefreshAdviceOption', 'AlternateCareofAddressOption',
@@ -104,6 +105,24 @@ class MultiPrefixExtensionFlags(TypedDict):
104105
P: int
105106

106107

108+
def mh_data_selector(pkt: 'dict[str, Any]') -> 'Field':
109+
"""Selector function for :attr:`MH.data` field.
110+
111+
Args:
112+
pkt: Packet data.
113+
114+
Returns:
115+
Returns a :class:`~pcapkit.corekit.fields.misc.SchemaField`
116+
wrapped :class:`~pcapkit.protocols.schema.misc.mh.Packet`
117+
subclass instance.
118+
119+
"""
120+
type = pkt['type'] # type: Enum_Packet
121+
length = pkt['length'] * 8 + 2
122+
123+
return SchemaField(length=length, schema=UnknownMessage)
124+
125+
107126
def mn_id_selector(pkt: 'dict[str, Any]') -> 'Field':
108127
"""Selector function for :attr:`MNIDOption.identifier` field.
109128
@@ -123,34 +142,6 @@ def mn_id_selector(pkt: 'dict[str, Any]') -> 'Field':
123142
return BytesField(length=pkt['length'] - 1)
124143

125144

126-
@schema_final
127-
class MH(Schema):
128-
"""Header schema for MH packets."""
129-
130-
#: Next header.
131-
next: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
132-
#: Header length.
133-
length: 'int' = UInt8Field()
134-
#: MH type.
135-
type: 'Enum_Packet' = EnumField(length=1, namespace=Enum_Packet)
136-
#: Reserved.
137-
reserved: 'bytes' = PaddingField(length=1)
138-
#: Checksum.
139-
chksum: 'bytes' = BytesField(length=2)
140-
#: Message data.
141-
data: 'bytes' = BytesField(length=lambda pkt: pkt['length'] * 8 + 2)
142-
#: Payload.
143-
payload: 'bytes' = PayloadField()
144-
145-
if TYPE_CHECKING:
146-
def __init__(self, next: 'Enum_TransType', length: 'int', type: 'Enum_Packet',
147-
chksum: 'bytes', data: 'bytes', payload: 'bytes | Protocol | Schema') -> 'None': ...
148-
149-
150-
class Packet(Schema):
151-
"""Header schema for MH packet data."""
152-
153-
154145
class Option(Schema):
155146
"""Header schema for MH options."""
156147

@@ -471,3 +462,42 @@ class CareofTestOption(Option):
471462

472463
if TYPE_CHECKING:
473464
def __init__(self, type: 'Enum_Option', length: 'int', token: 'bytes') -> 'None': ...
465+
466+
467+
class Packet(Schema):
468+
"""Header schema for MH packet data."""
469+
470+
471+
@schema_final
472+
class UnknownMessage(Packet):
473+
"""Header schema for MH unknown message type."""
474+
475+
#: Message data.
476+
data: 'bytes' = BytesField(length=lambda pkt: pkt['__length__'])
477+
478+
if TYPE_CHECKING:
479+
def __init__(self, data: 'bytes') -> 'None': ...
480+
481+
482+
@schema_final
483+
class MH(Schema):
484+
"""Header schema for MH packets."""
485+
486+
#: Next header.
487+
next: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
488+
#: Header length.
489+
length: 'int' = UInt8Field()
490+
#: MH type.
491+
type: 'Enum_Packet' = EnumField(length=1, namespace=Enum_Packet)
492+
#: Reserved.
493+
reserved: 'bytes' = PaddingField(length=1)
494+
#: Checksum.
495+
chksum: 'bytes' = BytesField(length=2)
496+
#: Message data.
497+
data: 'Packet' = SwitchField(selector=mh_data_selector)
498+
#: Payload.
499+
payload: 'bytes' = PayloadField()
500+
501+
if TYPE_CHECKING:
502+
def __init__(self, next: 'Enum_TransType', length: 'int', type: 'Enum_Packet',
503+
chksum: 'bytes', data: 'Packet | bytes', payload: 'bytes | Protocol | Schema') -> 'None': ...

0 commit comments

Comments
 (0)