Found while reviewing #378 (Copilot raised it there against three _import_next_layer sites). It is pre-existing on main, not introduced by that PR — filing separately so #378 stays scoped.
The gap
ProtocolBase._import_next_layer instantiates the next protocol with packet=packet:
next_ = protocol(file_, length, alias=proto, packet=packet,
layer=self._exlayer, protocol=self._exproto)
packet= reaches the protocol, but the schema layer reads its per-packet context from a separate special keyword, __packet__ (pcapkit/protocols/protocol.py:284,304 — packet = kwargs.get('__packet__', {})). Nothing bridges the two, so a schema's unpack/post_process always sees an empty packet dict, whatever the outer layer populated. The same shape appears in the Internet and IPv6 overrides of _import_next_layer.
Verified pre-existing: git show origin/main:pcapkit/protocols/protocol.py has the identical packet=packet call with no __packet__, before ESP existed.
Observable consequence
pcapkit/protocols/schema/internet/ipv6_route.py:157 is a real consumer — the RPL Source Route Header reconstructs its compressed addresses from the outer destination:
dst_val = cast('Optional[IPv6Address]', packet.get('dst'))
dst = dst_val.packed if dst_val is not None else None
...
if dst is None: # degraded path: elided prefix octets cannot be restored
Because dst is never supplied, that branch is always taken and the compressed addresses are never fully reconstructed, regardless of what IPv6.read populated.
Caveat on reachability
I have not been able to demonstrate this end to end on a real capture, because the RPL and source-route paths in pcapkit/protocols/internet/ipv6_route.py currently reject well-formed headers for an unrelated reason (_read_data_type_rpl / _read_data_type_src compare the schema's raw Hdr Ext Len octet against octet counts) — so the degraded branch may be masked today by an earlier failure. The __packet__ gap is established by reading the call chain; the user-visible effect is inferred, and confirming it likely depends on fixing the type-dispatch bugs first.
What a fix would touch
_import_next_layer in pcapkit/protocols/protocol.py, plus the Internet and IPv6 overrides, to pass the packet dict through as __packet__ as well as packet=. Worth checking whether any schema currently relies on receiving an empty dict before changing it, and it needs a test that asserts a schema's post_process actually sees an outer-layer value.
Found while reviewing #378 (Copilot raised it there against three
_import_next_layersites). It is pre-existing onmain, not introduced by that PR — filing separately so #378 stays scoped.The gap
ProtocolBase._import_next_layerinstantiates the next protocol withpacket=packet:packet=reaches the protocol, but the schema layer reads its per-packet context from a separate special keyword,__packet__(pcapkit/protocols/protocol.py:284,304—packet = kwargs.get('__packet__', {})). Nothing bridges the two, so a schema'sunpack/post_processalways sees an empty packet dict, whatever the outer layer populated. The same shape appears in theInternetandIPv6overrides of_import_next_layer.Verified pre-existing:
git show origin/main:pcapkit/protocols/protocol.pyhas the identicalpacket=packetcall with no__packet__, before ESP existed.Observable consequence
pcapkit/protocols/schema/internet/ipv6_route.py:157is a real consumer — the RPL Source Route Header reconstructs its compressed addresses from the outer destination:Because
dstis never supplied, that branch is always taken and the compressed addresses are never fully reconstructed, regardless of whatIPv6.readpopulated.Caveat on reachability
I have not been able to demonstrate this end to end on a real capture, because the RPL and source-route paths in
pcapkit/protocols/internet/ipv6_route.pycurrently reject well-formed headers for an unrelated reason (_read_data_type_rpl/_read_data_type_srccompare the schema's rawHdr Ext Lenoctet against octet counts) — so the degraded branch may be masked today by an earlier failure. The__packet__gap is established by reading the call chain; the user-visible effect is inferred, and confirming it likely depends on fixing the type-dispatch bugs first.What a fix would touch
_import_next_layerinpcapkit/protocols/protocol.py, plus theInternetandIPv6overrides, to pass the packet dict through as__packet__as well aspacket=. Worth checking whether any schema currently relies on receiving an empty dict before changing it, and it needs a test that asserts a schema'spost_processactually sees an outer-layer value.