]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/rthdr.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / lib / libc / net / rthdr.c
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  * 
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35
36 #include <netinet/in.h>
37 #include <netinet/ip6.h>
38
39 #include <string.h>
40 #include <stdio.h>
41
42 size_t
43 inet6_rthdr_space(type, seg)
44     int type, seg;
45 {
46     switch(type) {
47      case IPV6_RTHDR_TYPE_0:
48          if (seg < 1 || seg > 23)
49              return(0);
50          return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1)
51                            + sizeof(struct ip6_rthdr0)));
52      default:
53 #ifdef DEBUG
54          fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type);
55 #endif 
56          return(0);
57     }
58 }
59
60 struct cmsghdr *
61 inet6_rthdr_init(bp, type)
62     void *bp;
63     int type;
64 {
65     register struct cmsghdr *ch = (struct cmsghdr *)bp;
66     register struct ip6_rthdr *rthdr;
67
68     rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
69
70     ch->cmsg_level = IPPROTO_IPV6;
71     ch->cmsg_type = IPV6_RTHDR;
72
73     switch(type) {
74      case IPV6_RTHDR_TYPE_0:
75          ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr));
76          bzero(rthdr, sizeof(struct ip6_rthdr0));
77          rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
78          return(ch);
79      default:
80 #ifdef DEBUG
81          fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type);
82 #endif 
83          return(NULL);
84     }
85 }
86
87 int
88 inet6_rthdr_add(cmsg, addr, flags)
89     struct cmsghdr *cmsg;
90     const struct in6_addr *addr;
91     u_int flags;
92 {
93     register struct ip6_rthdr *rthdr;
94
95     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
96
97     switch(rthdr->ip6r_type) {
98      case IPV6_RTHDR_TYPE_0:
99      {
100          struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
101          if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
102 #ifdef DEBUG
103              fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags);
104 #endif 
105              return(-1);
106          }
107          if (rt0->ip6r0_segleft == 23) {
108 #ifdef DEBUG
109              fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
110 #endif 
111              return(-1);
112          }
113          if (flags == IPV6_RTHDR_STRICT) {
114              int c, b;
115              c = rt0->ip6r0_segleft / 8;
116              b = rt0->ip6r0_segleft % 8;
117              rt0->ip6r0_slmap[c] |= (1 << (7 - b));
118          }
119          rt0->ip6r0_segleft++;
120          bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
121                sizeof(struct in6_addr));
122          rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
123          cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
124          break;
125      }
126      default:
127 #ifdef DEBUG
128          fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n",
129                  rthdr->ip6r_type);
130 #endif 
131          return(-1);
132     }
133
134     return(0);
135 }
136
137 int
138 inet6_rthdr_lasthop(cmsg, flags)
139     struct cmsghdr *cmsg;
140     unsigned int flags;
141 {
142     register struct ip6_rthdr *rthdr;
143
144     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
145
146     switch(rthdr->ip6r_type) {
147      case IPV6_RTHDR_TYPE_0:
148      {
149          struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
150          if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
151 #ifdef DEBUG
152              fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags);
153 #endif 
154              return(-1);
155          }
156          if (rt0->ip6r0_segleft > 23) {
157 #ifdef DEBUG
158              fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
159 #endif 
160              return(-1);
161          }
162          if (flags == IPV6_RTHDR_STRICT) {
163              int c, b;
164              c = rt0->ip6r0_segleft / 8;
165              b = rt0->ip6r0_segleft % 8;
166              rt0->ip6r0_slmap[c] |= (1 << (7 - b));
167          }
168          break;
169      }
170      default:
171 #ifdef DEBUG
172          fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n",
173                  rthdr->ip6r_type);
174 #endif 
175          return(-1);
176     }
177
178     return(0);
179 }
180
181 #if 0
182 int
183 inet6_rthdr_reverse(in, out)
184     const struct cmsghdr *in;
185     struct cmsghdr *out;
186 {
187 #ifdef DEBUG
188     fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
189 #endif 
190     return -1;
191 }
192 #endif
193
194 int
195 inet6_rthdr_segments(cmsg)
196     const struct cmsghdr *cmsg;
197 {
198     register struct ip6_rthdr *rthdr;
199
200     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
201
202     switch(rthdr->ip6r_type) {
203     case IPV6_RTHDR_TYPE_0:
204       {
205         struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
206
207         if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
208 #ifdef DEBUG
209             fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n",
210                 rt0->ip6r0_len);
211 #endif 
212             return -1;
213         }
214
215         return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
216       }
217
218     default:
219 #ifdef DEBUG
220         fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n",
221             rthdr->ip6r_type);
222 #endif 
223         return -1;
224     }
225 }
226
227 struct in6_addr *
228 inet6_rthdr_getaddr(cmsg, index)
229     struct cmsghdr *cmsg;
230     int index;
231 {
232     register struct ip6_rthdr *rthdr;
233
234     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
235
236     switch(rthdr->ip6r_type) {
237     case IPV6_RTHDR_TYPE_0:
238       {
239         struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
240         int naddr;
241
242         if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
243 #ifdef DEBUG
244             fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n",
245                 rt0->ip6r0_len);
246 #endif 
247             return NULL;
248         }
249         naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
250         if (index <= 0 || naddr < index) {
251 #ifdef DEBUG
252             fprintf(stderr, "inet6_rthdr_getaddr: invalid index(%d)\n", index);
253 #endif 
254             return NULL;
255         }
256         return &rt0->ip6r0_addr[index - 1];
257       }
258
259     default:
260 #ifdef DEBUG
261         fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
262             rthdr->ip6r_type);
263 #endif 
264         return NULL;
265     }
266 }
267
268 int
269 inet6_rthdr_getflags(cmsg, index)
270     const struct cmsghdr *cmsg;
271     int index;
272 {
273     register struct ip6_rthdr *rthdr;
274
275     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
276
277     switch(rthdr->ip6r_type) {
278     case IPV6_RTHDR_TYPE_0:
279       {
280         struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
281         int naddr;
282
283         if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
284 #ifdef DEBUG
285             fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n",
286                 rt0->ip6r0_len);
287 #endif 
288             return -1;
289         }
290         naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
291         if (index < 0 || naddr < index) {
292 #ifdef DEBUG
293             fprintf(stderr, "inet6_rthdr_getflags: invalid index(%d)\n", index);
294 #endif 
295             return -1;
296         }
297         if (rt0->ip6r0_slmap[index / 8] & (0x80 >> (index % 8)))
298             return IPV6_RTHDR_STRICT;
299         else
300             return IPV6_RTHDR_LOOSE;
301       }
302
303     default:
304 #ifdef DEBUG
305         fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n",
306             rthdr->ip6r_type);
307 #endif 
308         return -1;
309     }
310 }