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