OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [newlib/] [libc/] [sys/] [linux/] [net/] [inet6_option.c] - Blame information for rev 207

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* Copyright (C) 2003 Free Software Foundation, Inc.
2
   This file is part of the GNU C Library.
3
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
4
 
5
   The GNU C Library is free software; you can redistribute it and/or
6
   modify it under the terms of the GNU Lesser General Public
7
   License as published by the Free Software Foundation; either
8
   version 2.1 of the License, or (at your option) any later version.
9
 
10
   The GNU C Library is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
   Lesser General Public License for more details.
14
 
15
   You should have received a copy of the GNU Lesser General Public
16
   License along with the GNU C Library; if not, write to the Free
17
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18
   02111-1307 USA.  */
19
 
20
#include <assert.h>
21
#include <string.h>
22
#include <netinet/in.h>
23
#include <netinet/ip6.h>
24
#include <sys/param.h>
25
#include <sys/socket.h>
26
#include "libc-symbols.h"
27
 
28
#define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
29
 
30
static void
31
internal_function
32
add_pad (struct cmsghdr *cmsg, int len)
33
{
34
  unsigned char *p = CMSG_DATA (cmsg) + cmsg->cmsg_len - CMSG_LEN (0);
35
 
36
  if (len == 1)
37
    /* Special handling for 1, a one-byte solution.  */
38
    *p++ = IP6OPT_PAD1;
39
  else if (len != 0)
40
    {
41
      /* Multibyte padding.  */
42
      *p++ = IP6OPT_PADN;
43
      *p++ = len - 2;   /* Discount the two header bytes.  */
44
      /* The rest is filled with zero.  */
45
      memset (p, '\0', len - 2);
46
      p += len - 2;
47
    }
48
 
49
  /* Account for the bytes.  */
50
  cmsg->cmsg_len += len;
51
}
52
 
53
 
54
static int
55
get_opt_end (const uint8_t **result, const uint8_t *startp,
56
             const uint8_t *endp)
57
{
58
  if (startp >= endp)
59
    /* Out of bounds.  */
60
    return -1;
61
 
62
  if (*startp == IP6OPT_PAD1)
63
    {
64
      /* Just this one byte.  */
65
      *result = startp + 1;
66
      return 0;
67
    }
68
 
69
  /* Now we know there must be at least two bytes.  */
70
  if (startp + 2 > endp
71
      /* Now we can get the length byte.  */
72
      || startp + startp[1] + 2 > endp)
73
    return -1;
74
 
75
  *result = startp + startp[1] + 2;
76
 
77
  return 0;
78
}
79
 
80
 
81
/* RFC 2292, 6.3.1
82
 
83
   This function returns the number of bytes required to hold an option
84
   when it is stored as ancillary data, including the cmsghdr structure
85
   at the beginning, and any padding at the end (to make its size a
86
   multiple of 8 bytes).  The argument is the size of the structure
87
   defining the option, which must include any pad bytes at the
88
   beginning (the value y in the alignment term "xn + y"), the type
89
   byte, the length byte, and the option data.  */
90
int
91
inet6_option_space (nbytes)
92
     int nbytes;
93
{
94
  /* Add room for the extension header.  */
95
  nbytes += sizeof (struct ip6_ext);
96
 
97
  return CMSG_SPACE (roundup (nbytes, 8));
98
}
99
 
100
 
101
/* RFC 2292, 6.3.2
102
 
103
   This function is called once per ancillary data object that will
104
   contain either Hop-by-Hop or Destination options.  It returns 0 on
105
   success or -1 on an error.  */
106
int
107
inet6_option_init (bp, cmsgp, type)
108
     void *bp;
109
     struct cmsghdr **cmsgp;
110
     int type;
111
{
112
  /* Only Hop-by-Hop or Destination options allowed.  */
113
  if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
114
    return -1;
115
 
116
  /* BP is a pointer to the previously allocated space.  */
117
  struct cmsghdr *newp = (struct cmsghdr *) bp;
118
 
119
  /* Initialize the message header.
120
 
121
     Length: No data yet, only the cmsghdr struct.  */
122
  newp->cmsg_len = CMSG_LEN (0);
123
  /* Originating protocol: obviously IPv6.  */
124
  newp->cmsg_level = IPPROTO_IPV6;
125
  /* Message type.  */
126
  newp->cmsg_type = type;
127
 
128
  /* Pass up the result.  */
129
  *cmsgp = newp;
130
 
131
  return 0;
132
}
133
 
134
 
