Tech-invite3GPPspaceIETFspace
959493929190898887868584838281807978777675747372717069686766656463626160595857565554535251504948474645444342414039383736353433323130292827262524232221201918171615141312111009080706050403020100
in Index   Prev   Next

RFC 3542

Advanced Sockets Application Program Interface (API) for IPv6

Pages: 77
Informational
Errata
Obsoletes:  2292
Part 3 of 3 – Pages 48 to 77
First   Prev   None

Top   ToC   RFC3542 - Page 48   prevText

12. Ordering of Ancillary Data and IPv6 Extension Headers

Three IPv6 extension headers can be specified by the application and returned to the application using ancillary data with sendmsg() and recvmsg(): the Routing header, Hop-by-Hop options header, and Destination options header. When multiple ancillary data objects are transferred via recvmsg() and these objects represent any of these three extension headers, their placement in the control buffer is directly tied to their location in the corresponding IPv6 datagram. For example, when the application has enabled the IPV6_RECVRTHDR and IPV6_RECVDSTOPTS options and later receives an IPv6 packet with extension headers in the following order: The IPv6 header A Hop-by-Hop options header A Destination options header (1) A Routing header An Authentication header A Destination options header (2) A UDP header and UDP data
Top   ToC   RFC3542 - Page 49
   then the application will receive three ancillary data objects in the
   following order:

      an object with cmsg_type set to IPV6_DSTOPTS, which represents
      the destination options header (1)
      an object with cmsg_type set to IPV6_RTHDR, which represents the
      Routing header
      an object with cmsg_type set to IPV6_DSTOPTS, which represents the
      destination options header (2)

   This example follows the header ordering described in [RFC-2460], but
   the receiving side of this specification does not assume the
   ordering.  Applications may receive any numbers of objects in any
   order according to the ordering of the received IPv6 datagram.

   For the sending side, however, this API imposes some ordering
   constraints according to [RFC-2460].  Applications using this API
   cannot make a packet with extension headers that do not follow the
   ordering.  Note, however, that this does not mean applications must
   always follow the restriction.  This is just a limitation in this API
   in order to give application programmers a guideline to construct
   headers in a practical manner.  Should an application need to make an
   outgoing packet in an arbitrary order about the extension headers,
   some other technique, such as the datalink interfaces BPF or DLPI,
   must be used.

   The followings are more details about the constraints:

   -  Each IPV6_xxx ancillary data object for a particular type of
      extension header can be specified at most once in a single control
      buffer.

   -  IPV6_xxx ancillary data objects can appear in any order in a
      control buffer, because there is no ambiguity of the ordering.

   -  Each set of IPV6_xxx ancillary data objects and sticky options
      will be put in the outgoing packet along with the header ordering
      described in [RFC-2460].

   -  An ancillary data object or a sticky option of IPV6_RTHDRDSTOPTS
      will affect the outgoing packet only when a Routing header is
      specified as an ancillary data object or a sticky option.
      Otherwise, the specified value for IPV6_RTHDRDSTOPTS will be
      ignored.
Top   ToC   RFC3542 - Page 50
   For example, when an application sends a UDP datagram with a control
   data buffer containing ancillary data objects in the following order:

      an object with cmsg_type set to IPV6_DSTOPTS
      an object with cmsg_type set to IPV6_RTHDRDSTOPTS
      an object with cmsg_type set to IPV6_HOPOPTS

   and the sending socket does not have any sticky options, then the
   outgoing packet would be constructed as follows:

      The IPv6 header
      A Hop-by-Hop options header
      A Destination options header
      A UDP header and UDP data

   where the destination options header corresponds to the ancillary
   data object with the type IPV6_DSTOPTS.

   Note that the constraints above do not necessarily mean that the
   outgoing packet sent on the wire always follows the header ordering
   specified in this API document.  The kernel may insert additional
   headers that break the ordering as a result.  For example, if the
   kernel supports Mobile IPv6, an additional destination options header
   may be inserted before an authentication header, even without a
   routing header.

   This API does not provide access to any other extension headers than
   the supported three types of headers.  In particular, no information
   is provided about the IP security headers on an incoming packet, nor
   can be specified for an outgoing packet.  This API is for
   applications that do not care about the existence of IP security
   headers.

13. IPv6-Specific Options with IPv4-Mapped IPv6 Addresses

The various socket options and ancillary data specifications defined in this document apply only to true IPv6 sockets. It is possible to create an IPv6 socket that actually sends and receives IPv4 packets, using IPv4-mapped IPv6 addresses, but the mapping of the options defined in this document to an IPv4 datagram is beyond the scope of this document. In general, attempting to specify an IPv6-only option, such as the Hop-by-Hop options, Destination options, or Routing header on an IPv6 socket that is using IPv4-mapped IPv6 addresses, will probably result in an error. Some implementations, however, may provide access to
Top   ToC   RFC3542 - Page 51
   the packet information (source/destination address, send/receive
   interface, and hop limit) on an IPv6 socket that is using IPv4-mapped
   IPv6 addresses.

14. Extended interfaces for rresvport, rcmd and rexec

Library functions that support the "r" commands hide the creation of a socket and the name resolution procedure from an application. When the libraries return an AF_INET6 socket to an application that do not support the address family, the application may encounter an unexpected result when, e.g., calling getpeername() for the socket. In order to support AF_INET6 sockets for the "r" commands while keeping backward compatibility, this section defines some extensions to the libraries.

14.1. rresvport_af

The rresvport() function is used by the rcmd() function, and this function is in turn called by many of the "r" commands such as rlogin. While new applications are not being written to use the rcmd() function, legacy applications such as rlogin will continue to use it and these will be ported to IPv6. rresvport() creates an IPv4/TCP socket and binds a "reserved port" to the socket. Instead of defining an IPv6 version of this function we define a new function that takes an address family as its argument. #include <unistd.h> int rresvport_af(int *port, int family); This function behaves the same as the existing rresvport() function, but instead of creating an AF_INET TCP socket, it can also create an AF_INET6 TCP socket. The family argument is either AF_INET or AF_INET6, and a new error return is EAFNOSUPPORT if the address family is not supported. (Note: There is little consensus on which header defines the rresvport() and rcmd() function prototypes. 4.4BSD defines it in <unistd.h>, others in <netdb.h>, and others don't define the function prototypes at all.)

