FreeBSD/sys/netpfil/pf/pf.c
/**
 * Checksum updates are a little complicated because the checksum in the TCP/UDP
 * header isn't always a full checksum. In some cases (i.e. output) it's a
 * pseudo-header checksum, which is a partial checksum over src/dst IP
 * addresses, protocol number and length.
 *
 * That means we have the following cases:
 *  * Input or forwarding: we don't have TSO, the checksum fields are full
 *  	checksums, we need to update the checksum whenever we change anything.
 *  * Output (i.e. the checksum is a pseudo-header checksum):
 *  	x The field being updated is src/dst address or affects the length of
 *  	the packet. We need to update the pseudo-header checksum (note that this
 *  	checksum is not ones' complement).
 *  	x Some other field is being modified (e.g. src/dst port numbers): We
 *  	don't have to update anything.
 **/
Checksum updates are a little complicated because the checksum in the TCP/UDP
header isn't always a full checksum. In some cases  it's a
pseudo-header checksum, which is a partial checksum over src/dst IP
addresses, protocol number and length.

That means we have the following cases:
Input or forwarding: we don't have TSO, the checksum fields are full
checksums, we need to update the checksum whenever we change anything.
Output :
x The field being updated is src/dst address or affects the length of
the packet. We need to update the pseudo-header checksum (note that this
checksum is not ones' complement).
x Some other field is being modified : We
don't have to update anything.
Checksum updates are a little complicated because the checksum in the TCP / UDP header isn ' t always a full checksum . In some cases it ' s a pseudo - header checksum which is a partial checksum over src / dst IP addresses protocol number and length . That means we have the following cases : Input or forwarding : we don ' t have TSO the checksum fields are full checksums we need to update the checksum whenever we change anything . Output : x The field being updated is src / dst address or affects the length of the packet . We need to update the pseudo - header checksum ( note that this checksum is not ones ' complement ) . x Some other field is being modified : We don ' t have to update anything .
u_int16_t
pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
{
	u_int32_t	l;
	if (udp && !cksum)
		return (0x0000);
	l = cksum + old - new;
	l = (l >> 16) + (l & 65535);
	l = l & 65535;
	if (udp && !l)
		return (0xFFFF);
	return (l);
}
u_int16_t pf_cksum_fixup ( u_int16_t cksum , u_int16_t old , u_int16_t new , u_int8_t udp ) { u_int32_t l ; if ( udp && ! cksum ) return ( 0x0000 ) ; l = cksum + old - new ; l = ( l >> 16 ) + ( l & 65535 ) ; l = l & 65535 ; if ( udp && ! l ) return ( 0xFFFF ) ; return ( l ) ; }
Checksum updates are a little complicated because the checksum in the TCP/UDP
 header isn't always a full checksum.
Checksum updates are a little complicated because the checksum in the TCP / UDP header isn ' t always a full checksum .