Network Working Group                                        R. Gilligan
Request for Comments: 2133                                      Freegate
Category: Informational                                       S. Thomson
                                                                J. Bound
                                                              W. Stevens
                                                              April 1997

               Basic Socket Interface Extensions for IPv6

Status of this Memo

   This memo provides information for the Internet community.  This memo
   does not specify an Internet standard of any kind.  Distribution of
   this memo is unlimited.


   The de facto standard application program interface (API) for TCP/IP
   applications is the "sockets" interface.  Although this API was
   developed for Unix in the early 1980s it has also been implemented on
   a wide variety of non-Unix systems.  TCP/IP applications written
   using the sockets API have in the past enjoyed a high degree of
   portability and we would like the same portability with IPv6
   applications.  But changes are required to the sockets API to support
   IPv6 and this memo describes these changes.  These include a new
   socket address structure to carry IPv6 addresses, new address
   conversion functions, and some new socket options.  These extensions
   are designed to provide access to the basic IPv6 features required by
   TCP and UDP applications, including multicasting, while introducing a
   minimum of change into the system and providing complete
   compatibility for existing IPv4 applications.  Additional extensions
   for advanced IPv6 features (raw sockets and access to the IPv6
   extension headers) are defined in another document [5].

Table of Contents

   1.  Introduction ................................................  2
   2.  Design Considerations .......................................  3
   2.1.  What Needs to be Changed ..................................  3
   2.2.  Data Types ................................................  5
   2.3.  Headers ...................................................  5
   2.4.  Structures ................................................  5
   3.  Socket Interface ............................................  5
   3.1.  IPv6 Address Family and Protocol Family ...................  5
   3.2.  IPv6 Address Structure ....................................  6

Gilligan, et. al.            Informational                      [Page 1]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   3.3.  Socket Address Structure for 4.3BSD-Based Systems .........  6
   3.4.  Socket Address Structure for 4.4BSD-Based Systems .........  7
   3.5.  The Socket Functions ......................................  8
   3.6.  Compatibility with IPv4 Applications ......................  9
   3.7.  Compatibility with IPv4 Nodes .............................  9
   3.8.  IPv6 Wildcard Address ..................................... 10
   3.9.  IPv6 Loopback Address ..................................... 11
   4.  Interface Identification .................................... 12
   4.1.  Name-to-Index ............................................. 13
   4.2.  Index-to-Name ............................................. 13
   4.3.  Return All Interface Names and Indexes .................... 14
   4.4.  Free Memory ............................................... 14
   5.  Socket Options .............................................. 14
   5.1.  Changing Socket Type ...................................... 15
   5.2.  Unicast Hop Limit ......................................... 16
   5.3.  Sending and Receiving Multicast Packets ................... 17
   6.  Library Functions ........................................... 19
   6.1.  Hostname-to-Address Translation ........................... 19
   6.2.  Address To Hostname Translation ........................... 22
   6.3.  Protocol-Independent Hostname and Service Name Translation  22
   6.4.  Socket Address Structure to Hostname and Service Name ..... 25
   6.5.  Address Conversion Functions .............................. 27
   6.6.  Address Testing Macros .................................... 28
   7.  Summary of New Definitions .................................. 29
   8.  Security Considerations ..................................... 31
   9.  Acknowledgments ............................................. 31
   10.  References ................................................. 31
   11.  Authors' Addresses ......................................... 32

1.  Introduction

   While IPv4 addresses are 32 bits long, IPv6 interfaces are identified
   by 128-bit addresses.  The socket interface make the size of an IP
   address quite visible to an application; virtually all TCP/IP
   applications for BSD-based systems have knowledge of the size of an
   IP address.  Those parts of the API that expose the addresses must be
   changed to accommodate the larger IPv6 address size.  IPv6 also
   introduces new features (e.g., flow label and priority), some of
   which must be made visible to applications via the API.  This memo
   defines a set of extensions to the socket interface to support the
   larger address size and new features of IPv6.

Gilligan, et. al.            Informational                      [Page 2]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