135
/* RFC 2292, 6.3.3
136
 
137
   This function appends a Hop-by-Hop option or a Destination option
138
   into an ancillary data object that has been initialized by
139
   inet6_option_init().  This function returns 0 if it succeeds or -1 on
140
   an error.  */
141
int
142
inet6_option_append (cmsg, typep, multx, plusy)
143
     struct cmsghdr *cmsg;
144
     const uint8_t *typep;
145
     int multx;
146
     int plusy;
147
{
148
  /* typep is a pointer to the 8-bit option type.  It is assumed that this
149
     field is immediately followed by the 8-bit option data length field,
150
     which is then followed immediately by the option data.
151
 
152
     The option types IP6OPT_PAD1 and IP6OPT_PADN also must be handled.  */
153
  int len = typep[0] == IP6OPT_PAD1 ? 1 : typep[1] + 2;
154
 
155
  /* Get the pointer to the space in the message.  */
156
  uint8_t *ptr = inet6_option_alloc (cmsg, len, multx, plusy);
157
  if (ptr == NULL)
158
    /* Some problem with the parameters.  */
159
    return -1;
160
 
161
  /* Copy the content.  */
162
  memcpy (ptr, typep, len);
163
 
164
  return 0;
165
}
166
 
167
 
168
/* RFC 2292, 6.3.4
169
 
170
   This function appends a Hop-by-Hop option or a Destination option
171
   into an ancillary data object that has been initialized by
172
   inet6_option_init().  This function returns a pointer to the 8-bit
173
   option type field that starts the option on success, or NULL on an
174
   error.  */
175
uint8_t *
176
inet6_option_alloc (cmsg, datalen, multx, plusy)
177
     struct cmsghdr *cmsg;
178
     int datalen;
179
     int multx;
180
     int plusy;
181
{
182
  /* The RFC limits the value of the alignment values.  */
183
  if ((multx != 1 && multx != 2 && multx != 4 && multx != 8)
184
      || ! (plusy >= 0 && plusy <= 7))
185
    return NULL;
186
 
187
  /* Current data size.  */
188
  int dsize = cmsg->cmsg_len - CMSG_LEN (0);
189
 
190
  /* The first two bytes of the option are for the extended header.  */
191
  if (__builtin_expect (dsize == 0, 0))
192
    {
193
      cmsg->cmsg_len += sizeof (struct ip6_ext);
194
      dsize = sizeof (struct ip6_ext);
195
    }
196
 
197
  /* First add padding.  */
198
  add_pad (cmsg, ((multx - (dsize & (multx - 1))) & (multx - 1)) + plusy);
199
 
200
  /* Return the pointer to the start of the option space.  */
201
  uint8_t *result = CMSG_DATA (cmsg) + cmsg->cmsg_len - CMSG_LEN (0);
202
  cmsg->cmsg_len += datalen;
203
 
204
  /* The extended option header length is measured in 8-byte groups.
205
     To represent the current length we might have to add padding.  */
206
  dsize = cmsg->cmsg_len - CMSG_LEN (0);
207
  add_pad (cmsg, (8 - (dsize & (8 - 1))) & (8 - 1));
208
 
209
  /* Record the new length of the option.  */
210
  assert (((cmsg->cmsg_len - CMSG_LEN (0)) % 8) == 0);
211
  int len8b = (cmsg->cmsg_len - CMSG_LEN (0)) / 8 - 1;
212
  if (len8b >= 256)
213
    /* Too long.  */
214
    return NULL;
215
 
216
  ((struct ip6_ext *) CMSG_DATA (cmsg))->ip6e_len = len8b;
217
 
218
  return result;
219
}
220
libc_hidden_def (inet6_option_alloc)
221
 
222
 
223
/* RFC 2292, 6.3.5
224
 
225
   This function processes the next Hop-by-Hop option or Destination
226
   option in an ancillary data object.  If another option remains to be
227
   processed, the return value of the function is 0 and *tptrp points to
228
   the 8-bit option type field (which is followed by the 8-bit option
229
   data length, followed by the option data).  If no more options remain
230
   to be processed, the return value is -1 and *tptrp is NULL.  If an
231
   error occurs, the return value is -1 and *tptrp is not NULL.  */
232
int
233
inet6_option_next (cmsg, tptrp)
234
     const struct cmsghdr *cmsg;
235
     uint8_t **tptrp;
