* inet/Makefile (routines): Add inet6_opt and inet6_rth.
	* inet/Versions (libc, GLIBC_2.5): Add inet6_opt_init,
	inet6_opt_append, inet6_opt_finish, inet6_opt_set_val, inet6_opt_next,
	inet6_opt_find, inet6_opt_get_val, inet6_rth_space, inet6_rth_init,
	inet6_rth_add, inet6_rth_reverse, inet6_rth_segments,
	and inet6_rth_getaddr.
	* inet/netinet/ip6.h (struct ip6_rthdr0): Make ip6r0_addr a flexible
	array.
	* inet/netinet/in.h (struct ip6_mtuinfo): Define.
	Mark inet6_option_* interfaces as deprecated.
	Declare inet6_opt_init, inet6_opt_append, inet6_opt_finish,
	inet6_opt_set_val, inet6_opt_next, inet6_opt_find, inet6_opt_get_val,
	inet6_rth_space, inet6_rth_init, inet6_rth_add, inet6_rth_reverse,
	inet6_rth_segments, and inet6_rth_getaddr.
	* inet/inet6_opt.c: New file.
	* inet/inet6_rth.c: New file.

	* inet/netinet/icmp6.h: Pretty printing.
This commit is contained in:
Ulrich Drepper 2006-05-25 04:50:06 +00:00
parent aec6b246ee
commit 07bfff20c7
9 changed files with 580 additions and 39 deletions

View File