14.2. rcmd_af

The existing rcmd() function can not transparently use AF_INET6 sockets since an application would not be prepared to handle AF_INET6 addresses returned by e.g., getpeername() on the file descriptor created by rcmd(). Thus a new function is needed.
Top   ToC   RFC3542 - Page 52
      int rcmd_af(char **ahost, unsigned short rport,
                  const char *locuser, const char *remuser,
                  const char *cmd, int *fd2p, int af)

   This function behaves the same as the existing rcmd() function, but
   instead of creating an AF_INET TCP socket, it can also create an
   AF_INET6 TCP socket.  The family argument is AF_INET, AF_INET6, or
   AF_UNSPEC.  When either AF_INET or AF_INET6 is specified, this
   function will create a socket of the specified address family.  When
   AF_UNSPEC is specified, it will try all possible address families
   until a connection can be established, and will return the associated
   socket of the connection.  A new error EAFNOSUPPORT will be returned
   if the address family is not supported.

14.3. rexec_af

The existing rexec() function can not transparently use AF_INET6 sockets since an application would not be prepared to handle AF_INET6 addresses returned by e.g., getpeername() on the file descriptor created by rexec(). Thus a new function is needed. int rexec_af(char **ahost, unsigned short rport, const char *name, const char *pass, const char *cmd, int *fd2p, int af) This function behaves the same as the existing rexec() function, but instead of creating an AF_INET TCP socket, it can also create an AF_INET6 TCP socket. The family argument is AF_INET, AF_INET6, or AF_UNSPEC. When either AF_INET or AF_INET6 is specified, this function will create a socket of the specified address family. When AF_UNSPEC is specified, it will try all possible address families until a connection can be established, and will return the associated socket of the connection. A new error EAFNOSUPPORT will be returned if the address family is not supported.

15. Summary of New Definitions

The following list summarizes the constants and structure, definitions discussed in this memo, sorted by header. <netinet/icmp6.h> ICMP6_DST_UNREACH <netinet/icmp6.h> ICMP6_DST_UNREACH_ADDR <netinet/icmp6.h> ICMP6_DST_UNREACH_ADMIN <netinet/icmp6.h> ICMP6_DST_UNREACH_BEYONDSCOPE <netinet/icmp6.h> ICMP6_DST_UNREACH_NOPORT <netinet/icmp6.h> ICMP6_DST_UNREACH_NOROUTE <netinet/icmp6.h> ICMP6_ECHO_REPLY <netinet/icmp6.h> ICMP6_ECHO_REQUEST <netinet/icmp6.h> ICMP6_INFOMSG_MASK
Top   ToC   RFC3542 - Page 53
      <netinet/icmp6.h> ICMP6_PACKET_TOO_BIG
      <netinet/icmp6.h> ICMP6_PARAMPROB_HEADER
      <netinet/icmp6.h> ICMP6_PARAMPROB_NEXTHEADER
      <netinet/icmp6.h> ICMP6_PARAMPROB_OPTION
      <netinet/icmp6.h> ICMP6_PARAM_PROB
      <netinet/icmp6.h> ICMP6_ROUTER_RENUMBERING
      <netinet/icmp6.h> ICMP6_RR_FLAGS_FORCEAPPLY
      <netinet/icmp6.h> ICMP6_RR_FLAGS_PREVDONE
      <netinet/icmp6.h> ICMP6_RR_FLAGS_REQRESULT
      <netinet/icmp6.h> ICMP6_RR_FLAGS_SPECSITE
      <netinet/icmp6.h> ICMP6_RR_FLAGS_TEST
      <netinet/icmp6.h> ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME
      <netinet/icmp6.h> ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME
      <netinet/icmp6.h> ICMP6_RR_PCOUSE_RAFLAGS_AUTO
      <netinet/icmp6.h> ICMP6_RR_PCOUSE_RAFLAGS_ONLINK
      <netinet/icmp6.h> ICMP6_RR_RESULT_FLAGS_FORBIDDEN
      <netinet/icmp6.h> ICMP6_RR_RESULT_FLAGS_OOB
      <netinet/icmp6.h> ICMP6_TIME_EXCEEDED
      <netinet/icmp6.h> ICMP6_TIME_EXCEED_REASSEMBLY
      <netinet/icmp6.h> ICMP6_TIME_EXCEED_TRANSIT
      <netinet/icmp6.h> MLD_LISTENER_QUERY
      <netinet/icmp6.h> MLD_LISTENER_REDUCTION
      <netinet/icmp6.h> MLD_LISTENER_REPORT
      <netinet/icmp6.h> ND_NA_FLAG_OVERRIDE
      <netinet/icmp6.h> ND_NA_FLAG_ROUTER
      <netinet/icmp6.h> ND_NA_FLAG_SOLICITED
      <netinet/icmp6.h> ND_NEIGHBOR_ADVERT
      <netinet/icmp6.h> ND_NEIGHBOR_SOLICIT
      <netinet/icmp6.h> ND_OPT_MTU
      <netinet/icmp6.h> ND_OPT_PI_FLAG_AUTO
      <netinet/icmp6.h> ND_OPT_PI_FLAG_ONLINK
      <netinet/icmp6.h> ND_OPT_PREFIX_INFORMATION
      <netinet/icmp6.h> ND_OPT_REDIRECTED_HEADER
      <netinet/icmp6.h> ND_OPT_SOURCE_LINKADDR
      <netinet/icmp6.h> ND_OPT_TARGET_LINKADDR
      <netinet/icmp6.h> ND_RA_FLAG_MANAGED
      <netinet/icmp6.h> ND_RA_FLAG_OTHER
      <netinet/icmp6.h> ND_REDIRECT
      <netinet/icmp6.h> ND_ROUTER_ADVERT
      <netinet/icmp6.h> ND_ROUTER_SOLICIT

      <netinet/icmp6.h> struct icmp6_filter{};
      <netinet/icmp6.h> struct icmp6_hdr{};
      <netinet/icmp6.h> struct icmp6_router_renum{};
      <netinet/icmp6.h> struct mld_hdr{};
      <netinet/icmp6.h> struct nd_neighbor_advert{};
      <netinet/icmp6.h> struct nd_neighbor_solicit{};
      <netinet/icmp6.h> struct nd_opt_hdr{};
