in6_pcb.c revision 1.7 1 /* $NetBSD: in6_pcb.c,v 1.7 1999/07/09 22:57:27 thorpej 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 #include "opt_ipsec.h"
68
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/malloc.h>
72 #include <sys/mbuf.h>
73 #include <sys/protosw.h>
74 #include <sys/socket.h>
75 #include <sys/socketvar.h>
76 #include <sys/ioctl.h>
77 #include <sys/errno.h>
78 #include <sys/time.h>
79 #include <sys/proc.h>
80
81 #include <net/if.h>
82 #include <net/route.h>
83
84 #include <netinet/in.h>
85 #include <netinet/in_var.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/ip.h>
88 #include <netinet/in_pcb.h>
89 #include <netinet6/ip6.h>
90 #include <netinet6/in6_pcb.h>
91 #include <netinet6/ip6_var.h>
92 #include <netinet6/nd6.h>
93
94 #include "loop.h"
95 #ifdef __NetBSD__
96 extern struct ifnet loif[NLOOP];
97 #endif
98
99 #ifdef IPSEC
100 #include <netinet6/ipsec.h>
101 #include <netkey/key.h>
102 #include <netkey/key_debug.h>
103 #endif /* IPSEC */
104
105 struct in6_addr zeroin6_addr;
106
107 int
108 in6_pcballoc(so, head)
109 struct socket *so;
110 struct in6pcb *head;
111 {
112 struct in6pcb *in6p;
113
114 MALLOC(in6p, struct in6pcb *, sizeof(*in6p), M_PCB, M_NOWAIT);
115 if (in6p == NULL)
116 return(ENOBUFS);
117 bzero((caddr_t)in6p, sizeof(*in6p));
118 in6p->in6p_head = head;
119 in6p->in6p_socket = so;
120 in6p->in6p_hops = -1; /* use kernel default */
121 in6p->in6p_icmp6filt = NULL;
122 #if 0
123 insque(in6p, head);
124 #else
125 in6p->in6p_next = head->in6p_next;
126 head->in6p_next = in6p;
127 in6p->in6p_prev = head;
128 in6p->in6p_next->in6p_prev = in6p;
129 #endif
130 so->so_pcb = (caddr_t)in6p;
131 return(0);
132 }
133
134 int
135 in6_pcbbind(in6p, nam)
136 register struct in6pcb *in6p;
137 struct mbuf *nam;
138 {
139 struct socket *so = in6p->in6p_socket;
140 struct in6pcb *head = in6p->in6p_head;
141 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
142 struct proc *p = curproc; /* XXX */
143 u_short lport = 0;
144 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
145 int error;
146
147 if (in6p->in6p_lport || !IN6_IS_ADDR_ANY(&in6p->in6p_laddr))
148 return(EINVAL);
149 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
150 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
151 (so->so_options & SO_ACCEPTCONN) == 0))
152 wild = IN6PLOOKUP_WILDCARD;
153 if (nam) {
154 sin6 = mtod(nam, struct sockaddr_in6 *);
155 if (nam->m_len != sizeof(*sin6))
156 return(EINVAL);
157 /*
158 * We should check the family, but old programs
159 * incorrectly fail to intialize it.
160 */
161 if (sin6->sin6_family != AF_INET6)
162 return(EAFNOSUPPORT);
163
164 /*
165 * If the scope of the destination is link-local, embed the
166 * interface index in the address.
167 */
168 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
169 /* XXX boundary check is assumed to be already done. */
170 /* XXX sin6_scope_id is weaker than advanced-api. */
171 struct in6_pktinfo *pi;
172 if (in6p->in6p_outputopts &&
173 (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
174 pi->ipi6_ifindex) {
175 sin6->sin6_addr.s6_addr16[1]
176 = htons(pi->ipi6_ifindex);
177 } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)
178 && in6p->in6p_moptions
179 && in6p->in6p_moptions->im6o_multicast_ifp) {
180 sin6->sin6_addr.s6_addr16[1] =
181 htons(in6p->in6p_moptions->im6o_multicast_ifp->if_index);
182 } else if (sin6->sin6_scope_id) {
183 /* boundary check */
184 if (sin6->sin6_scope_id < 0
185 || if_index < sin6->sin6_scope_id) {
186 return ENXIO; /* XXX EINVAL? */
187 }
188 sin6->sin6_addr.s6_addr16[1]
189 = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
190 /* this must be cleared for ifa_ifwithaddr() */
191 sin6->sin6_scope_id = 0;
192 }
193 }
194
195 lport = sin6->sin6_port;
196 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
197 /*
198 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
199 * allow compepte duplication of binding if
200 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
201 * and a multicast address is bound on both
202 * new and duplicated sockets.
203 */
204 if (so->so_options & SO_REUSEADDR)
205 reuseport = SO_REUSEADDR|SO_REUSEPORT;
206 } else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
207 struct sockaddr_in sin;
208
209 bzero(&sin, sizeof(sin));
210 sin.sin_len = sizeof(sin);
211 sin.sin_family = AF_INET;
212 bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
213 sizeof(sin.sin_addr));
214 if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0)
215 return EADDRNOTAVAIL;
216 } else if (!IN6_IS_ADDR_ANY(&sin6->sin6_addr)) {
217 struct ifaddr *ia = NULL;
218
219 sin6->sin6_port = 0; /* yech... */
220 if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
221 return(EADDRNOTAVAIL);
222
223 /*
224 * XXX: bind to an anycast address might accidentally
225 * cause sending a packet with anycast source address.
226 */
227 if (ia &&
228 ((struct in6_ifaddr *)ia)->ia6_flags &
229 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
230 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
231 return(EADDRNOTAVAIL);
232 }
233 }
234 if (lport) {
235 /* GROSS */
236 if (ntohs(lport) < IPV6PORT_RESERVED &&
237 (error = suser(p->p_ucred, &p->p_acflag)))
238 return(EACCES);
239
240 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
241 /* should check this but we can't ... */
242 #if 0
243 struct inpcb *t;
244
245 t = in_pcblookup_bind(&tcbtable,
246 (struct in_addr *)&sin6->sin6_addr.s6_addr32[3],
247 lport);
248 if (t && (reuseport & t->inp_socket->so_options) == 0)
249 return EADDRINUSE;
250 #endif
251 } else {
252 struct in6pcb *t;
253
254 t = in6_pcblookup(head, &zeroin6_addr, 0,
255 &sin6->sin6_addr, lport, wild);
256 if (t && (reuseport & t->in6p_socket->so_options) == 0)
257 return(EADDRINUSE);
258 }
259 }
260 in6p->in6p_laddr = sin6->sin6_addr;
261 }
262 if (lport == 0) {
263 u_short last_port;
264 void *t;
265
266 /* XXX IN6P_LOWPORT */
267
268 /* value out of range */
269 if (head->in6p_lport < IPV6PORT_ANONMIN)
270 head->in6p_lport = IPV6PORT_ANONMIN;
271 else if (head->in6p_lport > IPV6PORT_ANONMAX)
272 head->in6p_lport = IPV6PORT_ANONMIN;
273 last_port = head->in6p_lport;
274 goto startover; /*to randomize*/
275 for (;;) {
276 lport = htons(head->in6p_lport);
277 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) {
278 #if 0
279 t = in_pcblookup_bind(&tcbtable,
280 (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
281 lport);
282 #else
283 t = NULL;
284 #endif
285 } else {
286 t = in6_pcblookup(head, &zeroin6_addr, 0,
287 &in6p->in6p_laddr, lport, wild);
288 }
289 if (t == 0)
290 break;
291 startover:
292 if (head->in6p_lport >= IPV6PORT_ANONMAX)
293 head->in6p_lport = IPV6PORT_ANONMIN;
294 else
295 head->in6p_lport++;
296 if (head->in6p_lport == last_port)
297 return (EADDRINUSE);
298 }
299 }
300 in6p->in6p_lport = lport;
301 in6p->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/
302 return(0);
303 }
304
305 /*
306 * Connect from a socket to a specified address.
307 * Both address and port must be specified in argument sin6.
308 * If don't have a local address for this socket yet,
309 * then pick one.
310 */
311 int
312 in6_pcbconnect(in6p, nam)
313 struct in6pcb *in6p;
314 struct mbuf *nam;
315 {
316 struct in6_addr *in6a = NULL;
317 struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
318 struct in6_pktinfo *pi;
319 struct ifnet *ifp = NULL; /* outgoing interface */
320 int error = 0;
321 struct in6_addr mapped;
322
323 (void)&in6a; /* XXX fool gcc */
324
325 if (nam->m_len != sizeof(*sin6))
326 return(EINVAL);
327 if (sin6->sin6_family != AF_INET6)
328 return(EAFNOSUPPORT);
329 if (sin6->sin6_port == 0)
330 return(EADDRNOTAVAIL);
331
332 /* sanity check for mapped address case */
333 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
334 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
335 in6p->in6p_laddr.s6_addr16[5] = htons(0xffff);
336 if (!IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
337 return EINVAL;
338 } else {
339 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
340 return EINVAL;
341 }
342
343 /*
344 * If the scope of the destination is link-local, embed the interface
345 * index in the address.
346 */
347 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
348 /* XXX boundary check is assumed to be already done. */
349 /* XXX sin6_scope_id is weaker than advanced-api. */
350 if (in6p->in6p_outputopts &&
351 (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
352 pi->ipi6_ifindex) {
353 sin6->sin6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex);
354 ifp = ifindex2ifnet[pi->ipi6_ifindex];
355 }
356 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) &&
357 in6p->in6p_moptions &&
358 in6p->in6p_moptions->im6o_multicast_ifp) {
359 sin6->sin6_addr.s6_addr16[1] =
360 htons(in6p->in6p_moptions->im6o_multicast_ifp->if_index);
361 ifp = ifindex2ifnet[in6p->in6p_moptions->im6o_multicast_ifp->if_index];
362 } else if (sin6->sin6_scope_id) {
363 /* boundary check */
364 if (sin6->sin6_scope_id < 0
365 || if_index < sin6->sin6_scope_id) {
366 return ENXIO; /* XXX EINVAL? */
367 }
368 sin6->sin6_addr.s6_addr16[1]
369 = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
370 ifp = ifindex2ifnet[sin6->sin6_scope_id];
371 }
372 }
373
374 /* Source address selection. */
375 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
376 && in6p->in6p_laddr.s6_addr32[3] == 0) {
377 struct sockaddr_in sin, *sinp;
378
379 bzero(&sin, sizeof(sin));
380 sin.sin_len = sizeof(sin);
381 sin.sin_family = AF_INET;
382 bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
383 sizeof(sin.sin_addr));
384 sinp = in_selectsrc(&sin, (struct route *)&in6p->in6p_route,
385 in6p->in6p_socket->so_options, NULL, &error);
386 if (sinp == 0) {
387 if (error == 0)
388 error = EADDRNOTAVAIL;
389 return(error);
390 }
391 bzero(&mapped, sizeof(mapped));
392 mapped.s6_addr16[5] = htons(0xffff);
393 bcopy(&sinp->sin_addr, &mapped.s6_addr32[3], sizeof(sinp->sin_addr));
394 in6a = &mapped;
395 } else if (IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) {
396 in6a = in6_selectsrc(sin6, in6p->in6p_outputopts,
397 in6p->in6p_moptions, &in6p->in6p_route,
398 &error);
399 if (in6a == 0) {
400 if (error == 0)
401 error = EADDRNOTAVAIL;
402 return(error);
403 }
404 }
405 if (in6p->in6p_route.ro_rt)
406 ifp = in6p->in6p_route.ro_rt->rt_ifp;
407
408 /*
409 * Default hop limit selection. If a hoplimit was specified via ioctl,
410 * use it. Else if the outgoing interface is detected and the current
411 * hop limit of the interface was specified by router advertisement,
412 * use the value.
413 * Otherwise, use the system default hoplimit.
414 */
415 if (in6p->in6p_hops >= 0)
416 in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6p->in6p_hops;
417 else if (ifp)
418 in6p->in6p_ip6.ip6_hlim = nd_ifinfo[ifp->if_index].chlim;
419 else
420 in6p->in6p_ip6.ip6_hlim = ip6_defhlim;
421
422 if (in6_pcblookup(in6p->in6p_head,
423 &sin6->sin6_addr,
424 sin6->sin6_port,
425 IN6_IS_ADDR_ANY(&in6p->in6p_laddr) ?
426 in6a : &in6p->in6p_laddr,
427 in6p->in6p_lport,
428 0))
429 return(EADDRINUSE);
430 if (IN6_IS_ADDR_ANY(&in6p->in6p_laddr)
431 || (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
432 && in6p->in6p_laddr.s6_addr32[3] == 0)) {
433 if (in6p->in6p_lport == 0)
434 (void)in6_pcbbind(in6p, (struct mbuf *)0);
435 in6p->in6p_laddr = *in6a;
436 }
437 in6p->in6p_faddr = sin6->sin6_addr;
438 in6p->in6p_fport = sin6->sin6_port;
439 /*
440 * xxx kazu flowlabel is necessary for connect?
441 * but if this line is missing, the garbage value remains.
442 */
443 in6p->in6p_flowinfo = sin6->sin6_flowinfo;
444 return(0);
445 }
446
447 /*
448 * Return an IPv6 address, which is the most appropriate for given
449 * destination and user specified options.
450 * If necessary, this function lookups the routing table and return
451 * an entry to the caller for later use.
452 */
453 struct in6_addr *
454 in6_selectsrc(dstsock, opts, mopts, ro, errorp)
455 struct sockaddr_in6 *dstsock;
456 struct ip6_pktopts *opts;
457 struct ip6_moptions *mopts;
458 struct route_in6 *ro;
459 int *errorp;
460 {
461 struct in6_addr *dst;
462 struct in6_ifaddr *ia6 = 0;
463 struct in6_pktinfo *pi;
464
465 dst = &dstsock->sin6_addr;
466 *errorp = 0;
467
468 /*
469 * If the source address is explicitly specified by the caller,
470 * use it.
471 * If the caller doesn't specify the source address but
472 * the outgoing interface, use an address associated with
473 * the interface.
474 */
475 if (opts && (pi = opts->ip6po_pktinfo)) {
476 if (!IN6_IS_ADDR_ANY(&pi->ipi6_addr))
477 return(&pi->ipi6_addr);
478 else if (pi->ipi6_ifindex) {
479 /* XXX boundary check is assumed to be already done. */
480 ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
481 dst);
482 if (ia6 == 0) {
483 *errorp = EADDRNOTAVAIL;
484 return(0);
485 }
486 return(&satosin6(&ia6->ia_addr)->sin6_addr);
487 }
488 }
489
490 /*
491 * If the destination address is a multicast address and
492 * the outgoing interface for the address is specified
493 * by the caller, use an address associated with the interface.
494 * There is a sanity check here; if the destination has node-local
495 * scope, the outgoing interfacde should be a loopback address.
496 * Even if the outgoing interface is not specified, we also
497 * choose a loopback interface as the outgoing interface.
498 */
499 if (IN6_IS_ADDR_MULTICAST(dst)) {
500 struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
501 #ifdef __bsdi__
502 extern struct ifnet loif;
503 #endif
504
505 if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
506 #ifdef __bsdi__
507 ifp = &loif;
508 #else
509 ifp = &loif[0];
510 #endif
511 }
512
513 if (ifp) {
514 ia6 = in6_ifawithscope(ifp, dst);
515 if (ia6 == 0) {
516 *errorp = EADDRNOTAVAIL;
517 return(0);
518 }
519 return(&satosin6(&ia6->ia_addr)->sin6_addr);
520 }
521 }
522
523 /*
524 * XXX How should we use sin6_scope_id???
525 */
526
527 /*
528 * If the next hop address for the packet is specified
529 * by caller, use an address associated with the route
530 * to the next hop.
531 */
532 {
533 struct sockaddr_in6 *sin6_next;
534 struct rtentry *rt;
535
536 if (opts && opts->ip6po_nexthop) {
537 sin6_next = satosin6(opts->ip6po_nexthop);
538 rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
539 if (rt) {
540 ia6 = in6_ifawithscope(rt->rt_ifp, dst);
541 if (ia6 == 0)
542 ia6 = ifatoia6(rt->rt_ifa);
543 }
544 if (ia6 == 0) {
545 *errorp = EADDRNOTAVAIL;
546 return(0);
547 }
548 return(&satosin6(&ia6->ia_addr)->sin6_addr);
549 }
550 }
551
552 /*
553 * If route is known or can be allocated now,
554 * our src addr is taken from the i/f, else punt.
555 */
556 if (ro) {
557 if (ro->ro_rt &&
558 !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
559 RTFREE(ro->ro_rt);
560 ro->ro_rt = (struct rtentry *)0;
561 }
562 if (ro->ro_rt == (struct rtentry *)0 ||
563 ro->ro_rt->rt_ifp == (struct ifnet *)0) {
564 /* No route yet, so try to acquire one */
565 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
566 ro->ro_dst.sin6_family = AF_INET6;
567 ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
568 ro->ro_dst.sin6_addr = *dst;
569 if (IN6_IS_ADDR_MULTICAST(dst)) {
570 #ifdef __FreeBSD__
571 ro->ro_rt = rtalloc1(&((struct route *)ro)
572 ->ro_dst, 0, 0UL);
573 #endif /*__FreeBSD__*/
574 #if defined(__bsdi__) || defined(__NetBSD__)
575 ro->ro_rt = rtalloc1(&((struct route *)ro)
576 ->ro_dst, 0);
577 #endif /*__bsdi__*/
578 } else {
579 #if 0 /* XXX Is this correct? */
580 rtcalloc((struct route *)ro);
581 #else
582 rtalloc((struct route *)ro);
583 #endif
584 }
585 }
586
587 /*
588 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
589 * the address. But we don't know why it does so.
590 * It is necessary to ensure the scope even for lo0
591 * so doesn't check out IFF_LOOPBACK.
592 */
593
594 if (ro->ro_rt) {
595 ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
596 if (ia6 == 0) /* xxx scope error ?*/
597 ia6 = ifatoia6(ro->ro_rt->rt_ifa);
598 }
599 #if 0
600 /*
601 * xxx The followings are necessary? (kazu)
602 * I don't think so.
603 * It's for SO_DONTROUTE option in IPv4.(jinmei)
604 */
605 if (ia6 == 0) {
606 struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
607
608 sin6->sin6_addr = *dst;
609
610 ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
611 if (ia6 == 0)
612 ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
613 if (ia6 == 0)
614 return(0);
615 return(&satosin6(&ia6->ia_addr)->sin6_addr);
616 }
617 #endif /* 0 */
618 if (ia6 == 0) {
619 *errorp = EHOSTUNREACH; /* no route */
620 return(0);
621 }
622 return(&satosin6(&ia6->ia_addr)->sin6_addr);
623 }
624
625 *errorp = EADDRNOTAVAIL;
626 return(0);
627 }
628
629 void
630 in6_pcbdisconnect(in6p)
631 struct in6pcb *in6p;
632 {
633 bzero((caddr_t)&in6p->in6p_faddr, sizeof(in6p->in6p_faddr));
634 in6p->in6p_fport = 0;
635 if (in6p->in6p_socket->so_state & SS_NOFDREF)
636 in6_pcbdetach(in6p);
637 }
638
639 void
640 in6_pcbdetach(in6p)
641 struct in6pcb *in6p;
642 {
643 struct socket *so = in6p->in6p_socket;
644
645 #ifdef IPSEC
646 if (sotoin6pcb(so) != 0)
647 key_freeso(so);
648 ipsec6_delete_pcbpolicy(in6p);
649 #endif /* IPSEC */
650 sotoin6pcb(so) = 0;
651 sofree(so);
652 if (in6p->in6p_options)
653 m_freem(in6p->in6p_options);
654 if (in6p->in6p_outputopts) {
655 if (in6p->in6p_outputopts->ip6po_rthdr &&
656 in6p->in6p_outputopts->ip6po_route.ro_rt)
657 RTFREE(in6p->in6p_outputopts->ip6po_route.ro_rt);
658 if (in6p->in6p_outputopts->ip6po_m)
659 (void)m_free(in6p->in6p_outputopts->ip6po_m);
660 free(in6p->in6p_outputopts, M_IP6OPT);
661 }
662 if (in6p->in6p_route.ro_rt)
663 rtfree(in6p->in6p_route.ro_rt);
664 ip6_freemoptions(in6p->in6p_moptions);
665 #if 0
666 remque(in6p);
667 #else
668 in6p->in6p_next->in6p_prev = in6p->in6p_prev;
669 in6p->in6p_prev->in6p_next = in6p->in6p_next;
670 in6p->in6p_prev = NULL;
671 #endif
672 FREE(in6p, M_PCB);
673 }
674
675 void
676 in6_setsockaddr(in6p, nam)
677 struct in6pcb *in6p;
678 struct mbuf *nam;
679 {
680 struct sockaddr_in6 *sin6;
681
682 nam->m_len = sizeof(*sin6);
683 sin6 = mtod(nam, struct sockaddr_in6 *);
684 bzero((caddr_t)sin6, sizeof(*sin6));
685 sin6->sin6_family = AF_INET6;
686 sin6->sin6_len = sizeof(struct sockaddr_in6);
687 sin6->sin6_port = in6p->in6p_lport;
688 sin6->sin6_addr = in6p->in6p_laddr;
689 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
690 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
691 else
692 sin6->sin6_scope_id = 0; /*XXX*/
693 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
694 sin6->sin6_addr.s6_addr16[1] = 0;
695 }
696
697 void
698 in6_setpeeraddr(in6p, nam)
699 struct in6pcb *in6p;
700 struct mbuf *nam;
701 {
702 struct sockaddr_in6 *sin6;
703
704 nam->m_len = sizeof(*sin6);
705 sin6 = mtod(nam, struct sockaddr_in6 *);
706 bzero((caddr_t)sin6, sizeof(*sin6));
707 sin6->sin6_family = AF_INET6;
708 sin6->sin6_len = sizeof(struct sockaddr_in6);
709 sin6->sin6_port = in6p->in6p_fport;
710 sin6->sin6_addr = in6p->in6p_faddr;
711 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
712 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
713 else
714 sin6->sin6_scope_id = 0; /*XXX*/
715 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
716 sin6->sin6_addr.s6_addr16[1] = 0;
717 }
718
719 /*
720 * Pass some notification to all connections of a protocol
721 * associated with address dst. The local address and/or port numbers
722 * may be specified to limit the search. The "usual action" will be
723 * taken, depending on the ctlinput cmd. The caller must filter any
724 * cmds that are uninteresting (e.g., no error in the map).
725 * Call the protocol specific routine (if any) to report
726 * any errors for each matching socket.
727 *
728 * Must be called at splsoftnet.
729 */
730 int
731 in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
732 struct in6pcb *head;
733 struct sockaddr *dst;
734 u_int fport_arg, lport_arg;
735 struct in6_addr *laddr6;
736 int cmd;
737 void (*notify) __P((struct in6pcb *, int));
738 {
739 struct in6pcb *in6p, *oin6p;
740 struct in6_addr faddr6;
741 u_short fport = fport_arg, lport = lport_arg;
742 int errno;
743 int nmatch = 0;
744
745 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
746 return 0;
747 faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
748 if (IN6_IS_ADDR_ANY(&faddr6))
749 return 0;
750
751 /*
752 * Redirects go to all references to the destination,
753 * and use in_rtchange to invalidate the route cache.
754 * Dead host indications: notify all references to the destination.
755 * Otherwise, if we have knowledge of the local port and address,
756 * deliver only to that socket.
757 */
758 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
759 fport = 0;
760 lport = 0;
761 bzero((caddr_t)laddr6, sizeof(*laddr6));
762 if (cmd != PRC_HOSTDEAD)
763 notify = in6_rtchange;
764 }
765 if (notify == NULL)
766 return 0;
767 errno = inet6ctlerrmap[cmd];
768 for (in6p = head->in6p_next; in6p != head;) {
769 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,&faddr6) ||
770 in6p->in6p_socket == 0 ||
771 (lport && in6p->in6p_lport != lport) ||
772 (!IN6_IS_ADDR_ANY(laddr6) &&
773 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) ||
774 (fport && in6p->in6p_fport != fport)) {
775 in6p = in6p->in6p_next;
776 continue;
777 }
778 oin6p = in6p;
779 in6p = in6p->in6p_next;
780 (*notify)(oin6p, errno);
781 nmatch++;
782 }
783 return nmatch;
784 }
785
786 /*
787 * Check for alternatives when higher level complains
788 * about service problems. For now, invalidate cached
789 * routing information. If the route was created dynamically
790 * (by a redirect), time to try a default gateway again.
791 */
792 void
793 in6_losing(in6p)
794 struct in6pcb *in6p;
795 {
796 struct rtentry *rt;
797 struct rt_addrinfo info;
798
799 if ((rt = in6p->in6p_route.ro_rt) != NULL) {
800 in6p->in6p_route.ro_rt = 0;
801 bzero((caddr_t)&info, sizeof(info));
802 info.rti_info[RTAX_DST] =
803 (struct sockaddr *)&in6p->in6p_route.ro_dst;
804 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
805 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
806 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
807 if (rt->rt_flags & RTF_DYNAMIC)
808 (void)rtrequest(RTM_DELETE, rt_key(rt),
809 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
810 (struct rtentry **)0);
811 else
812 /*
813 * A new route can be allocated
814 * the next time output is attempted.
815 */
816 rtfree(rt);
817 }
818 }
819
820 /*
821 * After a routing change, flush old routing
822 * and allocate a (hopefully) better one.
823 */
824 void
825 in6_rtchange(in6p, errno)
826 struct in6pcb *in6p;
827 int errno;
828 {
829 if (in6p->in6p_route.ro_rt) {
830 rtfree(in6p->in6p_route.ro_rt);
831 in6p->in6p_route.ro_rt = 0;
832 /*
833 * A new route can be allocated the next time
834 * output is attempted.
835 */
836 }
837 }
838
839 struct in6pcb *
840 in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags)
841 struct in6pcb *head;
842 struct in6_addr *faddr6, *laddr6;
843 u_int fport_arg, lport_arg;
844 int flags;
845 {
846 struct in6pcb *in6p, *match = 0;
847 int matchwild = 3, wildcard;
848 u_short fport = fport_arg, lport = lport_arg;
849
850 for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
851 if (in6p->in6p_lport != lport)
852 continue;
853 wildcard = 0;
854 if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) {
855 if (IN6_IS_ADDR_ANY(laddr6))
856 wildcard++;
857 else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
858 continue;
859 } else {
860 if (!IN6_IS_ADDR_ANY(laddr6))
861 wildcard++;
862 }
863 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
864 if (IN6_IS_ADDR_ANY(faddr6))
865 wildcard++;
866 else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6)
867 || in6p->in6p_fport != fport)
868 continue;
869 } else {
870 if (!IN6_IS_ADDR_ANY(faddr6))
871 wildcard++;
872 }
873 if (wildcard && (flags & IN6PLOOKUP_WILDCARD) == 0)
874 continue;
875 if (wildcard < matchwild) {
876 match = in6p;
877 matchwild = wildcard;
878 if (matchwild == 0)
879 break;
880 }
881 }
882 return(match);
883 }
884
885 #ifndef TCP6
886 struct rtentry *
887 in6_pcbrtentry(in6p)
888 struct in6pcb *in6p;
889 {
890 struct route_in6 *ro;
891
892 ro = &in6p->in6p_route;
893
894 if (ro->ro_rt == NULL) {
895 /*
896 * No route yet, so try to acquire one.
897 */
898 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
899 bzero(&ro->ro_dst, sizeof(ro->ro_dst));
900 ro->ro_dst.sin6_family = AF_INET6;
901 ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
902 satosin6(&ro->ro_dst)->sin6_addr = in6p->in6p_faddr;
903 rtalloc((struct route *)ro);
904 }
905 }
906 return (ro->ro_rt);
907 }
908
909 struct in6pcb *
910 in6_pcblookup_connect(head, faddr6, fport_arg, laddr6, lport_arg)
911 struct in6pcb *head;
912 struct in6_addr *faddr6, *laddr6;
913 u_int fport_arg, lport_arg;
914 {
915 struct in6pcb *in6p;
916 u_short fport = fport_arg, lport = lport_arg;
917
918 for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
919 /* find exact match on both source and dest */
920 if (in6p->in6p_fport != fport)
921 continue;
922 if (in6p->in6p_lport != lport)
923 continue;
924 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
925 continue;
926 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6))
927 continue;
928 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
929 continue;
930 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
931 continue;
932 return in6p;
933 }
934 return NULL;
935 }
936
937 struct in6pcb *
938 in6_pcblookup_bind(head, laddr6, lport_arg)
939 struct in6pcb *head;
940 struct in6_addr *laddr6;
941 u_int lport_arg;
942 {
943 struct in6pcb *in6p, *match;
944 u_short lport = lport_arg;
945
946 match = NULL;
947 for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
948 /*
949 * find destination match. exact match is preferred
950 * against wildcard match.
951 */
952 if (in6p->in6p_fport != 0)
953 continue;
954 if (in6p->in6p_lport != lport)
955 continue;
956 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
957 match = in6p;
958 else if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
959 return in6p;
960 }
961 return match;
962 }
963 #endif
964