net/ipv6/exthdrs.c

Source file repositories/reference/linux-study-clean/net/ipv6/exthdrs.c

File Facts

System
Linux kernel
Corpus path
net/ipv6/exthdrs.c
Extension
.c
Size
33766 bytes
Lines
1405
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

if (nh[off] == IPV6_TLV_PAD1) {
			padlen++;
			if (padlen > 7)
				goto bad;
			off++;
			len--;
			continue;
		}
		if (len < 2)
			goto bad;
		optlen = nh[off + 1] + 2;
		if (optlen > len)
			goto bad;

		if (nh[off] == IPV6_TLV_PADN) {
			/* RFC 2460 states that the purpose of PadN is
			 * to align the containing header to multiples
			 * of 8. 7 is therefore the highest valid value.
			 * See also RFC 4942, Section 2.1.9.5.
			 */
			padlen += optlen;
			if (padlen > 7)
				goto bad;
			/* RFC 4942 recommends receiving hosts to
			 * actively check PadN payload to contain
			 * only zeroes.
			 */
			for (i = 2; i < optlen; i++) {
				if (nh[off + i] != 0)
					goto bad;
			}
		} else {
			tlv_count++;
			if (tlv_count > max_count)
				goto bad;

			if (hopbyhop) {
				switch (nh[off]) {
				case IPV6_TLV_ROUTERALERT:
					if (!ipv6_hop_ra(skb, off))
						return false;
					break;
				case IPV6_TLV_IOAM:
					if (!ipv6_hop_ioam(skb, off))
						return false;
					break;
				case IPV6_TLV_JUMBO:
					if (!ipv6_hop_jumbo(skb, off))
						return false;
					break;
				case IPV6_TLV_CALIPSO:
					if (!ipv6_hop_calipso(skb, off))
						return false;
					break;
				default:
					if (!ip6_tlvopt_unknown(skb, off,
								disallow_unknowns))
						return false;
					break;
				}
			} else {
				switch (nh[off]) {
#if IS_ENABLED(CONFIG_IPV6_MIP6)
				case IPV6_TLV_HAO:
					if (!ipv6_dest_hao(skb, off))
						return false;
					break;
#endif
				default:
					if (!ip6_tlvopt_unknown(skb, off,
								disallow_unknowns))
						return false;
					break;
				}
			}
			padlen = 0;

			/* recompute the network header pointer in case it has changed */
			nh = skb_network_header(skb);
		}
		off += optlen;
		len -= optlen;
	}

	if (len == 0)
		return true;
bad:
	kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR);
	return false;
}

Annotation

Implementation Notes