Top   ToC   RFC3542 - Page 54
      <netinet/icmp6.h> struct nd_opt_mtu{};
      <netinet/icmp6.h> struct nd_opt_prefix_info{};
      <netinet/icmp6.h> struct nd_opt_rd_hdr{};
      <netinet/icmp6.h> struct nd_redirect{};
      <netinet/icmp6.h> struct nd_router_advert{};
      <netinet/icmp6.h> struct nd_router_solicit{};
      <netinet/icmp6.h> struct rr_pco_match{};
      <netinet/icmp6.h> struct rr_pco_use{};
      <netinet/icmp6.h> struct rr_result{};

      <netinet/in.h>    IPPROTO_AH
      <netinet/in.h>    IPPROTO_DSTOPTS
      <netinet/in.h>    IPPROTO_ESP
      <netinet/in.h>    IPPROTO_FRAGMENT
      <netinet/in.h>    IPPROTO_HOPOPTS
      <netinet/in.h>    IPPROTO_ICMPV6
      <netinet/in.h>    IPPROTO_IPV6
      <netinet/in.h>    IPPROTO_NONE
      <netinet/in.h>    IPPROTO_ROUTING
      <netinet/in.h>    IPV6_CHECKSUM
      <netinet/in.h>    IPV6_DONTFRAG
      <netinet/in.h>    IPV6_DSTOPTS
      <netinet/in.h>    IPV6_HOPLIMIT
      <netinet/in.h>    IPV6_HOPOPTS

      <netinet/in.h>    IPV6_NEXTHOP
      <netinet/in.h>    IPV6_PATHMTU
      <netinet/in.h>    IPV6_PKTINFO
      <netinet/in.h>    IPV6_RECVDSTOPTS
      <netinet/in.h>    IPV6_RECVHOPLIMIT
      <netinet/in.h>    IPV6_RECVHOPOPTS
      <netinet/in.h>    IPV6_RECVPKTINFO
      <netinet/in.h>    IPV6_RECVRTHDR
      <netinet/in.h>    IPV6_RECVTCLASS
      <netinet/in.h>    IPV6_RTHDR
      <netinet/in.h>    IPV6_RTHDRDSTOPTS
      <netinet/in.h>    IPV6_RTHDR_TYPE_0
      <netinet/in.h>    IPV6_RECVPATHMTU
      <netinet/in.h>    IPV6_TCLASS
      <netinet/in.h>    IPV6_USE_MIN_MTU
      <netinet/in.h>    struct in6_pktinfo{};
      <netinet/in.h>    struct ip6_mtuinfo{};

      <netinet/ip6.h>   IP6F_MORE_FRAG
      <netinet/ip6.h>   IP6F_OFF_MASK
      <netinet/ip6.h>   IP6F_RESERVED_MASK
      <netinet/ip6.h>   IP6OPT_JUMBO
      <netinet/ip6.h>   IP6OPT_JUMBO_LEN
Top   ToC   RFC3542 - Page 55
      <netinet/ip6.h>   IP6OPT_MUTABLE
      <netinet/ip6.h>   IP6OPT_NSAP_ADDR
      <netinet/ip6.h>   IP6OPT_PAD1
      <netinet/ip6.h>   IP6OPT_PADN
      <netinet/ip6.h>   IP6OPT_ROUTER_ALERT
      <netinet/ip6.h>   IP6OPT_TUNNEL_LIMIT
      <netinet/ip6.h>   IP6OPT_TYPE_DISCARD
      <netinet/ip6.h>   IP6OPT_TYPE_FORCEICMP
      <netinet/ip6.h>   IP6OPT_TYPE_ICMP
      <netinet/ip6.h>   IP6OPT_TYPE_SKIP
      <netinet/ip6.h>   IP6_ALERT_AN
      <netinet/ip6.h>   IP6_ALERT_MLD
      <netinet/ip6.h>   IP6_ALERT_RSVP
      <netinet/ip6.h>   struct ip6_dest{};
      <netinet/ip6.h>   struct ip6_frag{};
      <netinet/ip6.h>   struct ip6_hbh{};
      <netinet/ip6.h>   struct ip6_hdr{};
      <netinet/ip6.h>   struct ip6_opt{};
      <netinet/ip6.h>   struct ip6_opt_jumbo{};
      <netinet/ip6.h>   struct ip6_opt_nsap{};
      <netinet/ip6.h>   struct ip6_opt_router{};
      <netinet/ip6.h>   struct ip6_opt_tunnel{};
      <netinet/ip6.h>   struct ip6_rthdr{};
      <netinet/ip6.h>   struct ip6_rthdr0{};

   The following list summarizes the function and macro prototypes
   discussed in this memo, sorted by header.

      <netinet/icmp6.h> void ICMP6_FILTER_SETBLOCK(int, struct
                                               icmp6_filter *);
      <netinet/icmp6.h> void
                        ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *);
      <netinet/icmp6.h> void
                        ICMP6_FILTER_SETPASS(int,
                                             struct icmp6_filter *);
      <netinet/icmp6.h> void
                        ICMP6_FILTER_SETPASSALL(struct icmp6_filter *);
      <netinet/icmp6.h> int  ICMP6_FILTER_WILLBLOCK(int,
                                           const struct icmp6_filter *);
      <netinet/icmp6.h> int  ICMP6_FILTER_WILLPASS(int,
                                           const struct icmp6_filter *);

      <netinet/in.h>    int IN6_ARE_ADDR_EQUAL(const struct in6_addr *,
                                           const struct in6_addr *);

      <netinet/in.h>    int inet6_opt_append(void *, socklen_t, int,
                                             uint8_t, socklen_t, uint_t,
                                             void **);
