Behind the Hotel Router: Engineering OTA for Networks You Don't Control
Photo: Tony Webster, CC BY 2.0, via Wikimedia Commons
Your test bench is a lie. Not intentionally, but almost every OTA pipeline is validated on a clean corporate network or a well-behaved home Wi-Fi setup: static DHCP leases, open outbound ports, DNS that resolves on the first try. The fleet, meanwhile, lives somewhere else entirely. It lives behind a Comcast gateway with a 300-second UDP timeout. It lives on a Marriott hotspot that intercepts every HTTP request with a login page. It lives in a Brooklyn apartment where six IoT devices share a mesh node and a 1.2 TB monthly data cap.
If your update protocol only works when the network cooperates, it doesn't work.
The captive portal is your first adversary
Captive portals — the login pages at hotels, airports, coffee shops, and increasingly MDU (multi-dwelling unit) shared networks — work by intercepting traffic. Your device connects to Wi-Fi, gets an IP address, and then every HTTP request is answered not by your server but by the portal's gateway, typically with a 302 redirect to an authentication page.
Devices that naively issue an HTTPS request for a firmware manifest will either fail the TLS handshake (because the portal can't present a valid certificate for your domain) or, worse, follow the redirect and parse a login page as if it were a manifest. Both failure modes are common, and both are avoidable.
The standard detection technique is a canary probe: make an unencrypted HTTP request to a known endpoint that should return a fixed, verifiable response — something like http://connectivity-check.yourdomain.example/ok returning the literal string ok. If the response body or status deviates, you're behind a captive portal. Android, Windows, and macOS all use variants of this; your devices should too.
What you do next is the interesting part. Options, in rough order of preference:
- Wait and retry. Many captive portals on shared residential networks open up after initial authentication by any user. A patient retry loop with exponential backoff costs nothing.
- Signal the problem. If the device has any out-of-band channel (BLE to a phone app, a status LED), surface it. A device that silently fails to update for six months is a support ticket you haven't received yet.
- Never fall back to plain HTTP for the payload itself. A captive portal proves the network can tamper with traffic. Signed manifests and encrypted payloads are non-negotiable, but treat the network as hostile regardless.
NAT timeouts and the long-poll problem
Many OTA architectures use long polling or persistent connections so the device learns about updates quickly. On a lab network, a TCP connection can idle for hours. Behind a typical consumer NAT gateway — and the ISP CGNAT layers increasingly stacked behind them — idle TCP mappings can be reclaimed in as little as 300 seconds, and UDP in under 60.
The failure mode is subtle: the device thinks its connection is alive, sends nothing for twenty minutes, then writes to a socket that the gateway has silently dropped. Depending on the TCP stack, that write can hang for many minutes before the connection errors out.
Practical mitigations:
- Keepalive intervals below the timeout floor. Application-level pings every 60–120 seconds are more reliable than TCP keepalives, which many embedded stacks implement poorly or not at all.
- Design for reconnect, not persistence. Treat any connection as disposable. If re-establishing a session is cheap and idempotent, NAT resets become noise instead of failures.
- Prefer device-initiated check-ins over server push. Push through NAT requires hole-punching or relays — complexity you probably don't need for firmware delivery, where a check-in cadence of minutes to hours is usually fine.
DNS weirdness is a reliability tax
Shared networks run DNS through ISP resolvers that are, charitably, inconsistent. You will see NXDOMAIN responses for names that resolve fine everywhere else, intermittent timeouts during gateway firmware updates, and — in the worst cases — ISP resolver hijacking that serves ad pages for unresolvable domains.
Two habits harden this considerably. First, resolve your update endpoints through multiple paths: query the system resolver, but have a fallback of well-known public resolvers (with the caveat that some locked-down networks block outbound port 53 to anything but their own resolvers — detect this and stop hammering). Second, pin your update infrastructure to stable, short hostnames and avoid DNS alias chains; every CNAME hop is another lookup that can fail.
If your fleet is large enough, cache resolved IPs on the device and treat DNS as a refresh mechanism rather than a dependency. A device that can still reach a cached IP during a resolver outage is a device that still updates.
Bandwidth-aware chunking for capped connections
The US has no shortage of metered and congested networks: satellite links in rural areas, hotspots with hard data caps, shared MDU connections that collapse every evening. A 40 MB firmware image pushed carelessly can eat a meaningful slice of a customer's monthly allowance — and generate an angry call.
Chunked, resumable downloads are the baseline. Break the payload into chunks (256 KB to 1 MB is a reasonable range for constrained devices), track completion persistently, and resume from the last verified chunk rather than restarting. This alone turns a flaky connection from a hard failure into a slow success.
Go further by making the size adaptive:
- Binary diffing shrinks most firmware updates by 80–95%. If you're not diffing, you're paying full freight on every device, every time.
- Network-quality probing — measure throughput on the first few chunks and, if the connection is slow or the user has flagged a metered network, defer or throttle.
- Scheduling hooks that let the device defer large transfers to off-peak hours, which matters on connections with time-dependent congestion.
Design the protocol as if the network is an adversary
The unifying principle: assume every hop between your device and your server can intercept, throttle, drop, or delay traffic, and build accordingly. TLS for the payload regardless of portal state. Signed manifests so a tampering gateway yields a verification failure, not a bricked unit. Idempotent, resumable transfers so interruptions cost seconds, not hours. Connectivity probes that distinguish "no internet" from "portal login required" from "DNS broken."
None of this is glamorous. It's a long checklist of unglamorous edge cases, which is precisely why fleets that do it update reliably and fleets that don't quietly rot. The last mile of your OTA pipeline isn't your CDN or your signing service — it's a seven-year-old router in a hallway closet, running firmware nobody has updated since install. Engineer for it, and everything upstream gets easier.