2.  Design Considerations

   There are a number of important considerations in designing changes
   to this well-worn API:

   -  The API changes should provide both source and binary
       compatibility for programs written to the original API.  That is,
       existing program binaries should continue to operate when run on
       a system supporting the new API.  In addition, existing
       applications that are re-compiled and run on a system supporting
       the new API should continue to operate.  Simply put, the API
       changes for IPv6 should not break existing programs.

   -  The changes to the API should be as small as possible in order to
       simplify the task of converting existing IPv4 applications to

   -  Where possible, applications should be able to use this API to
       interoperate with both IPv6 and IPv4 hosts.  Applications should
       not need to know which type of host they are communicating with.

   -  IPv6 addresses carried in data structures should be 64-bit
       aligned.  This is necessary in order to obtain optimum
       performance on 64-bit machine architectures.

   Because of the importance of providing IPv4 compatibility in the API,
   these extensions are explicitly designed to operate on machines that
   provide complete support for both IPv4 and IPv6.  A subset of this
   API could probably be designed for operation on systems that support
   only IPv6.  However, this is not addressed in this memo.

2.1.  What Needs to be Changed

   The socket interface API consists of a few distinct components:

    -  Core socket functions.

    -  Address data structures.

    -  Name-to-address translation functions.

    -  Address conversion functions.

    The core socket functions -- those functions that deal with such
    things as setting up and tearing down TCP connections, and sending
    and receiving UDP packets -- were designed to be transport
    independent.  Where protocol addresses are passed as function
    arguments, they are carried via opaque pointers.  A protocol-specific

Gilligan, et. al.            Informational                      [Page 3]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

    address data structure is defined for each protocol that the socket
    functions support.  Applications must cast pointers to these
    protocol-specific address structures into pointers to the generic
    "sockaddr" address structure when using the socket functions.  These
    functions need not change for IPv6, but a new IPv6-specific address
    data structure is needed.

    The "sockaddr_in" structure is the protocol-specific data structure
    for IPv4.  This data structure actually includes 8-octets of unused
    space, and it is tempting to try to use this space to adapt the
    sockaddr_in structure to IPv6.  Unfortunately, the sockaddr_in
    structure is not large enough to hold the 16-octet IPv6 address as
    well as the other information (address family and port number) that
    is needed.  So a new address data structure must be defined for IPv6.

    The name-to-address translation functions in the socket interface are
    gethostbyname() and gethostbyaddr().  These must be modified to
    support IPv6 and the semantics defined must provide 100% backward
    compatibility for all existing IPv4 applications, along with IPv6
    support for new applications.  Additionally, the POSIX 1003.g work in
    progress [4] specifies a new hostname-to-address translation function
    which is protocol independent.  This function can also be used with

    The address conversion functions -- inet_ntoa() and inet_addr() --
    convert IPv4 addresses between binary and printable form.  These
    functions are quite specific to 32-bit IPv4 addresses.  We have
    designed two analogous functions that convert both IPv4 and IPv6
    addresses, and carry an address type parameter so that they can be
    extended to other protocol families as well.

    Finally, a few miscellaneous features are needed to support IPv6.
    New interfaces are needed to support the IPv6 flow label, priority,
    and hop limit header fields.  New socket options are needed to
    control the sending and receiving of IPv6 multicast packets.

    The socket interface will be enhanced in the future to provide access
    to other IPv6 features.  These extensions are described in [5].

Gilligan, et. al.            Informational                      [Page 4]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

2.2.  Data Types

   The data types of the structure elements given in this memo are
   intended to be examples, not absolute requirements.  Whenever
   possible, POSIX 1003.1g data types are used:  u_intN_t means an
   unsigned integer of exactly N bits (e.g., u_int16_t) and u_intNm_t
   means an unsigned integer of at least N bits (e.g., u_int32m_t).  We
   also assume the argument data types from 1003.1g when possible (e.g.,
    the final argument to setsockopt() is a size_t value).  Whenever
   buffer sizes are specified, the POSIX 1003.1 size_t data type is used
   (e.g., the two length arguments to getnameinfo()).

2.3.  Headers

   When function prototypes and structures are shown we show the headers
   that must be #included to cause that item to be defined.

