Summary

  • RFC 3542 separated persistent, socket-wide IPv6 options from ancillary control data for one UDP or raw datagram. A per-message item overrides only the sticky option with the same name; unrelated defaults remain in force.
  • The scope has hard edges: a zero-length item can disable one option for one packet, queued receives may lack newly requested metadata, and TCP cannot inherit the same model because send calls do not map one-to-one to transmitted segments.

Picture a long-lived UDP socket carrying control traffic. The application has selected an interface, a traffic class and perhaps extension-header behavior that should apply to every datagram. One exceptional message needs a different routing header. The easy implementation is also the dangerous one: treat the exception as a replacement for the entire default bundle. The packet gets its special route, but silently loses policy the caller never meant to touch.

RFC 3542, published in May 2003 as Advanced Sockets Application Program Interface (API) for IPv6, made that scope explicit. It was Informational rather than a wire standard. Its subject was the boundary between an application and the kernel: how software asks for packet information, extension headers, hop limits, next hops, traffic class and Path MTU behavior without constructing every IPv6 byte by hand.

The specification described two sending surfaces. setsockopt() could set a “sticky” option for a socket, affecting transmitted packets until the application changed it. Ancillary data passed with sendmsg() could specify control information for one datagram on UDP or a raw socket. The distinction was temporal and structural: one surface established a standing default; the other declared a single-message exception.

The decisive rule appears in section 4.2. An ancillary item overrides a sticky option only when both carry the same option name. A per-datagram IPV6_RTHDR replaces the sticky routing header for that datagram. It does not disturb a sticky destination option, packet-information choice or other independently configured state. An exception receives authority over the cell it names, not over the whole socket.

That rule was a deliberate change from RFC 2292. In the earlier API, sticky options could be specified together through one socket option, so providing ancillary data replaced the set. RFC 3542 separated a larger collection of sticky and ancillary controls into individual options. Once the state became individually addressable, the override rule became individually scoped. The history is a reminder that an API’s data model determines the collateral effects of an update.

The same design permits an explicit absence. If a socket has a sticky IPV6_HOPOPTS value, a zero-length ancillary item of that type can suppress the Hop-by-Hop options header for one outgoing packet. The zero does not mean “forget all defaults.” It is a typed instruction: omit this one feature in this one message. The following datagram can return to the sticky value without rebuilding the rest of the socket policy.

Receiving has a different timing problem. An application first enables the relevant IPV6_RECVxxx options; recvmsg() then returns available information as ancillary objects. If a packet lacks a routing header, the corresponding object is absent. But RFC 3542 also warns that packets already queued when the receive option is enabled may not carry the newly requested ancillary information. Missing metadata therefore has at least two possible histories: the wire feature was absent, or the observation was activated too late.

TCP marks another boundary. The document does not define per-send ancillary transmission for TCP because application send operations and transmitted segments have no one-to-one correspondence. Sticky options are available, yet retransmitted segments may or may not use information set after the original transmission. Received optional information is also undefined for TCP, and the RFC specifically says it could not be used for access-control purposes in the way an application might imagine from UDP or raw sockets. Packet-scoped intent needs an actual packet scope.

Even checksum handling preserves the difference between one verified property and a complete verdict. The kernel verifies the mandatory ICMPv6 checksum and discards failures. It may perform additional checks, but a portable application must not assume those unspecified checks occurred. “Checksum accepted” is a receipt for that calculation, not a certificate that every field is meaningful or authorized.

Buffer construction carries the same lesson at a smaller scale. CMSG_SPACE includes the room required for alignment and allocation; CMSG_LEN supplies the length stored in the ancillary header, without trailing padding. The amount reserved and the logical object length are related but not interchangeable. Confusing them can make a correct payload inhabit an incorrectly described envelope.

Historical examples need present-day labels. RFC 3542 inherited an IPv6 Routing Header Type 0 example from the RFC 2460 era. RFC 8200 is now the IPv6 base specification and does not preserve Type 0 as current guidance. The example remains evidence about the API functions and their period, not a recommendation to deploy an obsolete routing mechanism.

This commission therefore stops before general IPv6 extension-header policy, Path MTU algorithms and forwarding behavior. It owns a control-scope transition: RFC 2292’s set-wide replacement became RFC 3542’s same-name override, with a typed one-packet disable and explicit limits where observation or segmentation breaks the analogy.

The durable operational rule is to record four layers separately: the socket default before the call, the ancillary exception supplied for the datagram, the packet the kernel actually emitted, and the result observed downstream. A successful sendmsg() proves that the interface accepted a request. Only running evidence shows which packet left and what happened to it. Narrow overrides protect the defaults; provenance protects the truth.

Sources