Skip to content

Add an opt-in V.34 handshake watchdog workaround with verified isolated builds - #14

Open
szeremeta1 wants to merge 4 commits into
strozfriedberg:masterfrom
szeremeta1:v34-carrier-watchdog
Open

szeremeta1 wants to merge 4 commits into
strozfriedberg:masterfrom
szeremeta1:v34-carrier-watchdog

Conversation

@szeremeta1

@szeremeta1 szeremeta1 commented Sep 2, 2026

Copy link
Copy Markdown

This adds an opt-in workaround for the handshake carrier-loss criterion discussed in #13. On one measured path, that criterion ended some otherwise recoverable handshakes after one second of low signal. The vendor threshold is its normal default; the original description of a packet path falling into an invalid dBm calibration was wrong. The underlying cause, including the RX noise/self-echo hypothesis raised in #13, remains separate from this workaround.

SLM_V34_LOWSIG=-1000000 reapplies a threshold below the signed 16-bit metric before each DSP fragment. With both supported variables unset, the wrapper calls the original directly, preserves its result, and performs no private DSP-state access or diagnostic getter calls. Optional SLM_V34_METRIC=N observations remain. The earlier copied research controls for fatal-status suppression, timeout extension, rate renegotiation, and retrain thresholds have been removed so this PR stays focused on the measured intervention.

The installer now accepts only the exact audited i386 vendor object by SHA-256. It resolves its own path before changing directories and builds into a separate staged output tree, leaving the source and its vendor object unchanged. Before publishing that tree, it checks distinct wrapper/original symbols and the actual vpcm_run to wrapper and wrapper to original call paths. Repeated invocation verifies the existing output; changed, partial, unrelated, or concurrently created output is preserved and refused. No vendor object is added by this PR and no vendor instruction is patched.

Historical evidence is 19/30 completed calls with the original criterion versus 27/30 with it disabled in interleaved testing on one installation (two-sided Fisher exact p = 0.030). Every completed call reported 33,600 bit/s caller receive rate in both arms. These figures support fewer failed handshakes on that setup; they do not establish a rate improvement, both directional rates, or 99% reliability across hardware. The methods and corrections remain available.

Validation: 10 isolated wrapper checks passed with both macOS Clang and Linux GCC. They include an inaccessible object pointer with the knobs off, exact argument/fatal-result passthrough, strict integer validation, and threshold reapplication after a vendor reset using the same object address. The real upstream i386 blob builds and links successfully on Linux. Installer checks passed for relative paths containing spaces, verified repeat installation, unchanged source inputs, tampered/unrelated-output preservation, failed-build cleanup, an unsupported blob, deliberately broken vendor call-site linkage, and a destination created during the build. These are component/build checks; no additional modem-call reliability claim is made by this PR revision.

On a packet path, dsplibs.o's V.34 carrier-loss watchdog hangs up after one
unbroken second below a signal threshold selected from a dBm-indexed table that
cannot be indexed, so the lookup falls through to an out-of-range clamp (101).
The protocol-legal quiet between handshake stages runs longer than one second on
such a path, so healthy calls are terminated with `vpcm: Link Error`.

slm_v34_watchdog.c interposes VPcmV34Progress via `objcopy --weaken-symbol` and
rewrites the threshold before each fragment; apply_watchdog_hook.sh installs it
and asserts at build time that the interposition bound. No vendor instruction is
modified and no vendor object is redistributed. Everything is off unless an
environment variable is set; SLM_V34_LOWSIG=-1000000 disables the criterion.

On one production installation this moved call completion from 19/30 to 27/30
(Fisher exact, two-sided, p = 0.030). See strozfriedberg#13 and
https://dialup.litenet.tel/research/v34-modem/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 2, 2026 04:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The job was not started because the account is locked due to a billing issue.

szeremeta1 and others added 2 commits September 8, 2026 15:55
…ath falls into

I had this wrong. The paragraph said the threshold lookup "falls through to
an out-of-range clamp" because RTP audio carries no dBm reference. It doesn't
work like that: the field the table is indexed by is zeroed when the datapump
is created and nothing ever writes it, so every installation gets the same
value (101, about -45 dBm). What a packet path actually changes is how long
the handshake's legal pauses run, and that is what the one-second watchdog
trips on. Discussion in strozfriedberg#13.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The installer resolved its own relative path after changing into the vendor
source directory. A normal relative invocation could replace dsplibs.o and
then fail to find the wrapper; the next attempt could report already hooked
without compiling or checking the executable. It also accepted any object
with a matching symbol name even though the wrapper used fixed private
layout offsets.

Build a separate staged tree from the exact audited upstream i386 object,
verify both actual call paths, and publish only the completed directory.
Repeated invocations verify unchanged inputs and output. Failed builds,
unsupported blobs, changed output, and concurrently created destinations
leave the original source and any existing output intact.

Reduce the wrapper to the low-signal threshold intervention and optional
metric observation. With both controls unset it returns directly through the
original without private-state reads or diagnostic getters. Remove the
unrelated fatal, timeout-extension, renegotiation, and retrain controls and
their allocator-address-based per-call state. Parse integers completely.

Correct the README's implication that the vendor threshold itself is wrong,
state that the historical rate is caller receive rate, and distinguish the
19/30 versus 27/30 result from a hardware-independent reliability claim.
RX noise and self-echo remain separate experiments, not findings of this PR.

Ten wrapper component checks pass on macOS Clang and Linux GCC. A real
upstream-blob i386 build passes in an isolated Linux temporary directory.
Installer checks cover relative paths with spaces, verified repeat builds,
source preservation, tampered and unrelated output, failed compilation,
unsupported ABI, broken caller linkage, and concurrent output creation.
No service was restarted and no modem call was placed by this change.
@szeremeta1 szeremeta1 changed the title Optional fix for unreliable V.34: correct the carrier-loss watchdog threshold Add an opt-in V.34 handshake watchdog workaround with verified isolated builds Sep 10, 2026
The historical A/B shared additional host recovery and buffering changes. State that the public installer isolates this watchdog hook and that the deposited artifacts do not reconstruct all predecessor host patches and service configuration. This clarification changes no measurements, component behavior or claimed hardware coverage.
@szeremeta1

Copy link
Copy Markdown
Author

One thing found this week that bears on how much this PR matters, rather than on the PR itself.

On the answering side there is no fallback from a failed handshake — not a slow one, none at all. slmodemd/modem.c:1578 discards the AT automode bit, so the modem is locked to whatever AT+MS named and will not try another datapump; the blob's own trace says so on every call as v8: create: caller 0, automode 0, dp id 34. A caller whose modem cannot complete that one modulation gets ATA, a few seconds of relayed audio, and silence, on every redial, for ever.

So on an answering pool, a handshake that ends is not a retry at a lower rate. It is the whole call. That is the case for this PR's workaround being worth having and it is not made in the PR body, which reasons entirely in terms of completion rate.

It is also the case for a second, much smaller change, which is on diag/no-carrier-reason and discussed in #13: at default verbosity that failure prints nothing at all — no change dp, no error, no reason. One MODEM_INFO in modem_hup's STATE_DP_ESTAB branch names what was offered, whether automode was asked for, which datapump was actually running and how many samples went by, and a handshake that completes still prints nothing new.

No change to this PR is proposed. Its measurement, its scope and its corrections stand as written.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants