Add an opt-in V.34 handshake watchdog workaround with verified isolated builds - #14
szeremeta1 wants to merge 4 commits into
Conversation
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>
…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.
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.
|
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. 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 No change to this PR is proposed. Its measurement, its scope and its corrections stand as written. |
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=-1000000reapplies 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. OptionalSLM_V34_METRIC=Nobservations 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_runto 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.