Documentation
¶
Overview ¶
Package discovery is the controller's DNS-SD browser: it finds commissionable nodes on the network and follows the operational instance of a commissioned one (ADR 0020, stage 1).
It ports the shape of matter.js's discovery stack at 0ceb202d:
- Names and Name are the shared record cache, matter.js DnssdNames and DnssdName (packages/general/src/net/dns-sd/).
- Service is the live view of one DNS-SD service name, matter.js IpService; Service.Resolve runs IpServiceResolution.
- Solicitor is the query loop with its retry schedule, matter.js DnssdSolicitor / QueryMulticaster.
- TXTData and ParseTXTData are the TXT parser, matter.js DiscoveryData of packages/protocol/src/common/Scanner.ts.
- Scanner is matter.js's CommissionableMdnsScanner (packages/protocol/src/mdns/).
- Names.Service gives the operational service of one node, the way a matter.js Peer owns an IpService for its `<CFID>-<NODEID>._matter._tcp.local` name.
matter.js runs this stack on one JavaScript event loop. The Go port keeps that model: every Names owns one goroutine that holds all cache, service, solicitor and scanner state; the exported methods hand their work to it and wait. Work matter.js defers to a microtask (record-change notification, deletion of an unused name) runs on the loop right after the operation that caused it, and work it defers to a macrotask (query coalescing, service-change coalescing) runs after that. User callbacks never run on the loop.
The package imports mdns and the standard library only; it does not import bridge/, node/, device/ or endpoint/ (ADR 0020).
Index ¶
- Constants
- Variables
- func CompareDesirability(a, b Address) int
- func OperationalQName(compressedFabricID [8]byte, nodeID uint64) string
- func ParseTxtDecimal(value string, limit uint64) (uint64, bool)
- func SelectionPreference(ip netip.Addr) int
- type Address
- type AddressChange
- type AddressChangeKind
- type Changes
- type Device
- type Discovery
- type Identifier
- func AnyCommissionable() Identifier
- func ByDeviceType(deviceType uint32) Identifier
- func ByInstanceID(id string) Identifier
- func ByLongDiscriminator(d uint16) Identifier
- func ByProduct(product uint16) Identifier
- func ByShortDiscriminator(d uint8) Identifier
- func ByVendor(vendor uint16) Identifier
- func ByVendorProduct(vendor, product uint16) Identifier
- type Name
- type Names
- type Parameters
- type Record
- type Retries
- type Scanner
- type Service
- func (s *Service) AddressChanges(ctx context.Context) <-chan AddressChange
- func (s *Service) Addresses() []Address
- func (s *Service) Changes(ctx context.Context) <-chan struct{}
- func (s *Service) Close()
- func (s *Service) HasTXTRecord() bool
- func (s *Service) Name() *Name
- func (s *Service) Parameters() Parameters
- func (s *Service) Reachable() bool
- func (s *Service) Resolve(ctx context.Context) ([]Address, error)
- func (s *Service) Status() *Status
- func (s *Service) TXTData() TXTData
- type Solicitation
- type Solicitor
- type Status
- func (st *Status) Connecting(result <-chan bool)
- func (st *Status) ConnectionInitiatedAt() time.Time
- func (st *Status) IsConnecting() bool
- func (st *Status) IsResolving() bool
- func (st *Status) LastReceiptAt() time.Time
- func (st *Status) Reachable() bool
- func (st *Status) SetLastReceiptAt(at time.Time)
- func (st *Status) SetReachable(reachable bool)
- type SupportedTransports
- type TXTData
Constants ¶
const ( TypeA = mdns.DNSTypeA TypePTR = mdns.DNSTypePTR TypeTXT = mdns.DNSTypeTXT TypeAAAA = mdns.DNSTypeAAAA TypeSRV = mdns.DNSTypeSRV )
Record types a Record carries a value for.
const ( // DefaultEvictionDelay is how long a record survives once a goodbye // or a cache-flush record supersedes it (RFC 6762 §10.1). DefaultEvictionDelay = time.Second // DefaultMinTTL is the lowest TTL a record is cached with; a shorter // one is raised to it ("the value that Apple uses"). DefaultMinTTL = 15 * time.Second )
Cache defaults. Mirrors matter.js 0ceb202d packages/general/src/net/dns-sd/DnssdNames.ts:549-552 (DnssdNames.defaults).
const ( PreferenceIPv6LinkLocal = iota PreferenceIPv6ULA PreferenceIPv6 PreferenceIPv4 )
Selection preferences, lower first. Mirrors matter.js 0ceb202d packages/general/src/net/ServerAddress.ts:170-176 (ServerAddress.SelectionPreference).
const ( // CommissioningRetryInterval caps a scanner discovery's retry interval // so queries stay dense inside a commissioning window. CommissioningRetryInterval = 30 * time.Second )
Scanner constants. Mirrors matter.js 0ceb202d packages/protocol/src/mdns/CommissionableMdnsScanner.ts:69-75.
const DefaultTTLGraceFactor = 1.05
DefaultTTLGraceFactor is the factor applied to a record's TTL when its expiry is computed, so timing jitter does not expire it early and cause spurious queries. Mirrors matter.js 0ceb202d packages/general/src/net/dns-sd/DnssdName.ts:25 DEFAULT_TTL_GRACE_FACTOR.
Variables ¶
var DefaultRetries = Retries{ InitialInterval: time.Second, JitterFactor: 0.2, BackoffFactor: 2, MaximumInterval: time.Hour, }
DefaultRetries is the solicitor's schedule: 1 s, doubling, jitter up to 20 %, at most one hour. Mirrors matter.js 0ceb202d packages/general/src/net/dns-sd/DnssdSolicitor.ts:94-99 (DnssdSolicitor.DefaultRetries).
var ErrClosed = errors.New("discovery: closed")
ErrClosed is returned by an operation on a Names that has been closed.
Functions ¶
func CompareDesirability ¶
CompareDesirability orders two addresses for communication, negative when a is preferred: selection preference first, then health, then — when both are known — the higher DNS priority value. Mirrors matter.js 0ceb202d packages/general/src/net/ServerAddressSet.ts:165-184 (compareDesirability).
func OperationalQName ¶
OperationalQName is the DNS-SD name of a node's operational instance, `<CFID>-<NODEID>._matter._tcp.local`, both ids as 16 upper-case hex digits, without the trailing dot. Mirrors matter.js 0ceb202d packages/protocol/src/mdns/MdnsConsts.ts:36-37 (getOperationalDeviceQname); it is mdns.OperationalInstanceQName without the root dot.
func ParseTxtDecimal ¶
ParseTxtDecimal parses a numeric TXT value: a decimal integer without leading zeros (/^(0|[1-9]\d*)$/) no greater than limit; anything else is absent. Mirrors matter.js 0ceb202d packages/protocol/src/common/Scanner.ts:153-159 (parseTxtDecimal).
func SelectionPreference ¶
SelectionPreference ranks an IP for connection attempts: IPv6 link-local, then ULA (fc00::/7), then other IPv6, then IPv4. It classifies the address text as matter.js does — ULA by /^f[cd]/i, link-local by /^fe[89ab]/i, IPv6 by a ":" — so an IPv4-mapped IPv6 address counts as IPv6. Mirrors matter.js 0ceb202d packages/general/src/net/ServerAddress.ts:178-209 (selectionPreferenceOfIp).
Types ¶
type Address ¶
type Address struct {
IP netip.Addr
Port uint16
// HealthyAt is the last successful use, zero when unknown.
HealthyAt time.Time
// UnhealthyAt is the last failed use, zero when unknown.
UnhealthyAt time.Time
// Priority is the DNS priority, nil when unknown.
Priority *uint16
}
Address is one way to reach a service: matter.js ServerAddressIp (packages/general/src/net/ServerAddress.ts), an IP and port with the health and DNS priority the desirability order weighs. An IPv6 link-local address carries the zone of the interface its AAAA arrived on.
type AddressChange ¶
type AddressChange struct {
Kind AddressChangeKind
Address Address
}
AddressChange is one element of Service.AddressChanges, matter.js IpService.AddressChange.
type AddressChangeKind ¶
type AddressChangeKind int
AddressChangeKind says whether an AddressChange adds or deletes.
const ( AddressAdded AddressChangeKind = iota AddressDeleted )
Address change kinds.
type Changes ¶
Changes is one coalesced notification of a Name's record changes, matter.js DnssdName.Changes.
type Device ¶
type Device struct {
TXTData
// InstanceID is the first label of the node's `_matterc._udp` name.
InstanceID string
// D is the long discriminator.
D uint16
// CM is the commissioning mode.
CM uint8
// Hostname is the host the node's SRV records agree on, without its
// domain; "" while there is none or they disagree.
Hostname string
// Addresses are the node's addresses, most desirable first.
Addresses []Address
}
Device is a commissionable node as the scanner reports it, matter.js CommissionableDevice (packages/protocol/src/common/Scanner.ts:203-211).
type Discovery ¶
type Discovery struct {
Solicitation
// Retries overrides fields of [DefaultRetries] for this discovery;
// nil keeps the default.
Retries *Retries
}
Discovery is a Solicitation repeated on a retry schedule, matter.js DnssdSolicitor.Discovery.
type Identifier ¶
type Identifier struct {
// contains filtered or unexported fields
}
Identifier selects the commissionable nodes a Scanner looks for, matter.js CommissionableDeviceIdentifiers (packages/protocol/src/common/Scanner.ts:237-265). The zero value is AnyCommissionable. Identifiers compare with ==, which is how Scanner.Cancel matches a running search.
func AnyCommissionable ¶
func AnyCommissionable() Identifier
AnyCommissionable selects every node in commissioning mode 1 or 2.
func ByDeviceType ¶
func ByDeviceType(deviceType uint32) Identifier
ByDeviceType selects nodes announcing this device type.
func ByInstanceID ¶
func ByInstanceID(id string) Identifier
ByInstanceID selects the node with this instance name (the first label of its `_matterc._udp` name).
func ByLongDiscriminator ¶
func ByLongDiscriminator(d uint16) Identifier
ByLongDiscriminator selects nodes announcing this 12-bit discriminator.
func ByProduct ¶
func ByProduct(product uint16) Identifier
ByProduct selects nodes of this product, whatever the vendor.
func ByShortDiscriminator ¶
func ByShortDiscriminator(d uint8) Identifier
ByShortDiscriminator selects nodes whose discriminator's upper four bits are d.
func ByVendorProduct ¶
func ByVendorProduct(vendor, product uint16) Identifier
ByVendorProduct selects nodes of this vendor and product.
func (Identifier) MatchesBLE ¶ added in v0.7.0
func (id Identifier) MatchesBLE(d *Device) bool
MatchesBLE reports whether id selects d, a device a BLE advertisement describes (controller/ble): as Identifier does over DNS-SD, and never for an identifier Identifier.SupportedOverBLE refuses. Mirrors common/BleScanner.ts:497-541 (#getCommissionableDevices).
func (Identifier) SupportedOverBLE ¶ added in v0.7.0
func (id Identifier) SupportedOverBLE() bool
SupportedOverBLE reports whether a BLE scan can select by id: an instance id and a device type are not in a BLE advertisement. Mirrors matter.js 0ceb202d packages/protocol/src/common/BleScanner.ts:476-496 (#buildCommissionableQueryIdentifier, undefined for both).
type Name ¶
type Name struct {
// contains filtered or unexported fields
}
Name holds the records of one DNS-SD name, matter.js DnssdName (packages/general/src/net/dns-sd/DnssdName.ts). A Name exists while it has an unexpired record or an observer; Names.Get creates one.
func (*Name) IsDiscovered ¶
IsDiscovered reports whether the name holds at least one record.
func (*Name) Parameters ¶
func (n *Name) Parameters() Parameters
Parameters returns the TXT parameters of the name.
type Names ¶
type Names struct {
// contains filtered or unexported fields
}
Names is the record cache of DNS-SD names collected by multicast DNS, matter.js DnssdNames (packages/general/src/net/dns-sd/DnssdNames.ts). It receives every response on its mdns.QueryConn, keeps the records of the names it cares about with their TTLs, and serves the Service views, the Solicitor and the Scanner built on it.
Records enter the cache when their name ends with `._matter._tcp.local`, `._matterc._udp.local` or `._matterd._udp.local` (the ingress filter of matter.js MdnsService), when a scanner's filter accepts them, or when their name is already in the cache (an SRV target, a name someone observes). An A/AAAA record for a host not yet in the cache is staged and replayed once an SRV names that host — but only from a packet that carried a relevant record, so unrelated LAN announcements cannot attach addresses to a later Matter SRV target.
func NewNames ¶
NewNames returns a cache receiving on conn. The cache owns conn from here on: Names.Close closes it.
func Open ¶
Open joins the mDNS groups (mdns.OpenQueryConn) and returns a cache receiving on them. Close it to leave the groups.
func (*Names) Close ¶
Close stops the cache: every discovery ends, every waiter returns, the connection closes. Idempotent.
func (*Names) DiscoveredNames ¶
DiscoveredNames returns the names that currently hold records, in the order they entered the cache.
func (*Names) Get ¶
Get returns the Name for qname (case-insensitive, without the trailing dot), creating it when it does not exist. A name created here and never observed stays in the cache until a record of it is deleted.
type Parameters ¶
Parameters are the key/value pairs of a service's TXT records, matter.js DnssdParameters (packages/general/src/net/dns-sd/DnssdParameters.ts): the raw bytes per key; Parameters.Get decodes them as UTF-8.
func (Parameters) Get ¶
func (p Parameters) Get(key string) (string, bool)
Get returns the value of key decoded as UTF-8 (an invalid byte becomes U+FFFD) and whether the key is present. The key matches regardless of case, an exact match first. Mirrors matter.js packages/general/src/net/dns-sd/DnssdParameters.ts:36-46 (get/raw fold the key to lower case).
type Record ¶
type Record struct {
// Name is the owner name, without the trailing dot.
Name string
Type mdns.DNSType
// TTL is the record's lifetime as installed: the advertised TTL, raised
// to the cache's minimum, or the eviction delay once superseded.
TTL time.Duration
CacheFlush bool
// IP is the address of an A or AAAA record.
IP netip.Addr
// PTR is the target of a PTR record.
PTR string
// SRV is the value of an SRV record.
SRV mdns.DNSSRV
// TXT is the entries of a TXT record.
TXT [][]byte
// InstalledAt is when the record entered the cache (the packet's
// receive time).
InstalledAt time.Time
// ExpiresAt is InstalledAt + TTL × the grace factor.
ExpiresAt time.Time
// SourceIntf is the name of the interface an AAAA record arrived on,
// "" for every other record (matter.js keeps it for AAAA only, to zone
// an fe80:: address).
SourceIntf string
}
Record is one cached DNS record: matter.js DnssdName.Record, the decoded record plus the time it was installed and the time it expires. A Record handed out by this package is a copy; its TXT slices must not be modified.
type Retries ¶
type Retries struct {
// Timeout bounds the schedule's total time.
Timeout time.Duration
// MaximumCount bounds the number of intervals.
MaximumCount int
// InitialInterval is the first interval.
InitialInterval time.Duration
// BackoffFactor multiplies the interval after each step.
BackoffFactor float64
// MaximumInterval caps an interval, jitter included.
MaximumInterval time.Duration
// JitterFactor adds up to this fraction of the interval, at random.
JitterFactor float64
}
Retries configures a retry schedule, matter.js RetrySchedule.Configuration (packages/general/src/net/RetrySchedule.ts). A zero field is unset: in a Discovery it takes the solicitor's default, in the schedule itself it means "none" (no timeout, no count limit, no maximum, no jitter) or the schedule's own default (initial interval 1 s, backoff ×2).
type Scanner ¶
type Scanner struct {
// contains filtered or unexported fields
}
Scanner finds commissionable nodes by DNS-SD, matter.js CommissionableMdnsScanner (packages/protocol/src/mdns/CommissionableMdnsScanner.ts). It admits the `_matterc._udp` and `_matterd._udp` records to the cache, follows PTRs to instance names, builds a Device once an instance's TXT carries a valid D and CM, and reports it once it has an address.
func NewScanner ¶
NewScanner returns a scanner on names. Close it when done.
func (*Scanner) Cancel ¶
func (s *Scanner) Cancel(id Identifier)
Cancel ends every running search for id; each returns what it found. Mirrors matter.js 0ceb202d CommissionableMdnsScanner.ts:264-270.
func (*Scanner) Close ¶
func (s *Scanner) Close()
Close ends every search, stops the speculative queries, withdraws the scanner's ingress filter and releases its services. Mirrors matter.js 0ceb202d CommissionableMdnsScanner.ts:117-138.
func (*Scanner) Discovered ¶
func (s *Scanner) Discovered(id Identifier) []Device
Discovered returns the cached nodes id selects that have an address, without querying. Mirrors matter.js 0ceb202d CommissionableMdnsScanner.ts:258-262.
func (*Scanner) FindCommissionable ¶
func (s *Scanner) FindCommissionable(ctx context.Context, id Identifier, found func(Device)) ([]Device, error)
FindCommissionable searches for the nodes id selects until ctx ends or Scanner.Cancel cancels the search, calling found (when not nil) for each node once, and returns every node it found. It first reports the cached matches that have an address; if found cancels the search there, no query is sent. Then it queries the network — `_matterc._udp.local` and the identifier's subtype or instance name, retrying at most every CommissioningRetryInterval. found runs on the caller's goroutine. The error is ErrClosed when the cache closes, nil otherwise. Mirrors matter.js 0ceb202d CommissionableMdnsScanner.ts:165-256 (findCommissionableDevicesContinuously).
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is the live view of one DNS-SD service name: its SRV targets, the addresses they resolve to, and its TXT parameters, updated as the Names cache changes. It is matter.js IpService (packages/general/src/net/dns-sd/IpService.ts). Close it when done; an open Service keeps its name and SRV targets in the cache.
func NewService ¶
NewService returns the view of qname (without the trailing dot) on names, seeded from the records already cached.
func (*Service) AddressChanges ¶
func (s *Service) AddressChanges(ctx context.Context) <-chan AddressChange
AddressChanges streams the service's addresses: first every known address as an add, then — whenever the set changes — deletions first, then additions in desirability order. The channel closes when ctx ends, the service closes or the cache closes. Mirrors matter.js 0ceb202d IpService.ts:137-200 (addressChanges), including its restart: when the set changes while changes are being delivered, the set is read again and an address already counted as known in the interrupted round is not delivered again.
func (*Service) Addresses ¶
Addresses returns the known addresses, most desirable first (CompareDesirability).
func (*Service) Changes ¶
Changes signals every change of the service — its addresses or its TXT parameters — coalesced: one pending signal stands for any number of changes. The channel closes when ctx ends or the cache closes. It is matter.js IpService.changed (IpService.ts:122-124, emitted at :342-355), which a peer observes for its discovery data (Peer.ts:126-139).
func (*Service) Close ¶
func (s *Service) Close()
Close releases the service's observers, letting the cache drop its names once nothing else holds them, and stops an active resolution of its Status, waiting for it to end (matter.js IpService.ts:85-88 with IpServiceStatus.ts:36-41). Idempotent.
func (*Service) HasTXTRecord ¶
HasTXTRecord reports whether a TXT record of the service is known, even one without keys. Mirrors matter.js 0ceb202d IpService.ts:103-110.
func (*Service) Parameters ¶
func (s *Service) Parameters() Parameters
Parameters returns the service's TXT parameters.
func (*Service) Reachable ¶
Reachable reports whether the service is believed reachable: set when a new address appears (matter.js IpServiceStatus.isReachable, set by IpService.ts:324-325), and by Status.
func (*Service) Resolve ¶
Resolve queries for the service until an address it did not know when Resolve started appears, and returns the addresses then known, most desirable first. It asks for SRV and TXT of the service name — with its SRV targets' records as known answers — and for A and AAAA of every SRV target that has no address yet, on the solicitor's default schedule, following the SRV targets as they change. It returns ctx's error when ctx ends first and ErrClosed when the cache closes. Mirrors matter.js 0ceb202d packages/general/src/net/dns-sd/IpServiceResolution.ts:26-134.
func (*Service) TXTData ¶
TXTData parses the service's TXT parameters (ParseTXTData).
type Solicitation ¶
type Solicitation struct {
// Name is the name to query.
Name *Name
// RecordTypes are the record types to ask for.
RecordTypes []mdns.DNSType
// AssociatedNames, when set, returns further names whose records go
// into the query as known answers. It is read when the query is built,
// so it may change between retries.
AssociatedNames func() []*Name
}
Solicitation asks for record types of one name, matter.js DnssdSolicitor.Solicitation.
type Solicitor ¶
type Solicitor struct {
// contains filtered or unexported fields
}
Solicitor sends the queries of a Names cache, matter.js QueryMulticaster (packages/general/src/net/dns-sd/DnssdSolicitor.ts): solicitations made in one loop task go out as one packet, and repeated discovery of one name runs one schedule however many callers want it.
func (*Solicitor) Discover ¶
Discover queries for the discovery's name now and again on its retry schedule until ctx ends or the schedule runs out. While one discovery of a name runs, a second one for the same name joins it rather than querying twice, and the first caller's fields drive both. It returns nil when ctx ends or the schedule runs out, ErrClosed when the cache closes. Mirrors matter.js 0ceb202d DnssdSolicitor.ts:154-205.
func (*Solicitor) Solicit ¶
func (s *Solicitor) Solicit(sol Solicitation)
Solicit sends one query for the solicitation, coalesced with the other solicitations of the same loop task. Mirrors matter.js 0ceb202d DnssdSolicitor.ts:131-152.
type Status ¶
type Status struct {
// contains filtered or unexported fields
}
Status tracks the reachability of a Service and drives its discovery: while the service is not reachable and a connection attempt is outstanding, it resolves the service actively (Service.Resolve) until the service is reachable again with no attempt outstanding. It is matter.js IpServiceStatus (packages/general/src/net/dns-sd/IpServiceStatus.ts:23-205 at 0ceb202d); Service.Reachable is its isReachable flag.
func (*Status) Connecting ¶
Connecting registers a connection attempt whose outcome result delivers: true marks the service reachable, false — or result closing without a value, matter.js's rejected promise — unreachable. While any attempt is outstanding Status.IsConnecting is true; the status starts resolving if the service is not reachable. Mirrors IpServiceStatus.ts:104-150.
func (*Status) ConnectionInitiatedAt ¶
ConnectionInitiatedAt is when the latest connection attempt was registered, zero once none is outstanding (IpServiceStatus.ts:100-102, :119-123, :146).
func (*Status) IsConnecting ¶
IsConnecting reports whether a connection attempt registered with Status.Connecting is outstanding (IpServiceStatus.ts:48-50).
func (*Status) IsResolving ¶
IsResolving reports whether the status is resolving the service (IpServiceStatus.ts:74-76).
func (*Status) LastReceiptAt ¶
LastReceiptAt is the last receipt from the service's node a connection recorded, zero when none (IpServiceStatus.ts:92-98).
func (*Status) SetLastReceiptAt ¶
SetLastReceiptAt records a receipt from the service's node.
func (*Status) SetReachable ¶
SetReachable sets the reachability: clearing it while a connection attempt is outstanding starts resolving, setting it with none outstanding stops a resolution. Mirrors IpServiceStatus.ts:78-90.
type SupportedTransports ¶
SupportedTransports is the `T` TXT key decoded: bit 1 TCP client, bit 2 TCP server, bit 0 reserved. Mirrors matter.js 0ceb202d packages/protocol/src/common/SupportedTransportsBitmap.ts:9-23.
type TXTData ¶
type TXTData struct {
// VP is "<vendor>" or "<vendor>+<product>", each re-formatted from its
// parsed value.
VP *string
// DT is the device type.
DT *uint32
// DN is the device name.
DN *string
// RI is the rotating device identifier.
RI *string
// PH is the pairing hint; 0 is illegal and absent.
PH *uint32
// PI is the pairing instruction.
PI *string
// SII is the session idle interval.
SII *time.Duration
// SAI is the session active interval.
SAI *time.Duration
// SAT is the session active threshold.
SAT *time.Duration
// T is the supported transports.
T *SupportedTransports
// ICD is the ICD long-idle-time operating mode, 0 or 1.
ICD *uint8
}
TXTData is what a node announces in its TXT record, matter.js DiscoveryData (packages/protocol/src/common/Scanner.ts:29-69). A nil field is absent: not announced, or announced with a value matter.js rejects, so that the protocol default applies. The commissionable `D` and `CM` keys are the Scanner's (see Device); the same type serves operational TXT records (Service.TXTData), as matter.js's Peer parses them with DiscoveryData too.
func ParseTXTData ¶
func ParseTXTData(p Parameters) TXTData
ParseTXTData reads the TXT keys matter.js knows: DN, RI and PI verbatim; VP split at "+", the vendor ≤ 65535 or VP dropped, the product parsed on its own and dropped alone; DT ≤ 2³²−1; PH ≤ 2³²−1 and not 0; ICD 0 or 1; T ≤ 65535 as the transports bitmap; SII and SAI ≤ 3 600 000 ms; SAT 1..65535 ms. A value matter.js rejects is absent. Mirrors matter.js 0ceb202d packages/protocol/src/common/Scanner.ts:71-145.