Top   ToC   RFC3542 - Page 56
      <netinet/in.h>    int inet6_opt_get_val(void *, int, void *,
                                              socklen_t);
      <netinet/in.h>    int inet6_opt_find(void *, socklen_t,
                                           int, uint8_t ,
                                           socklen_t *, void **);
      <netinet/in.h>    int inet6_opt_finish(void *, socklen_t, int);
      <netinet/in.h>    int inet6_opt_init(void *, socklen_t);
      <netinet/in.h>    int inet6_opt_next(void *, socklen_t,
                                           int, uint8_t *,
                                           socklen_t *, void **);
      <netinet/in.h>    int inet6_opt_set_val(void *, int,
                                              void *, socklen_t);

      <netinet/in.h>    int inet6_rth_add(void *,
                                          const struct in6_addr *);
      <netinet/in.h>    struct in6_addr inet6_rth_getaddr(const void *,
                                                          int);
      <netinet/in.h>    void *inet6_rth_init(void *, socklen_t,
                                             int, int);
      <netinet/in.h>    int inet6_rth_reverse(const void *, void *);
      <netinet/in.h>    int inet6_rth_segments(const void *);
      <netinet/in.h>    soccklen_t inet6_rth_space(int, int);

      <netinet/ip6.h>   int  IP6OPT_TYPE(uint8_t);

      <sys/socket.h>    socklen_t CMSG_LEN(socklen_t);
      <sys/socket.h>    socklen_t CMSG_SPACE(socklen_t);

      <unistd.h>        int rresvport_af(int *, int);
      <unistd.h>        int rcmd_af(char **, unsigned short,
                                    const char *, const char *,
                                    const char *, int *, int);
      <unistd.h>        int rexec_af(char **, unsigned short,
                                     const char *, const char *,
                                     const char *, int *, int);

16. Security Considerations

The setting of certain Hop-by-Hop options and Destination options may be restricted to privileged processes. Similarly some Hop-by-Hop options and Destination options may not be returned to non-privileged applications. The ability to specify an arbitrary source address using IPV6_PKTINFO must be prevented; at least for non-privileged processes.
Top   ToC   RFC3542 - Page 57

17. Changes from RFC 2292

Significant changes that affect the compatibility to RFC 2292: - Removed the IPV6_PKTOPTIONS socket option by allowing sticky options to be set with individual setsockopt() calls. - Removed the ability to be able to specify Hop-by-Hop and Destination options using multiple ancillary data items. The application, using the inet6_opt_xxx() routines (see below), is responsible for formatting the whole extension header. - Removed the support for the loose/strict Routing header since that has been removed from the IPv6 specification. - Loosened the constraints for jumbo payload option that this option was always hidden from applications. - Disabled the use of the IPV6_HOPLIMIT sticky option. - Removed ip6r0_addr field from the ip6_rthdr structure. - Intentionally unspecified how to get received packet's information on TCP sockets. New features: - Added IPV6_RTHDRDSTOPTS to specify a Destination Options header before the Routing header. - Added separate IPV6_RECVxxx options to enable the receipt of the corresponding ancillary data items. - Added inet6_rth_xxx() and inet6_opt_xxx() functions to deal with routing or IPv6 options headers. - Added extensions of libraries for the "r" commands. - Introduced additional IPv6 option definitions such as IP6OPT_PAD1. - Added MLD and router renumbering definitions. - Added MTU-related socket options and ancillary data items. - Added options and ancillary data items to manipulate the traffic class field.
Top   ToC   RFC3542 - Page 58
   -  Changed the name of ICMPv6 unreachable code 2 to be "beyond scope
      of source address."  ICMP6_DST_UNREACH_NOTNEIGHBOR was removed
      with this change.

   Clarifications:

   -  Added clarifications on extension headers ordering; for the
      sending side, assume the recommended ordering described in RFC
      2460.  For the receiving side, do not assume any ordering and pass
      all headers to the application in the received order.

   -  Added a summary about the interface selection rule.

   -  Clarified the ordering between IPV6_MULTICAST_IF and the
      IPV6_PKTINFO sticky option for multicast packets.

   -  Clarified how sticky options and the ICMPv6 filter are turned off
      and that getsockopt() of a sticky option returns what was set with
      setsockopt().

   -  Clarified that IPV6_NEXTHOP should be ignored for a multicast
      destination, that it should not contradict with the specified
      outgoing interface, and that the next hop should be a sockaddr_in6
      structure.

   -  Clarified corner cases of IPV6_CHECKSUM.

   -  Aligned with the POSIX standard.

   Editorial changes:

   -  Replaced MUST with must (since this is an informational document).

   -  Revised abstract to be more clear and concise, particularly
      concentrating on differences from RFC 2292.

   -  Made the URL of assigned numbers less specific so that it would be
      more robust for future changes.

   -  Updated the reference to the basic API.

   -  Added a reference to the latest POSIX standard.

   -  Moved general specifications of ancillary data and CMSG macros to
      the appendix.
Top   ToC   RFC3542 - Page 59

18. References

