This page drills the 4.3.18 UDP — header, use cases, checksum (index 4.3.18) into the ground. We will compute checksums by hand, hit every overflow and edge case, and prove each answer. If you have not yet seen One's complement arithmetic , read the preliminary theory and the first two examples slowly — they build it from zero.
Before we compute anything, we fix the exact notation and the exact algorithm. Every example below leans on these three tools, so nothing appears unexplained.
Definition The overline = bitwise complement
For a 16-bit value x , the notation x means "flip every one of its 16 bits" — every 1 becomes 0 and every 0 becomes 1. This is the one's complement of x .
Example: 0x0000 = 0xFFFF (all zeros become all ones), and 0x69CF = 0x9630 .
Why we need it: the transmitted checksum is defined as sum , and the whole receiver test rests on the identity x + x = 0xFFFF (a value and its flip are complements , so together they light up all 16 bits).
Definition Carry vs low bits — how to split a spilled sum
When a sum exceeds 16 bits it looks like a 5-hex-digit number S . We split it into two pieces with plain integer operations:
low16 = S mod 0x10000 , carry = ⌊ S / 0x10000 ⌋
In words: low16 is "keep only the bottom 4 hex digits"; carry is "everything that stuck out past bit 15." The wrapped result is low16 + carry . Crucially, carry is the whole multi-bit overflow , folded in one addition — not one bit at a time.
Why this formula: 0x10000 is exactly 65536 = 2 16 , the first value that no longer fits in 16 bits. Dividing by it peels off the overflow; the remainder is what fits.
Read the two figures now — they carry this algorithm visually.
Intuition Figure 1 — the 16-bit number line and its ceiling
The figure below draws every 16-bit value as a point on a line running from 0x0000 (=0) up to the red dashed ceiling 0xFFFF (=65535). The yellow shaded strip past the ceiling is the "overflow" region — any sum that lands there has a 17th bit set. The green curved arrow shows the wrap : that overflow is not deleted, it is folded back to the low end and added in. This picture is the geometric meaning of "carry-wrap."
Figure 1 — sums live in 0..65535; anything spilling into the yellow strip wraps back around (green arrow).
Intuition Figure 2 — the fold-until-done flowchart (referenced from C3b)
The figure below turns the algorithm into a flowchart: add the words → test spill? → if yes, fold the whole carry in one step and loop back to the test (green, "repeat") → if no, complement (red) → and finally the zero-rule box. The loop-back arrow is the whole reason a cascade is handled: after one full fold we test again, and only fold a second time if the result still spilled.
Figure 2 — add, spill?, fold the whole carry, repeat, then flip. The green loop-back handles cascades.
Every worked example below is tagged with the cell it fills.
Cell
Case class
What makes it special
C1
No overflow
Words add up small; carry never leaves 16 bits.
C2
Single wrap-around
Sum crosses 0xFFFF once; recycle one carry.
C3
Cascading wrap
Folding the wrapped carry causes another carry.
C4
Genuine-zero result
Computed sum is all-ones → checksum would be 0x0000 → must send 0xFFFF.
C5
Disabled checksum
Sender transmits literal 0x0000 (IPv4 opt-out).
C6
Pseudo-header included
Source/dest IP folded in; catches misdelivery.
C7
Error slips through
Two compensating bit flips pass the check.
C8
Length + odd payload
Compute Length; pad a final odd byte into a word.
C9
Word-problem (DNS)
Real latency comparison: why UDP not TCP.
C10
Exam twist
Reconstruct a missing field from the given checksum.
The number 16 above means the field is 16 bits wide = 4 hex digits = values 0x0000..0xFFFF = 0..65535. Whenever a sum climbs above 0xFFFF , it no longer fits and the wrap-around (Figure 1) fires.
Worked example C1 — Straight sum, no overflow
Words: w 1 = 0x1234 , w 2 = 0x2345 , w 3 = 0x3456 . Find the checksum.
Forecast: guess — will the total stay under 0xFFFF (which is 65535)? Roughly 0 x 1234 ≈ 4660 , 0 x 2345 ≈ 9029 , 0 x 3456 ≈ 13398 . Sum ≈ 27087 — comfortably below 65535, so no wrap .
Add all three. 0x1234 + 0x2345 + 0x3456 = 0x69CF .
Why this step? The checksum is a running sum of the 16-bit words — this is the raw sum before any complement.
Check for overflow. 0x69CF has 4 hex digits → it fits in 16 bits; 0x69CF ≤ 0xFFFF , so the while-loop never runs.
Why this step? The wrap-around rule only fires when the sum exceeds 0xFFFF; here it never did.
Complement (flip every bit). 0x69CF = 0x9630 .
Why this step? We transmit the complement so the receiver can add everything and expect all-ones.
Answer: 0x9630.
Verify: receiver adds sum + checksum: 0x69CF + 0x9630 = 0xFFFF ✓ — all ones, accept.
Worked example C2 — Single wrap-around
Words: w 1 = 0x4500 , w 2 = 0xF6CB , w 3 = 0x0000 . (Same as the parent note — do it again to feel the wrap.)
Forecast: 0 x F 6 C B ≈ 63179 is already near the ceiling 65535; adding anything positive will spill over the ceiling in Figure 1. Expect one carry to recycle.
Add w 1 + w 2 . 0x4500 + 0xF6CB = 0x13BCB .
Why this step? Plain addition — but note it now has 5 hex digits, so bit 16 (the leading 1) is set. That is the overflow.
Wrap the carry using the split formula. low16 = 0x13BCB mod 0x10000 = 0x3BCB ; carry = ⌊ 0x13BCB / 0x10000 ⌋ = 0x1 . Fold: 0x3BCB + 0x1 = 0x3BCC .
Why this step? This is exactly the split defined in preliminary theory — one's-complement addition recycles the overflow instead of discarding it.
Add w 3 . 0x3BCC + 0x0000 = 0x3BCC . No new spill.
Why this step? Adding a zero word changes nothing — this models an all-zero payload word.
Complement. 0x3BCC = 0xC433 .
Answer: 0xC433.
Verify: 0x3BCC + 0xC433 = 0xFFFF ✓.
Worked example C3 — Wrap that lands on the ceiling
Words: w 1 = 0xFFFF , w 2 = 0xFFFF . This is the meanest single-fold input — both words are maxed out.
Forecast: two 0xFFFF values sum to 0x1FFFE . Folding the carry 1 onto 0xFFFE gives 0xFFFF — a single clean fold that lands exactly on the ceiling. Let's confirm.
Add. 0xFFFF + 0xFFFF = 0x1FFFE .
Why this step? Two maxed words guarantee overflow — bit 16 is set.
Wrap the carry. low16 = 0xFFFE , carry = 0x1 → 0xFFFE + 0x1 = 0xFFFF . This is still ≤ 0xFFFF , so the while-loop stops.
Why this step? The fold lands exactly on 0xFFFF with no further carry — one fold is enough.
Complement. 0xFFFF = 0x0000 .
Why this step? The complement of all-ones is all-zeros — which is a forbidden transmit value! (See C4.)
Answer before the zero-rule: 0x0000 → must transmit 0xFFFF (jump to C4 for why).
Verify: sum-before-complement was 0xFFFF; and indeed 0xFFFF + 0x0000 = 0xFFFF , so the raw complement is 0x0000.
Worked example C3b — A genuine two-iteration cascade (fold the whole carry each time)
Words: w 1 = 0xFFFF , w 2 = 0xFFFF , w 3 = 0xFFFE . We fold the entire carry in one step (exactly as the algorithm says), then test again — and here the folded result itself spills, forcing a second fold. This is the case Figure 2's green loop-back exists for.
Forecast: three near-maxed words give a big sum whose top part is 0x2 (a carry of 2). Fold all of it in one step; guess whether the result still exceeds 0xFFFF. It will — so the while-loop runs a second time.
Add all three. 0xFFFF + 0xFFFF + 0xFFFE = 0x2FFFC .
Why this step? The sum has 5 hex digits with top part 0x2 → the whole overflow is carry = 0x2, and low16 = 0xFFFC.
First fold (whole carry at once). low16 + carry = 0xFFFC + 0x2 = 0xFFFE ... wait, check: 0xFFFC + 0x2 = 0xFFFE , and 0xFFFE ≤ 0xFFFF — one fold suffices here. So this input does not cascade. We need a bigger low16.
Why this step? Whether a cascade happens depends on whether low16 + carry itself crosses the ceiling.
To force a true cascade, pick w 1 = 0xFFFF , w 2 = 0xFFFF , w 3 = 0xFFFF , w 4 = 0xFFFF (four maxed words):
Add. 4 × 0xFFFF = 0x3FFFC .
Why? Top part 0x3 → carry = 0x3, low16 = 0xFFFC.
First fold (whole carry). 0xFFFC + 0x3 = 0x0FFFF = 0xFFFF . Spill test: ≤ 0xFFFF , stop — still one fold. Also clean. The truly cascading input is one where low16 + carry overshoots:
Guaranteed cascade — five maxed words: w 1 .. w 5 = 0xFFFF .
Add. 5 × 0xFFFF = 0x4FFFB .
Why? carry = 0x4, low16 = 0xFFFB.
First fold (whole carry). 0xFFFB + 0x4 = 0x0FFFF = 0xFFFF — still no second fold. Sums of n copies of 0xFFFF always fold cleanly. To actually cascade we need low16 high and carry high independently , so use words that are not all-max:
The cascade, finally: w 1 = 0xFFFF , w 2 = 0xFFFF , w 3 = 0x0002 .
Add. 0xFFFF + 0xFFFF + 0x0002 = 0x20000 .
Why? carry = 0x2, low16 = 0x0000.
First fold (whole carry at once). 0x0000 + 0x2 = 0x0002 . Test: ≤ 0xFFFF , stop.
Why? Folding the entire multi-bit carry 0x2 in one step gives 0x0002 directly — no cascade even here.
Complement. 0x0002 = 0xFFFD . Answer: 0xFFFD.
The honest lesson: when you fold the whole carry in one step as the algorithm specifies, a genuine second iteration is rare — it needs low16 + carry to itself exceed 0xFFFF. That happens, for instance, with w 1 = 0xFFFF , w 2 = 0xFFFE , w 3 = 0xFFFF , w 4 = 0x0003 : sum = 0x2FFFF , carry = 0x2, low16 = 0xFFFF; first fold = 0xFFFF + 0x2 = 0x10001 which still spills → second fold = 0x0001 + 0x1 = 0x0002 ; test clear. The while-loop ran twice , folding the whole carry each time — precisely the loop-back in Figure 2. Complement: 0x0002 = 0xFFFD . Answer: 0xFFFD.
Verify: for the two-iteration input, final sum = 0x0002 and 0x0002 + 0xFFFD = 0xFFFF ✓.
Worked example C4 — Result is genuinely zero
Words: w 1 = 0x8000 , w 2 = 0x7FFF .
Forecast: 0 x 8000 + 0 x 7 F F F = 0 x F F F F exactly — the sum is all-ones, so its complement is 0x0000. But 0x0000 means "no checksum"! We must dodge it.
Add. 0x8000 + 0x7FFF = 0xFFFF . No overflow.
Why? Two words that happen to be bitwise complements sum to all-ones.
Complement. 0xFFFF = 0x0000 .
Why? Flip every 1 to 0.
Apply the zero-rule. A computed 0x0000 is transmitted as 0xFFFF instead.
Why this step? In one's complement, 0x0000 and 0xFFFF both represent numeric zero (positive vs negative zero). The literal 0x0000 is reserved to mean "sender disabled the checksum," so we send the other representation of zero.
Answer: 0xFFFF.
Verify: receiver adds 0xFFFF (sum) + 0xFFFF (checksum) = 0x1FFFE → fold → 0xFFFF ✓ — still all-ones, accept.
Worked example C5 — Checksum disabled (IPv4)
Scenario: a UDP sender on IPv4 chooses not to compute a checksum. What is in the checksum field, and what must the receiver do? Contrast IPv6.
Forecast: guess — is disabling legal? On IPv4, yes; on IPv6, no.
Field value. The sender writes the literal 0x0000 .
Why? 0x0000 is the reserved "no checksum" sentinel (that is exactly why C4 had to avoid producing it).
Receiver behavior. On seeing 0x0000, the receiver skips the checksum test entirely and accepts whatever arrived.
Why? There is nothing to verify against; corruption cannot be detected for this datagram.
IPv6 difference. IPv6 removed the IP-layer data checksum, so UDP's checksum is mandatory — 0x0000 is illegal there and a genuine-zero result is sent as 0xFFFF (as in C4).
Answer: IPv4 field = 0x0000 = disabled; IPv6 forbids it.
Verify (logic): disabled ⇒ no all-ones test performed ⇒ any datagram accepted. Consistent with "unreliable = no recovery, and here not even detection."
Worked example C6 — Pseudo-header folds in the destination IP
Given: source IP 192.168.0.1, dest IP 10.0.0.5, protocol = 17, UDP length = 8, and UDP header words Source Port 0x1F90 (8080), Dest Port 0x0035 (53), Length 0x0008, Checksum field 0x0000 (to be filled). Payload empty.
Forecast: the checksum will change if the destination IP changes even by one bit — that is the whole point of the pseudo-header. Expect a multi-word sum; guess whether it wraps (it will not — the words are small).
Split IPs into 16-bit words. 192.168.0.1 → 0xC0A8, 0x0001. 10.0.0.5 → 0x0A00, 0x0005.
Why? The pseudo-header treats each 32-bit IP as two 16-bit words, matching the checksum's word size.
Protocol + length pseudo-words. Protocol 17 = 0x11 sits in the low byte with a zero pad byte → 0x0011; the UDP length repeats as 0x0008.
Why? The pseudo-header carries {srcIP, dstIP, 0x00, protocol, UDP-length}.
Sum every word (pseudo-header + real UDP header, with the checksum field itself as 0):
0xC0A8 + 0x0001 + 0x0A00 + 0x0005 + 0x0011 + 0x0008 + 0x1F90 + 0x0035 + 0x0008 + 0x0000
Add them in order: 0xC0A8 + 0x0001 = 0xC0A9 ; + 0x0A00 = 0xCAA9 ; + 0x0005 = 0xCAAE ; + 0x0011 = 0xCABF ; + 0x0008 = 0xCAC7 ; + 0x1F90 = 0xEA57 ; + 0x0035 = 0xEA8C ; + 0x0008 = 0xEA94 ; + 0x0000 = 0xEA94 .
Why? Every word that must be protected — including the addresses — enters the sum.
Check for overflow. Running total 0xEA94 (that is 60052 ) has 4 hex digits, ≤ 0xFFFF — no wrap , the while-loop never runs.
Why? All the words are small; nothing spilled past the ceiling of Figure 1.
Complement. 0xEA94 = 0x156B .
Why? Transmit the flip so the receiver expects all-ones.
Answer: 0x156B.
Verify: original: 0xEA94 + 0x156B = 0xFFFF ✓. Now flip one bit of the dest IP (10.0.0.5 → 10.0.0.7, word 0x0005→0x0007): the sum rises by 2 to 0xEA96, and 0xEA96 + 0x156B = 0x10001 → fold → 0x0002 = 0xFFFF → fails , exactly as intended — a datagram sent to the wrong machine is caught.
Worked example C7 — Two errors cancel and slip through
Setup: original words w 1 = 0x1000 , w 2 = 0x2000 . In transit w 1 becomes 0x1001 (+1) and w 2 becomes 0x1FFF (−1). Does the checksum catch it?
Forecast: the sum is unchanged, so — guess — the check will pass despite corruption. This is the checksum's blind spot.
Original sum. 0x1000 + 0x2000 = 0x3000 ; checksum = 0x3000 = 0xCFFF .
Why? Establish the transmitted checksum.
Corrupted sum. 0x1001 + 0x1FFF = 0x3000 — identical .
Why this step? + 1 and − 1 cancel; the running sum is the same total.
Receiver test. 0x3000 + 0xCFFF = 0xFFFF → all-ones → accepted (wrongly) .
Why? A 16-bit sum cannot distinguish two inputs with the same total.
Answer: the corruption is undetected — this is why "checksum OK" ≠ "data definitely fine." Use a crypto hash / TLS for real integrity.
Verify: both sums equal 0x3000; check passes in both cases → error invisible. Confirmed.
Worked example C8 — Length field, plus padding an odd-length payload
(a) A UDP datagram carries 20 bytes of payload. What is the Length field?
(b) A received datagram claims Length = 0x0004. Is it valid?
(c) A datagram's payload is the 3 bytes 0x41 0x42 0x43 (ASCII "ABC") — an odd byte count. How does the checksum handle a leftover byte, and what payload words go into the sum?
Forecast: Length = header + data = 8 + data . For (c), the checksum works on 16-bit words , but 3 bytes is one full word (0x4142) plus one lonely byte 0x43 — guess how it is squared up.
(a) Compute. Length = 8 + 20 = 28 = 0x001C .
Why? The Length field spans the entire UDP datagram — the 8-byte header plus payload.
(b) Minimum check. The header alone is 8 bytes, so the smallest legal Length is 8 = 0x0008 . A value of 4 is impossible — shorter than the mandatory header, so a robust stack drops it. (Length exactly 8 = header only, empty payload, is legal.)
Why? Length < 8 is a malformed/degenerate datagram; the field bottoms out at 8, never below.
(c) Pad the odd byte. Group the payload into 16-bit words two bytes at a time: 0x41,0x42 → 0x4142. One byte 0x43 is left over. For checksum purposes only , append a virtual zero byte: 0x43,0x00 → 0x4300. So the payload contributes words 0x4142 and 0x4300 to the sum.
Why this step? The one's-complement sum is defined over 16-bit words; a trailing odd byte must be padded with 0x00 on the right so it forms a full word. The pad is not transmitted and the Length field still reports the true odd byte count.
Answers: (a) 28 (0x001C) ; (b) invalid (below 8); (c) checksum words 0x4142 and 0x4300 — Length reports 8 + 3 = 11 = 0x000B .
Verify: 8 + 20 = 28 ✓; 4 < 8 ⇒ malformed ✓; odd payload 3 bytes → pad to words 0x4142,0x4300, and Length = 8 + 3 = 11 ✓.
Worked example C9 — Word problem: why DNS uses UDP
Setup: one round-trip time (RTT) between you and a DNS resolver is 40 ms. A DNS lookup is one small query + one small reply. Compare the time to first byte of the answer for UDP vs TCP.
Forecast: TCP must first do a 3-way handshake (SYN, SYN-ACK, ACK) before sending the query. Guess: TCP costs one extra RTT.
UDP timeline. Send query (½ RTT out) → reply comes back (½ RTT in) = 1 RTT = 40 ms .
Why? UDP is connectionless — the very first packet carries data. No setup.
TCP timeline. Handshake = 1 RTT (SYN out ½, SYN-ACK back ½; the ACK piggybacks the query) → reply = 1 RTT. Total = 2 RTT = 80 ms .
Why this step? TCP cannot send application data until the connection is established.
Overhead comparison. UDP header 8 bytes vs TCP 20 bytes → 12 bytes saved per packet too.
Why? For a tiny lookup, both latency and header overhead of reliability outweigh its benefit — see TCP — header, three-way handshake, reliability .
Answer: UDP 40 ms , TCP 80 ms — UDP is 2× faster to the answer here. (This is exactly why DNS resolution defaults to UDP, and why QUIC and HTTP-3 rebuilds reliability over UDP to keep the low latency.)
Verify: UDP = 1 × 40 = 40 ; TCP = 2 × 40 = 80 ; ratio = 80/40 = 2 ✓.
Worked example C10 — Exam twist: recover a missing word from the checksum
Given: words w 1 = 0x1122 , w 2 = ? (unknown), and the transmitted checksum = 0x9A9A . Find w 2 (assume no overflow in the original sum).
Forecast: the checksum is the complement of the sum, so the sum must be the complement of the checksum. Work backwards, then subtract off the word we know.
Recover the sum. Since checksum = sum , apply the overline again: sum = checksum = 0x9A9A = 0x6565 .
Why this step? Flipping bits twice returns the original, so sum = sum — the complement undoes itself.
Solve for w 2 . We know w 1 + w 2 = sum , so w 2 = sum − w 1 = 0x6565 − 0x1122 = 0x5443 .
Why this step? Simple subtraction, valid because we assumed no wrap in the original sum (so the sum is just w 1 + w 2 ).
Answer: w 2 = 0x5443 .
Verify: 0x1122 + 0x5443 = 0x6565 , and 0x6565 = 0x9A9A ✓, and the receiver test: 0x6565 + 0x9A9A = 0xFFFF ✓.
Recall Quick self-test across the matrix
Which cell forces you to transmit 0xFFFF even though your math produced zero? ::: C4 — genuine-zero sum, because 0x0000 is reserved for "disabled."
Why does the pseudo-header include the destination IP? ::: C6 — so a datagram misdelivered to the wrong machine fails the checksum.
Give an error the checksum cannot catch. ::: C7 — two compensating flips (+1 and −1) that leave the total unchanged.
Smallest legal UDP Length value? ::: C8 — 8 (header only, empty payload); anything below 8 is malformed.
How is a trailing odd byte handled in the checksum? ::: C8 — pad it on the right with a virtual 0x00 to form a full 16-bit word; the pad is not transmitted and Length still reports the true byte count.
What does the overline x mean? ::: Flip every one of the 16 bits — the one's complement of x .
Mnemonic The wrap-around loop
"Add, spill, fold, repeat — then flip." Add the words; while it spills past 0xFFFF, fold the whole carry back in; repeat until no spill; then flip all bits for the checksum (Figure 2).
Related depth: One's complement arithmetic · IP — datagrams and addressing · Transport layer — ports and multiplexing · 4.3.18 UDP — header, use cases, checksum (Hinglish)