Back to index

glibc  2.9
inet6_rth.c
Go to the documentation of this file.
00001 /* Copyright (C) 2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2006.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <string.h>
00021 #include <netinet/in.h>
00022 #include <netinet/ip6.h>
00023 
00024 
00025 /* RFC 3542, 7.1
00026 
00027    This function returns the number of bytes required to hold a
00028    Routing header of the specified type containing the specified
00029    number of segments (addresses).  For an IPv6 Type 0 Routing header,
00030    the number of segments must be between 0 and 127, inclusive.  */
00031 socklen_t
00032 inet6_rth_space (int type, int segments)
00033 {
00034   switch (type)
00035     {
00036     case IPV6_RTHDR_TYPE_0:
00037       if (segments < 0 || segments > 127)
00038        return 0;
00039 
00040       return sizeof (struct ip6_rthdr0) + segments * sizeof (struct in6_addr);
00041     }
00042 
00043   return 0;
00044 }
00045 
00046 
00047 /* RFC 3542, 7.2
00048 
00049    This function initializes the buffer pointed to by BP to contain a
00050    Routing header of the specified type and sets ip6r_len based on the
00051    segments parameter.  */
00052 void *
00053 inet6_rth_init (void *bp, socklen_t bp_len, int type, int segments)
00054 {
00055   struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
00056 
00057   switch (type)
00058     {
00059     case IPV6_RTHDR_TYPE_0:
00060       /* Make sure the parameters are valid and the buffer is large enough.  */
00061       if (segments < 0 || segments > 127)
00062        break;
00063 
00064       socklen_t len = (sizeof (struct ip6_rthdr0)
00065                      + segments * sizeof (struct in6_addr));
00066       if (len > bp_len)
00067        break;
00068 
00069       /* Some implementations seem to initialize the whole memory area.  */
00070       memset (bp, '\0', len);
00071 
00072       /* Length in units of 8 octets.  */
00073       rthdr->ip6r_len = segments * sizeof (struct in6_addr) / 8;
00074       rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
00075       return bp;
00076     }
00077 
00078   return NULL;
00079 }
00080 
00081 
00082 /* RFC 3542, 7.3
00083 
00084    This function adds the IPv6 address pointed to by addr to the end of
00085    the Routing header being constructed.  */
00086 int
00087 inet6_rth_add (void *bp, const struct in6_addr *addr)
00088 {
00089   struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
00090 
00091   switch (rthdr->ip6r_type)
00092     {
00093       struct ip6_rthdr0 *rthdr0;
00094     case IPV6_RTHDR_TYPE_0:
00095       rthdr0 = (struct ip6_rthdr0 *) rthdr;
00096 
00097       memcpy (&rthdr0->ip6r0_addr[rthdr0->ip6r0_segleft++],
00098              addr, sizeof (struct in6_addr));
00099 
00100       return 0;
00101     }
00102 
00103   return -1;
00104 }
00105 
00106 
00107 /* RFC 3542, 7.4
00108 
00109    This function takes a Routing header extension header (pointed to by
00110    the first argument) and writes a new Routing header that sends
00111    datagrams along the reverse of that route.  The function reverses the
00112    order of the addresses and sets the segleft member in the new Routing
00113    header to the number of segments.  */
00114 int
00115 inet6_rth_reverse (const void *in, void *out)
00116 {
00117   struct ip6_rthdr *in_rthdr = (struct ip6_rthdr *) in;
00118 
00119   switch (in_rthdr->ip6r_type)
00120     {
00121       struct ip6_rthdr0 *in_rthdr0;
00122       struct ip6_rthdr0 *out_rthdr0;
00123     case IPV6_RTHDR_TYPE_0:
00124       in_rthdr0 = (struct ip6_rthdr0 *) in;
00125       out_rthdr0 = (struct ip6_rthdr0 *) out;
00126 
00127       /* Copy header, not the addresses.  The memory regions can overlap.  */
00128       memmove (out_rthdr0, in_rthdr0, sizeof (struct ip6_rthdr0));
00129 
00130       int total = in_rthdr0->ip6r0_segleft * 8 / sizeof (struct in6_addr);
00131       for (int i = 0; i < total / 2; ++i)
00132        {
00133          /* Remember, IN_RTHDR0 and OUT_RTHDR0 might overlap.  */
00134          struct in6_addr temp = in_rthdr0->ip6r0_addr[i];
00135          out_rthdr0->ip6r0_addr[i] = in_rthdr0->ip6r0_addr[total - 1 - i];
00136          out_rthdr0->ip6r0_addr[total - 1 - i] = temp;
00137        }
00138       if (total % 2 != 0 && in != out)
00139        out_rthdr0->ip6r0_addr[total / 2] = in_rthdr0->ip6r0_addr[total / 2];
00140 
00141       return 0;
00142     }
00143 
00144   return -1;
00145 }
00146 
00147 
00148 /* RFC 3542, 7.5
00149 
00150    This function returns the number of segments (addresses) contained in
00151    the Routing header described by BP.  */
00152 int
00153 inet6_rth_segments (const void *bp)
00154 {
00155   struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
00156 
00157   switch (rthdr->ip6r_type)
00158     {
00159     case IPV6_RTHDR_TYPE_0:
00160 
00161       return rthdr->ip6r_len * 8 / sizeof (struct in6_addr);
00162     }
00163 
00164   return -1;
00165 }
00166 
00167 
00168 /* RFC 3542, 7.6
00169 
00170    This function returns a pointer to the IPv6 address specified by
00171    index (which must have a value between 0 and one less than the
00172    value returned by 'inet6_rth_segments') in the Routing header
00173    described by BP.  */
00174 struct in6_addr *
00175 inet6_rth_getaddr (const void *bp, int index)
00176 {
00177   struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
00178 
00179   switch (rthdr->ip6r_type)
00180     {
00181        struct ip6_rthdr0 *rthdr0;
00182     case IPV6_RTHDR_TYPE_0:
00183       rthdr0 = (struct ip6_rthdr0 *) rthdr;
00184 
00185       if (index >= rthdr0->ip6r0_len * 8 / sizeof (struct in6_addr))
00186        break;
00187 
00188       return &rthdr0->ip6r0_addr[index];
00189     }
00190 
00191   return NULL;
00192 }