[RFC-1981] McCann, J., Deering, S. and J. Mogul, "Path MTU Discovery for IP version 6", RFC 1981, August 1996. [RFC-2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", RFC 2460, December 1998. [RFC-3493] Gilligan, R., Thomson, S., Bound, J., McCann, J. and W. Stevens, "Basic Socket Interface Extensions for IPv6", RFC 3493, March 2003. [POSIX] IEEE Std. 1003.1-2001 Standard for Information Technology -- Portable Operating System Interface (POSIX). Open group Technical Standard: Base Specifications, Issue 6, December 2001. ISO/IEC 9945:2002. http://www.opengroup.org/austin [TCPIPILLUST] Wright, G., Stevens, W., "TCP/IP Illustrated, Volume 2: The Implementation", Addison Wesley, 1994.

19. Acknowledgments

Matt Thomas and Jim Bound have been working on the technical details in this document for over a year. Keith Sklower is the original implementor of ancillary data in the BSD networking code. Craig Metz provided lots of feedback, suggestions, and comments based on his implementing many of these features as the document was being written. Mark Andrews first proposed the idea of the IPV6_USE_MIN_MTU option. Jun-ichiro Hagino contributed text for the traffic class API from a document of his own. The following provided comments on earlier drafts: Pascal Anelli, Hamid Asayesh, Ran Atkinson, Karl Auerbach, Hamid Asayesh, Don Coolidge, Matt Crawford, Sam T. Denton, Richard Draves, Francis Dupont, Toerless Eckert, Lilian Fernandes, Bob Gilligan, Gerri Harter, Tim Hartrick, Bob Halley, Masaki Hirabaru, Michael Hunter, Yoshinobu Inoue, Mukesh Kacker, A. N. Kuznetsov, Sam Manthorpe, Pedro Marques, Jack McCann, der Mouse, John Moy, Lori Napoli, Thomas Narten, Atsushi Onoe, Steve Parker, Charles Perkins, Ken Powell, Tom Pusateri, Pedro Roque, Sameer Shah, Peter Sjodin, Stephen P. Spackman, Jinmei Tatuya, Karen Tracey, Sowmini Varadhan, Quaizar Vohra, Carl Williams, Steve Wise, Eric Wong, Farrell Woods, Kazu Yamamoto, Vladislav Yasevich, and Yoshifuji Hideaki.
Top   ToC   RFC3542 - Page 60

20. Appendix A: Ancillary Data Overview

4.2BSD allowed file descriptors to be transferred between separate processes across a UNIX domain socket using the sendmsg() and recvmsg() functions. Two members of the msghdr structure, msg_accrights and msg_accrightslen, were used to send and receive the descriptors. When the OSI protocols were added to 4.3BSD Reno in 1990 the names of these two fields in the msghdr structure were changed to msg_control and msg_controllen, because they were used by the OSI protocols for "control information", although the comments in the source code call this "ancillary data". Other than the OSI protocols, the use of ancillary data has been rare. In 4.4BSD, for example, the only use of ancillary data with IPv4 is to return the destination address of a received UDP datagram if the IP_RECVDSTADDR socket option is set. With Unix domain sockets ancillary data is still used to send and receive descriptors. Nevertheless the ancillary data fields of the msghdr structure provide a clean way to pass information in addition to the data that is being read or written. The inclusion of the msg_control and msg_controllen members of the msghdr structure along with the cmsghdr structure that is pointed to by the msg_control member is required by the Posix sockets API standard.

20.1. The msghdr Structure

The msghdr structure is used by the recvmsg() and sendmsg() functions. Its Posix definition is: struct msghdr { void *msg_name; /* ptr to socket address structure */ socklen_t msg_namelen; /* size of socket address structure */ struct iovec *msg_iov; /* scatter/gather array */ int msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data */ socklen_t msg_controllen; /* ancillary data buffer length */ int msg_flags; /* flags on received message */ }; The structure is declared as a result of including <sys/socket.h>. (Note: Before Posix the two "void *" pointers were typically "char *", and the two socklen_t members were typically integers. Earlier drafts of Posix had the two socklen_t members as size_t, but it then changed these to socklen_t to simplify binary portability for 64-bit
Top   ToC   RFC3542 - Page 61
   implementations and to align Posix with X/Open's Networking Services,
   Issue 5.  The change in msg_control to a "void *" pointer affects any
   code that increments this pointer.)

   Most Berkeley-derived implementations limit the amount of ancillary
   data in a call to sendmsg() to no more than 108 bytes (an mbuf).
   This API requires a minimum of 10240 bytes of ancillary data, but it
   is recommended that the amount be limited only by the buffer space
   reserved by the socket (which can be modified by the SO_SNDBUF socket
   option).  (Note: This magic number 10240 was picked as a value that
   should always be large enough.  108 bytes is clearly too small as the
   maximum size of a Routing header is 2048 bytes.)

20.2. The cmsghdr Structure

The cmsghdr structure describes ancillary data objects transferred by recvmsg() and sendmsg(). Its Posix definition is: struct cmsghdr { socklen_t cmsg_len; /* #bytes, including this header */ int cmsg_level; /* originating protocol */ int cmsg_type; /* protocol-specific type */ /* followed by unsigned char cmsg_data[]; */ }; This structure is declared as a result of including <sys/socket.h>. (Note: Before Posix the cmsg_len member was an integer, and not a socklen_t. See the Note in the previous section for why socklen_t is used here.) As shown in this definition, normally there is no member with the name cmsg_data[]. Instead, the data portion is accessed using the CMSG_xxx() macros, as described in Section 20.3. Nevertheless, it is common to refer to the cmsg_data[] member. When ancillary data is sent or received, any number of ancillary data objects can be specified by the msg_control and msg_controllen members of the msghdr structure, because each object is preceded by a cmsghdr structure defining the object's length (the cmsg_len member). Historically Berkeley-derived implementations have passed only one object at a time, but this API allows multiple objects to be passed in a single call to sendmsg() or recvmsg(). The following example shows two ancillary data objects in a control buffer.
Top   ToC   RFC3542 - Page 62
|<--------------------------- msg_controllen ------------------------->|
|                                 OR                                   |
|<--------------------------- msg_controllen ---------------------->|
|                                                                      |
|<----- ancillary data object ----->|<---- ancillary data object ----->|
|<------ min CMSG_SPACE() --------->|<----- min CMSG_SPACE() --------->|
|                                   |                                  |
|<---------- cmsg_len ---------->|  |<-------- cmsg_len ----------->|  |
|<--------- CMSG_LEN() --------->|  |<------- CMSG_LEN() ---------->|  |
|                                |  |                               |  |
+-----+-----+-----+--+-----------+--+-----+-----+-----+--+----------+--+
|cmsg_|cmsg_|cmsg_|XX|   cmsg_   |XX|cmsg_|cmsg_|cmsg_|XX|  cmsg_   |XX|
|len  |level|type |XX|   data[]  |XX|len  |level|type |XX|  data[]  |XX|
+-----+-----+-----+--+-----------+--+-----+-----+-----+--+----------+--+
^
|
msg_control
points here

   The fields shown as "XX" are possible padding, between the cmsghdr
   structure and the data, and between the data and the next cmsghdr
   structure, if required by the implementation.  While sending an
   application may or may not include padding at the end of last
   ancillary data in msg_controllen and implementations must accept both
   as valid.  On receiving a portable application must provide space for
   padding at the end of the last ancillary data as implementations may
   copy out the padding at the end of the control message buffer and
   include it in the received msg_controllen.  When recvmsg() is called
   if msg_controllen is too small for all the ancillary data items
   including any trailing padding after the last item an implementation
   may set MSG_CTRUNC.

20.3. Ancillary Data Object Macros

To aid in the manipulation of ancillary data objects, three macros from 4.4BSD are defined by Posix: CMSG_DATA(), CMSG_NXTHDR(), and CMSG_FIRSTHDR(). Before describing these macros, we show the following example of how they might be used with a call to recvmsg(). struct msghdr msg; struct cmsghdr *cmsgptr; /* fill in msg */ /* call recvmsg() */
Top   ToC   RFC3542 - Page 63
      for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
           cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
          if (cmsgptr->cmsg_len == 0) {
              /* Error handling */
           break;
          }
          if (cmsgptr->cmsg_level == ... &&
              cmsgptr->cmsg_type == ... ) {
              u_char  *ptr;

              ptr = CMSG_DATA(cmsgptr);
              /* process data pointed to by ptr */
          }
      }

   We now describe the three Posix macros, followed by two more that are
   new with this API: CMSG_SPACE() and CMSG_LEN().  All these macros are
   defined as a result of including <sys/socket.h>.