236
{
237
  /* Make sure it is an option of the right type.  */
238
  if (cmsg->cmsg_level != IPPROTO_IPV6
239
      || (cmsg->cmsg_type != IPV6_HOPOPTS && cmsg->cmsg_type != IPV6_DSTOPTS))
240
    return -1;
241
 
242
  /* Pointer to the extension header.  We only compute the address, we
243
     don't access anything yet.  */
244
  const struct ip6_ext *ip6e = (const struct ip6_ext *) CMSG_DATA (cmsg);
245
 
246
  /* Make sure the message is long enough.  */
247
  if (cmsg->cmsg_len < CMSG_LEN (sizeof (struct ip6_ext))
248
      /* Now we can access the extension header.  */
249
      || cmsg->cmsg_len < CMSG_LEN ((ip6e->ip6e_len + 1) * 8))
250
    /* Too small.  */
251
    return -1;
252
 
253
  /* Determine the address of the byte past the message.  */
254
  const uint8_t *endp = CMSG_DATA (cmsg) + (ip6e->ip6e_len + 1) * 8;
255
 
256
  const uint8_t *result;
257
  if (tptrp == NULL)
258
    /* This is the first call, return the first option if there is one.  */
259
    result = (const uint8_t *) (ip6e + 1);
260
  else
261
    {
262
      /* Make sure *TPTRP points to a beginning of a new option in
263
         the message.  The upper limit is checked in get_opt_end.  */
264
      if (*tptrp < (const uint8_t *) (ip6e + 1))
265
        return -1;
266
 
267
      /* Get the beginning of the next option.  */
268
      if (get_opt_end (&result, *tptrp, endp) != 0)
269
        return -1;
270
    }
271
 
272
  /* We know where the next option starts.  */
273
  *tptrp = (uint8_t *) result;
274
 
275
  /* Check the option is fully represented in the message.  */
276
  return get_opt_end (&result, result, endp);
277
}
278
 
279
 
280
/* RFC 2292, 6.3.6
281
 
282
   This function is similar to the previously described
283
   inet6_option_next() function, except this function lets the caller
284
   specify the option type to be searched for, instead of always
285
   returning the next option in the ancillary data object.  cmsg is a
286
   pointer to cmsghdr structure of which cmsg_level equals IPPROTO_IPV6
287
   and cmsg_type equals either IPV6_HOPOPTS or IPV6_DSTOPTS.  */
288
int
289
inet6_option_find (cmsg, tptrp, type)
290
     const struct cmsghdr *cmsg;
291
     uint8_t **tptrp;
292
     int type;
293
{
294
  /* Make sure it is an option of the right type.  */
295
  if (cmsg->cmsg_level != IPPROTO_IPV6
296
      || (cmsg->cmsg_type != IPV6_HOPOPTS && cmsg->cmsg_type != IPV6_DSTOPTS))
297
    return -1;
298
 
299
  /* Pointer to the extension header.  We only compute the address, we
300
     don't access anything yet.  */
301
  const struct ip6_ext *ip6e = (const struct ip6_ext *) CMSG_DATA (cmsg);
302
 
303
  /* Make sure the message is long enough.  */
304
  if (cmsg->cmsg_len < CMSG_LEN (sizeof (struct ip6_ext))
305
      /* Now we can access the extension header.  */
306
      || cmsg->cmsg_len < CMSG_LEN ((ip6e->ip6e_len + 1) * 8))
307
    /* Too small.  */
308
    return -1;
309
 
310
  /* Determine the address of the byte past the message.  */
311
  const uint8_t *endp = CMSG_DATA (cmsg) + (ip6e->ip6e_len + 1) * 8;
312
 
313
  const uint8_t *next;
314
  if (tptrp == NULL)
315
    /* This is the first call, return the first option if there is one.  */
316
    next = (const uint8_t *) (ip6e + 1);
317
  else
318
    {
319
      /* Make sure *TPTRP points to a beginning of a new option in
320
         the message.  The upper limit is checked in get_opt_end.  */
321
      if (*tptrp < (const uint8_t *) (ip6e + 1))
322
        return -1;
323
 
324
      /* Get the beginning of the next option.  */
325
      if (get_opt_end (&next, *tptrp, endp) != 0)
326
        return -1;
327
    }
328
 
329
  /* Now search for the appropriate typed entry.  */
330
  const uint8_t *result;
331
  do
332
    {
333
      result = next;
334
 
335
      /* Get the end of this entry.  */
336
      if (get_opt_end (&next, result, endp) != 0)
337
        return -1;
338
    }
339
  while (*result != type);
340
 
341
  /* We know where the next option starts.  */
342
  *tptrp = (uint8_t *) result;
343
 
344
  /* Success.  */
345
  return 0;
346
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.