@packet-schema/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collect-refs.d.ts +4 -0
- package/dist/collect-refs.d.ts.map +1 -0
- package/dist/collect-refs.js +76 -0
- package/dist/collect-refs.js.map +1 -0
- package/dist/constraint.d.ts +66 -0
- package/dist/constraint.d.ts.map +1 -0
- package/dist/constraint.js +286 -0
- package/dist/constraint.js.map +1 -0
- package/dist/expr.d.ts +32 -0
- package/dist/expr.d.ts.map +1 -0
- package/dist/expr.js +190 -0
- package/dist/expr.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +7 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +217 -0
- package/dist/layout.js.map +1 -0
- package/dist/normalize.d.ts +37 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +857 -0
- package/dist/normalize.js.map +1 -0
- package/dist/types.d.ts +538 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +4 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +1222 -0
- package/dist/validate.js.map +1 -0
- package/dist/values.d.ts +31 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +73 -0
- package/dist/values.js.map +1 -0
- package/dist/yaml.d.ts +11 -0
- package/dist/yaml.d.ts.map +1 -0
- package/dist/yaml.js +145 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +35 -0
- package/schemas/psdl-0.5.yaml +1223 -0
|
@@ -0,0 +1,1223 @@
|
|
|
1
|
+
$schema: https://json-schema.org/draft/2020-12/schema
|
|
2
|
+
$id: https://packet-schema.dev/schemas/psdl-0.5.yaml
|
|
3
|
+
title: PSDL 0.5
|
|
4
|
+
description: |-
|
|
5
|
+
Packet Schema Definition Language 0.5 — canonical YAML schema for a single
|
|
6
|
+
packet definition file. The top-level document IS the Packet object.
|
|
7
|
+
|
|
8
|
+
Authoring shorthands (bare integer → ExprLit, bare field-id string →
|
|
9
|
+
ExprRef) are normalized to full object form by the parser before
|
|
10
|
+
JSON Schema validation. The schema validates the normalized form only.
|
|
11
|
+
|
|
12
|
+
# ──────────────────────────────────────────────────────────────────────
|
|
13
|
+
# Packet (top-level)
|
|
14
|
+
# ──────────────────────────────────────────────────────────────────────
|
|
15
|
+
type: object
|
|
16
|
+
required: [name, body]
|
|
17
|
+
unevaluatedProperties: false
|
|
18
|
+
$comment: |-
|
|
19
|
+
Some PSDL rules are intentionally validator-layer-only and cannot be encoded
|
|
20
|
+
in JSON Schema: imported-name visibility (§1.3), §11.4 lint warnings
|
|
21
|
+
(version-absent, recursive-def constraint skip, checksumParams on a named
|
|
22
|
+
CRC), and the placement restriction forbidding `virtual` fields inside
|
|
23
|
+
defs/NamedStruct bodies (§11.1). See the ImportEntry note for the import
|
|
24
|
+
examples.
|
|
25
|
+
properties:
|
|
26
|
+
version:
|
|
27
|
+
type: string
|
|
28
|
+
pattern: '^\d+\.\d+$'
|
|
29
|
+
description: |-
|
|
30
|
+
PSDL version string (e.g. "0.5"). Strongly recommended.
|
|
31
|
+
See §15 for version compatibility rules.
|
|
32
|
+
name:
|
|
33
|
+
type: string
|
|
34
|
+
minLength: 1
|
|
35
|
+
description: Unique packet identifier (globally unique within a packet set).
|
|
36
|
+
abbrev:
|
|
37
|
+
type: string
|
|
38
|
+
description: |-
|
|
39
|
+
Protocol filter name used by codegen (e.g. Wireshark).
|
|
40
|
+
Defaults to `name` if absent.
|
|
41
|
+
rowBits:
|
|
42
|
+
type: integer
|
|
43
|
+
minimum: 1
|
|
44
|
+
description: "Deprecated: use rendererHints.rowBits. Accepted for pre-0.5 compatibility."
|
|
45
|
+
body:
|
|
46
|
+
type: array
|
|
47
|
+
items:
|
|
48
|
+
$ref: '#/$defs/Container'
|
|
49
|
+
constraints:
|
|
50
|
+
type: array
|
|
51
|
+
items:
|
|
52
|
+
$ref: '#/$defs/Constraint'
|
|
53
|
+
byteOrder:
|
|
54
|
+
type: string
|
|
55
|
+
enum: [BE, LE]
|
|
56
|
+
description: Default byte order for all multi-byte integer fields.
|
|
57
|
+
description:
|
|
58
|
+
type: string
|
|
59
|
+
rendererHints:
|
|
60
|
+
$ref: '#/$defs/RendererHints'
|
|
61
|
+
meta:
|
|
62
|
+
$ref: '#/$defs/PacketMeta'
|
|
63
|
+
defs:
|
|
64
|
+
type: object
|
|
65
|
+
description: Named Struct definitions available for reuse via `ref` containers.
|
|
66
|
+
additionalProperties:
|
|
67
|
+
$ref: '#/$defs/NamedStruct'
|
|
68
|
+
imports:
|
|
69
|
+
type: array
|
|
70
|
+
description: |-
|
|
71
|
+
Cross-file def imports. Makes defs from other PSDL files available
|
|
72
|
+
under a namespace prefix. See §1.2.
|
|
73
|
+
items:
|
|
74
|
+
$ref: '#/$defs/ImportEntry'
|
|
75
|
+
|
|
76
|
+
$defs:
|
|
77
|
+
|
|
78
|
+
# ────────────────────────────────────────────────────────────────────
|
|
79
|
+
# Cross-file imports
|
|
80
|
+
# ────────────────────────────────────────────────────────────────────
|
|
81
|
+
ImportEntry:
|
|
82
|
+
type: object
|
|
83
|
+
required: [source, as]
|
|
84
|
+
additionalProperties: false
|
|
85
|
+
description: |-
|
|
86
|
+
Imports defs from another PSDL file under a local namespace prefix.
|
|
87
|
+
NOTE: JSON Schema cannot enforce the following constraints; they MUST be
|
|
88
|
+
enforced by the validator layer:
|
|
89
|
+
- All `as` values in the imports array must be unique (duplicate as
|
|
90
|
+
prefix is a validation error per §1.2 and §11.1).
|
|
91
|
+
- Circular import chains (A imports B imports A) are a validation error.
|
|
92
|
+
See §1.2 for the full import rules.
|
|
93
|
+
properties:
|
|
94
|
+
source:
|
|
95
|
+
type: string
|
|
96
|
+
minLength: 1
|
|
97
|
+
description: |-
|
|
98
|
+
Opaque path / package reference. Resolution is tool-layer concern
|
|
99
|
+
(filesystem path, npm package, URL).
|
|
100
|
+
as:
|
|
101
|
+
type: string
|
|
102
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_]*$'
|
|
103
|
+
description: |-
|
|
104
|
+
Namespace prefix used to reference imported defs.
|
|
105
|
+
Must match [a-zA-Z][a-zA-Z0-9_]* (see §1.2).
|
|
106
|
+
|
|
107
|
+
# ────────────────────────────────────────────────────────────────────
|
|
108
|
+
# Packet metadata
|
|
109
|
+
# ────────────────────────────────────────────────────────────────────
|
|
110
|
+
PacketMeta:
|
|
111
|
+
type: object
|
|
112
|
+
additionalProperties: false
|
|
113
|
+
description: RFC, alias, and classification metadata for tooling (codegen, Chrome extension, LSP, catalog).
|
|
114
|
+
properties:
|
|
115
|
+
rfc:
|
|
116
|
+
$ref: '#/$defs/RfcRef'
|
|
117
|
+
description: RFC provenance (bare number, or {defined, updates}).
|
|
118
|
+
section:
|
|
119
|
+
type: string
|
|
120
|
+
description: RFC section reference (e.g. "3.1").
|
|
121
|
+
aliases:
|
|
122
|
+
type: array
|
|
123
|
+
items: { type: string }
|
|
124
|
+
description: Alternative names for this packet type.
|
|
125
|
+
tags:
|
|
126
|
+
type: array
|
|
127
|
+
items: { type: string }
|
|
128
|
+
description: >-
|
|
129
|
+
Free-form classification tags for catalog grouping/search (§1.1).
|
|
130
|
+
Multi-axis; the vocabulary is governed by the catalog layer, not the
|
|
131
|
+
schema (open strings, like aliases — unlike the closed field `category`).
|
|
132
|
+
family:
|
|
133
|
+
type: string
|
|
134
|
+
description: Optional single grouping key for a family of related packet types (e.g. "bgp") (§1.1).
|
|
135
|
+
|
|
136
|
+
# ────────────────────────────────────────────────────────────────────
|
|
137
|
+
# Normative levels and RFC provenance
|
|
138
|
+
# ────────────────────────────────────────────────────────────────────
|
|
139
|
+
NormativeLevel:
|
|
140
|
+
type: string
|
|
141
|
+
enum: [must, should, may]
|
|
142
|
+
description: |-
|
|
143
|
+
RFC 2119 normative strength. Absent is treated as "must" for constraints
|
|
144
|
+
and as "may" for value-dictionary and enum-variant entries (§9.1, §5.3).
|
|
145
|
+
|
|
146
|
+
RfcRef:
|
|
147
|
+
description: |-
|
|
148
|
+
RFC provenance. Either a bare RFC number (legacy 0.5 form) or an object
|
|
149
|
+
recording the defining RFC plus the chain of updating RFCs (§5.4).
|
|
150
|
+
oneOf:
|
|
151
|
+
- type: integer
|
|
152
|
+
- type: object
|
|
153
|
+
required: [defined]
|
|
154
|
+
additionalProperties: false
|
|
155
|
+
properties:
|
|
156
|
+
defined: { type: integer, description: RFC that originally defined this field. }
|
|
157
|
+
updates:
|
|
158
|
+
type: array
|
|
159
|
+
description: |-
|
|
160
|
+
RFCs that later updated this field's layout or semantics. Each
|
|
161
|
+
entry is either a bare RFC number (no section) or an object
|
|
162
|
+
{ rfc (required), section? } naming the section of that updating
|
|
163
|
+
RFC (§5.4). The defining RFC's own section is carried by the
|
|
164
|
+
sibling meta.section.
|
|
165
|
+
items:
|
|
166
|
+
oneOf:
|
|
167
|
+
- type: integer
|
|
168
|
+
- type: object
|
|
169
|
+
required: [rfc]
|
|
170
|
+
additionalProperties: false
|
|
171
|
+
properties:
|
|
172
|
+
rfc: { type: integer, description: An updating RFC number. }
|
|
173
|
+
section: { type: string, description: 'Section of that updating RFC (e.g. "3").' }
|
|
174
|
+
|
|
175
|
+
# ────────────────────────────────────────────────────────────────────
|
|
176
|
+
# Per-field / per-group RFC metadata
|
|
177
|
+
# ────────────────────────────────────────────────────────────────────
|
|
178
|
+
FieldMeta:
|
|
179
|
+
type: object
|
|
180
|
+
additionalProperties: false
|
|
181
|
+
description: Per-field or per-group RFC annotation used by Chrome extension and LSP.
|
|
182
|
+
properties:
|
|
183
|
+
rfc:
|
|
184
|
+
$ref: '#/$defs/RfcRef'
|
|
185
|
+
description: RFC provenance (bare number, or {defined, updates}).
|
|
186
|
+
section:
|
|
187
|
+
type: string
|
|
188
|
+
description: RFC section reference for this specific field.
|
|
189
|
+
|
|
190
|
+
# ────────────────────────────────────────────────────────────────────
|
|
191
|
+
# Renderer hints
|
|
192
|
+
# ────────────────────────────────────────────────────────────────────
|
|
193
|
+
RendererHints:
|
|
194
|
+
type: object
|
|
195
|
+
additionalProperties: false
|
|
196
|
+
description: |-
|
|
197
|
+
Display-only metadata. A packet without rowBits is a valid PSDL
|
|
198
|
+
document; renderers should fall back to 32 if absent.
|
|
199
|
+
properties:
|
|
200
|
+
rowBits:
|
|
201
|
+
type: integer
|
|
202
|
+
minimum: 1
|
|
203
|
+
description: Number of bits per row in the wire diagram.
|
|
204
|
+
sections:
|
|
205
|
+
type: array
|
|
206
|
+
description: |-
|
|
207
|
+
Visual section labels for the wire diagram. Display-only;
|
|
208
|
+
no effect on wire layout or expression scoping.
|
|
209
|
+
items:
|
|
210
|
+
$ref: '#/$defs/RendererSection'
|
|
211
|
+
|
|
212
|
+
RendererSection:
|
|
213
|
+
type: object
|
|
214
|
+
required: [id, label, fields]
|
|
215
|
+
additionalProperties: false
|
|
216
|
+
description: A labelled visual region in the wire diagram renderer.
|
|
217
|
+
properties:
|
|
218
|
+
id:
|
|
219
|
+
type: string
|
|
220
|
+
minLength: 1
|
|
221
|
+
description: Unique identifier for this section.
|
|
222
|
+
label:
|
|
223
|
+
type: string
|
|
224
|
+
minLength: 1
|
|
225
|
+
description: Human-readable section header.
|
|
226
|
+
fields:
|
|
227
|
+
type: array
|
|
228
|
+
items: { type: string }
|
|
229
|
+
description: |-
|
|
230
|
+
Ordered list of field ids or group ids belonging to this section.
|
|
231
|
+
|
|
232
|
+
# ────────────────────────────────────────────────────────────────────
|
|
233
|
+
# Checksum algorithm parameters
|
|
234
|
+
# ────────────────────────────────────────────────────────────────────
|
|
235
|
+
ChecksumParams:
|
|
236
|
+
type: object
|
|
237
|
+
additionalProperties: false
|
|
238
|
+
description: |-
|
|
239
|
+
CRC algorithm parameters for codegen. Allows full specification of
|
|
240
|
+
arbitrary CRC variants without a custom algorithm name string.
|
|
241
|
+
Only valid on a field whose checksumAlgorithm uses the CRC parameter
|
|
242
|
+
model; pairing it with a named non-CRC algorithm (internet, adler32)
|
|
243
|
+
is a validation error (§8, §11.1).
|
|
244
|
+
properties:
|
|
245
|
+
polynomial:
|
|
246
|
+
oneOf:
|
|
247
|
+
- { type: integer, minimum: 0 }
|
|
248
|
+
- { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
|
|
249
|
+
description: |-
|
|
250
|
+
Generator polynomial (normal / non-reflected form). A bare integer is
|
|
251
|
+
accepted for values ≤ 2^53−1; values needing more than 53 bits (e.g.
|
|
252
|
+
NVMe CRC-64/ECMA-182 polynomial 0xAD93D23594C935A9) MUST be written as
|
|
253
|
+
a 0x hex string so the full 64-bit precision survives. Note: the
|
|
254
|
+
schema accepts any non-negative integer, but the validator rejects a
|
|
255
|
+
bare integer above 2^53−1 (write it as a hex string instead) — schema
|
|
256
|
+
acceptance is not validity here (§8 Integer precision, §11.1).
|
|
257
|
+
initValue:
|
|
258
|
+
oneOf:
|
|
259
|
+
- { type: integer, minimum: 0 }
|
|
260
|
+
- { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
|
|
261
|
+
description: |-
|
|
262
|
+
Initial CRC register value. Same precision rule as polynomial: use a
|
|
263
|
+
0x hex string for values above 2^53−1.
|
|
264
|
+
finalXOR:
|
|
265
|
+
oneOf:
|
|
266
|
+
- { type: integer, minimum: 0 }
|
|
267
|
+
- { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
|
|
268
|
+
description: |-
|
|
269
|
+
Value XORed with the final CRC result. Same precision rule as
|
|
270
|
+
polynomial: use a 0x hex string for values above 2^53−1.
|
|
271
|
+
inputReflect:
|
|
272
|
+
type: boolean
|
|
273
|
+
description: Reflect each input byte before processing.
|
|
274
|
+
outputReflect:
|
|
275
|
+
type: boolean
|
|
276
|
+
description: Reflect the final CRC before applying finalXOR.
|
|
277
|
+
width:
|
|
278
|
+
type: integer
|
|
279
|
+
minimum: 1
|
|
280
|
+
maximum: 64
|
|
281
|
+
description: |-
|
|
282
|
+
CRC width in bits (1–64). Optional; when absent the width equals the
|
|
283
|
+
checksum value field's declared bit width. Required when the field's
|
|
284
|
+
type has no single declared bit width (e.g. bytes), §8.
|
|
285
|
+
|
|
286
|
+
# ────────────────────────────────────────────────────────────────────
|
|
287
|
+
# Expressions
|
|
288
|
+
# ────────────────────────────────────────────────────────────────────
|
|
289
|
+
Expr:
|
|
290
|
+
description: |-
|
|
291
|
+
Pure, serialisable arithmetic / comparison expression.
|
|
292
|
+
Authoring shorthands:
|
|
293
|
+
bare integer N → { kind: lit, value: N }
|
|
294
|
+
bare string "f" → { kind: ref, field: "f" } (if matches field-id pattern)
|
|
295
|
+
These are normalized to full objects before schema validation.
|
|
296
|
+
oneOf:
|
|
297
|
+
- $ref: '#/$defs/ExprLit'
|
|
298
|
+
- $ref: '#/$defs/ExprRef'
|
|
299
|
+
- $ref: '#/$defs/ExprOp'
|
|
300
|
+
- $ref: '#/$defs/ExprCond'
|
|
301
|
+
- $ref: '#/$defs/ExprPeek'
|
|
302
|
+
- $ref: '#/$defs/ExprLookup'
|
|
303
|
+
- $ref: '#/$defs/ExprWireSize'
|
|
304
|
+
- $ref: '#/$defs/ExprPrevIter'
|
|
305
|
+
- $ref: '#/$defs/ExprRemaining'
|
|
306
|
+
- $ref: '#/$defs/ExprEnclosingBits'
|
|
307
|
+
- $ref: '#/$defs/ExprEnclosingField'
|
|
308
|
+
|
|
309
|
+
ExprLit:
|
|
310
|
+
type: object
|
|
311
|
+
required: [kind, value]
|
|
312
|
+
additionalProperties: false
|
|
313
|
+
properties:
|
|
314
|
+
kind: { const: lit }
|
|
315
|
+
value: { type: integer }
|
|
316
|
+
|
|
317
|
+
ExprRef:
|
|
318
|
+
type: object
|
|
319
|
+
required: [kind, field]
|
|
320
|
+
additionalProperties: false
|
|
321
|
+
description: |-
|
|
322
|
+
Value of a named field by id. If field is a repeat container's id (not a
|
|
323
|
+
leaf field), the expression evaluates to that repeat's completed iteration
|
|
324
|
+
count (the env[repeat.id] value mandated by §10.7 for both eos and
|
|
325
|
+
fixed-count repeats), not bytes; for the wire-byte footprint use wireSize.
|
|
326
|
+
See §4.
|
|
327
|
+
properties:
|
|
328
|
+
kind: { const: ref }
|
|
329
|
+
field: { type: string, minLength: 1 }
|
|
330
|
+
|
|
331
|
+
ExprOp:
|
|
332
|
+
type: object
|
|
333
|
+
required: [kind, op, a, b]
|
|
334
|
+
additionalProperties: false
|
|
335
|
+
properties:
|
|
336
|
+
kind: { const: op }
|
|
337
|
+
op:
|
|
338
|
+
type: string
|
|
339
|
+
enum:
|
|
340
|
+
- "+" # addition
|
|
341
|
+
- "-" # subtraction
|
|
342
|
+
- "*" # multiplication
|
|
343
|
+
- "/" # integer division (truncated toward zero)
|
|
344
|
+
- "%" # remainder
|
|
345
|
+
- "<<" # left shift (32-bit)
|
|
346
|
+
- ">>" # arithmetic right shift (32-bit)
|
|
347
|
+
- "==" # equal → 0 or 1
|
|
348
|
+
- "!=" # not equal → 0 or 1
|
|
349
|
+
- "<" # less than → 0 or 1
|
|
350
|
+
- "<=" # less or equal → 0 or 1
|
|
351
|
+
- ">" # greater than → 0 or 1
|
|
352
|
+
- ">=" # greater/equal → 0 or 1
|
|
353
|
+
- "&" # bitwise AND (32-bit)
|
|
354
|
+
- "|" # bitwise OR (32-bit)
|
|
355
|
+
- "^" # bitwise XOR (32-bit)
|
|
356
|
+
a: { $ref: '#/$defs/Expr' }
|
|
357
|
+
b: { $ref: '#/$defs/Expr' }
|
|
358
|
+
|
|
359
|
+
ExprCond:
|
|
360
|
+
type: object
|
|
361
|
+
required: [kind, test, t, f]
|
|
362
|
+
additionalProperties: false
|
|
363
|
+
description: Ternary — evaluates t if test ≠ 0, otherwise f.
|
|
364
|
+
properties:
|
|
365
|
+
kind: { const: cond }
|
|
366
|
+
test: { $ref: '#/$defs/Expr' }
|
|
367
|
+
t: { $ref: '#/$defs/Expr' }
|
|
368
|
+
f: { $ref: '#/$defs/Expr' }
|
|
369
|
+
|
|
370
|
+
ExprPeek:
|
|
371
|
+
type: object
|
|
372
|
+
required: [kind, bits]
|
|
373
|
+
additionalProperties: false
|
|
374
|
+
description: |-
|
|
375
|
+
Read-ahead in the bit stream without consuming. Valid only in
|
|
376
|
+
switch.on, optional.when, and repeat.count (including until).
|
|
377
|
+
See §10.6 for parse-position semantics per context.
|
|
378
|
+
properties:
|
|
379
|
+
kind: { const: peek }
|
|
380
|
+
bits:
|
|
381
|
+
type: integer
|
|
382
|
+
minimum: 1
|
|
383
|
+
maximum: 64
|
|
384
|
+
description: 'Number of bits to read ahead; an integer in 1–64 (§4, §11.1).'
|
|
385
|
+
offset: { $ref: '#/$defs/Expr' }
|
|
386
|
+
|
|
387
|
+
ExprLookup:
|
|
388
|
+
type: object
|
|
389
|
+
required: [kind, key, table]
|
|
390
|
+
additionalProperties: false
|
|
391
|
+
description: |-
|
|
392
|
+
Discrete table lookup. Maps an integer key to an integer value.
|
|
393
|
+
If the key is absent from the table, the result is 0.
|
|
394
|
+
Useful for non-linear encodings such as CAN FD DLC-to-byte-count.
|
|
395
|
+
properties:
|
|
396
|
+
kind: { const: lookup }
|
|
397
|
+
key: { $ref: '#/$defs/Expr' }
|
|
398
|
+
table:
|
|
399
|
+
type: object
|
|
400
|
+
description: |-
|
|
401
|
+
Map from non-negative decimal integer key (as string) to integer
|
|
402
|
+
result value. Keys must match ^(0|[1-9][0-9]*)$ — negative keys,
|
|
403
|
+
hex literals, and non-numeric keys are a validation error (§4, §11.1).
|
|
404
|
+
propertyNames:
|
|
405
|
+
type: string
|
|
406
|
+
pattern: '^(0|[1-9][0-9]*)$'
|
|
407
|
+
additionalProperties: { type: integer }
|
|
408
|
+
|
|
409
|
+
ExprWireSize:
|
|
410
|
+
type: object
|
|
411
|
+
required: [kind, target]
|
|
412
|
+
additionalProperties: false
|
|
413
|
+
description: |-
|
|
414
|
+
Total bytes consumed on the wire by a named container or field
|
|
415
|
+
(`target`), including all recursively nested content for containers.
|
|
416
|
+
For a leaf field this is the field's wire footprint (bits/8 for
|
|
417
|
+
fixed-width types; the encoded size for varint/berLength). May appear in
|
|
418
|
+
constraints, in a Field.computedFrom hint, and in body expressions when
|
|
419
|
+
the target precedes the expression in document order (same
|
|
420
|
+
forward-reference rule as ref). Absent target yields 0. In
|
|
421
|
+
constraints/computedFrom it is evaluated bottom-up after recursive
|
|
422
|
+
encoding for length back-propagation (§4).
|
|
423
|
+
properties:
|
|
424
|
+
kind: { const: wireSize }
|
|
425
|
+
target:
|
|
426
|
+
type: string
|
|
427
|
+
minLength: 1
|
|
428
|
+
description: Id of the named container or field whose wire byte size is returned.
|
|
429
|
+
|
|
430
|
+
ExprPrevIter:
|
|
431
|
+
type: object
|
|
432
|
+
required: [kind, field]
|
|
433
|
+
additionalProperties: false
|
|
434
|
+
description: |-
|
|
435
|
+
Value of a named field from the most recently completed iteration of the
|
|
436
|
+
immediately enclosing repeat. Valid only inside repeat.count.until
|
|
437
|
+
(§4, §10.4). On the first iteration yields the field's seeded value
|
|
438
|
+
(§10.2) or 0.
|
|
439
|
+
properties:
|
|
440
|
+
kind: { const: prevIter }
|
|
441
|
+
field:
|
|
442
|
+
type: string
|
|
443
|
+
minLength: 1
|
|
444
|
+
description: Id of the field whose previous-iteration value is returned.
|
|
445
|
+
|
|
446
|
+
ExprRemaining:
|
|
447
|
+
type: object
|
|
448
|
+
required: [kind]
|
|
449
|
+
additionalProperties: false
|
|
450
|
+
description: |-
|
|
451
|
+
Bytes remaining in the immediately enclosing scope-providing container
|
|
452
|
+
(bounded scope, encrypted.plaintext, or top-level body) at the point of
|
|
453
|
+
evaluation: (scope byte budget) − (bytes already consumed). Replaces the
|
|
454
|
+
former per-scope byte-budget primitives (see §4).
|
|
455
|
+
Valid in bytes.n and other body expressions
|
|
456
|
+
(including inside cond) — last-data-consuming position, mid-scope, or in
|
|
457
|
+
a cond. For end-anchored fields, size the preceding data field
|
|
458
|
+
remaining - <constByteCount> and place the fixed-width end fields after
|
|
459
|
+
it (§5). Using it outside a scope-providing container is a validation
|
|
460
|
+
error (§4). Used inside an encrypted.plaintext whose encrypted container
|
|
461
|
+
omits wireBits, the plaintext budget is undefined and remaining there is
|
|
462
|
+
a validation error (§5 Encrypted, §11.1).
|
|
463
|
+
properties:
|
|
464
|
+
kind: { const: remaining }
|
|
465
|
+
|
|
466
|
+
ExprEnclosingBits:
|
|
467
|
+
type: object
|
|
468
|
+
required: [kind]
|
|
469
|
+
additionalProperties: false
|
|
470
|
+
description: |-
|
|
471
|
+
Absolute bit budget of the nearest scope-providing container that carries
|
|
472
|
+
one: inside an encrypted.plaintext it equals the enclosing encrypted
|
|
473
|
+
container's wireBits expression (evaluated during parse, subject to the
|
|
474
|
+
normal forward-reference rule); at the top-level body it is the externally
|
|
475
|
+
decoder-injected total packet bit count (a constant available before
|
|
476
|
+
parsing, exempt from forward-reference). (A bounded scope's budget is
|
|
477
|
+
authored in bytes, so it does not provide enclosingBits.) Bit-precision
|
|
478
|
+
counterpart of `remaining`; merges the former per-scope bit-budget
|
|
479
|
+
primitives into one form (see §4). Authors write
|
|
480
|
+
enclosingBits / 8 for a byte boundary. Using it outside an encrypted.plaintext struct or the top-level
|
|
481
|
+
body is a validation error; at the top-level body it requires the decoder
|
|
482
|
+
to inject the total packet size (otherwise a runtime error); inside an
|
|
483
|
+
encrypted.plaintext whose encrypted container omits wireBits the budget is
|
|
484
|
+
undefined (validation error, §11.1). §4, §10.1.
|
|
485
|
+
properties:
|
|
486
|
+
kind: { const: enclosingBits }
|
|
487
|
+
|
|
488
|
+
ExprEnclosingField:
|
|
489
|
+
type: object
|
|
490
|
+
required: [kind, field]
|
|
491
|
+
additionalProperties: false
|
|
492
|
+
description: |-
|
|
493
|
+
Value of a named field from the immediately enclosing protocol layer's
|
|
494
|
+
parsed state (cross-layer access, §7). Valid in constraints only; using
|
|
495
|
+
it in a body expression is a validation error. If no enclosing layer is
|
|
496
|
+
present the expression yields 0 (same as an absent-field reference).
|
|
497
|
+
properties:
|
|
498
|
+
kind: { const: enclosingField }
|
|
499
|
+
field:
|
|
500
|
+
type: string
|
|
501
|
+
minLength: 1
|
|
502
|
+
description: Id of the field in the enclosing layer's PSDL document.
|
|
503
|
+
|
|
504
|
+
# ────────────────────────────────────────────────────────────────────
|
|
505
|
+
# Wire types
|
|
506
|
+
# ────────────────────────────────────────────────────────────────────
|
|
507
|
+
Type:
|
|
508
|
+
oneOf:
|
|
509
|
+
- $ref: '#/$defs/TypeInt'
|
|
510
|
+
- $ref: '#/$defs/TypeBits'
|
|
511
|
+
- $ref: '#/$defs/TypeBytes'
|
|
512
|
+
- $ref: '#/$defs/TypeEnum'
|
|
513
|
+
- $ref: '#/$defs/TypeVarint'
|
|
514
|
+
- $ref: '#/$defs/TypeBerLength'
|
|
515
|
+
|
|
516
|
+
TypeInt:
|
|
517
|
+
type: object
|
|
518
|
+
required: [kind, bits]
|
|
519
|
+
additionalProperties: false
|
|
520
|
+
description: Fixed-width integer.
|
|
521
|
+
properties:
|
|
522
|
+
kind: { const: int }
|
|
523
|
+
bits: { type: integer, minimum: 1 }
|
|
524
|
+
signed: { type: boolean }
|
|
525
|
+
|
|
526
|
+
TypeBits:
|
|
527
|
+
type: object
|
|
528
|
+
required: [kind, n]
|
|
529
|
+
additionalProperties: false
|
|
530
|
+
description: |-
|
|
531
|
+
Raw bit field (no numeric semantics). A bits field that is a whole number
|
|
532
|
+
of bytes wide (n a multiple of 8, > 8) and begins on a byte boundary
|
|
533
|
+
follows the packet-level byteOrder for its multi-byte read; any other
|
|
534
|
+
width, or a field beginning/ending mid-byte, is a raw MSB-first bit run
|
|
535
|
+
with no byte-order swap (§12).
|
|
536
|
+
properties:
|
|
537
|
+
kind: { const: bits }
|
|
538
|
+
n: { type: integer, minimum: 1 }
|
|
539
|
+
|
|
540
|
+
TypeBytes:
|
|
541
|
+
type: object
|
|
542
|
+
required: [kind, n]
|
|
543
|
+
additionalProperties: false
|
|
544
|
+
description: |-
|
|
545
|
+
Variable-length byte array; length given by an expression (in bytes) or by
|
|
546
|
+
a `delimiter` form (§3). To consume all remaining bytes of the
|
|
547
|
+
enclosing scope-providing container use n: { kind: remaining } (§4). For
|
|
548
|
+
end-anchored fields, size this field n: remaining - <constByteCount> and
|
|
549
|
+
place the fixed-width end fields after it (§5).
|
|
550
|
+
properties:
|
|
551
|
+
kind: { const: bytes }
|
|
552
|
+
n:
|
|
553
|
+
oneOf:
|
|
554
|
+
- $ref: '#/$defs/Expr'
|
|
555
|
+
- $ref: '#/$defs/BytesDelimited'
|
|
556
|
+
|
|
557
|
+
BytesDelimited:
|
|
558
|
+
type: object
|
|
559
|
+
required: [delimiter]
|
|
560
|
+
additionalProperties: false
|
|
561
|
+
description: |-
|
|
562
|
+
Delimiter-terminated byte length (§3). The field spans from the current
|
|
563
|
+
parse position up to and including the first complete occurrence of the
|
|
564
|
+
delimiter byte sequence; the delimiter is always consumed and is part of
|
|
565
|
+
the field's wire footprint. Length is decoder-determined and forward-only.
|
|
566
|
+
Unrelated to the repeat.count.until after-iteration predicate (§5).
|
|
567
|
+
properties:
|
|
568
|
+
delimiter:
|
|
569
|
+
type: array
|
|
570
|
+
minItems: 1
|
|
571
|
+
items: { type: integer, minimum: 0, maximum: 255 }
|
|
572
|
+
description: Non-empty list of delimiter byte values (each 0–255), e.g. [13, 10] for CRLF or [0] for NUL.
|
|
573
|
+
|
|
574
|
+
ValueEntry:
|
|
575
|
+
type: object
|
|
576
|
+
additionalProperties: false
|
|
577
|
+
description: |-
|
|
578
|
+
Open value-dictionary entry (§5.3). Annotates one discrete value or an
|
|
579
|
+
inclusive range with meaning, normative strength, and provenance. Purely
|
|
580
|
+
annotational: does not close the value space and carries no wire semantics.
|
|
581
|
+
properties:
|
|
582
|
+
value:
|
|
583
|
+
type: integer
|
|
584
|
+
description: Single value. Mutually exclusive with `range`/`pattern`.
|
|
585
|
+
range:
|
|
586
|
+
type: array
|
|
587
|
+
minItems: 2
|
|
588
|
+
maxItems: 2
|
|
589
|
+
items: { type: integer }
|
|
590
|
+
description: Inclusive [min, max] (min ≤ max enforced by the validator). Mutually exclusive with `value`/`pattern`.
|
|
591
|
+
pattern:
|
|
592
|
+
type: string
|
|
593
|
+
pattern: '^[01xX]+$'
|
|
594
|
+
description: >-
|
|
595
|
+
Ternary bit-pattern predicate (0/1/x; uppercase X is accepted as a
|
|
596
|
+
synonym for x), read like a binary literal (rightmost char = bit 0).
|
|
597
|
+
Matches when every non-x bit equals the observed bit, e.g. "xxxx11"
|
|
598
|
+
for the DSCP experimental pool. Mutually exclusive with
|
|
599
|
+
`value`/`range`.
|
|
600
|
+
name: { type: string, description: Short machine-style symbol (e.g. "EF"). }
|
|
601
|
+
label: { type: string, description: Human-readable label. }
|
|
602
|
+
doc: { type: string }
|
|
603
|
+
level: { $ref: '#/$defs/NormativeLevel' }
|
|
604
|
+
meta: { $ref: '#/$defs/FieldMeta' }
|
|
605
|
+
oneOf:
|
|
606
|
+
- required: [value]
|
|
607
|
+
- required: [range]
|
|
608
|
+
- required: [pattern]
|
|
609
|
+
|
|
610
|
+
Subfield:
|
|
611
|
+
type: object
|
|
612
|
+
required: [id, name, mask]
|
|
613
|
+
additionalProperties: false
|
|
614
|
+
description: |-
|
|
615
|
+
Mask-addressed bit subfield over a parent int / byte-aligned bits field
|
|
616
|
+
(§12). The subfield decodes a slice of the parent's byte-order-resolved
|
|
617
|
+
integer value (value bit 0 = LSB). Display/annotation only — no wire bits,
|
|
618
|
+
no parse semantics. The mask must fit the parent's declared width (a
|
|
619
|
+
validator-layer check). Render-position placement is not guaranteed by 0.5.
|
|
620
|
+
properties:
|
|
621
|
+
id:
|
|
622
|
+
type: string
|
|
623
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
|
|
624
|
+
name:
|
|
625
|
+
type: string
|
|
626
|
+
mask:
|
|
627
|
+
oneOf:
|
|
628
|
+
- { type: integer, minimum: 0 }
|
|
629
|
+
- { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
|
|
630
|
+
description: |-
|
|
631
|
+
Bit mask over the parent's decoded value (bit 0 = LSB). A bare integer
|
|
632
|
+
for ≤ 2^53−1; a 0x hex string for wider masks (D9 precedent), decoded
|
|
633
|
+
at full 64-bit precision.
|
|
634
|
+
doc: { type: string }
|
|
635
|
+
values: { type: array, items: { $ref: '#/$defs/ValueEntry' } }
|
|
636
|
+
level: { $ref: '#/$defs/NormativeLevel' }
|
|
637
|
+
category: { $ref: '#/$defs/CategoryToken' }
|
|
638
|
+
meta: { $ref: '#/$defs/FieldMeta' }
|
|
639
|
+
|
|
640
|
+
EnumVariant:
|
|
641
|
+
description: |-
|
|
642
|
+
Enum variant label. Either a plain string or an object with label, doc,
|
|
643
|
+
level (absent ≡ may, §9.1), and meta (§5.4).
|
|
644
|
+
oneOf:
|
|
645
|
+
- type: string
|
|
646
|
+
- type: object
|
|
647
|
+
required: [label]
|
|
648
|
+
additionalProperties: false
|
|
649
|
+
properties:
|
|
650
|
+
label: { type: string }
|
|
651
|
+
doc: { type: string }
|
|
652
|
+
level: { $ref: '#/$defs/NormativeLevel' }
|
|
653
|
+
meta: { $ref: '#/$defs/FieldMeta' }
|
|
654
|
+
|
|
655
|
+
TypeEnum:
|
|
656
|
+
type: object
|
|
657
|
+
required: [kind, bits, variants]
|
|
658
|
+
additionalProperties: false
|
|
659
|
+
description: Named enumeration; keys are numeric values.
|
|
660
|
+
properties:
|
|
661
|
+
kind: { const: enum }
|
|
662
|
+
bits: { type: integer, minimum: 1 }
|
|
663
|
+
variants:
|
|
664
|
+
type: object
|
|
665
|
+
propertyNames: { pattern: '^(0|[1-9][0-9]*)$' }
|
|
666
|
+
additionalProperties:
|
|
667
|
+
$ref: '#/$defs/EnumVariant'
|
|
668
|
+
|
|
669
|
+
TypeVarint:
|
|
670
|
+
type: object
|
|
671
|
+
required: [kind, encoding]
|
|
672
|
+
additionalProperties: false
|
|
673
|
+
description: |-
|
|
674
|
+
Variable-length integer. `encoding` names the scheme; predefined values
|
|
675
|
+
are quic, protobuf, cbor, ea-terminated, leb128. Arbitrary strings are
|
|
676
|
+
accepted for custom encodings (codec is responsible for implementing them).
|
|
677
|
+
properties:
|
|
678
|
+
kind: { const: varint }
|
|
679
|
+
encoding:
|
|
680
|
+
type: string
|
|
681
|
+
minLength: 1
|
|
682
|
+
$comment: |-
|
|
683
|
+
Predefined well-known values: quic, protobuf, cbor, ea-terminated,
|
|
684
|
+
leb128. Arbitrary strings are accepted for custom encodings. Linting
|
|
685
|
+
tools SHOULD warn when the value is non-empty but does not match any
|
|
686
|
+
of the five predefined values (likely a typo, e.g. "quite" for "quic").
|
|
687
|
+
|
|
688
|
+
TypeBerLength:
|
|
689
|
+
type: object
|
|
690
|
+
required: [kind]
|
|
691
|
+
additionalProperties: false
|
|
692
|
+
description: |-
|
|
693
|
+
BER-encoded length field (1–N bytes, self-describing). maxBytes caps the
|
|
694
|
+
maximum encoded length (1–5, default 5). Declaring maxBytes > 5 is a
|
|
695
|
+
validation error. Receiving a wire-encoded length exceeding maxBytes is
|
|
696
|
+
a runtime error.
|
|
697
|
+
properties:
|
|
698
|
+
kind: { const: berLength }
|
|
699
|
+
maxBytes:
|
|
700
|
+
type: integer
|
|
701
|
+
minimum: 1
|
|
702
|
+
maximum: 5
|
|
703
|
+
description: Maximum allowed BER encoded length in bytes (default 5).
|
|
704
|
+
|
|
705
|
+
# ────────────────────────────────────────────────────────────────────
|
|
706
|
+
# Category tokens
|
|
707
|
+
# ────────────────────────────────────────────────────────────────────
|
|
708
|
+
CategoryToken:
|
|
709
|
+
type: string
|
|
710
|
+
enum:
|
|
711
|
+
- addressing # source / destination address
|
|
712
|
+
- identifier # version, type, protocol number
|
|
713
|
+
- length # length / size field
|
|
714
|
+
- type # type / kind discriminator
|
|
715
|
+
- flags # boolean flag bits
|
|
716
|
+
- reserved # must-be-zero / future use
|
|
717
|
+
- checksum # integrity check value
|
|
718
|
+
- variable # payload or generic variable data
|
|
719
|
+
- payload-marker # marks the start of upper-layer payload
|
|
720
|
+
|
|
721
|
+
# ────────────────────────────────────────────────────────────────────
|
|
722
|
+
# Container hierarchy
|
|
723
|
+
# ────────────────────────────────────────────────────────────────────
|
|
724
|
+
Container:
|
|
725
|
+
description: |-
|
|
726
|
+
Any node that can appear in a packet body, def body, group, repeat
|
|
727
|
+
element, switch arm, bounded scope, or encrypted.plaintext field list.
|
|
728
|
+
A single uniform container union applies in every position (the former
|
|
729
|
+
Container/ContainerNoTrailer split existed only to gate trailer
|
|
730
|
+
placement, which has been removed in favour of ordinary end-anchored
|
|
731
|
+
fields, §5). Member order follows the §5 narrative.
|
|
732
|
+
Discriminated by `kind`; Field may omit `kind` (defaults to "field").
|
|
733
|
+
oneOf:
|
|
734
|
+
- $ref: '#/$defs/Field'
|
|
735
|
+
- $ref: '#/$defs/Virtual'
|
|
736
|
+
- $ref: '#/$defs/Group'
|
|
737
|
+
- $ref: '#/$defs/Optional'
|
|
738
|
+
- $ref: '#/$defs/Repeat'
|
|
739
|
+
- $ref: '#/$defs/Switch'
|
|
740
|
+
- $ref: '#/$defs/AlignContainer'
|
|
741
|
+
- $ref: '#/$defs/BoundedContainer'
|
|
742
|
+
- $ref: '#/$defs/Encrypted'
|
|
743
|
+
- $ref: '#/$defs/RefContainer'
|
|
744
|
+
|
|
745
|
+
Field:
|
|
746
|
+
type: object
|
|
747
|
+
required: [id, name, type]
|
|
748
|
+
additionalProperties: false
|
|
749
|
+
description: |-
|
|
750
|
+
A single wire field. `kind` may be omitted (defaults to "field").
|
|
751
|
+
Field `id` must match [a-zA-Z][a-zA-Z0-9_-]* and must not contain ".".
|
|
752
|
+
properties:
|
|
753
|
+
kind:
|
|
754
|
+
type: string
|
|
755
|
+
enum: [field]
|
|
756
|
+
id:
|
|
757
|
+
type: string
|
|
758
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
|
|
759
|
+
description: |-
|
|
760
|
+
Stable identifier used in expressions and cross-references.
|
|
761
|
+
Must not contain "." (reserved as the ref-expansion separator).
|
|
762
|
+
name:
|
|
763
|
+
type: string
|
|
764
|
+
description: Human-readable label.
|
|
765
|
+
type:
|
|
766
|
+
$ref: '#/$defs/Type'
|
|
767
|
+
doc:
|
|
768
|
+
type: string
|
|
769
|
+
meta:
|
|
770
|
+
$ref: '#/$defs/FieldMeta'
|
|
771
|
+
category:
|
|
772
|
+
$ref: '#/$defs/CategoryToken'
|
|
773
|
+
defaultValue:
|
|
774
|
+
type: integer
|
|
775
|
+
description: |-
|
|
776
|
+
Seed value injected into the env before parsing. Honoured for
|
|
777
|
+
fields inside defs as well as top-level fields. If const is also
|
|
778
|
+
set, const takes priority for env seeding.
|
|
779
|
+
byteOrder:
|
|
780
|
+
type: string
|
|
781
|
+
enum: [BE, LE]
|
|
782
|
+
description: |-
|
|
783
|
+
Per-field byte order override. Only affects int and enum types.
|
|
784
|
+
next:
|
|
785
|
+
type: object
|
|
786
|
+
description: |-
|
|
787
|
+
Protocol-linking map: field value → next-layer packet name.
|
|
788
|
+
Values SHOULD match the `name` or `meta.aliases` of the target
|
|
789
|
+
packet. The special key "_" is the catch-all default.
|
|
790
|
+
additionalProperties:
|
|
791
|
+
type: string
|
|
792
|
+
checksumAlgorithm:
|
|
793
|
+
type: string
|
|
794
|
+
description: |-
|
|
795
|
+
Algorithm for computing this checksum. Well-known values:
|
|
796
|
+
internet, crc32, crc32c, crc16, adler32. Arbitrary strings
|
|
797
|
+
accepted for custom algorithms (codec is responsible). A field
|
|
798
|
+
carrying checksumAlgorithm is computed and filled by the codec on
|
|
799
|
+
serialize after the covered fields are encoded (the authored/wire
|
|
800
|
+
value is ignored for output), analogous to the computedFrom contract
|
|
801
|
+
for length fields (§8, §4).
|
|
802
|
+
checksumCovers:
|
|
803
|
+
type: array
|
|
804
|
+
description: |-
|
|
805
|
+
Ordered list of field ids fed into the checksum computation.
|
|
806
|
+
Supports dotted paths (e.g. "src.oct0"), ref-container ids
|
|
807
|
+
(e.g. "src" → expands to all leaf fields of that ref in order), and
|
|
808
|
+
repeat-container ids (e.g. "chunks" → expands to the concatenated
|
|
809
|
+
wire bytes of every iteration in parse order, including any inner
|
|
810
|
+
align padding consumed within each iteration). When a checksum field
|
|
811
|
+
appears inside a repeat element, ids in its checksumCovers resolve
|
|
812
|
+
within the current iteration's scope (the repeat-indexed "#N"
|
|
813
|
+
instance), exactly as ref does (§10.4) — enabling per-block CRCs
|
|
814
|
+
(e.g. DNP3). See §8.
|
|
815
|
+
items:
|
|
816
|
+
type: string
|
|
817
|
+
checksumPseudoHeader:
|
|
818
|
+
type: string
|
|
819
|
+
enum: [ipv4, ipv6]
|
|
820
|
+
description: |-
|
|
821
|
+
Well-known pseudo-header prepended before checksumCovers when
|
|
822
|
+
computing the checksum. Used for TCP/UDP over IP.
|
|
823
|
+
checksumParams:
|
|
824
|
+
$ref: '#/$defs/ChecksumParams'
|
|
825
|
+
const:
|
|
826
|
+
type: integer
|
|
827
|
+
description: |-
|
|
828
|
+
Fixed value this field must carry. A mismatch is a runtime error.
|
|
829
|
+
Takes priority over defaultValue for env seeding; seeds the env
|
|
830
|
+
even when defaultValue is absent.
|
|
831
|
+
display:
|
|
832
|
+
type: string
|
|
833
|
+
enum: [dec, hex, oct, bin, ascii, utf8, addr]
|
|
834
|
+
description: |-
|
|
835
|
+
Display hint for renderers and Wireshark codegen. For numeric fields
|
|
836
|
+
a base (dec/hex/oct/bin, default dec); for bytes fields a rendering
|
|
837
|
+
(ascii/utf8/addr, default hex). No effect on wire encoding (§14).
|
|
838
|
+
values:
|
|
839
|
+
type: array
|
|
840
|
+
items: { $ref: '#/$defs/ValueEntry' }
|
|
841
|
+
description: |-
|
|
842
|
+
Open value dictionary for this field's discrete values (§5.3).
|
|
843
|
+
Annotational only; does not close the value space.
|
|
844
|
+
subfields:
|
|
845
|
+
type: array
|
|
846
|
+
items: { $ref: '#/$defs/Subfield' }
|
|
847
|
+
description: |-
|
|
848
|
+
Mask-addressed bit subfields over this int / byte-aligned bits field
|
|
849
|
+
(§12). Display/annotation only; value bit 0 = LSB of the decoded
|
|
850
|
+
value. The int-or-byte-aligned-bits restriction and the mask-fits-width
|
|
851
|
+
rule are validator-layer checks (§11.1).
|
|
852
|
+
computedFrom:
|
|
853
|
+
$ref: '#/$defs/ExprWireSize'
|
|
854
|
+
description: |-
|
|
855
|
+
Serializer hint only (does not affect parsing). Must be a wireSize
|
|
856
|
+
expression; instructs the codec to compute and fill this length
|
|
857
|
+
field bottom-up after recursive encoding is complete (§4, §6).
|
|
858
|
+
Using any other expression is a validation error.
|
|
859
|
+
allOf:
|
|
860
|
+
# §8/§11.1: checksumParams may only refine a CRC parameter model. Using it
|
|
861
|
+
# with a named non-CRC algorithm (internet, adler32) is a validation error —
|
|
862
|
+
# these algorithms have fixed internal parameters incompatible with the CRC set.
|
|
863
|
+
- if:
|
|
864
|
+
properties:
|
|
865
|
+
checksumAlgorithm:
|
|
866
|
+
enum: [internet, adler32]
|
|
867
|
+
required: [checksumAlgorithm]
|
|
868
|
+
then:
|
|
869
|
+
not:
|
|
870
|
+
required: [checksumParams]
|
|
871
|
+
|
|
872
|
+
Virtual:
|
|
873
|
+
type: object
|
|
874
|
+
required: [kind, id, expr]
|
|
875
|
+
additionalProperties: false
|
|
876
|
+
description: |-
|
|
877
|
+
Computed auxiliary field that consumes zero wire bytes. Its expr is
|
|
878
|
+
evaluated at parse time using the same forward-reference rules as body
|
|
879
|
+
expressions; its id is added to the env for subsequent expressions,
|
|
880
|
+
constraints, and checksumCovers (§5 Virtual field). Forbidden inside
|
|
881
|
+
defs/NamedStruct bodies (§11.1) — that placement restriction is enforced
|
|
882
|
+
by the validator layer, not this schema.
|
|
883
|
+
properties:
|
|
884
|
+
kind: { const: virtual }
|
|
885
|
+
id:
|
|
886
|
+
type: string
|
|
887
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
|
|
888
|
+
description: Identifier added to the env and usable in subsequent expressions.
|
|
889
|
+
expr: { $ref: '#/$defs/Expr' }
|
|
890
|
+
name: { type: string }
|
|
891
|
+
doc: { type: string }
|
|
892
|
+
|
|
893
|
+
Optional:
|
|
894
|
+
type: object
|
|
895
|
+
required: [kind, when, container]
|
|
896
|
+
additionalProperties: false
|
|
897
|
+
description: |-
|
|
898
|
+
Conditionally includes a container. `when` evaluated as boolean
|
|
899
|
+
(0 = absent, non-zero = present). Nesting Optional inside Optional
|
|
900
|
+
is allowed; inner `when` is evaluated only if the outer is present
|
|
901
|
+
(short-circuit semantics). See §10.8.
|
|
902
|
+
properties:
|
|
903
|
+
kind: { const: optional }
|
|
904
|
+
id:
|
|
905
|
+
type: string
|
|
906
|
+
description: |-
|
|
907
|
+
Optional identifier for the optional container. Used by §13
|
|
908
|
+
rendererHints.sections and wireSize (§4). Note wireSize on an
|
|
909
|
+
absent optional's inner field yields 0; target the inner field id,
|
|
910
|
+
not the optional container id.
|
|
911
|
+
when: { $ref: '#/$defs/Expr' }
|
|
912
|
+
container: { $ref: '#/$defs/Container' }
|
|
913
|
+
doc:
|
|
914
|
+
type: string
|
|
915
|
+
description: Description for LSP hover documentation.
|
|
916
|
+
meta:
|
|
917
|
+
$ref: '#/$defs/FieldMeta'
|
|
918
|
+
description: |-
|
|
919
|
+
Per-region RFC annotation { rfc?, section? } enabling LSP hover and
|
|
920
|
+
per-region RFC deep-linking for this optional container (§5).
|
|
921
|
+
Available through the source AST only (§5.4): the optional is
|
|
922
|
+
transparent in the flat normalized model.
|
|
923
|
+
|
|
924
|
+
Struct:
|
|
925
|
+
type: object
|
|
926
|
+
required: [id, fields]
|
|
927
|
+
additionalProperties: false
|
|
928
|
+
description: |-
|
|
929
|
+
Named list of containers; used in Repeat.element, Switch.cases arms,
|
|
930
|
+
and Encrypted.plaintext. Does not carry the recursive property — only
|
|
931
|
+
NamedStruct (used exclusively in defs) may be recursive.
|
|
932
|
+
properties:
|
|
933
|
+
id:
|
|
934
|
+
type: string
|
|
935
|
+
minLength: 1
|
|
936
|
+
doc:
|
|
937
|
+
type: string
|
|
938
|
+
description: Description for LSP hover and tooling documentation.
|
|
939
|
+
meta:
|
|
940
|
+
$ref: '#/$defs/FieldMeta'
|
|
941
|
+
description: |-
|
|
942
|
+
Per-region RFC annotation { rfc?, section? } for the inline struct
|
|
943
|
+
used as a Switch arm or Repeat element, enabling LSP hover and
|
|
944
|
+
per-region RFC deep-linking (§5). Available through the source AST
|
|
945
|
+
only (§5.4): the inline struct is transparent in the flat
|
|
946
|
+
normalized model.
|
|
947
|
+
fields:
|
|
948
|
+
type: array
|
|
949
|
+
items:
|
|
950
|
+
$ref: '#/$defs/Container'
|
|
951
|
+
|
|
952
|
+
NamedStruct:
|
|
953
|
+
type: object
|
|
954
|
+
required: [id, fields]
|
|
955
|
+
additionalProperties: false
|
|
956
|
+
description: |-
|
|
957
|
+
Struct type used exclusively as defs map values. Extends Struct with
|
|
958
|
+
the recursive property, which is meaningless (and therefore forbidden)
|
|
959
|
+
on anonymous inline structs used in Repeat.element, Switch.cases, or
|
|
960
|
+
Encrypted.plaintext.
|
|
961
|
+
properties:
|
|
962
|
+
id:
|
|
963
|
+
type: string
|
|
964
|
+
minLength: 1
|
|
965
|
+
doc:
|
|
966
|
+
type: string
|
|
967
|
+
description: Description for LSP hover and tooling documentation.
|
|
968
|
+
meta:
|
|
969
|
+
$ref: '#/$defs/FieldMeta'
|
|
970
|
+
description: |-
|
|
971
|
+
RFC annotation { rfc?, section? } for the def as a whole (§5.4, §6).
|
|
972
|
+
Documentation-grade provenance available through the source AST
|
|
973
|
+
only: a ref expansion is transparent and emits no container field,
|
|
974
|
+
so this meta does not appear in the normalized/layout output.
|
|
975
|
+
recursive:
|
|
976
|
+
type: boolean
|
|
977
|
+
description: |-
|
|
978
|
+
When true, this struct may contain ref containers pointing to
|
|
979
|
+
itself (direct) or to other recursive: true structs (indirect).
|
|
980
|
+
The decoder is responsible for depth limiting. Disables the
|
|
981
|
+
circular-reference validation check for this struct.
|
|
982
|
+
fields:
|
|
983
|
+
type: array
|
|
984
|
+
items:
|
|
985
|
+
$ref: '#/$defs/Container'
|
|
986
|
+
|
|
987
|
+
Group:
|
|
988
|
+
type: object
|
|
989
|
+
required: [kind, id, name, children]
|
|
990
|
+
additionalProperties: false
|
|
991
|
+
description: |-
|
|
992
|
+
Logical grouping of adjacent fields. Groups collapse to a single row
|
|
993
|
+
in the wire diagram and expose sub-field detail on hover.
|
|
994
|
+
properties:
|
|
995
|
+
kind: { const: group }
|
|
996
|
+
id: { type: string, minLength: 1 }
|
|
997
|
+
name: { type: string }
|
|
998
|
+
doc:
|
|
999
|
+
type: string
|
|
1000
|
+
description: Description for LSP hover documentation.
|
|
1001
|
+
meta:
|
|
1002
|
+
$ref: '#/$defs/FieldMeta'
|
|
1003
|
+
category: { $ref: '#/$defs/CategoryToken' }
|
|
1004
|
+
children:
|
|
1005
|
+
type: array
|
|
1006
|
+
items:
|
|
1007
|
+
$ref: '#/$defs/Container'
|
|
1008
|
+
|
|
1009
|
+
RepeatCount:
|
|
1010
|
+
description: |-
|
|
1011
|
+
Repetition specifier: a numeric expression, the string "eos"
|
|
1012
|
+
(repeat until the boundary of the nearest enclosing scope-providing
|
|
1013
|
+
container — a bounded scope, an encrypted.plaintext struct, or the
|
|
1014
|
+
top-level body, §5), or an until-condition object.
|
|
1015
|
+
oneOf:
|
|
1016
|
+
- $ref: '#/$defs/Expr'
|
|
1017
|
+
- type: string
|
|
1018
|
+
const: eos
|
|
1019
|
+
- type: object
|
|
1020
|
+
required: [until]
|
|
1021
|
+
additionalProperties: false
|
|
1022
|
+
properties:
|
|
1023
|
+
until: { $ref: '#/$defs/Expr' }
|
|
1024
|
+
|
|
1025
|
+
Repeat:
|
|
1026
|
+
type: object
|
|
1027
|
+
required: [kind, id, element, count]
|
|
1028
|
+
additionalProperties: false
|
|
1029
|
+
description: |-
|
|
1030
|
+
Repeats a Struct a given number of times. The decoder injects the
|
|
1031
|
+
completed iteration count into env[repeat.id] before normalization — for
|
|
1032
|
+
count: eos repeats (where it is detected at parse time) and for
|
|
1033
|
+
fixed-count repeats (where it trivially equals the count expression),
|
|
1034
|
+
§10.7. A ref whose field is this repeat's id therefore evaluates to that
|
|
1035
|
+
iteration count (§4).
|
|
1036
|
+
properties:
|
|
1037
|
+
kind: { const: repeat }
|
|
1038
|
+
id: { type: string, minLength: 1 }
|
|
1039
|
+
name: { type: string }
|
|
1040
|
+
element: { $ref: '#/$defs/Struct' }
|
|
1041
|
+
count: { $ref: '#/$defs/RepeatCount' }
|
|
1042
|
+
category: { $ref: '#/$defs/CategoryToken' }
|
|
1043
|
+
doc: { type: string }
|
|
1044
|
+
|
|
1045
|
+
Switch:
|
|
1046
|
+
type: object
|
|
1047
|
+
required: [kind, id, on, cases]
|
|
1048
|
+
additionalProperties: false
|
|
1049
|
+
description: |-
|
|
1050
|
+
Selects one Struct arm based on a discriminator expression.
|
|
1051
|
+
Case key formats: exact decimal "6", range "0-127", list "6,17,58",
|
|
1052
|
+
or catch-all "_". Keys are matched in order: exact → list → range → "_".
|
|
1053
|
+
The "_" key must appear inside the cases map (no separate default property).
|
|
1054
|
+
properties:
|
|
1055
|
+
kind: { const: switch }
|
|
1056
|
+
id: { type: string, minLength: 1 }
|
|
1057
|
+
name: { type: string }
|
|
1058
|
+
on: { $ref: '#/$defs/Expr' }
|
|
1059
|
+
cases:
|
|
1060
|
+
type: object
|
|
1061
|
+
description: |-
|
|
1062
|
+
Keys: decimal "6", range "0-127", list "6,17,58", or "_" (catch-all).
|
|
1063
|
+
Evaluation order: exact → list → range → "_".
|
|
1064
|
+
additionalProperties:
|
|
1065
|
+
$ref: '#/$defs/Struct'
|
|
1066
|
+
doc: { type: string }
|
|
1067
|
+
|
|
1068
|
+
Encrypted:
|
|
1069
|
+
type: object
|
|
1070
|
+
required: [kind, id, plaintext]
|
|
1071
|
+
additionalProperties: false
|
|
1072
|
+
description: |-
|
|
1073
|
+
Marks a region as encrypted. In wire view the region appears as an
|
|
1074
|
+
opaque block; in semantic view plaintext fields are shown. Inside
|
|
1075
|
+
plaintext the remaining and enclosingBits expressions are available, but
|
|
1076
|
+
only when wireBits is present: wireBits is the plaintext byte/bit budget,
|
|
1077
|
+
so if it is absent the plaintext budget is undefined and
|
|
1078
|
+
remaining/enclosingBits inside it are validation errors (§5, §11.1).
|
|
1079
|
+
properties:
|
|
1080
|
+
kind: { const: encrypted }
|
|
1081
|
+
id: { type: string, minLength: 1 }
|
|
1082
|
+
name: { type: string }
|
|
1083
|
+
plaintext: { $ref: '#/$defs/Struct' }
|
|
1084
|
+
wireBits: { $ref: '#/$defs/Expr' }
|
|
1085
|
+
contextNote:
|
|
1086
|
+
type: string
|
|
1087
|
+
minLength: 1
|
|
1088
|
+
description: Human-readable note shown in the encrypted-region tooltip.
|
|
1089
|
+
headerProtected:
|
|
1090
|
+
type: array
|
|
1091
|
+
description: |-
|
|
1092
|
+
Field ids that are header-protected by the cipher: either inside this
|
|
1093
|
+
plaintext, or a plaintext-external header field declared earlier in
|
|
1094
|
+
this body (§5). Annotation only. The same-body resolution is a
|
|
1095
|
+
validator-layer check (JSON Schema cannot express it).
|
|
1096
|
+
items: { type: string }
|
|
1097
|
+
category: { $ref: '#/$defs/CategoryToken' }
|
|
1098
|
+
doc: { type: string }
|
|
1099
|
+
meta:
|
|
1100
|
+
$ref: '#/$defs/FieldMeta'
|
|
1101
|
+
description: RFC provenance for the encrypted region (§5.4).
|
|
1102
|
+
|
|
1103
|
+
RefContainer:
|
|
1104
|
+
type: object
|
|
1105
|
+
required: [kind, ref, id]
|
|
1106
|
+
additionalProperties: false
|
|
1107
|
+
description: |-
|
|
1108
|
+
Inlines a named Struct from `defs` (or imported defs). Expanded field
|
|
1109
|
+
ids are prefixed with `{id}.` (e.g. ref id "src" + field "oct0" →
|
|
1110
|
+
"src.oct0"). Inside a repeat, expanded ids become "{ref.id}.{field.id}#N".
|
|
1111
|
+
The ref target must exist in defs or an imported namespace.
|
|
1112
|
+
Non-recursive circular references are a validation error.
|
|
1113
|
+
A ref is a transparent expansion (inherits surrounding scope).
|
|
1114
|
+
properties:
|
|
1115
|
+
kind: { const: ref }
|
|
1116
|
+
ref:
|
|
1117
|
+
type: string
|
|
1118
|
+
minLength: 1
|
|
1119
|
+
description: |-
|
|
1120
|
+
Key into the packet-level `defs` map, or a namespaced import
|
|
1121
|
+
reference (e.g. "addr.ipv4Addr").
|
|
1122
|
+
id:
|
|
1123
|
+
type: string
|
|
1124
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
|
|
1125
|
+
name: { type: string }
|
|
1126
|
+
|
|
1127
|
+
AlignContainer:
|
|
1128
|
+
type: object
|
|
1129
|
+
required: [kind, to]
|
|
1130
|
+
additionalProperties: false
|
|
1131
|
+
description: |-
|
|
1132
|
+
Consumes zero or more bytes to align the current parse position to a
|
|
1133
|
+
given bit boundary, measured from the absolute wire/packet origin. `to`
|
|
1134
|
+
must be a positive integer power of 2 and a multiple of 8. If a preceding
|
|
1135
|
+
sub-byte bits field left the cursor mid-byte, align first rounds up to the
|
|
1136
|
+
next whole byte, then advances to the `to` boundary (§5). Inside a bounded
|
|
1137
|
+
scope, padding bytes are charged against the scope byte budget; an align
|
|
1138
|
+
whose padding exceeds the remaining budget is a runtime error (§5). At the
|
|
1139
|
+
top-level body (or any scope), if the computed padding would run past the
|
|
1140
|
+
injected end-of-data the align consumes only the bytes actually available
|
|
1141
|
+
and does not error (it caps at the scope/packet end) — covering SCTP
|
|
1142
|
+
last-chunk optional padding (RFC 4960 §3.2), §5.
|
|
1143
|
+
Alignment padding bytes are excluded from any enclosing checksum coverage
|
|
1144
|
+
unless this container's `id` is explicitly listed in checksumCovers. `to`
|
|
1145
|
+
not a positive power of 2 that is a multiple of 8 is a validation error.
|
|
1146
|
+
properties:
|
|
1147
|
+
kind: { const: align }
|
|
1148
|
+
to:
|
|
1149
|
+
type: integer
|
|
1150
|
+
minimum: 1
|
|
1151
|
+
description: |-
|
|
1152
|
+
Alignment target in bits. Must be a positive integer power of 2 and
|
|
1153
|
+
a multiple of 8 (e.g. 8, 16, 32, 64). Validator MUST reject values
|
|
1154
|
+
that are not a power of 2 or not a multiple of 8.
|
|
1155
|
+
fill:
|
|
1156
|
+
type: integer
|
|
1157
|
+
minimum: 0
|
|
1158
|
+
maximum: 255
|
|
1159
|
+
description: |-
|
|
1160
|
+
Byte value used to fill padding bytes during serialization. When
|
|
1161
|
+
present, decoders also validate that incoming padding bytes equal
|
|
1162
|
+
this value (mismatch is a validation warning, §11.3). Range 0–255;
|
|
1163
|
+
values outside this range are a validation error. When absent,
|
|
1164
|
+
the fill value is encoder/decoder-defined. Example use: SCTP and
|
|
1165
|
+
Diameter mandate zero-fill padding (fill: 0).
|
|
1166
|
+
id:
|
|
1167
|
+
type: string
|
|
1168
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
|
|
1169
|
+
description: Optional identifier if the padding bytes need to be referenced.
|
|
1170
|
+
doc: { type: string }
|
|
1171
|
+
|
|
1172
|
+
BoundedContainer:
|
|
1173
|
+
type: object
|
|
1174
|
+
required: [kind, id, bytes, fields]
|
|
1175
|
+
additionalProperties: false
|
|
1176
|
+
description: |-
|
|
1177
|
+
Constrains parsing of its contents to a declared byte count. Creates a
|
|
1178
|
+
sub-stream cursor so that count:eos repeats terminate at the scope boundary.
|
|
1179
|
+
Inside a bounded scope, n: { kind: remaining } on a bytes field consumes
|
|
1180
|
+
all remaining bytes in this scope. Bounded scopes may be nested. A
|
|
1181
|
+
count: eos repeat more generally terminates at the boundary of its nearest
|
|
1182
|
+
enclosing scope-providing container — a bounded scope, an
|
|
1183
|
+
encrypted.plaintext struct (its wireBits budget), or the top-level body —
|
|
1184
|
+
not only a bounded scope (same scope-provider list as remaining/
|
|
1185
|
+
enclosingBits, §4, §5).
|
|
1186
|
+
properties:
|
|
1187
|
+
kind: { const: bounded }
|
|
1188
|
+
id:
|
|
1189
|
+
type: string
|
|
1190
|
+
pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
|
|
1191
|
+
description: Scope identifier.
|
|
1192
|
+
bytes:
|
|
1193
|
+
$ref: '#/$defs/Expr'
|
|
1194
|
+
description: Expression giving the byte count of this scope.
|
|
1195
|
+
fields:
|
|
1196
|
+
type: array
|
|
1197
|
+
items:
|
|
1198
|
+
$ref: '#/$defs/Container'
|
|
1199
|
+
description: Ordered list of containers parsed within the scope.
|
|
1200
|
+
name: { type: string }
|
|
1201
|
+
doc: { type: string }
|
|
1202
|
+
meta:
|
|
1203
|
+
$ref: '#/$defs/FieldMeta'
|
|
1204
|
+
description: RFC provenance for the bounded region (§5.4).
|
|
1205
|
+
|
|
1206
|
+
# ────────────────────────────────────────────────────────────────────
|
|
1207
|
+
# Constraints
|
|
1208
|
+
# ────────────────────────────────────────────────────────────────────
|
|
1209
|
+
Constraint:
|
|
1210
|
+
type: object
|
|
1211
|
+
required: [lhs, rhs]
|
|
1212
|
+
additionalProperties: false
|
|
1213
|
+
description: |-
|
|
1214
|
+
Equality constraint between two expressions. Evaluated independently
|
|
1215
|
+
of body parsing; may reference any field regardless of document position.
|
|
1216
|
+
Back-propagation is fixpoint-iterated: the solver reruns until no new
|
|
1217
|
+
fields are resolved in a pass. Only single-unknown linear expressions
|
|
1218
|
+
can be auto-solved; multi-unknown / non-linear are validation-only.
|
|
1219
|
+
properties:
|
|
1220
|
+
lhs: { $ref: '#/$defs/Expr' }
|
|
1221
|
+
rhs: { $ref: '#/$defs/Expr' }
|
|
1222
|
+
doc: { type: string }
|
|
1223
|
+
level: { $ref: '#/$defs/NormativeLevel' }
|