20.3.1. CMSG_FIRSTHDR

struct cmsghdr *CMSG_FIRSTHDR(const struct msghdr *mhdr); CMSG_FIRSTHDR() returns a pointer to the first cmsghdr structure in the msghdr structure pointed to by mhdr. The macro returns NULL if there is no ancillary data pointed to by the msghdr structure (that is, if either msg_control is NULL or if msg_controllen is less than the size of a cmsghdr structure). One possible implementation could be #define CMSG_FIRSTHDR(mhdr) \ ( (mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ (struct cmsghdr *)(mhdr)->msg_control : \ (struct cmsghdr *)NULL ) (Note: Most existing implementations do not test the value of msg_controllen, and just return the value of msg_control. The value of msg_controllen must be tested, because if the application asks recvmsg() to return ancillary data, by setting msg_control to point to the application's buffer and setting msg_controllen to the length of this buffer, the kernel indicates that no ancillary data is available by setting msg_controllen to 0 on return. It is also easier to put this test into this macro, than making the application perform the test.)
Top   ToC   RFC3542 - Page 64

20.3.2. CMSG_NXTHDR

As described in Section 5.1, CMSG_NXTHDR has been extended to handle a NULL 2nd argument to mean "get the first header". This provides an alternative way of coding the processing loop shown earlier: struct msghdr msg; struct cmsghdr *cmsgptr = NULL; /* fill in msg */ /* call recvmsg() */ while ((cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) != NULL) { if (cmsgptr->cmsg_len == 0) { /* Error handling */ break; } if (cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ... ) { u_char *ptr; ptr = CMSG_DATA(cmsgptr); /* process data pointed to by ptr */ } } One possible implementation could be: #define CMSG_NXTHDR(mhdr, cmsg) \ (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ (((u_char *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) \ + ALIGN_D(sizeof(struct cmsghdr)) > \ (u_char *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ (struct cmsghdr *)((u_char *)(cmsg) + \ ALIGN_H((cmsg)->cmsg_len)))) The macros ALIGN_H() and ALIGN_D(), which are implementation dependent, round their arguments up to the next even multiple of whatever alignment is required for the start of the cmsghdr structure and the data, respectively. (This is probably a multiple of 4 or 8 bytes.) They are often the same macro in implementations platforms where alignment requirement for header and data is chosen to be identical.
Top   ToC   RFC3542 - Page 65

20.3.3. CMSG_DATA

unsigned char *CMSG_DATA(const struct cmsghdr *cmsg); CMSG_DATA() returns a pointer to the data (what is called the cmsg_data[] member, even though such a member is not defined in the structure) following a cmsghdr structure. One possible implementation could be: #define CMSG_DATA(cmsg) ( (u_char *)(cmsg) + \ ALIGN_D(sizeof(struct cmsghdr)) )

20.3.4. CMSG_SPACE

CMSG_SPACE is new with this API (see Section 5.2). It is used to determine how much space needs to be allocated for an ancillary data item. One possible implementation could be: #define CMSG_SPACE(length) ( ALIGN_D(sizeof(struct cmsghdr)) + \ ALIGN_H(length) )

20.3.5. CMSG_LEN

CMSG_LEN is new with this API (see Section 5.3). It returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any padding needed to satisfy alignment requirements. One possible implementation could be: #define CMSG_LEN(length) ( ALIGN_D(sizeof(struct cmsghdr)) + \ length )

21. Appendix B: Examples Using the inet6_rth_XXX() Functions

Here we show an example for both sending Routing headers and processing and reversing a received Routing header.

21.1. Sending a Routing Header

As an example of these Routing header functions defined in this document, we go through the function calls for the example on p. 17 of [RFC-2460]. The source is S, the destination is D, and the three intermediate nodes are I1, I2, and I3.
Top   ToC   RFC3542 - Page 66
              S -----> I1 -----> I2 -----> I3 -----> D

      src:    *    S         S         S         S   S
      dst:    D   I1        I2        I3         D   D
      A[1]:  I1   I2        I1        I1        I1  I1
      A[2]:  I2   I3        I3        I2        I2  I2
      A[3]:  I3    D         D         D        I3  I3
      #seg:   3    3         2         1         0   3

   src and dst are the source and destination IPv6 addresses in the IPv6
   header.  A[1], A[2], and A[3] are the three addresses in the Routing
   header.  #seg is the Segments Left field in the Routing header.

   The six values in the column beneath node S are the values in the
   Routing header specified by the sending application using sendmsg()
   of setsockopt().  The function calls by the sender would look like:

      void  *extptr;
      socklen_t   extlen;
      struct msghdr  msg;
      struct cmsghdr  *cmsgptr;
      int   cmsglen;
      struct sockaddr_in6  I1, I2, I3, D;

      extlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, 3);
      cmsglen = CMSG_SPACE(extlen);
      cmsgptr = malloc(cmsglen);
      cmsgptr->cmsg_len = CMSG_LEN(extlen);
      cmsgptr->cmsg_level = IPPROTO_IPV6;
      cmsgptr->cmsg_type = IPV6_RTHDR;

      extptr = CMSG_DATA(cmsgptr);
      extptr = inet6_rth_init(extptr, extlen, IPV6_RTHDR_TYPE_0, 3);

      inet6_rth_add(extptr, &I1.sin6_addr);
      inet6_rth_add(extptr, &I2.sin6_addr);
      inet6_rth_add(extptr, &I3.sin6_addr);

      msg.msg_control = cmsgptr;
      msg.msg_controllen = cmsglen;

      /* finish filling in msg{}, msg_name = D */
      /* call sendmsg() */

   We also assume that the source address for the socket is not
   specified (i.e., the asterisk in the figure).
