]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/in6_src.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_src.c
1 /* $KAME: in6_src.c,v 1.10 2000/03/28 09:02:23 k-sugyou Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1982, 1986, 1991, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
65 */
66
67 /* for MIP6 */
68 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
69 #include "opt_inet.h"
70 #endif
71
72 #ifdef __NetBSD__
73 #include "opt_ipsec.h"
74 #endif
75
76 #include <sys/param.h>
77 #include <sys/systm.h>
78 #include <sys/malloc.h>
79 #include <sys/mbuf.h>
80 #include <sys/protosw.h>
81 #include <sys/socket.h>
82 #include <sys/socketvar.h>
83 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
84 #include <sys/ioctl.h>
85 #endif
86 #include <sys/errno.h>
87 #include <sys/time.h>
88 #include <sys/proc.h>
89
90 #include <net/if.h>
91 #include <net/route.h>
92
93 #include <netinet/in.h>
94 #include <netinet/in_var.h>
95 #include <netinet/in_systm.h>
96 #include <netinet/ip.h>
97 #include <netinet/in_pcb.h>
98 #include <netinet6/in6_var.h>
99 #include <netinet/ip6.h>
100 #if !(defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802))
101 #include <netinet6/in6_pcb.h>
102 #endif
103 #include <netinet6/ip6_var.h>
104 #include <netinet6/nd6.h>
105
106 #include <net/net_osdep.h>
107
108 #ifndef __bsdi__
109 #include "loop.h"
110 #endif
111 #if defined(__NetBSD__) || defined(__OpenBSD__)
112 extern struct ifnet loif[NLOOP];
113 #endif
114
115 #if MIP6
116 #include <netinet6/mip6.h>
117 #include <netinet6/mip6_common.h>
118
119 extern struct nd_prefix *(*mip6_get_home_prefix_hook) __P((void));
120 #endif
121
122 /*
123 * Return an IPv6 address, which is the most appropriate for given
124 * destination and user specified options.
125 * If necessary, this function lookups the routing table and return
126 * an entry to the caller for later use.
127 */
128 struct in6_addr *
129 in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
130 struct sockaddr_in6 *dstsock;
131 struct ip6_pktopts *opts;
132 struct ip6_moptions *mopts;
133 struct route_in6 *ro;
134 struct in6_addr *laddr;
135 int *errorp;
136 {
137 struct in6_addr *dst;
138 struct in6_ifaddr *ia6 = 0;
139 struct in6_pktinfo *pi = NULL;
140
141 dst = &dstsock->sin6_addr;
142 *errorp = 0;
143
144 /*
145 * If the source address is explicitly specified by the caller,
146 * use it.
147 */
148 if (opts && (pi = opts->ip6po_pktinfo) &&
149 !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
150 return(&pi->ipi6_addr);
151
152 /*
153 * If the source address is not specified but the socket(if any)
154 * is already bound, use the bound address.
155 */
156 if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
157 return(laddr);
158
159 /*
160 * If the caller doesn't specify the source address but
161 * the outgoing interface, use an address associated with
162 * the interface.
163 */
164 if (pi && pi->ipi6_ifindex) {
165 /* XXX boundary check is assumed to be already done. */
166 ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
167 dst);
168 if (ia6 == 0) {
169 *errorp = EADDRNOTAVAIL;
170 return(0);
171 }
172 return(&satosin6(&ia6->ia_addr)->sin6_addr);
173 }
174
175 /*
176 * If the destination address is a link-local unicast address or
177 * a multicast address, and if the outgoing interface is specified
178 * by the sin6_scope_id filed, use an address associated with the
179 * interface.
180 * XXX: We're now trying to define more specific semantics of
181 * sin6_scope_id field, so this part will be rewritten in
182 * the near future.
183 */
184 if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
185 dstsock->sin6_scope_id) {
186 /*
187 * I'm not sure if boundary check for scope_id is done
188 * somewhere...
189 */
190 if (dstsock->sin6_scope_id < 0 ||
191 if_index < dstsock->sin6_scope_id) {
192 *errorp = ENXIO; /* XXX: better error? */
193 return(0);
194 }
195 ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
196 dst);
197 if (ia6 == 0) {
198 *errorp = EADDRNOTAVAIL;
199 return(0);
200 }
201 return(&satosin6(&ia6->ia_addr)->sin6_addr);
202 }
203
204 /*
205 * If the destination address is a multicast address and
206 * the outgoing interface for the address is specified
207 * by the caller, use an address associated with the interface.
208 * There is a sanity check here; if the destination has node-local
209 * scope, the outgoing interfacde should be a loopback address.
210 * Even if the outgoing interface is not specified, we also
211 * choose a loopback interface as the outgoing interface.
212 */
213 if (IN6_IS_ADDR_MULTICAST(dst)) {
214 struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
215 #ifdef __bsdi__
216 #if _BSDI_VERSION >= 199802
217 extern struct ifnet *loifp;
218 #else
219 extern struct ifnet loif;
220 struct ifnet *loifp = &loif;
221 #endif
222 #endif
223
224 if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
225 #ifdef __bsdi__
226 ifp = loifp;
227 #else
228 ifp = &loif[0];
229 #endif
230 }
231
232 if (ifp) {
233 ia6 = in6_ifawithscope(ifp, dst);
234 if (ia6 == 0) {
235 *errorp = EADDRNOTAVAIL;
236 return(0);
237 }
238 return(&satosin6(&ia6->ia_addr)->sin6_addr);
239 }
240 }
241
242 /*
243 * If the next hop address for the packet is specified
244 * by caller, use an address associated with the route
245 * to the next hop.
246 */
247 {
248 struct sockaddr_in6 *sin6_next;
249 struct rtentry *rt;
250
251 if (opts && opts->ip6po_nexthop) {
252 sin6_next = satosin6(opts->ip6po_nexthop);
253 rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
254 if (rt) {
255 ia6 = in6_ifawithscope(rt->rt_ifp, dst);
256 if (ia6 == 0)
257 ia6 = ifatoia6(rt->rt_ifa);
258 }
259 if (ia6 == 0) {
260 *errorp = EADDRNOTAVAIL;
261 return(0);
262 }
263 return(&satosin6(&ia6->ia_addr)->sin6_addr);
264 }
265 }
266
267 #if MIP6
268 /*
269 * This is needed to assure that the Home Address is used for
270 * outgoing packets when not at home. We can't choose any other
271 * address if we want to keep connections up during movement.
272 */
273 if (mip6_get_home_prefix_hook) { /* Only Mobile Node */
274 struct nd_prefix *pr;
275 if ((pr = (*mip6_get_home_prefix_hook)()) &&
276 !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) {
277 if (in6_addrscope(dst) ==
278 in6_addrscope(&pr->ndpr_addr)) {
279 #if MIP6_DEBUG
280 /* Noisy but useful */
281 mip6_debug("%s: Local address %s is chosen "
282 "for pcb to dest %s.\n",
283 __FUNCTION__,
284 ip6_sprintf(&pr->ndpr_addr),
285 ip6_sprintf(dst));
286 #endif
287 return(&pr->ndpr_addr);
288 }
289 }
290 }
291 #endif /* MIP6 */
292
293 /*
294 * If route is known or can be allocated now,
295 * our src addr is taken from the i/f, else punt.
296 */
297 if (ro) {
298 if (ro->ro_rt &&
299 !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
300 RTFREE(ro->ro_rt);
301 ro->ro_rt = (struct rtentry *)0;
302 }
303 if (ro->ro_rt == (struct rtentry *)0 ||
304 ro->ro_rt->rt_ifp == (struct ifnet *)0) {
305 /* No route yet, so try to acquire one */
306 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
307 ro->ro_dst.sin6_family = AF_INET6;
308 ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
309 ro->ro_dst.sin6_addr = *dst;
310 if (IN6_IS_ADDR_MULTICAST(dst)) {
311 #if defined( __FreeBSD__) || defined (__APPLE__)
312 ro->ro_rt = rtalloc1(&((struct route *)ro)
313 ->ro_dst, 0, 0UL);
314 #else
315 ro->ro_rt = rtalloc1(&((struct route *)ro)
316 ->ro_dst, 0);
317 #endif /*__FreeBSD__*/
318 } else {
319 #ifdef __bsdi__ /* bsdi needs rtcalloc to make a host route */
320 rtcalloc((struct route *)ro);
321 #else
322 rtalloc((struct route *)ro);
323 #endif
324 }
325 }
326
327 /*
328 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
329 * the address. But we don't know why it does so.
330 * It is necessary to ensure the scope even for lo0
331 * so doesn't check out IFF_LOOPBACK.
332 */
333
334 if (ro->ro_rt) {
335 ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
336 if (ia6 == 0) /* xxx scope error ?*/
337 ia6 = ifatoia6(ro->ro_rt->rt_ifa);
338 }
339 #if 0
340 /*
341 * xxx The followings are necessary? (kazu)
342 * I don't think so.
343 * It's for SO_DONTROUTE option in IPv4.(jinmei)
344 */
345 if (ia6 == 0) {
346 struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
347
348 sin6->sin6_addr = *dst;
349
350 ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
351 if (ia6 == 0)
352 ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
353 if (ia6 == 0)
354 return(0);
355 return(&satosin6(&ia6->ia_addr)->sin6_addr);
356 }
357 #endif /* 0 */
358 if (ia6 == 0) {
359 *errorp = EHOSTUNREACH; /* no route */
360 return(0);
361 }
362 return(&satosin6(&ia6->ia_addr)->sin6_addr);
363 }
364
365 *errorp = EADDRNOTAVAIL;
366 return(0);
367 }
368
369 /*
370 * Default hop limit selection. The precedence is as follows:
371 * 1. Hoplimit value specified via ioctl.
372 * 2. (If the outgoing interface is detected) the current
373 * hop limit of the interface specified by router advertisement.
374 * 3. The system default hoplimit.
375 */
376 #if HAVE_NRL_INPCB
377 #define in6pcb inpcb
378 #define in6p_hops inp_hops
379 #endif
380 int
381 in6_selecthlim(in6p, ifp)
382 struct in6pcb *in6p;
383 struct ifnet *ifp;
384 {
385 if (in6p && in6p->in6p_hops >= 0)
386 return(in6p->in6p_hops);
387 else if (ifp)
388 return(nd_ifinfo[ifp->if_index].chlim);
389 else
390 return(ip6_defhlim);
391 }
392 #if HAVE_NRL_INPCB
393 #undef in6pcb
394 #undef in6p_hops
395 #endif
396
397 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) && !defined(__APPLE__)
398 /*
399 * Find an empty port and set it to the specified PCB.
400 */
401 #if HAVE_NRL_INPCB /* XXX: I really hate such ugly macros...(jinmei) */
402 #define in6pcb inpcb
403 #define in6p_socket inp_socket
404 #define in6p_lport inp_lport
405 #define in6p_head inp_head
406 #define in6p_flags inp_flags
407 #define IN6PLOOKUP_WILDCARD INPLOOKUP_WILDCARD
408 #endif
409 int
410 in6_pcbsetport(laddr, in6p)
411 struct in6_addr *laddr;
412 struct in6pcb *in6p;
413 {
414 struct socket *so = in6p->in6p_socket;
415 struct in6pcb *head = in6p->in6p_head;
416 u_int16_t last_port, lport = 0;
417 int wild = 0;
418 void *t;
419 u_int16_t min, max;
420 #ifdef __NetBSD__
421 struct proc *p = curproc; /* XXX */
422 #endif
423
424 /* XXX: this is redundant when called from in6_pcbbind */
425 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
426 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
427 (so->so_options & SO_ACCEPTCONN) == 0))
428 wild = IN6PLOOKUP_WILDCARD;
429
430 if (in6p->in6p_flags & IN6P_LOWPORT) {
431 #ifdef __NetBSD__
432 if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
433 return (EACCES);
434 #else
435 if ((so->so_state & SS_PRIV) == 0)
436 return (EACCES);
437 #endif
438 min = IPV6PORT_RESERVEDMIN;
439 max = IPV6PORT_RESERVEDMAX;
440 } else {
441 min = IPV6PORT_ANONMIN;
442 max = IPV6PORT_ANONMAX;
443 }
444
445 /* value out of range */
446 if (head->in6p_lport < min)
447 head->in6p_lport = min;
448 else if (head->in6p_lport > max)
449 head->in6p_lport = min;
450 last_port = head->in6p_lport;
451 goto startover; /*to randomize*/
452 for (;;) {
453 lport = htons(head->in6p_lport);
454 if (IN6_IS_ADDR_V4MAPPED(laddr)) {
455 #if 0
456 t = in_pcblookup_bind(&tcbtable,
457 (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
458 lport);
459 #else
460 t = NULL;
461 #endif
462 } else {
463 #if HAVE_NRL_INPCB
464 /* XXX: ugly cast... */
465 t = in_pcblookup(head, (struct in_addr *)&zeroin6_addr,
466 0, (struct in_addr *)laddr,
467 lport, wild | INPLOOKUP_IPV6);
468 #else
469 t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
470 lport, wild);
471 #endif
472 }
473 if (t == 0)
474 break;
475 startover:
476 if (head->in6p_lport >= max)
477 head->in6p_lport = min;
478 else
479 head->in6p_lport++;
480 if (head->in6p_lport == last_port)
481 return (EADDRINUSE);
482 }
483
484 in6p->in6p_lport = lport;
485 return(0); /* success */
486 }
487 #if HAVE_NRL_INPCB
488 #undef in6pcb
489 #undef in6p_socket
490 #undef in6p_lport
491 #undef in6p_head
492 #undef in6p_flags
493 #undef IN6PLOOKUP_WILDCARD
494 #endif
495 #endif /* !FreeBSD3 && !OpenBSD*/