source: rtems-libbsd/freebsd/lib/libc/net/rthdr.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

  • Property mode set to 100644
File size: 9.8 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*      $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $  */
4
5/*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD$");
36
37#include <rtems/bsd/sys/param.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40
41#include <netinet/in.h>
42#include <netinet/ip6.h>
43
44#include <string.h>
45#include <stdio.h>
46
47/*
48 * RFC2292 API
49 */
50
51size_t
52inet6_rthdr_space(type, seg)
53        int type, seg;
54{
55        switch (type) {
56        case IPV6_RTHDR_TYPE_0:
57                if (seg < 1 || seg > 23)
58                        return (0);
59#ifdef COMPAT_RFC2292
60                return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
61                    sizeof(struct ip6_rthdr0)));
62#else
63                return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
64                    sizeof(struct ip6_rthdr0)));
65#endif
66        default:
67                return (0);
68        }
69}
70
71struct cmsghdr *
72inet6_rthdr_init(bp, type)
73        void *bp;
74        int type;
75{
76        struct cmsghdr *ch = (struct cmsghdr *)bp;
77        struct ip6_rthdr *rthdr;
78
79        rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
80
81        ch->cmsg_level = IPPROTO_IPV6;
82        ch->cmsg_type = IPV6_RTHDR;
83
84        switch (type) {
85        case IPV6_RTHDR_TYPE_0:
86#ifdef COMPAT_RFC2292
87                ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
88                    sizeof(struct in6_addr));
89#else
90                ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
91#endif
92
93                bzero(rthdr, sizeof(struct ip6_rthdr0));
94                rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
95                return (ch);
96        default:
97                return (NULL);
98        }
99}
100
101/* ARGSUSED */
102int
103inet6_rthdr_add(cmsg, addr, flags)
104        struct cmsghdr *cmsg;
105        const struct in6_addr *addr;
106        u_int flags;
107{
108        struct ip6_rthdr *rthdr;
109
110        rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
111
112        switch (rthdr->ip6r_type) {
113        case IPV6_RTHDR_TYPE_0:
114        {
115                struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
116                if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
117                        return (-1);
118                if (rt0->ip6r0_segleft == 23)
119                        return (-1);
120
121#ifdef COMPAT_RFC1883           /* XXX */
122                if (flags == IPV6_RTHDR_STRICT) {
123                        int c, b;
124                        c = rt0->ip6r0_segleft / 8;
125                        b = rt0->ip6r0_segleft % 8;
126                        rt0->ip6r0_slmap[c] |= (1 << (7 - b));
127                }
128#else
129                if (flags != IPV6_RTHDR_LOOSE)
130                        return (-1);
131#endif
132                rt0->ip6r0_segleft++;
133                bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
134                    sizeof(struct in6_addr));
135                rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
136                cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
137                break;
138        }
139        default:
140                return (-1);
141        }
142
143        return (0);
144}
145
146/* ARGSUSED */
147int
148inet6_rthdr_lasthop(cmsg, flags)
149        struct cmsghdr *cmsg;
150        unsigned int flags;
151{
152        struct ip6_rthdr *rthdr;
153
154        rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
155
156        switch (rthdr->ip6r_type) {
157        case IPV6_RTHDR_TYPE_0:
158        {
159                struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
160#ifdef COMPAT_RFC1883           /* XXX */
161                if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
162                        return (-1);
163#endif /* COMPAT_RFC1883 */
164                if (rt0->ip6r0_segleft > 23)
165                        return (-1);
166#ifdef COMPAT_RFC1883           /* XXX */
167                if (flags == IPV6_RTHDR_STRICT) {
168                        int c, b;
169                        c = rt0->ip6r0_segleft / 8;
170                        b = rt0->ip6r0_segleft % 8;
171                        rt0->ip6r0_slmap[c] |= (1 << (7 - b));
172                }
173#else
174                if (flags != IPV6_RTHDR_LOOSE)
175                        return (-1);
176#endif /* COMPAT_RFC1883 */
177                break;
178        }
179        default:
180                return (-1);
181        }
182
183        return (0);
184}
185
186#if 0
187int
188inet6_rthdr_reverse(in, out)
189        const struct cmsghdr *in;
190        struct cmsghdr *out;
191{
192
193        return (-1);
194}
195#endif
196
197int
198inet6_rthdr_segments(cmsg)
199        const struct cmsghdr *cmsg;
200{
201        struct ip6_rthdr *rthdr;
202
203        rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
204
205        switch (rthdr->ip6r_type) {
206        case IPV6_RTHDR_TYPE_0:
207        {
208                struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
209
210                if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
211                        return (-1);
212
213                return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
214        }
215
216        default:
217                return (-1);
218        }
219}
220
221struct in6_addr *
222inet6_rthdr_getaddr(cmsg, idx)
223        struct cmsghdr *cmsg;
224        int idx;
225{
226        struct ip6_rthdr *rthdr;
227
228        rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
229
230        switch (rthdr->ip6r_type) {
231        case IPV6_RTHDR_TYPE_0:
232        {
233                struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
234                int naddr;
235
236                if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
237                        return NULL;
238                naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
239                if (idx <= 0 || naddr < idx)
240                        return NULL;
241#ifdef COMPAT_RFC2292
242                return (((struct in6_addr *)(rt0 + 1)) + idx - 1);
243#else
244                return (((struct in6_addr *)(rt0 + 1)) + idx);
245#endif
246        }
247
248        default:
249                return NULL;
250        }
251}
252
253int
254inet6_rthdr_getflags(cmsg, idx)
255        const struct cmsghdr *cmsg;
256        int idx;
257{
258        struct ip6_rthdr *rthdr;
259
260        rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
261
262        switch (rthdr->ip6r_type) {
263        case IPV6_RTHDR_TYPE_0:
264        {
265                struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
266                int naddr;
267
268                if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
269                        return (-1);
270                naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
271                if (idx < 0 || naddr < idx)
272                        return (-1);
273#ifdef COMPAT_RFC1883           /* XXX */
274                if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
275                        return IPV6_RTHDR_STRICT;
276                else
277                        return IPV6_RTHDR_LOOSE;
278#else
279                return IPV6_RTHDR_LOOSE;
280#endif /* COMPAT_RFC1883 */
281        }
282
283        default:
284                return (-1);
285        }
286}
287
288/*
289 * RFC3542 API
290 */
291
292socklen_t
293inet6_rth_space(int type, int segments)
294{
295        switch (type) {
296        case IPV6_RTHDR_TYPE_0:
297                if ((segments >= 0) && (segments <= 127))
298                        return (((segments * 2) + 1) << 3);
299                /* FALLTHROUGH */
300        default:
301                return (0);     /* type not suppported */
302        }
303}
304
305void *
306inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
307{
308        struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
309        struct ip6_rthdr0 *rth0;
310
311        switch (type) {
312        case IPV6_RTHDR_TYPE_0:
313                /* length validation */
314                if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
315                        return (NULL);
316                /* segment validation */
317                if ((segments < 0) || (segments > 127))
318                        return (NULL);
319
320                memset(bp, 0, bp_len);
321                rth0 = (struct ip6_rthdr0 *)rth;
322                rth0->ip6r0_len = segments * 2;
323                rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
324                rth0->ip6r0_segleft = 0;
325                rth0->ip6r0_reserved = 0;
326                break;
327        default:
328                return (NULL);  /* type not supported */
329        }
330
331        return (bp);
332}
333
334int
335inet6_rth_add(void *bp, const struct in6_addr *addr)
336{
337        struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
338        struct ip6_rthdr0 *rth0;
339        struct in6_addr *nextaddr;
340
341        switch (rth->ip6r_type) {
342        case IPV6_RTHDR_TYPE_0:
343                rth0 = (struct ip6_rthdr0 *)rth;
344                /* Don't exceed the number of stated segments */
345                if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2))
346                        return (-1);
347                nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
348                *nextaddr = *addr;
349                rth0->ip6r0_segleft++;
350                break;
351        default:
352                return (-1);    /* type not supported */
353        }
354
355        return (0);
356}
357
358int
359inet6_rth_reverse(const void *in, void *out)
360{
361        struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
362        struct ip6_rthdr0 *rth0_in, *rth0_out;
363        int i, segments;
364
365        switch (rth_in->ip6r_type) {
366        case IPV6_RTHDR_TYPE_0:
367                rth0_in = (struct ip6_rthdr0 *)in;
368                rth0_out = (struct ip6_rthdr0 *)out;
369
370                /* parameter validation XXX too paranoid? */
371                if (rth0_in->ip6r0_len % 2)
372                        return (-1);
373                segments = rth0_in->ip6r0_len / 2;
374
375                /* we can't use memcpy here, since in and out may overlap */
376                memmove((void *)rth0_out, (void *)rth0_in,
377                        ((rth0_in->ip6r0_len) + 1) << 3);
378                rth0_out->ip6r0_segleft = segments;
379
380                /* reverse the addresses */
381                for (i = 0; i < segments / 2; i++) {
382                        struct in6_addr addr_tmp, *addr1, *addr2;
383
384                        addr1 = (struct in6_addr *)(rth0_out + 1) + i;
385                        addr2 = (struct in6_addr *)(rth0_out + 1) +
386                                (segments - i - 1);
387                        addr_tmp = *addr1;
388                        *addr1 = *addr2;
389                        *addr2 = addr_tmp;
390                }
391
392                break;
393        default:
394                return (-1);    /* type not supported */
395        }
396
397        return (0);
398}
399
400int
401inet6_rth_segments(const void *bp)
402{
403        struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
404        struct ip6_rthdr0 *rh0;
405        int addrs;
406
407        switch (rh->ip6r_type) {
408        case IPV6_RTHDR_TYPE_0:
409                rh0 = (struct ip6_rthdr0 *)bp;
410
411                /*
412                 * Validation for a type-0 routing header.
413                 * Is this too strict?
414                 */
415                if ((rh0->ip6r0_len % 2) != 0 ||
416                    (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
417                        return (-1);
418
419                return (addrs);
420        default:
421                return (-1);    /* unknown type */
422        }
423}
424
425struct in6_addr *
426inet6_rth_getaddr(const void *bp, int idx)
427{
428        struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
429        struct ip6_rthdr0 *rh0;
430        int addrs;
431
432        switch (rh->ip6r_type) {
433        case IPV6_RTHDR_TYPE_0:
434                 rh0 = (struct ip6_rthdr0 *)bp;
435
436                /*
437                 * Validation for a type-0 routing header.
438                 * Is this too strict?
439                 */
440                if ((rh0->ip6r0_len % 2) != 0 ||
441                    (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
442                        return (NULL);
443
444                if (idx < 0 || addrs <= idx)
445                        return (NULL);
446
447                return (((struct in6_addr *)(rh0 + 1)) + idx);
448        default:
449                return (NULL);  /* unknown type */
450                break;
451        }
452}
Note: See TracBrowser for help on using the repository browser.