Top   ToC   RFC3542 - Page 67
   The four columns of six values that are then shown between the five
   nodes are the values of the fields in the packet while the packet is
   in transit between the two nodes.  Notice that before the packet is
   sent by the source node S, the source address is chosen (replacing
   the asterisk), I1 becomes the destination address of the datagram,
   the two addresses A[2] and A[3] are "shifted up", and D is moved to
   A[3].

   The columns of values that are shown beneath the destination node are
   the values returned by recvmsg(), assuming the application has
   enabled both the IPV6_RECVPKTINFO and IPV6_RECVRTHDR socket options.
   The source address is S (contained in the sockaddr_in6 structure
   pointed to by the msg_name member), the destination address is D
   (returned as an ancillary data object in an in6_pktinfo structure),
   and the ancillary data object specifying the Routing header will
   contain three addresses (I1, I2, and I3).  The number of segments in
   the Routing header is known from the Hdr Ext Len field in the Routing
   header (a value of 6, indicating 3 addresses).

   The return value from inet6_rth_segments() will be 3 and
   inet6_rth_getaddr(0) will return I1, inet6_rth_getaddr(1) will return
   I2, and inet6_rth_getaddr(2) will return I3,

   If the receiving application then calls inet6_rth_reverse(), the
   order of the three addresses will become I3, I2, and I1.

   We can also show what an implementation might store in the ancillary
   data object as the Routing header is being built by the sending
   process.  If we assume a 32-bit architecture where sizeof(struct
   cmsghdr) equals 12, with a desired alignment of 4-byte boundaries,
   then the call to inet6_rth_space(3) returns 68: 12 bytes for the
   cmsghdr structure and 56 bytes for the Routing header (8 + 3*16).

   The call to inet6_rth_init() initializes the ancillary data object to
   contain a Type 0 Routing header:

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_len = 20                                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_level = IPPROTO_IPV6                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_type = IPV6_RTHDR                                  |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Next Header  | Hdr Ext Len=6 | Routing Type=0|  Seg Left=0   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Reserved                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Top   ToC   RFC3542 - Page 68
   The first call to inet6_rth_add() adds I1 to the list.

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_len = 36                                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_level = IPPROTO_IPV6                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_type = IPV6_RTHDR                                  |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Next Header  | Hdr Ext Len=6 | Routing Type=0|  Seg Left=1   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Reserved                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                           Address[1] = I1                     +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   cmsg_len is incremented by 16, and the Segments Left field is
   incremented by 1.
Top   ToC   RFC3542 - Page 69
   The next call to inet6_rth_add() adds I2 to the list.

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_len = 52                                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_level = IPPROTO_IPV6                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_type = IPV6_RTHDR                                  |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Next Header  | Hdr Ext Len=6 | Routing Type=0|  Seg Left=2   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Reserved                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                           Address[1] = I1                     +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                           Address[2] = I2                     +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   cmsg_len is incremented by 16, and the Segments Left field is
   incremented by 1.
Top   ToC   RFC3542 - Page 70
   The last call to inet6_rth_add() adds I3 to the list.

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_len = 68                                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_level = IPPROTO_IPV6                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       cmsg_type = IPV6_RTHDR                                  |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Next Header  | Hdr Ext Len=6 | Routing Type=0|  Seg Left=3   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Reserved                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                           Address[1] = I1                     +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                           Address[2] = I2                     +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                           Address[3] = I3                     +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   cmsg_len is incremented by 16, and the Segments Left field is
   incremented by 1.

21.2. Receiving Routing Headers

This example assumes that the application has enabled IPV6_RECVRTHDR socket option. The application prints and reverses a source route and uses that to echo the received data.
Top   ToC   RFC3542 - Page 71
      struct sockaddr_in6     addr;
      struct msghdr           msg;
      struct iovec            iov;
      struct cmsghdr          *cmsgptr;
      socklen_t               cmsgspace;
      void                    *extptr;
      int                     extlen;

      int                     segments;
      int                     i;
      char                    databuf[8192];

      segments = 100;        /* Enough */
      extlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, segments);
      cmsgspace = CMSG_SPACE(extlen);
      cmsgptr = malloc(cmsgspace);
      if (cmsgptr == NULL) {
              perror("malloc");
              exit(1);
      }
      extptr = CMSG_DATA(cmsgptr);

      msg.msg_control = cmsgptr;
      msg.msg_controllen = cmsgspace;
      msg.msg_name = (struct sockaddr *)&addr;
      msg.msg_namelen = sizeof (addr);
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      iov.iov_base = databuf;
      iov.iov_len = sizeof (databuf);
      msg.msg_flags = 0;
      if (recvmsg(s, &msg, 0) == -1) {
              perror("recvmsg");
              return;
      }
      if (msg.msg_controllen != 0 &&
          cmsgptr->cmsg_level == IPPROTO_IPV6 &&
          cmsgptr->cmsg_type == IPV6_RTHDR) {
              struct in6_addr *in6;
              char asciiname[INET6_ADDRSTRLEN];
              struct ip6_rthdr *rthdr;

              rthdr = (struct ip6_rthdr *)extptr;
              segments = inet6_rth_segments(extptr);
              printf("route (%d segments, %d left): ",
                  segments, rthdr->ip6r_segleft);
              for (i = 0; i < segments; i++) {
                      in6 = inet6_rth_getaddr(extptr, i);
Top   ToC   RFC3542 - Page 72
                      if (in6 == NULL)
                              printf("<NULL> ");
                      else
                              printf("%s ", inet_ntop(AF_INET6,
                                  (void *)in6->s6_addr,
                                  asciiname, INET6_ADDRSTRLEN));
              }
              if (inet6_rth_reverse(extptr, extptr) == -1) {
                      printf("reverse failed");
                      return;
              }
      }
      iov.iov_base = databuf;
      iov.iov_len = strlen(databuf);
      if (sendmsg(s, &msg, 0) == -1)
              perror("sendmsg");
      if (cmsgptr != NULL)
              free(cmsgptr);

   Note: The above example is a simple illustration.  It skips some
   error checks, including those involving the MSG_TRUNC and MSG_CTRUNC
   flags.  It also leaves some type mismatches in favor of brevity.

22. Appendix C: Examples Using the inet6_opt_XXX() Functions

This shows how Hop-by-Hop and Destination options can be both built as well as parsed using the inet6_opt_XXX() functions. These examples assume that there are defined values for OPT_X and OPT_Y. Note: The example is a simple illustration. It skips some error checks and leaves some type mismatches in favor of brevity.

22.1. Building Options

We now provide an example that builds two Hop-by-Hop options using the example in Appendix B of [RFC-2460]. void *extbuf; socklen_t extlen; int currentlen; void *databuf; int offset; uint8_t value1; uint16_t value2; uint32_t value4; uint64_t value8; /* Estimate the length */
Top   ToC   RFC3542 - Page 73
      currentlen = inet6_opt_init(NULL, 0);
      if (currentlen == -1)
              return (-1);
      currentlen = inet6_opt_append(NULL, 0, currentlen, OPT_X,
                                    12, 8, NULL);
      if (currentlen == -1)
              return (-1);
      currentlen = inet6_opt_append(NULL, 0, currentlen, OPT_Y,
                                    7, 4, NULL);
      if (currentlen == -1)
              return (-1);
      currentlen = inet6_opt_finish(NULL, 0, currentlen);
      if (currentlen == -1)
              return (-1);
      extlen = currentlen;

      extbuf = malloc(extlen);
      if (extbuf == NULL) {
              perror("malloc");
              return (-1);
      }
      currentlen = inet6_opt_init(extbuf, extlen);
      if (currentlen == -1)
              return (-1);

      currentlen = inet6_opt_append(extbuf, extlen, currentlen,
          OPT_X, 12, 8, &databuf);
      if (currentlen == -1)
              return (-1);
      /* Insert value 0x12345678 for 4-octet field */
      offset = 0;
      value4 = 0x12345678;
      offset = inet6_opt_set_val(databuf, offset,
                                 &value4, sizeof (value4));
      /* Insert value 0x0102030405060708 for 8-octet field */
      value8 = 0x0102030405060708;
      offset = inet6_opt_set_val(databuf, offset,
                                 &value8, sizeof (value8));

      currentlen = inet6_opt_append(extbuf, extlen, currentlen,
          OPT_Y, 7, 4, &databuf);
      if (currentlen == -1)
              return (-1);
      /* Insert value 0x01 for 1-octet field */
      offset = 0;
      value1 = 0x01;
      offset = inet6_opt_set_val(databuf, offset,
                                 &value1, sizeof (value1));
Top   ToC   RFC3542 - Page 74
      /* Insert value 0x1331 for 2-octet field */
      value2 = 0x1331;
      offset = inet6_opt_set_val(databuf, offset,
                                 &value2, sizeof (value2));
      /* Insert value 0x01020304 for 4-octet field */
      value4 = 0x01020304;
      offset = inet6_opt_set_val(databuf, offset,
                                 &value4, sizeof (value4));

      currentlen = inet6_opt_finish(extbuf, extlen, currentlen);
      if (currentlen == -1)
              return (-1);
      /* extbuf and extlen are now completely formatted */

22.2. Parsing Received Options

This example parses and prints the content of the two options in the previous example. int print_opt(void *extbuf, socklen_t extlen) { struct ip6_dest *ext; int currentlen; uint8_t type; socklen_t len; void *databuf; int offset; uint8_t value1; uint16_t value2; uint32_t value4; uint64_t value8; ext = (struct ip6_dest *)extbuf; printf("nxt %u, len %u (bytes %d)\n", ext->ip6d_nxt, ext->ip6d_len, (ext->ip6d_len + 1) * 8); currentlen = 0; while (1) { currentlen = inet6_opt_next(extbuf, extlen, currentlen, &type, &len, &databuf); if (currentlen == -1) break; printf("Received opt %u len %u\n", type, len); switch (type) { case OPT_X:
Top   ToC   RFC3542 - Page 75
                              offset = 0;
                              offset =
                                  inet6_opt_get_val(databuf, offset,
                                                    &value4,
                                                    sizeof (value4));
                              printf("X 4-byte field %x\n", value4);
                              offset =
                                  inet6_opt_get_val(databuf, offset,
                                                    &value8,
                                                    sizeof (value8));
                              printf("X 8-byte field %llx\n", value8);
                              break;
                      case OPT_Y:
                              offset = 0;
                              offset =
                                  inet6_opt_get_val(databuf, offset,
                                                    &value1,
                                                    sizeof (value1));
                              printf("Y 1-byte field %x\n", value1);
                              offset =
                                  inet6_opt_get_val(databuf, offset,
                                                    &value2,
                                                    sizeof (value2));
                              printf("Y 2-byte field %x\n", value2);
                              offset =
                                  inet6_opt_get_val(databuf, offset,
                                                    &value4,
                                                    sizeof (value4));
                              printf("Y 4-byte field %x\n", value4);
                              break;
                      default:
                              printf("Unknown option %u\n", type);
                              break;
                      }
              }
              return (0);
      }
Top   ToC   RFC3542 - Page 76

23. Authors' Addresses

W. Richard Stevens (deceased) Matt Thomas 3am Software Foundry 8053 Park Villa Circle Cupertino, CA 95014 EMail: matt@3am-software.com Erik Nordmark Sun Microsystems Laboratories, Europe 180, avenue de l'Europe 38334 SAINT ISMIER Cedex, France Phone: +33 (0)4 74 18 88 03 Fax: +33 (0)4 76 18 88 88 EMail: Erik.Nordmark@sun.com Tatuya JINMEI Corporate Research & Development Center, Toshiba Corporation 1 Komukai Toshiba-cho, Kawasaki-shi Kanagawa 212-8582, Japan EMail: jinmei@isl.rdc.toshiba.co.jp
Top   ToC   RFC3542 - Page 77

24. Full Copyright Statement

Copyright (C) The Internet Society (2003). All Rights Reserved. This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns. This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society.