2.4.  Structures

   When structures are described the members shown are the ones that
   must appear in an implementation.  Additional, nonstandard members
   may also be defined by an implementation.

   The ordering shown for the members of a structure is the recommended
   ordering, given alignment considerations of multibyte members, but an
   implementation may order the members differently.

3.  Socket Interface

   This section specifies the socket interface changes for IPv6.

3.1.  IPv6 Address Family and Protocol Family

   A new address family name, AF_INET6, is defined in <sys/socket.h>.
   The AF_INET6 definition distinguishes between the original
   sockaddr_in address data structure, and the new sockaddr_in6 data

   A new protocol family name, PF_INET6, is defined in <sys/socket.h>.
   Like most of the other protocol family names, this will usually be
   defined to have the same value as the corresponding address family

       #define PF_INET6        AF_INET6

   The PF_INET6 is used in the first argument to the socket() function
   to indicate that an IPv6 socket is being created.

Gilligan, et. al.            Informational                      [Page 5]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

3.2.  IPv6 Address Structure

   A new data structure to hold a single IPv6 address is defined as

       #include <netinet/in.h>

       struct in6_addr {
           u_int8_t  s6_addr[16];      /* IPv6 address */

   This data structure contains an array of sixteen 8-bit elements,
   which make up one 128-bit IPv6 address.  The IPv6 address is stored
   in network byte order.

3.3.  Socket Address Structure for 4.3BSD-Based Systems

   In the socket interface, a different protocol-specific data structure
   is defined to carry the addresses for each protocol suite.  Each
   protocol-specific data structure is designed so it can be cast into a
   protocol-independent data structure -- the "sockaddr" structure.
   Each has a "family" field that overlays the "sa_family" of the
   sockaddr data structure.  This field identifies the type of the data

   The sockaddr_in structure is the protocol-specific address data
   structure for IPv4.  It is used to pass addresses between
   applications and the system in the socket functions.  The following
   structure is defined to carry IPv6 addresses:

       #include <netinet/in.h>

       struct sockaddr_in6 {
           u_int16m_t      sin6_family;    /* AF_INET6 */
           u_int16m_t      sin6_port;      /* transport layer port # */
           u_int32m_t      sin6_flowinfo;  /* IPv6 flow information */
           struct in6_addr sin6_addr;      /* IPv6 address */

   This structure is designed to be compatible with the sockaddr data
   structure used in the 4.3BSD release.

   The sin6_family field identifies this as a sockaddr_in6 structure.
   This field overlays the sa_family field when the buffer is cast to a
   sockaddr data structure.  The value of this field must be AF_INET6.

Gilligan, et. al.            Informational                      [Page 6]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   The sin6_port field contains the 16-bit UDP or TCP port number.  This
   field is used in the same way as the sin_port field of the
   sockaddr_in structure.  The port number is stored in network byte

   The sin6_flowinfo field is a 32-bit field that contains two pieces of
   information: the 24-bit IPv6 flow label and the 4-bit priority field.
   The contents and interpretation of this member is unspecified at this

   The sin6_addr field is a single in6_addr structure (defined in the
   previous section).  This field holds one 128-bit IPv6 address.  The
   address is stored in network byte order.

   The ordering of elements in this structure is specifically designed
   so that the sin6_addr field will be aligned on a 64-bit boundary.
   This is done for optimum performance on 64-bit architectures.

   Notice that the sockaddr_in6 structure will normally be larger than
   the generic sockaddr structure.  On many existing implementations the
   sizeof(struct sockaddr_in) equals sizeof(struct sockaddr), with both
   being 16 bytes.  Any existing code that makes this assumption needs
   to be examined carefully when converting to IPv6.

3.4.  Socket Address Structure for 4.4BSD-Based Systems

   The 4.4BSD release includes a small, but incompatible change to the
   socket interface.  The "sa_family" field of the sockaddr data
   structure was changed from a 16-bit value to an 8-bit value, and the
   space saved used to hold a length field, named "sa_len".  The
   sockaddr_in6 data structure given in the previous section cannot be
   correctly cast into the newer sockaddr data structure.  For this
   reason, the following alternative IPv6 address data structure is
   provided to be used on systems based on 4.4BSD:

       #include <netinet/in.h>

       #define SIN6_LEN

       struct sockaddr_in6 {
           u_char          sin6_len;       /* length of this struct */
           u_char          sin6_family;    /* AF_INET6 */
           u_int16m_t      sin6_port;      /* transport layer port # */
           u_int32m_t      sin6_flowinfo;  /* IPv6 flow information */
           struct in6_addr sin6_addr;      /* IPv6 address */

Gilligan, et. al.            Informational                      [Page 7]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   The only differences between this data structure and the 4.3BSD
   variant are the inclusion of the length field, and the change of the
   family field to a 8-bit data type.  The definitions of all the other
   fields are identical to the structure defined in the previous

   Systems that provide this version of the sockaddr_in6 data structure
   must also declare SIN6_LEN as a result of including the
   <netinet/in.h> header.  This macro allows applications to determine
   whether they are being built on a system that supports the 4.3BSD or
   4.4BSD variants of the data structure.

3.5.  The Socket Functions

   Applications call the socket() function to create a socket descriptor
   that represents a communication endpoint.  The arguments to the
   socket() function tell the system which protocol to use, and what
   format address structure will be used in subsequent functions.  For
   example, to create an IPv4/TCP socket, applications make the call:

       s = socket(PF_INET, SOCK_STREAM, 0);

   To create an IPv4/UDP socket, applications make the call:

       s = socket(PF_INET, SOCK_DGRAM, 0);

   Applications may create IPv6/TCP and IPv6/UDP sockets by simply using
   the constant PF_INET6 instead of PF_INET in the first argument.  For
   example, to create an IPv6/TCP socket, applications make the call:

       s = socket(PF_INET6, SOCK_STREAM, 0);

   To create an IPv6/UDP socket, applications make the call:

       s = socket(PF_INET6, SOCK_DGRAM, 0);

   Once the application has created a PF_INET6 socket, it must use the
   sockaddr_in6 address structure when passing addresses in to the
   system.  The functions that the application uses to pass addresses
   into the system are:


Gilligan, et. al.            Informational                      [Page 8]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   The system will use the sockaddr_in6 address structure to return
   addresses to applications that are using PF_INET6 sockets.  The
   functions that return an address from the system to an application


   No changes to the syntax of the socket functions are needed to
   support IPv6, since all of the "address carrying" functions use an
   opaque address pointer, and carry an address length as a function

3.6.  Compatibility with IPv4 Applications

   In order to support the large base of applications using the original
   API, system implementations must provide complete source and binary
   compatibility with the original API.  This means that systems must
   continue to support PF_INET sockets and the sockaddr_in address
   structure.  Applications must be able to create IPv4/TCP and IPv4/UDP
   sockets using the PF_INET constant in the socket() function, as
   described in the previous section.  Applications should be able to
   hold a combination of IPv4/TCP, IPv4/UDP, IPv6/TCP and IPv6/UDP
   sockets simultaneously within the same process.

   Applications using the original API should continue to operate as
   they did on systems supporting only IPv4.  That is, they should
   continue to interoperate with IPv4 nodes.

3.7.  Compatibility with IPv4 Nodes

   The API also provides a different type of compatibility: the ability
   for IPv6 applications to interoperate with IPv4 applications.  This
   feature uses the IPv4-mapped IPv6 address format defined in the IPv6
   addressing architecture specification [2].  This address format
   allows the IPv4 address of an IPv4 node to be represented as an IPv6
   address.  The IPv4 address is encoded into the low-order 32 bits of
   the IPv6 address, and the high-order 96 bits hold the fixed prefix
   0:0:0:0:0:FFFF.  IPv4-mapped addresses are written as follows:


   These addresses are often generated automatically by the
   gethostbyname() function when the specified host has only IPv4
   addresses (as described in Section 6.1).

Gilligan, et. al.            Informational                      [Page 9]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   Applications may use PF_INET6 sockets to open TCP connections to IPv4
   nodes, or send UDP packets to IPv4 nodes, by simply encoding the
   destination's IPv4 address as an IPv4-mapped IPv6 address, and
   passing that address, within a sockaddr_in6 structure, in the
   connect() or sendto() call.  When applications use PF_INET6 sockets
   to accept TCP connections from IPv4 nodes, or receive UDP packets
   from IPv4 nodes, the system returns the peer's address to the
   application in the accept(), recvfrom(), or getpeername() call using
   a sockaddr_in6 structure encoded this way.

   Few applications will likely need to know which type of node they are
   interoperating with.  However, for those applications that do need to
   know, the IN6_IS_ADDR_V4MAPPED() macro, defined in Section 6.6, is

3.8.  IPv6 Wildcard Address

   While the bind() function allows applications to select the source IP
   address of UDP packets and TCP connections, applications often want
   the system to select the source address for them.  With IPv4, one
   specifies the address as the symbolic constant INADDR_ANY (called the
   "wildcard" address) in the bind() call, or simply omits the bind()

   Since the IPv6 address type is a structure (struct in6_addr), a
   symbolic constant can be used to initialize an IPv6 address variable,
   but cannot be used in an assignment.  Therefore systems provide the
   IPv6 wildcard address in two forms.

   The first version is a global variable named "in6addr_any" that is an
   in6_addr structure.  The extern declaration for this variable is
   defined in <netinet/in.h>:

       extern const struct in6_addr in6addr_any;

Gilligan, et. al.            Informational                     [Page 10]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   Applications use in6addr_any similarly to the way they use INADDR_ANY
   in IPv4.  For example, to bind a socket to port number 23, but let
   the system select the source address, an application could use the
   following code:

       struct sockaddr_in6 sin6;
        . . .
       sin6.sin6_family = AF_INET6;
       sin6.sin6_flowinfo = 0;
       sin6.sin6_port = htons(23);
       sin6.sin6_addr = in6addr_any;  /* structure assignment */
        . . .
       if (bind(s, (struct sockaddr *) &sin6, sizeof(sin6)) == -1)
               . . .

   The other version is a symbolic constant named IN6ADDR_ANY_INIT and
   is defined in <netinet/in.h>.  This constant can be used to
   initialize an in6_addr structure:

       struct in6_addr anyaddr = IN6ADDR_ANY_INIT;

   Note that this constant can be used ONLY at declaration time.  It can
   not be used to assign a previously declared in6_addr structure.  For
   example, the following code will not work:

       /* This is the WRONG way to assign an unspecified address */
       struct sockaddr_in6 sin6;
        . . .
       sin6.sin6_addr = IN6ADDR_ANY_INIT; /* will NOT compile */

   Be aware that the IPv4 INADDR_xxx constants are all defined in host
   byte order but the IPv6 IN6ADDR_xxx constants and the IPv6
   in6addr_xxx externals are defined in network byte order.

3.9.  IPv6 Loopback Address

   Applications may need to send UDP packets to, or originate TCP
   connections to, services residing on the local node.  In IPv4, they
   can do this by using the constant IPv4 address INADDR_LOOPBACK in
   their connect(), sendto(), or sendmsg() call.

   IPv6 also provides a loopback address to contact local TCP and UDP
   services.  Like the unspecified address, the IPv6 loopback address is
   provided in two forms -- a global variable and a symbolic constant.

Gilligan, et. al.            Informational                     [Page 11]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   The global variable is an in6_addr structure named
   "in6addr_loopback."  The extern declaration for this variable is
   defined in <netinet/in.h>:

       extern const struct in6_addr in6addr_loopback;

   Applications use in6addr_loopback as they would use INADDR_LOOPBACK
   in IPv4 applications (but beware of the byte ordering difference
   mentioned at the end of the previous section).  For example, to open
   a TCP connection to the local telnet server, an application could use
   the following code:

       struct sockaddr_in6 sin6;
        . . .
       sin6.sin6_family = AF_INET6;
       sin6.sin6_flowinfo = 0;
       sin6.sin6_port = htons(23);
       sin6.sin6_addr = in6addr_loopback;  /* structure assignment */
        . . .
       if (connect(s, (struct sockaddr *) &sin6, sizeof(sin6)) == -1)
               . . .

   The symbolic constant is named IN6ADDR_LOOPBACK_INIT and is defined
   in <netinet/in.h>.  It can be used at declaration time ONLY; for

       struct in6_addr loopbackaddr = IN6ADDR_LOOPBACK_INIT;

   Like IN6ADDR_ANY_INIT, this constant cannot be used in an assignment
   to a previously declared IPv6 address variable.

4.  Interface Identification

   This API uses an interface index (a small positive integer) to
   identify the local interface on which a multicast group is joined
   (Section 5.3).  Additionally, the advanced API [5] uses these same
   interface indexes to identify the interface on which a datagram is
   received, or to specify the interface on which a datagram is to be

   Interfaces are normally known by names such as "le0", "sl1", "ppp2",
   and the like.  On Berkeley-derived implementations, when an interface
   is made known to the system, the kernel assigns a unique positive
   integer value (called the interface index) to that interface.  These
   are small positive integers that start at 1.  (Note that 0 is never
   used for an interface index.)  There may be gaps so that there is no
   current interface for a particular positive interface index.

Gilligan, et. al.            Informational                     [Page 12]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   This API defines two functions that map between an interface name and
   index, a third function that returns all the interface names and
   indexes, and a fourth function to return the dynamic memory allocated
   by the previous function.  How these functions are implemented is
   left up to the implementation.  4.4BSD implementations can implement
   these functions using the existing sysctl() function with the
   NET_RT_LIST command.  Other implementations may wish to use ioctl()
   for this purpose.

4.1.  Name-to-Index

   The first function maps an interface name into its corresponding

       #include <net/if.h>

       unsigned int  if_nametoindex(const char *ifname);

   If the specified interface does not exist, the return value is 0.

4.2.  Index-to-Name

   The second function maps an interface index into its corresponding

       #include <net/if.h>

       char  *if_indextoname(unsigned int ifindex, char *ifname);

   The ifname argument must point to a buffer of at least IFNAMSIZ bytes
   into which the interface name corresponding to the specified index is
   returned.  (IFNAMSIZ is also defined in <net/if.h> and its value
   includes a terminating null byte at the end of the interface name.)
   This pointer is also the return value of the function.  If there is
   no interface corresponding to the specified index, NULL is returned.

Gilligan, et. al.            Informational                     [Page 13]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

4.3.  Return All Interface Names and Indexes

   The final function returns an array of if_nameindex structures, one
   structure per interface.

       #include <net/if.h>

       struct if_nameindex {
         unsigned int   if_index;  /* 1, 2, ... */
         char          *if_name;   /* null terminated name: "le0", ... */

       struct if_nameindex  *if_nameindex(void);

   The end of the array of structures is indicated by a structure with
   an if_index of 0 and an if_name of NULL.  The function returns a NULL
   pointer upon an error.

   The memory used for this array of structures along with the interface
   names pointed to by the if_name members is obtained dynamically.
   This memory is freed by the next function.

4.4.  Free Memory

   The following function frees the dynamic memory that was allocated by

       #include <net/if.h>

       void  if_freenameindex(struct if_nameindex *ptr);

   The argument to this function must be a pointer that was returned by

5.  Socket Options

   A number of new socket options are defined for IPv6.  All of these
   new options are at the IPPROTO_IPV6 level.  That is, the "level"
   parameter in the getsockopt() and setsockopt() calls is IPPROTO_IPV6
   when using these options.  The constant name prefix IPV6_ is used in
   all of the new socket options.  This serves to clearly identify these
   options as applying to IPv6.

   The declaration for IPPROTO_IPV6, the new IPv6 socket options, and
   related constants defined in this section are obtained by including
   the header <netinet/in.h>.

Gilligan, et. al.            Informational                     [Page 14]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

5.1.  Changing Socket Type

   Unix allows open sockets to be passed between processes via the
   exec() call and other means.  It is a relatively common application
   practice to pass open sockets across exec() calls.  Thus it is
   possible for an application using the original API to pass an open
   PF_INET socket to an application that is expecting to receive a
   PF_INET6 socket.  Similarly, it is possible for an application using
   the extended API to pass an open PF_INET6 socket to an application
   using the original API, which would be equipped only to deal with
   PF_INET sockets.  Either of these cases could cause problems, because
   the application that is passed the open socket might not know how to
   decode the address structures returned in subsequent socket

   To remedy this problem, a new setsockopt() option is defined that
   allows an application to "convert" a PF_INET6 socket into a PF_INET
   socket and vice versa.

   An IPv6 application that is passed an open socket from an unknown
   process may use the IPV6_ADDRFORM setsockopt() option to "convert"
   the socket to PF_INET6.  Once that has been done, the system will
   return sockaddr_in6 address structures in subsequent socket

   An IPv6 application that is about to pass an open PF_INET6 socket to
   a program that is not be IPv6 capable can "downgrade" the socket to
   PF_INET before calling exec().  After that, the system will return
   sockaddr_in address structures to the application that was exec()'ed.
   Be aware that you cannot downgrade an IPv6 socket to an IPv4 socket
   unless all nonwildcard addresses already associated with the IPv6
   socket are IPv4-mapped IPv6 addresses.

   The IPV6_ADDRFORM option is valid at both the IPPROTO_IP and
   IPPROTO_IPV6 levels.  The only valid option values are PF_INET6 and
   PF_INET.  For example, to convert a PF_INET6 socket to PF_INET, a
   program would call:

       int  addrform = PF_INET;

       if (setsockopt(s, IPPROTO_IPV6, IPV6_ADDRFORM,
                      (char *) &addrform, sizeof(addrform)) == -1)
           perror("setsockopt IPV6_ADDRFORM");

Gilligan, et. al.            Informational                     [Page 15]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   An application may use IPV6_ADDRFORM with getsockopt() to learn
   whether an open socket is a PF_INET of PF_INET6 socket.  For example:

       int  addrform;
       size_t  len = sizeof(addrform);

       if (getsockopt(s, IPPROTO_IPV6, IPV6_ADDRFORM,
                      (char *) &addrform, &len) == -1)
           perror("getsockopt IPV6_ADDRFORM");
       else if (addrform == PF_INET)
           printf("This is an IPv4 socket.\n");
       else if (addrform == PF_INET6)
           printf("This is an IPv6 socket.\n");
           printf("This system is broken.\n");

5.2.  Unicast Hop Limit

   A new setsockopt() option controls the hop limit used in outgoing
   unicast IPv6 packets.  The name of this option is IPV6_UNICAST_HOPS,
   and it is used at the IPPROTO_IPV6 layer.  The following example
   illustrates how it is used:

       int  hoplimit = 10;

       if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
                      (char *) &hoplimit, sizeof(hoplimit)) == -1)
           perror("setsockopt IPV6_UNICAST_HOPS");

   When the IPV6_UNICAST_HOPS option is set with setsockopt(), the
   option value given is used as the hop limit for all subsequent
   unicast packets sent via that socket.  If the option is not set, the
   system selects a default value.  The integer hop limit value (called
   x) is interpreted as follows:

       x < -1:        return an error of EINVAL
       x == -1:       use kernel default
       0 <= x <= 255: use x
       x >= 256:      return an error of EINVAL

Gilligan, et. al.            Informational                     [Page 16]

RFC 2133            IPv6 Socket Interface Extensions          April 1997

   The IPV6_UNICAST_HOPS option may be used with getsockopt() to
   determine the hop limit value that the system will use for subsequent
   unicast packets sent via that socket.  For example:

       int  hoplimit;
       size_t  len = sizeof(hoplimit);

       if (getsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
                      (char *) &hoplimit, &len) == -1)
           perror("getsockopt IPV6_UNICAST_HOPS");
           printf("Using %d for hop limit.\n", hoplimit);

5.3.  Sending and Receiving Multicast Packets

   IPv6 applications may send UDP multicast packets by simply specifying
   an IPv6 multicast address in the address argument of the sendto()

   Three socket options at the IPPROTO_IPV6 layer control some of the
   parameters for sending multicast packets.  Set