1 /** $MirOS: src/lib/libc/net/rthdr.c,v 1.3 2005/07/09 13:23:33 tg Exp $ */
2 /* $OpenBSD: rthdr.c,v 1.7 2005/03/25 13:24:12 otto Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.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 __RCSID("$MirOS: src/lib/libc/net/rthdr.c,v 1.3 2005/07/09 13:23:33 tg Exp $");
43
44 size_t
inet6_rthdr_space(int type,int seg)45 inet6_rthdr_space(int type, int seg)
46 {
47 switch (type) {
48 case IPV6_RTHDR_TYPE_0:
49 if (seg < 1 || seg > 23)
50 return (0);
51 return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
52 sizeof(struct ip6_rthdr0)));
53 default:
54 return (0);
55 }
56 }
57
58 struct cmsghdr *
inet6_rthdr_init(void * bp,int type)59 inet6_rthdr_init(void *bp, int type)
60 {
61 struct cmsghdr *ch = (struct cmsghdr *)bp;
62 struct ip6_rthdr *rthdr;
63
64 rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
65
66 ch->cmsg_level = IPPROTO_IPV6;
67 ch->cmsg_type = IPV6_RTHDR;
68
69 switch (type) {
70 case IPV6_RTHDR_TYPE_0:
71 ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
72 memset(rthdr, 0, sizeof(struct ip6_rthdr0));
73 rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
74 return (ch);
75 default:
76 return (NULL);
77 }
78 }
79
80 int
inet6_rthdr_add(struct cmsghdr * cmsg,const struct in6_addr * addr,u_int flags)81 inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags)
82 {
83 struct ip6_rthdr *rthdr;
84
85 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
86
87 switch (rthdr->ip6r_type) {
88 case IPV6_RTHDR_TYPE_0:
89 {
90 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
91 if (flags != IPV6_RTHDR_LOOSE)
92 return (-1);
93 if (rt0->ip6r0_segleft == 23)
94 return (-1);
95 rt0->ip6r0_segleft++;
96 memmove((caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), addr,
97 sizeof(struct in6_addr));
98 rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
99 cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
100 break;
101 }
102 default:
103 return (-1);
104 }
105
106 return (0);
107 }
108
109 int
inet6_rthdr_lasthop(struct cmsghdr * cmsg,unsigned int flags)110 inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags)
111 {
112 struct ip6_rthdr *rthdr;
113
114 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
115
116 switch (rthdr->ip6r_type) {
117 case IPV6_RTHDR_TYPE_0:
118 {
119 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
120 if (flags != IPV6_RTHDR_LOOSE)
121 return (-1);
122 if (rt0->ip6r0_segleft > 23)
123 return (-1);
124 break;
125 }
126 default:
127 return (-1);
128 }
129
130 return (0);
131 }
132
133 #if 0
134 int
135 inet6_rthdr_reverse(in, out)
136 const struct cmsghdr *in;
137 struct cmsghdr *out;
138 {
139
140 return (-1);
141 }
142 #endif
143
144 int
inet6_rthdr_segments(const struct cmsghdr * cmsg)145 inet6_rthdr_segments(const struct cmsghdr *cmsg)
146 {
147 struct ip6_rthdr *rthdr;
148
149 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
150
151 switch (rthdr->ip6r_type) {
152 case IPV6_RTHDR_TYPE_0:
153 {
154 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
155
156 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
157 return (-1);
158
159 return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
160 }
161
162 default:
163 return (-1);
164 }
165 }
166
167 struct in6_addr *
inet6_rthdr_getaddr(struct cmsghdr * cmsg,int index)168 inet6_rthdr_getaddr(struct cmsghdr *cmsg, int index)
169 {
170 struct ip6_rthdr *rthdr;
171
172 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
173
174 switch (rthdr->ip6r_type) {
175 case IPV6_RTHDR_TYPE_0:
176 {
177 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
178 int naddr;
179
180 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
181 return NULL;
182 naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
183 if (index <= 0 || naddr < index)
184 return NULL;
185 return ((struct in6_addr *)(rt0 + 1)) + index;
186 }
187
188 default:
189 return NULL;
190 }
191 }
192
193 int
inet6_rthdr_getflags(const struct cmsghdr * cmsg,int index)194 inet6_rthdr_getflags(const struct cmsghdr *cmsg, int index)
195 {
196 struct ip6_rthdr *rthdr;
197
198 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
199
200 switch (rthdr->ip6r_type) {
201 case IPV6_RTHDR_TYPE_0:
202 {
203 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
204 int naddr;
205
206 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
207 return (-1);
208 naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
209 if (index < 0 || naddr < index)
210 return (-1);
211 return IPV6_RTHDR_LOOSE;
212 }
213
214 default:
215 return (-1);
216 }
217 }
218