Repository navigation
HIPv1 R1_Counter (128) parses as UnassignedParameter: R1CounterParameter registers code=129 only #690
Description
Activity
- addedbugIssues reporting a defect (set by the bug report template; a default, not an assessment)Issues reporting a defect (set by the bug report template; a default, not an assessment)
on Sep 23, 2026 Two things measured while fixing #672, both of which change how this issue should be picked up.
The mechanism is already there — this does not need a metaclass change
EnumSchemainpcapkit/protocols/schema/schema.pyalready documents a multi-code registration in
its own class docstring:class MultipleSchema(MySchema, code=[MyEnum.TWO, MyEnum.THREE]): ...
So the fix is plausibly the one-line
class R1CounterParameter(Parameter, code=[Enum_Parameter.R1_Counter, Enum_Parameter.R1_COUNTER]):
rather than anything in
schema.pyitself. Worth saying because the issue text above asks "whichever
the schema metaclass supports more honestly", which reads as an invitation to go widen it — and
wideningschema.pywould collide with the registry-generalisation work currently in flight against
that file. Not verified end to end here (this was out of scope for #672), so treat it as a starting
point rather than a finished answer: the HIPv1 guard in_read_param_r1_counter
(schema.type == 128 and version != 1) and the generator'sHIP_VERSION = {129: 2, 128: 1}both
need to still hold once 128 resolves to a real schema.Note it will also require deleting
hip-parameter/R1_CounterfromEXPECTED_FAILURESin
tests/protocols/test_option_roundtrip_unit.pyin the same change: that table's
test_round_trip_is_identity_or_a_recorded_gapfails an entry whose case has started passing, so the
round-trip suite goes red the moment this lands without the deletion.This is an independent cause from #672, and each was masking the other
Recorded because #664's worker attributed
R1_Counter's failure to the counter width (#672), and
whether both were in play was not established. Both are, and which one you see depends entirely on
HIP_COPIES. Measured with the round trip over the 49 HIP codes, CPython 3.14.7, editable finder
stripped viagetattr(f, '__module__', '')andpcapkit.__file__asserted to the tree under test:tree HIP_COPIES=1HIP_COPIES=2f0999858eCONSTRUCT—ProtocolError: HIPv1: invalid formatPARSE—AttributeError: 'UnassignedParameter' object has no attribute 'counter'#672 + #679 PARSE—AttributeError: 'UnassignedParameter' object has no attribute 'counter'PARSE— sameReading that:
- At one copy on
main, the width defect fires first. A 12-octet record is4 (mod 8), so
HIP.make'stotal_length // 8 + 4loses the remainder and_read_hip_param's exact length check
rejects it before dispatch is ever reached. The registry defect is invisible behind it — which is
why attributing the failure to the width is correct for that measurement. - At two copies, the pair cancels the four-octet shortfall, construction succeeds, and the
registry defect is what fails. That is the setting the case table actually runs at, which is why
EXPECTED_FAILURESrecordsPARSE/"no attribute 'counter'"— correctly attributed to this
issue, not to R1_COUNTER packs 12 octets where RFC 7401 §5.2.3 requires 16:counteris 4 octets, not the stated 8 #672. - After R1_COUNTER packs 12 octets where RFC 7401 §5.2.3 requires 16:
counteris 4 octets, not the stated 8 #672 the width defect is gone at both settings and this one remains at both. So neither
subsumes the other: two independent defects in one parameter, each of which hid the other under a
differentHIP_COPIES.
Concretely for this issue: #672 does not move
hip-parameter/R1_Counter. Verified by importing
EXPECTED_FAILURESrather than grepping it (the table cannot be grepped reliably) on both trees —
44 entries on each, byte-identical, with this entry'sstatus, message andfile:lineunchanged.
The entry stays until this issue is fixed, which is also why it is the sole remaining blocker to the
tally in #689.- At one copy on
- added 7 commits that reference this issue
on Sep 23, 2026 - added 7 commits that reference this issue
on Sep 24, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
R1CounterParameterinpcapkit/protocols/schema/internet/hip.pyis declaredi.e. for code 129 only. The HIP parameter registry that
_read_hip_paramconsults iskeyed on that
code=, so code 128 —R1_Counter, the HIPv1 spelling of the sameparameter — resolves to
Parameter.__default__, which isUnassignedParameter. Thereader is then handed a schema with a
value: bytesand nocounter, and fails withThe asymmetry is that the method dispatch does not have the problem.
_read_param_*and_make_param_*are found by enumeration member name, andpcapkit/protocols/internet/hip.pymaps both codes to the same handler:
So code 128 constructs correctly —
_make_param_r1_counterbuilds a realR1CounterParameter, and_read_param_r1_countereven guards it, raising forschema.type == 128 and version != 1. It is only the parse direction that cannot find theschema.
Measured
CPython 3.14.7, editable finder stripped via
getattr(f, '__module__', ''),pcapkit.__file__asserted to the worktree before any other import. On the tree with #672applied, so the width is already correct and this is the only defect left in the parameter:
Same failure at one copy and at two, so the
HIP_COPIESpair never routed around it.Consequence
A HIPv1 R1 packet read off the wire loses its R1 generation counter, and pcapkit raises
rather than degrading.
RFC 5201§5.2.3 gives code 128 the same 4 + 8 layout RFC 7401§5.2.3 gives 129, so the two are the same parameter under two numbers and one schema class
should serve both.
Suggested fix
Register the class for both codes.
EnumSchema'scode=takes a single member, so thiswants either a second registration for 128 against the same class or a widening of
code=to accept several — whichever the schema metaclass supports more honestly. Worthchecking whether any other parameter in the module has the same v1/v2 code pair and the
same gap.
tests/protocols/test_option_roundtrip_unit.pyrecords this today aship-parameter/R1_Counter,Gap('PARSE', "no attribute 'counter'", ...); fixing it meansdeleting that entry, which the table's own note asks for rather than leaving it behind.
Found while fixing #672. #672 widened the counter field to the 8 octets RFC 7401 §5.2.3
requires and deliberately did not touch this, since it is a registry-keying defect rather
than a width one and the
R1_Counterexpected-failure entry is unchanged by it. It is alsothe sole remaining blocker to the tally in #689.