Blame inet/inet6_rth.c

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