@ -1,5 +1,25 @@
2006-05-24 Ulrich Drepper <drepper@redhat.com>
[BZ #2693]
* inet/Makefile (routines): Add inet6_opt and inet6_rth.
* inet/Versions (libc, GLIBC_2.5): Add inet6_opt_init,
inet6_opt_append, inet6_opt_finish, inet6_opt_set_val, inet6_opt_next,
inet6_opt_find, inet6_opt_get_val, inet6_rth_space, inet6_rth_init,
inet6_rth_add, inet6_rth_reverse, inet6_rth_segments,
and inet6_rth_getaddr.
* inet/netinet/ip6.h (struct ip6_rthdr0): Make ip6r0_addr a flexible
array.
* inet/netinet/in.h (struct ip6_mtuinfo): Define.
Mark inet6_option_* interfaces as deprecated.
Declare inet6_opt_init, inet6_opt_append, inet6_opt_finish,
inet6_opt_set_val, inet6_opt_next, inet6_opt_find, inet6_opt_get_val,
inet6_rth_space, inet6_rth_init, inet6_rth_add, inet6_rth_reverse,
inet6_rth_segments, and inet6_rth_getaddr.
* inet/inet6_opt.c: New file.
* inet/inet6_rth.c: New file.
* inet/netinet/icmp6.h: Pretty printing.
[BZ #2683]
* elf/dl-addr.c (_dl_addr): Don't match undefined references.

7
NEWS
View File

@ -1,4 +1,4 @@
GNU C Library NEWS -- history of user-visible changes. 2006-05-07
GNU C Library NEWS -- history of user-visible changes. 2006-05-24
Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
See the end for copying conditions.
@ -23,11 +23,14 @@ Version 2.5
site might have problems with default behavior.
Implemented by Ulrich Drepper.
* Iterating over entire database in NIS and NIS+ can be slow. With the
* Iterating over entire database in NIS can be slow. With the
SETENT_BATCH_READ option in /etc/default/nss a system admin can decide
to trade time for memory. The entire database will be read at once.
Implemented by Ulrich Drepper.
* The interfaces introduced in RFC 3542 have been implemented by
Ulrich Drepper.
Version 2.4

View File

@ -1,4 +1,4 @@
# Copyright (C) 1991-2002, 2003, 2004 Free Software Foundation, Inc.
# Copyright (C) 1991-2002, 2003, 2004, 2006 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@ -47,7 +47,7 @@ routines := htonl htons \
getaliasent_r getaliasent getaliasname getaliasname_r \
in6_addr getnameinfo if_index ifaddrs inet6_option \
getipv4sourcefilter setipv4sourcefilter \
getsourcefilter setsourcefilter
getsourcefilter setsourcefilter inet6_opt inet6_rth
aux := check_pf ifreq

View File

@ -78,6 +78,12 @@ libc {
getipv4sourcefilter; setipv4sourcefilter;
getsourcefilter; setsourcefilter;
}
GLIBC_2.5 {
inet6_opt_init; inet6_opt_append; inet6_opt_finish; inet6_opt_set_val;
inet6_opt_next; inet6_opt_find; inet6_opt_get_val;
inet6_rth_space; inet6_rth_init; inet6_rth_add; inet6_rth_reverse;
inet6_rth_segments; inet6_rth_getaddr;
}
GLIBC_PRIVATE {
# functions used in other libraries
__internal_endnetgrent; __internal_getnetgrent_r;

278
inet/inet6_opt.c Normal file
View File

@ -0,0 +1,278 @@
/* Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2006.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
/* RFC 3542, 10.1
This function returns the number of bytes needed for the empty
extension header i.e., without any options. If EXTBUF is not NULL it
also initializes the extension header to have the correct length
field. In that case if the EXTLEN value is not a positive (i.e.,
non-zero) multiple of 8 the function fails and returns -1. */
int
inet6_opt_init (void *extbuf, socklen_t extlen)
{
if (extbuf != NULL)
{
if (extlen <= 0 || (extlen % 8) != 0)
return -1;
/* Fill in the length in units of 8 octets. */
struct ip6_hbh *extp = (struct ip6_hbh *) extbuf;
extp->ip6h_len = extlen / 8;
}
return sizeof (struct ip6_hbh);
}
static void
add_padding (uint8_t *extbuf, int offset, int npad)
{
if (npad == 1)
extbuf[offset] = IP6OPT_PAD1;
else
{
struct ip6_opt *pad_opt = (struct ip6_opt *) (extbuf + offset);
pad_opt->ip6o_type = IP6OPT_PADN;
pad_opt->ip6o_len = npad - sizeof (struct ip6_opt);
/* Clear the memory used by the padding. */
memset (pad_opt + 1, '\0', pad_opt->ip6o_len);
}
}
/* RFC 3542, 10.2
This function returns the updated total length taking into account
adding an option with length 'len' and alignment 'align'. If
EXTBUF is not NULL then, in addition to returning the length, the
function inserts any needed pad option, initializes the option
(setting the type and length fields) and returns a pointer to the
location for the option content in databufp. If the option does
not fit in the extension header buffer the function returns -1. */
int
inet6_opt_append (void *extbuf, socklen_t extlen, int offset, uint8_t type,
socklen_t len, uint8_t align, void **databufp)
{
/* Check minimum offset. */
if (offset < sizeof (struct ip6_hbh))
return -1;
/* One cannot add padding options. */
if (type == IP6OPT_PAD1 || type == IP6OPT_PADN)
return -1;
/* The option length must fit in one octet. */
if (len > 255)
return -1;
/* The alignment can only by 1, 2, 4, or 8 and must not exceed the
option length. */
if (align == 0 || align > 8 || (align & (align - 1)) != 0 || align > len)
return -1;
/* Determine the needed padding for alignment. Following the
current content of the buffer we have the is the IPv6 option type
and length, followed immediately by the data. The data has the
alignment constraints. Therefore padding must be inserted in the
form of padding options before the new option. */
int data_offset = offset + sizeof (struct ip6_opt);
int npad = (align - data_offset % align) & (align - 1);
/* Now we can check whether the buffer is large enough. */
if (data_offset + npad + len > extlen)
return -1;
if (npad != 0)
{
if (extbuf != NULL)
add_padding (extbuf, offset, npad);
offset += npad;
}
/* Now prepare the option itself. */
if (extbuf != NULL)
{
struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
opt->ip6o_type = type;
opt->ip6o_len = len;
*databufp = opt + 1;
}
return offset + sizeof (struct ip6_opt) + len;
}
/* RFC 3542, 10.3
This function returns the updated total length taking into account
the final padding of the extension header to make it a multiple of
8 bytes. If EXTBUF is not NULL the function also initializes the
option by inserting a Pad1 or PadN option of the proper length. */
int
inet6_opt_finish (void *extbuf, socklen_t extlen, int offset)
{
/* Check minimum offset. */
if (offset < sizeof (struct ip6_hbh))
return -1;
/* Required padding at the end. */
int npad = (8 - (offset & 7)) & 7;
/* Make sure the buffer is large enough. */
if (offset + npad > extlen)
return -1;
if (extbuf != NULL)
add_padding (extbuf, offset, npad);
return offset + npad;
}
/* RFC 3542, 10.4
This function inserts data items of various sizes in the data
portion of the option. VAL should point to the data to be
inserted. OFFSET specifies where in the data portion of the option
the value should be inserted; the first byte after the option type
and length is accessed by specifying an offset of zero. */
int
inet6_opt_set_val (void *databuf, int offset, void *val, socklen_t vallen)
{
memcpy ((uint8_t *) databuf + offset, val, vallen);
return offset + vallen;
}
/* RFC 3542, 10.5
This function parses received option extension headers returning
the next option. EXTBUF and EXTLEN specifies the extension header.
OFFSET should either be zero (for the first option) or the length
returned by a previous call to 'inet6_opt_next' or
'inet6_opt_find'. It specifies the position where to continue
scanning the extension buffer. */
int
inet6_opt_next (void *extbuf, socklen_t extlen, int offset, uint8_t *typep,
socklen_t *lenp, void **databufp)
{
if (offset == 0)
offset = sizeof (struct ip6_hbh);
else if (offset < sizeof (struct ip6_hbh))
return -1;
while (offset < extlen)
{
struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
if (opt->ip6o_type == IP6OPT_PAD1)
/* Single byte padding. */
++offset;
else if (opt->ip6o_type == IP6OPT_PADN)
offset += sizeof (struct ip6_opt) + opt->ip6o_len;
else
{
/* Check whether the option is valid. */
offset += sizeof (struct ip6_opt) + opt->ip6o_len;
if (offset > extlen)
return -1;
*typep = opt->ip6o_type;
*lenp = opt->ip6o_len;
*databufp = opt + 1;
return offset;
}
}
return -1;
}
/* RFC 3542, 10.6
This function is similar to the previously described
'inet6_opt_next' function, except this function lets the caller
specify the option type to be searched for, instead of always
returning the next option in the extension header. */
int
inet6_opt_find (void *extbuf, socklen_t extlen, int offset, uint8_t type,
socklen_t *lenp, void **databufp)
{
if (offset == 0)
offset = sizeof (struct ip6_hbh);
else if (offset < sizeof (struct ip6_hbh))
return -1;
while (offset < extlen)
{
struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
if (opt->ip6o_type == IP6OPT_PAD1)
{
/* Single byte padding. */
++offset;
if (type == IP6OPT_PAD1)
{
*lenp = 0;
*databufp = (uint8_t *) extbuf + offset;
return offset;
}
}
else if (opt->ip6o_type != type)
offset += sizeof (struct ip6_opt) + opt->ip6o_len;
else
{
/* Check whether the option is valid. */
offset += sizeof (struct ip6_opt) + opt->ip6o_len;
if (offset > extlen)
return -1;
*lenp = opt->ip6o_len;
*databufp = opt + 1;
return offset;
}
}
return -1;
}
/* RFC 3542, 10.7
This function extracts data items of various sizes in the data
portion of the option. */
int
inet6_opt_get_val (void *databuf, int offset, void *val, socklen_t vallen)
{
memcpy (val, (uint8_t *) databuf + offset, vallen);
return offset + vallen;
}

192
inet/inet6_rth.c Normal file
View File

@ -0,0 +1,192 @@
/* Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2006.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
/* RFC 3542, 7.1
This function returns the number of bytes required to hold a
Routing header of the specified type containing the specified
number of segments (addresses). For an IPv6 Type 0 Routing header,
the number of segments must be between 0 and 127, inclusive. */
socklen_t
inet6_rth_space (int type, int segments)
{
switch (type)
{
case IPV6_RTHDR_TYPE_0:
if (segments < 0 || segments > 127)
return 0;
return sizeof (struct ip6_rthdr0) + segments * sizeof (struct in6_addr);
}
return 0;
}
/* RFC 3542, 7.2
This function initializes the buffer pointed to by BP to contain a
Routing header of the specified type and sets ip6r_len based on the
segments parameter. */
void *
inet6_rth_init (void *bp, socklen_t bp_len, int type, int segments)
{
struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
switch (type)
{
case IPV6_RTHDR_TYPE_0:
/* Make sure the parameters are valid and the buffer is large enough. */
if (segments < 0 || segments > 127)
break;
socklen_t len = (sizeof (struct ip6_rthdr0)
+ segments * sizeof (struct in6_addr));
if (len > bp_len)
break;
/* Some implementations seem to initialize the whole memory area. */
memset (bp, '\0', len);
/* Length in units of 8 octets. */
rthdr->ip6r_len = segments * sizeof (struct in6_addr) / 8;
rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
return bp;
}
return NULL;
}
/* RFC 3542, 7.3
This function adds the IPv6 address pointed to by addr to the end of
the Routing header being constructed. */
int
inet6_rth_add (void *bp, const struct in6_addr *addr)
{
struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
switch (rthdr->ip6r_type)
{
struct ip6_rthdr0 *rthdr0;
case IPV6_RTHDR_TYPE_0:
rthdr0 = (struct ip6_rthdr0 *) rthdr;
memcpy (&rthdr0->ip6r0_addr[rthdr0->ip6r0_segleft++],
addr, sizeof (struct in6_addr));
return 0;
}
return -1;
}
/* RFC 3542, 7.4
This function takes a Routing header extension header (pointed to by
the first argument) and writes a new Routing header that sends
datagrams along the reverse of that route. The function reverses the
order of the addresses and sets the segleft member in the new Routing
header to the number of segments. */
int
inet6_rth_reverse (const void *in, void *out)
{
struct ip6_rthdr *in_rthdr = (struct ip6_rthdr *) in;
switch (in_rthdr->ip6r_type)
{
struct ip6_rthdr0 *in_rthdr0;
struct ip6_rthdr0 *out_rthdr0;
case IPV6_RTHDR_TYPE_0:
in_rthdr0 = (struct ip6_rthdr0 *) in;
out_rthdr0 = (struct ip6_rthdr0 *) out;
/* Copy header, not the addresses. The memory regions can overlap. */
memmove (out_rthdr0, in_rthdr0, sizeof (struct ip6_rthdr0));
int total = in_rthdr0->ip6r0_segleft * 8 / sizeof (struct in6_addr);
for (int i = 0; i < total / 2; ++i)
{
/* Remember, IN_RTHDR0 and OUT_RTHDR0 might overlap. */
struct in6_addr temp = in_rthdr0->ip6r0_addr[i];
out_rthdr0->ip6r0_addr[i] = in_rthdr0->ip6r0_addr[total - 1 - i];
out_rthdr0->ip6r0_addr[total - 1 - i] = temp;
}
if (total % 2 != 0 && in != out)
out_rthdr0->ip6r0_addr[total / 2] = in_rthdr0->ip6r0_addr[total / 2];
return 0;
}
return -1;
}
/* RFC 3542, 7.5
This function returns the number of segments (addresses) contained in
the Routing header described by BP. */
int
inet6_rth_segments (const void *bp)
{
struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
switch (rthdr->ip6r_type)
{
case IPV6_RTHDR_TYPE_0:
return rthdr->ip6r_len * 8 / sizeof (struct in6_addr);
}
return -1;
}
/* RFC 3542, 7.6
This function returns a pointer to the IPv6 address specified by
index (which must have a value between 0 and one less than the
value returned by 'inet6_rth_segments') in the Routing header
described by BP. */
struct in6_addr *
inet6_rth_getaddr (const void *bp, int index)
{
struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
switch (rthdr->ip6r_type)
{
struct ip6_rthdr0 *rthdr0;
case IPV6_RTHDR_TYPE_0:
rthdr0 = (struct ip6_rthdr0 *) rthdr;
if (index >= rthdr0->ip6r0_len * 8 / sizeof (struct in6_addr))
break;
return &rthdr0->ip6r0_addr[index];
}
return NULL;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1991,92,93,94,95,96,97,2000 Free Software Foundation, Inc.
/* Copyright (C) 1991-1997,2000,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -300,11 +300,11 @@ struct rr_pco_use /* use prefix part */
#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10
#if BYTE_ORDER == BIG_ENDIAN
# define ICMP6_RR_PCOUSE_DECRVLTIME 0x80000000
# define ICMP6_RR_PCOUSE_DECRPLTIME 0x40000000
# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000
# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000
#elif BYTE_ORDER == LITTLE_ENDIAN
# define ICMP6_RR_PCOUSE_DECRVLTIME 0x80
# define ICMP6_RR_PCOUSE_DECRPLTIME 0x40
# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80
# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40
#endif
struct rr_result /* router renumbering result message */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1991-2001, 2003, 2004 Free Software Foundation, Inc.
/* Copyright (C) 1991-2001, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -459,21 +459,62 @@ struct in6_pktinfo
unsigned int ipi6_ifindex; /* send/recv interface index */
};
/* IPv6 MTU information. */
struct ip6_mtuinfo
{
struct sockaddr_in6 ip6m_addr; /* dst address including zone ID */
uint32_t ip6m_mtu; /* path MTU in host byte order */
};
#ifdef __USE_GNU
/* Hop-by-Hop and Destination Options Processing. */
extern int inet6_option_space (int __nbytes) __THROW;
/* Obsolete hop-by-hop and Destination Options Processing (RFC 2292). */
extern int inet6_option_space (int __nbytes)
__THROW __attribute_deprecated__;
extern int inet6_option_init (void *__bp, struct cmsghdr **__cmsgp,
int __type) __THROW;
int __type) __THROW __attribute_deprecated__;
extern int inet6_option_append (struct cmsghdr *__cmsg,
__const uint8_t *__typep, int __multx,
int __plusy) __THROW;
int __plusy) __THROW __attribute_deprecated__;
extern uint8_t *inet6_option_alloc (struct cmsghdr *__cmsg, int __datalen,
int __multx, int __plusy) __THROW;
int __multx, int __plusy)
__THROW __attribute_deprecated__;
extern int inet6_option_next (__const struct cmsghdr *__cmsg,
uint8_t **__tptrp) __THROW;
uint8_t **__tptrp)
__THROW __attribute_deprecated__;
extern int inet6_option_find (__const struct cmsghdr *__cmsg,
uint8_t **__tptrp, int __type) __THROW;
uint8_t **__tptrp, int __type)
__THROW __attribute_deprecated__;
/* Hop-by-Hop and Destination Options Processing (RFC 3542). */
extern int inet6_opt_init (void *__extbuf, socklen_t __extlen) __THROW;
extern int inet6_opt_append (void *__extbuf, socklen_t __extlen, int __offset,
uint8_t __type, socklen_t __len, uint8_t __align,
void **__databufp) __THROW;
extern int inet6_opt_finish (void *__extbuf, socklen_t __extlen, int __offset)
__THROW;
extern int inet6_opt_set_val (void *__databuf, int __offset, void *__val,
socklen_t __vallen) __THROW;
extern int inet6_opt_next (void *__extbuf, socklen_t __extlen, int __offset,
uint8_t *__typep, socklen_t *__lenp,
void **__databufp) __THROW;
extern int inet6_opt_find (void *__extbuf, socklen_t __extlen, int __offset,
uint8_t __type, socklen_t *__lenp,
void **__databufp) __THROW;
extern int inet6_opt_get_val (void *__databuf, int __offset, void *__val,
socklen_t __vallen) __THROW;
/* Routing Header Option (RFC 3542). */
extern socklen_t inet6_rth_space (int __type, int __segments) __THROW;
extern void *inet6_rth_init (void *__bp, socklen_t __bp_len, int __type,
int __segments) __THROW;
extern int inet6_rth_add (void *__bp, __const struct in6_addr *__addr) __THROW;
extern int inet6_rth_reverse (__const void *__in, void *__out) __THROW;
extern int inet6_rth_segments (__const void *__bp) __THROW;
extern struct in6_addr *inet6_rth_getaddr (__const void *__bp, int __index)
__THROW;
/* Multicast source filter support. */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1991-1997, 2001, 2003 Free Software Foundation, Inc.
/* Copyright (C) 1991-1997, 2001, 2003, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -89,7 +89,8 @@ struct ip6_rthdr0
uint8_t ip6r0_segleft; /* segments left */
uint8_t ip6r0_reserved; /* reserved field */
uint8_t ip6r0_slmap[3]; /* strict/loose bit map */
struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */
/* followed by up to 127 struct in6_addr */
struct in6_addr ip6r0_addr[0];
};
/* Fragment header */