]>
Commit | Line | Data |
---|---|---|
91447636 | 1 | /* |
b0d623f7 | 2 | * Copyright (c) 2003-2008 Apple Inc. All rights reserved. |
91447636 | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
91447636 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
91447636 | 27 | */ |
1c79356b A |
28 | /* |
29 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
30 | * All rights reserved. | |
9bccf70c | 31 | * |
1c79356b A |
32 | * Redistribution and use in source and binary forms, with or without |
33 | * modification, are permitted provided that the following conditions | |
34 | * are met: | |
35 | * 1. Redistributions of source code must retain the above copyright | |
36 | * notice, this list of conditions and the following disclaimer. | |
37 | * 2. Redistributions in binary form must reproduce the above copyright | |
38 | * notice, this list of conditions and the following disclaimer in the | |
39 | * documentation and/or other materials provided with the distribution. | |
40 | * 3. Neither the name of the project nor the names of its contributors | |
41 | * may be used to endorse or promote products derived from this software | |
42 | * without specific prior written permission. | |
9bccf70c | 43 | * |
1c79356b A |
44 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
54 | * SUCH DAMAGE. | |
9bccf70c | 55 | * |
1c79356b A |
56 | */ |
57 | ||
58 | /* | |
59 | * Copyright (c) 1982, 1986, 1991, 1993 | |
60 | * The Regents of the University of California. All rights reserved. | |
61 | * | |
62 | * Redistribution and use in source and binary forms, with or without | |
63 | * modification, are permitted provided that the following conditions | |
64 | * are met: | |
65 | * 1. Redistributions of source code must retain the above copyright | |
66 | * notice, this list of conditions and the following disclaimer. | |
67 | * 2. Redistributions in binary form must reproduce the above copyright | |
68 | * notice, this list of conditions and the following disclaimer in the | |
69 | * documentation and/or other materials provided with the distribution. | |
70 | * 3. All advertising materials mentioning features or use of this software | |
71 | * must display the following acknowledgement: | |
72 | * This product includes software developed by the University of | |
73 | * California, Berkeley and its contributors. | |
74 | * 4. Neither the name of the University nor the names of its contributors | |
75 | * may be used to endorse or promote products derived from this software | |
76 | * without specific prior written permission. | |
77 | * | |
78 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
79 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
80 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
81 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
82 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
83 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
84 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
85 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
86 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
87 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
88 | * SUCH DAMAGE. | |
89 | * | |
90 | * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 | |
91 | */ | |
92 | ||
1c79356b A |
93 | #include <sys/param.h> |
94 | #include <sys/systm.h> | |
95 | #include <sys/malloc.h> | |
96 | #include <sys/mbuf.h> | |
9bccf70c | 97 | #include <sys/domain.h> |
1c79356b A |
98 | #include <sys/protosw.h> |
99 | #include <sys/socket.h> | |
100 | #include <sys/socketvar.h> | |
101 | #include <sys/sockio.h> | |
102 | #include <sys/errno.h> | |
103 | #include <sys/time.h> | |
104 | #include <sys/proc.h> | |
105 | ||
106 | #include <net/if.h> | |
107 | #include <net/if_types.h> | |
108 | #include <net/route.h> | |
109 | ||
110 | #include <netinet/in.h> | |
111 | #include <netinet/in_var.h> | |
112 | #include <netinet/in_systm.h> | |
113 | #include <netinet/ip6.h> | |
9bccf70c | 114 | #include <netinet/ip_var.h> |
1c79356b A |
115 | #include <netinet6/ip6_var.h> |
116 | #include <netinet6/nd6.h> | |
117 | #include <netinet/in_pcb.h> | |
118 | #include <netinet6/in6_pcb.h> | |
119 | #include <net/if_types.h> | |
120 | ||
91447636 A |
121 | #include <kern/kern_types.h> |
122 | #include <kern/zalloc.h> | |
123 | ||
1c79356b A |
124 | #if IPSEC |
125 | #include <netinet6/ipsec.h> | |
9bccf70c A |
126 | #if INET6 |
127 | #include <netinet6/ipsec6.h> | |
128 | #endif | |
129 | #include <netinet6/ah.h> | |
130 | #if INET6 | |
131 | #include <netinet6/ah6.h> | |
132 | #endif | |
1c79356b | 133 | #include <netkey/key.h> |
1c79356b A |
134 | #endif /* IPSEC */ |
135 | ||
9bccf70c | 136 | struct in6_addr zeroin6_addr; |
1c79356b | 137 | |
2d21ac55 A |
138 | /* |
139 | in6_pcblookup_local_and_cleanup does everything | |
140 | in6_pcblookup_local does but it checks for a socket | |
141 | that's going away. Since we know that the lock is | |
142 | held read+write when this function is called, we | |
143 | can safely dispose of this socket like the slow | |
144 | timer would usually do and return NULL. This is | |
145 | great for bind. | |
146 | */ | |
147 | static struct inpcb* | |
148 | in6_pcblookup_local_and_cleanup( | |
149 | struct inpcbinfo *pcbinfo, | |
150 | struct in6_addr *laddr, | |
151 | u_int lport_arg, | |
152 | int wild_okay) | |
153 | { | |
154 | struct inpcb *inp; | |
155 | ||
156 | /* Perform normal lookup */ | |
157 | inp = in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay); | |
158 | ||
159 | /* Check if we found a match but it's waiting to be disposed */ | |
160 | if (inp && inp->inp_wantcnt == WNT_STOPUSING) { | |
161 | struct socket *so = inp->inp_socket; | |
162 | ||
163 | lck_mtx_lock(inp->inpcb_mtx); | |
164 | ||
165 | if (so->so_usecount == 0) { | |
b0d623f7 A |
166 | if (inp->inp_state != INPCB_STATE_DEAD) |
167 | in6_pcbdetach(inp); | |
2d21ac55 A |
168 | in_pcbdispose(inp); |
169 | inp = NULL; | |
170 | } | |
171 | else { | |
172 | lck_mtx_unlock(inp->inpcb_mtx); | |
173 | } | |
174 | } | |
175 | ||
176 | return inp; | |
177 | } | |
1c79356b | 178 | int |
91447636 A |
179 | in6_pcbbind( |
180 | struct inpcb *inp, | |
181 | struct sockaddr *nam, | |
182 | struct proc *p) | |
1c79356b A |
183 | { |
184 | struct socket *so = inp->inp_socket; | |
1c79356b A |
185 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL; |
186 | struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | |
187 | u_short lport = 0; | |
188 | int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); | |
1c79356b | 189 | |
91447636 | 190 | if (!in6_ifaddrs) /* XXX broken! */ |
1c79356b A |
191 | return (EADDRNOTAVAIL); |
192 | if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) | |
193 | return(EINVAL); | |
194 | if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) | |
9bccf70c | 195 | wild = 1; |
91447636 A |
196 | socket_unlock(so, 0); /* keep reference */ |
197 | lck_rw_lock_exclusive(pcbinfo->mtx); | |
1c79356b | 198 | if (nam) { |
9bccf70c | 199 | sin6 = (struct sockaddr_in6 *)nam; |
91447636 A |
200 | if (nam->sa_len != sizeof(*sin6)) { |
201 | lck_rw_done(pcbinfo->mtx); | |
202 | socket_lock(so, 0); | |
1c79356b | 203 | return(EINVAL); |
91447636 | 204 | } |
1c79356b | 205 | /* |
9bccf70c | 206 | * family check. |
1c79356b | 207 | */ |
91447636 A |
208 | if (nam->sa_family != AF_INET6) { |
209 | lck_rw_done(pcbinfo->mtx); | |
210 | socket_lock(so, 0); | |
1c79356b | 211 | return(EAFNOSUPPORT); |
91447636 | 212 | } |
1c79356b | 213 | |
9bccf70c | 214 | /* KAME hack: embed scopeid */ |
91447636 A |
215 | if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0) { |
216 | lck_rw_done(pcbinfo->mtx); | |
217 | socket_lock(so, 0); | |
9bccf70c | 218 | return EINVAL; |
91447636 | 219 | } |
9bccf70c A |
220 | /* this must be cleared for ifa_ifwithaddr() */ |
221 | sin6->sin6_scope_id = 0; | |
1c79356b A |
222 | |
223 | lport = sin6->sin6_port; | |
224 | if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { | |
225 | /* | |
226 | * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; | |
227 | * allow compepte duplication of binding if | |
228 | * SO_REUSEPORT is set, or if SO_REUSEADDR is set | |
229 | * and a multicast address is bound on both | |
230 | * new and duplicated sockets. | |
231 | */ | |
232 | if (so->so_options & SO_REUSEADDR) | |
233 | reuseport = SO_REUSEADDR|SO_REUSEPORT; | |
234 | } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { | |
235 | struct ifaddr *ia = NULL; | |
236 | ||
237 | sin6->sin6_port = 0; /* yech... */ | |
91447636 A |
238 | if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0) { |
239 | lck_rw_done(pcbinfo->mtx); | |
240 | socket_lock(so, 0); | |
1c79356b | 241 | return(EADDRNOTAVAIL); |
91447636 | 242 | } |
1c79356b A |
243 | |
244 | /* | |
245 | * XXX: bind to an anycast address might accidentally | |
246 | * cause sending a packet with anycast source address. | |
9bccf70c A |
247 | * We should allow to bind to a deprecated address, since |
248 | * the application dare to use it. | |
1c79356b A |
249 | */ |
250 | if (ia && | |
251 | ((struct in6_ifaddr *)ia)->ia6_flags & | |
9bccf70c | 252 | (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) { |
91447636 A |
253 | ifafree(ia); |
254 | lck_rw_done(pcbinfo->mtx); | |
255 | socket_lock(so, 0); | |
1c79356b A |
256 | return(EADDRNOTAVAIL); |
257 | } | |
91447636 A |
258 | ifafree(ia); |
259 | ia = NULL; | |
1c79356b A |
260 | } |
261 | if (lport) { | |
262 | struct inpcb *t; | |
263 | ||
264 | /* GROSS */ | |
b0d623f7 | 265 | if (ntohs(lport) < IPV6PORT_RESERVED && |
91447636 A |
266 | ((so->so_state & SS_PRIV) == 0)) { |
267 | lck_rw_done(pcbinfo->mtx); | |
268 | socket_lock(so, 0); | |
1c79356b | 269 | return(EACCES); |
91447636 | 270 | } |
1c79356b A |
271 | |
272 | if (so->so_uid && | |
273 | !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { | |
2d21ac55 | 274 | t = in6_pcblookup_local_and_cleanup(pcbinfo, |
9bccf70c A |
275 | &sin6->sin6_addr, lport, |
276 | INPLOOKUP_WILDCARD); | |
1c79356b A |
277 | if (t && |
278 | (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || | |
279 | !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || | |
280 | (t->inp_socket->so_options & | |
281 | SO_REUSEPORT) == 0) && | |
2d21ac55 A |
282 | (so->so_uid != t->inp_socket->so_uid) && |
283 | ((t->inp_socket->so_flags & SOF_REUSESHAREUID) == 0)) { | |
91447636 A |
284 | lck_rw_done(pcbinfo->mtx); |
285 | socket_lock(so, 0); | |
1c79356b | 286 | return (EADDRINUSE); |
91447636 | 287 | } |
9bccf70c A |
288 | if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && |
289 | IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { | |
290 | struct sockaddr_in sin; | |
291 | ||
292 | in6_sin6_2_sin(&sin, sin6); | |
2d21ac55 | 293 | t = in_pcblookup_local_and_cleanup(pcbinfo, |
9bccf70c A |
294 | sin.sin_addr, lport, |
295 | INPLOOKUP_WILDCARD); | |
2d21ac55 | 296 | if (t && (t->inp_socket->so_options & SO_REUSEPORT) == 0 && |
9bccf70c A |
297 | (so->so_uid != |
298 | t->inp_socket->so_uid) && | |
299 | (ntohl(t->inp_laddr.s_addr) != | |
300 | INADDR_ANY || | |
301 | INP_SOCKAF(so) == | |
91447636 A |
302 | INP_SOCKAF(t->inp_socket))) { |
303 | ||
304 | lck_rw_done(pcbinfo->mtx); | |
305 | socket_lock(so, 0); | |
9bccf70c | 306 | return (EADDRINUSE); |
91447636 | 307 | } |
9bccf70c | 308 | } |
1c79356b | 309 | } |
2d21ac55 | 310 | t = in6_pcblookup_local_and_cleanup(pcbinfo, &sin6->sin6_addr, |
1c79356b | 311 | lport, wild); |
91447636 A |
312 | if (t && (reuseport & t->inp_socket->so_options) == 0) { |
313 | lck_rw_done(pcbinfo->mtx); | |
314 | socket_lock(so, 0); | |
1c79356b | 315 | return(EADDRINUSE); |
91447636 | 316 | } |
9bccf70c A |
317 | if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && |
318 | IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { | |
319 | struct sockaddr_in sin; | |
320 | ||
321 | in6_sin6_2_sin(&sin, sin6); | |
2d21ac55 | 322 | t = in_pcblookup_local_and_cleanup(pcbinfo, sin.sin_addr, |
9bccf70c A |
323 | lport, wild); |
324 | if (t && | |
325 | (reuseport & t->inp_socket->so_options) | |
326 | == 0 && | |
327 | (ntohl(t->inp_laddr.s_addr) | |
328 | != INADDR_ANY || | |
329 | INP_SOCKAF(so) == | |
91447636 A |
330 | INP_SOCKAF(t->inp_socket))) { |
331 | lck_rw_done(pcbinfo->mtx); | |
332 | socket_lock(so, 0); | |
9bccf70c | 333 | return (EADDRINUSE); |
91447636 | 334 | } |
9bccf70c | 335 | } |
1c79356b A |
336 | } |
337 | inp->in6p_laddr = sin6->sin6_addr; | |
338 | } | |
91447636 | 339 | socket_lock(so, 0); |
1c79356b | 340 | if (lport == 0) { |
9bccf70c | 341 | int e; |
91447636 A |
342 | if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, p, 1)) != 0) { |
343 | lck_rw_done(pcbinfo->mtx); | |
9bccf70c | 344 | return(e); |
91447636 | 345 | } |
1c79356b | 346 | } |
9bccf70c A |
347 | else { |
348 | inp->inp_lport = lport; | |
91447636 | 349 | if (in_pcbinshash(inp, 1) != 0) { |
9bccf70c A |
350 | inp->in6p_laddr = in6addr_any; |
351 | inp->inp_lport = 0; | |
91447636 | 352 | lck_rw_done(pcbinfo->mtx); |
9bccf70c A |
353 | return (EAGAIN); |
354 | } | |
91447636 A |
355 | } |
356 | lck_rw_done(pcbinfo->mtx); | |
2d21ac55 | 357 | sflt_notify(so, sock_evt_bound, NULL); |
1c79356b A |
358 | return(0); |
359 | } | |
360 | ||
361 | /* | |
362 | * Transform old in6_pcbconnect() into an inner subroutine for new | |
363 | * in6_pcbconnect(): Do some validity-checking on the remote | |
364 | * address (in mbuf 'nam') and then determine local host address | |
365 | * (i.e., which interface) to use to access that remote host. | |
366 | * | |
367 | * This preserves definition of in6_pcbconnect(), while supporting a | |
368 | * slightly different version for T/TCP. (This is more than | |
369 | * a bit of a kludge, but cleaning up the internal interfaces would | |
370 | * have forced minor changes in every protocol). | |
371 | */ | |
372 | ||
373 | int | |
91447636 A |
374 | in6_pcbladdr( |
375 | struct inpcb *inp, | |
376 | struct sockaddr *nam, | |
377 | struct in6_addr *plocal_addr6) | |
1c79356b | 378 | { |
91447636 A |
379 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; |
380 | struct in6_addr *addr6 = NULL; | |
381 | struct in6_addr src_storage; | |
382 | ||
1c79356b A |
383 | struct ifnet *ifp = NULL; |
384 | int error = 0; | |
385 | ||
386 | if (nam->sa_len != sizeof (*sin6)) | |
387 | return (EINVAL); | |
388 | if (sin6->sin6_family != AF_INET6) | |
389 | return (EAFNOSUPPORT); | |
390 | if (sin6->sin6_port == 0) | |
391 | return (EADDRNOTAVAIL); | |
392 | ||
9bccf70c A |
393 | /* KAME hack: embed scopeid */ |
394 | if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0) | |
395 | return EINVAL; | |
1c79356b | 396 | |
91447636 | 397 | if (in6_ifaddrs) { |
1c79356b A |
398 | /* |
399 | * If the destination address is UNSPECIFIED addr, | |
400 | * use the loopback addr, e.g ::1. | |
401 | */ | |
1c79356b A |
402 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) |
403 | sin6->sin6_addr = in6addr_loopback; | |
404 | } | |
405 | { | |
406 | /* | |
407 | * XXX: in6_selectsrc might replace the bound local address | |
408 | * with the address specified by setsockopt(IPV6_PKTINFO). | |
409 | * Is it the intended behavior? | |
410 | */ | |
91447636 | 411 | addr6 = in6_selectsrc(sin6, inp->in6p_outputopts, |
1c79356b A |
412 | inp->in6p_moptions, |
413 | &inp->in6p_route, | |
91447636 A |
414 | &inp->in6p_laddr, &src_storage, &error); |
415 | if (addr6 == 0) { | |
1c79356b A |
416 | if (error == 0) |
417 | error = EADDRNOTAVAIL; | |
418 | return(error); | |
419 | } | |
91447636 | 420 | *plocal_addr6 = *addr6; |
1c79356b | 421 | /* |
9bccf70c | 422 | * Don't do pcblookup call here; return interface in |
1c79356b A |
423 | * plocal_addr6 |
424 | * and exit to caller, that will do the lookup. | |
425 | */ | |
426 | } | |
427 | ||
b0d623f7 | 428 | /* XXX: what is the point in doing this? */ |
1c79356b A |
429 | if (inp->in6p_route.ro_rt) |
430 | ifp = inp->in6p_route.ro_rt->rt_ifp; | |
431 | ||
432 | return(0); | |
433 | } | |
434 | ||
435 | /* | |
436 | * Outer subroutine: | |
437 | * Connect from a socket to a specified address. | |
438 | * Both address and port must be specified in argument sin. | |
439 | * If don't have a local address for this socket yet, | |
440 | * then pick one. | |
441 | */ | |
442 | int | |
443 | in6_pcbconnect(inp, nam, p) | |
91447636 | 444 | struct inpcb *inp; |
1c79356b A |
445 | struct sockaddr *nam; |
446 | struct proc *p; | |
447 | { | |
91447636 A |
448 | struct in6_addr addr6; |
449 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; | |
450 | struct inpcb *pcb; | |
1c79356b A |
451 | int error; |
452 | ||
453 | /* | |
55e303ae A |
454 | * Call inner routine, to assign local interface address. |
455 | * in6_pcbladdr() may automatically fill in sin6_scope_id. | |
1c79356b | 456 | */ |
9bccf70c | 457 | if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0) |
1c79356b | 458 | return(error); |
91447636 A |
459 | socket_unlock(inp->inp_socket, 0); |
460 | pcb = in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr, | |
1c79356b A |
461 | sin6->sin6_port, |
462 | IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) | |
91447636 A |
463 | ? &addr6 : &inp->in6p_laddr, |
464 | inp->inp_lport, 0, NULL); | |
465 | socket_lock(inp->inp_socket, 0); | |
466 | if (pcb != NULL) { | |
0b4c1975 | 467 | in_pcb_checkstate(pcb, WNT_RELEASE, pcb == inp ? 1 : 0); |
1c79356b A |
468 | return (EADDRINUSE); |
469 | } | |
470 | if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { | |
471 | if (inp->inp_lport == 0) { | |
472 | error = in6_pcbbind(inp, (struct sockaddr *)0, p); | |
473 | if (error) | |
474 | return (error); | |
475 | } | |
91447636 A |
476 | inp->in6p_laddr = addr6; |
477 | } | |
478 | if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->mtx)) { | |
479 | /*lock inversion issue, mostly with udp multicast packets */ | |
480 | socket_unlock(inp->inp_socket, 0); | |
481 | lck_rw_lock_exclusive(inp->inp_pcbinfo->mtx); | |
482 | socket_lock(inp->inp_socket, 0); | |
1c79356b A |
483 | } |
484 | inp->in6p_faddr = sin6->sin6_addr; | |
485 | inp->inp_fport = sin6->sin6_port; | |
9bccf70c A |
486 | /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ |
487 | inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; | |
488 | if (inp->in6p_flags & IN6P_AUTOFLOWLABEL) | |
489 | inp->in6p_flowinfo |= | |
490 | (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); | |
1c79356b A |
491 | |
492 | in_pcbrehash(inp); | |
91447636 | 493 | lck_rw_done(inp->inp_pcbinfo->mtx); |
1c79356b A |
494 | return (0); |
495 | } | |
496 | ||
1c79356b A |
497 | void |
498 | in6_pcbdisconnect(inp) | |
499 | struct inpcb *inp; | |
500 | { | |
91447636 A |
501 | if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->mtx)) { |
502 | /*lock inversion issue, mostly with udp multicast packets */ | |
503 | socket_unlock(inp->inp_socket, 0); | |
504 | lck_rw_lock_exclusive(inp->inp_pcbinfo->mtx); | |
505 | socket_lock(inp->inp_socket, 0); | |
506 | } | |
1c79356b A |
507 | bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr)); |
508 | inp->inp_fport = 0; | |
9bccf70c A |
509 | /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ |
510 | inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; | |
1c79356b | 511 | in_pcbrehash(inp); |
91447636 | 512 | lck_rw_done(inp->inp_pcbinfo->mtx); |
1c79356b A |
513 | if (inp->inp_socket->so_state & SS_NOFDREF) |
514 | in6_pcbdetach(inp); | |
515 | } | |
516 | ||
517 | void | |
518 | in6_pcbdetach(inp) | |
519 | struct inpcb *inp; | |
520 | { | |
521 | struct socket *so = inp->inp_socket; | |
522 | struct inpcbinfo *ipi = inp->inp_pcbinfo; | |
523 | ||
524 | #if IPSEC | |
91447636 | 525 | if (inp->in6p_sp != NULL) { |
9bccf70c | 526 | ipsec6_delete_pcbpolicy(inp); |
91447636 | 527 | } |
1c79356b | 528 | #endif /* IPSEC */ |
9bccf70c | 529 | |
91447636 | 530 | if (in_pcb_checkstate(inp, WNT_STOPUSING, 1) != WNT_STOPUSING) |
2d21ac55 | 531 | printf("in6_pcbdetach so=%p can't be marked dead ok\n", so); |
91447636 A |
532 | |
533 | inp->inp_state = INPCB_STATE_DEAD; | |
534 | ||
535 | if ((so->so_flags & SOF_PCBCLEARING) == 0) { | |
536 | inp->inp_vflag = 0; | |
537 | so->so_flags |= SOF_PCBCLEARING; | |
538 | inp->inp_gencnt = ++ipi->ipi_gencnt; | |
539 | if (inp->in6p_options) | |
540 | m_freem(inp->in6p_options); | |
541 | ip6_freepcbopts(inp->in6p_outputopts); | |
542 | ip6_freemoptions(inp->in6p_moptions); | |
c910b4d9 | 543 | if (inp->in6p_route.ro_rt) { |
91447636 | 544 | rtfree(inp->in6p_route.ro_rt); |
c910b4d9 A |
545 | inp->in6p_route.ro_rt = NULL; |
546 | } | |
91447636 A |
547 | /* Check and free IPv4 related resources in case of mapped addr */ |
548 | if (inp->inp_options) | |
549 | (void)m_free(inp->inp_options); | |
550 | ip_freemoptions(inp->inp_moptions); | |
551 | inp->inp_moptions = NULL; | |
552 | ||
553 | } | |
1c79356b A |
554 | } |
555 | ||
55e303ae A |
556 | struct sockaddr * |
557 | in6_sockaddr(port, addr_p) | |
558 | in_port_t port; | |
559 | struct in6_addr *addr_p; | |
560 | { | |
561 | struct sockaddr_in6 *sin6; | |
562 | ||
563 | MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK); | |
b0d623f7 A |
564 | if (sin6 == NULL) |
565 | return NULL; | |
55e303ae A |
566 | bzero(sin6, sizeof *sin6); |
567 | sin6->sin6_family = AF_INET6; | |
568 | sin6->sin6_len = sizeof(*sin6); | |
569 | sin6->sin6_port = port; | |
570 | sin6->sin6_addr = *addr_p; | |
571 | if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) | |
572 | sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]); | |
573 | else | |
574 | sin6->sin6_scope_id = 0; /*XXX*/ | |
575 | if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) | |
576 | sin6->sin6_addr.s6_addr16[1] = 0; | |
577 | ||
578 | return (struct sockaddr *)sin6; | |
579 | } | |
580 | ||
581 | struct sockaddr * | |
582 | in6_v4mapsin6_sockaddr(port, addr_p) | |
583 | in_port_t port; | |
584 | struct in_addr *addr_p; | |
585 | { | |
586 | struct sockaddr_in sin; | |
587 | struct sockaddr_in6 *sin6_p; | |
588 | ||
589 | bzero(&sin, sizeof sin); | |
590 | sin.sin_family = AF_INET; | |
591 | sin.sin_len = sizeof(sin); | |
592 | sin.sin_port = port; | |
593 | sin.sin_addr = *addr_p; | |
594 | ||
595 | MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME, | |
596 | M_WAITOK); | |
b0d623f7 A |
597 | if (sin6_p == NULL) |
598 | return NULL; | |
55e303ae A |
599 | in6_sin_2_v4mapsin6(&sin, sin6_p); |
600 | ||
601 | return (struct sockaddr *)sin6_p; | |
602 | } | |
603 | ||
1c79356b A |
604 | /* |
605 | * The calling convention of in6_setsockaddr() and in6_setpeeraddr() was | |
606 | * modified to match the pru_sockaddr() and pru_peeraddr() entry points | |
607 | * in struct pr_usrreqs, so that protocols can just reference then directly | |
608 | * without the need for a wrapper function. The socket must have a valid | |
609 | * (i.e., non-nil) PCB, but it should be impossible to get an invalid one | |
610 | * except through a kernel programming error, so it is acceptable to panic | |
611 | * (or in this case trap) if the PCB is invalid. (Actually, we don't trap | |
612 | * because there actually /is/ a programming error somewhere... XXX) | |
613 | */ | |
614 | int | |
615 | in6_setsockaddr(so, nam) | |
616 | struct socket *so; | |
617 | struct sockaddr **nam; | |
618 | { | |
91447636 | 619 | struct inpcb *inp; |
55e303ae A |
620 | struct in6_addr addr; |
621 | in_port_t port; | |
1c79356b | 622 | |
1c79356b A |
623 | inp = sotoinpcb(so); |
624 | if (!inp) { | |
1c79356b A |
625 | return EINVAL; |
626 | } | |
55e303ae A |
627 | port = inp->inp_lport; |
628 | addr = inp->in6p_laddr; | |
1c79356b | 629 | |
55e303ae | 630 | *nam = in6_sockaddr(port, &addr); |
b0d623f7 A |
631 | if (*nam == NULL) |
632 | return ENOBUFS; | |
1c79356b A |
633 | return 0; |
634 | } | |
635 | ||
636 | int | |
637 | in6_setpeeraddr(so, nam) | |
638 | struct socket *so; | |
639 | struct sockaddr **nam; | |
640 | { | |
1c79356b | 641 | struct inpcb *inp; |
55e303ae A |
642 | struct in6_addr addr; |
643 | in_port_t port; | |
1c79356b | 644 | |
1c79356b A |
645 | inp = sotoinpcb(so); |
646 | if (!inp) { | |
1c79356b A |
647 | return EINVAL; |
648 | } | |
55e303ae A |
649 | port = inp->inp_fport; |
650 | addr = inp->in6p_faddr; | |
1c79356b | 651 | |
55e303ae | 652 | *nam = in6_sockaddr(port, &addr); |
b0d623f7 A |
653 | if (*nam == NULL) |
654 | return ENOBUFS; | |
1c79356b A |
655 | return 0; |
656 | } | |
657 | ||
658 | int | |
659 | in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam) | |
660 | { | |
661 | struct inpcb *inp = sotoinpcb(so); | |
662 | int error; | |
663 | ||
664 | if (inp == NULL) | |
665 | return EINVAL; | |
666 | if (inp->inp_vflag & INP_IPV4) { | |
667 | error = in_setsockaddr(so, nam); | |
668 | if (error == 0) | |
b0d623f7 A |
669 | error = in6_sin_2_v4mapsin6_in_sock(nam); |
670 | } else { | |
671 | /* scope issues will be handled in in6_setsockaddr(). */ | |
672 | error = in6_setsockaddr(so, nam); | |
673 | } | |
1c79356b A |
674 | return error; |
675 | } | |
676 | ||
677 | int | |
678 | in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) | |
679 | { | |
680 | struct inpcb *inp = sotoinpcb(so); | |
681 | int error; | |
682 | ||
683 | if (inp == NULL) | |
684 | return EINVAL; | |
685 | if (inp->inp_vflag & INP_IPV4) { | |
686 | error = in_setpeeraddr(so, nam); | |
687 | if (error == 0) | |
b0d623f7 A |
688 | error = in6_sin_2_v4mapsin6_in_sock(nam); |
689 | } else { | |
690 | /* scope issues will be handled in in6_setpeeraddr(). */ | |
691 | error = in6_setpeeraddr(so, nam); | |
692 | } | |
1c79356b A |
693 | return error; |
694 | } | |
695 | ||
696 | /* | |
697 | * Pass some notification to all connections of a protocol | |
698 | * associated with address dst. The local address and/or port numbers | |
699 | * may be specified to limit the search. The "usual action" will be | |
700 | * taken, depending on the ctlinput cmd. The caller must filter any | |
701 | * cmds that are uninteresting (e.g., no error in the map). | |
702 | * Call the protocol specific routine (if any) to report | |
703 | * any errors for each matching socket. | |
704 | * | |
705 | * Must be called at splnet. | |
706 | */ | |
707 | void | |
91447636 A |
708 | in6_pcbnotify(pcbinfo, dst, fport_arg, src, lport_arg, cmd, notify) |
709 | struct inpcbinfo *pcbinfo; | |
55e303ae A |
710 | struct sockaddr *dst; |
711 | const struct sockaddr *src; | |
1c79356b | 712 | u_int fport_arg, lport_arg; |
1c79356b | 713 | int cmd; |
91447636 A |
714 | // struct inpcb *(*notify)(struct inpcb *, int); |
715 | void (*notify)(struct inpcb *, int); | |
1c79356b A |
716 | { |
717 | struct inpcb *inp, *ninp; | |
9bccf70c | 718 | struct sockaddr_in6 sa6_src, *sa6_dst; |
1c79356b | 719 | u_short fport = fport_arg, lport = lport_arg; |
9bccf70c | 720 | u_int32_t flowinfo; |
91447636 A |
721 | int errno; |
722 | struct inpcbhead *head = pcbinfo->listhead; | |
1c79356b A |
723 | |
724 | if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6) | |
725 | return; | |
9bccf70c A |
726 | |
727 | sa6_dst = (struct sockaddr_in6 *)dst; | |
728 | if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr)) | |
1c79356b A |
729 | return; |
730 | ||
9bccf70c A |
731 | /* |
732 | * note that src can be NULL when we get notify by local fragmentation. | |
733 | */ | |
55e303ae | 734 | sa6_src = (src == NULL) ? sa6_any : *(const struct sockaddr_in6 *)src; |
9bccf70c A |
735 | flowinfo = sa6_src.sin6_flowinfo; |
736 | ||
1c79356b A |
737 | /* |
738 | * Redirects go to all references to the destination, | |
739 | * and use in6_rtchange to invalidate the route cache. | |
740 | * Dead host indications: also use in6_rtchange to invalidate | |
741 | * the cache, and deliver the error to all the sockets. | |
742 | * Otherwise, if we have knowledge of the local port and address, | |
743 | * deliver only to that socket. | |
744 | */ | |
745 | if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { | |
746 | fport = 0; | |
747 | lport = 0; | |
9bccf70c | 748 | bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr)); |
1c79356b | 749 | |
9bccf70c A |
750 | if (cmd != PRC_HOSTDEAD) |
751 | notify = in6_rtchange; | |
1c79356b A |
752 | } |
753 | errno = inet6ctlerrmap[cmd]; | |
91447636 | 754 | lck_rw_lock_shared(pcbinfo->mtx); |
9bccf70c A |
755 | for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { |
756 | ninp = LIST_NEXT(inp, inp_list); | |
1c79356b | 757 | |
9bccf70c | 758 | if ((inp->inp_vflag & INP_IPV6) == 0) |
1c79356b A |
759 | continue; |
760 | ||
9bccf70c A |
761 | /* |
762 | * Detect if we should notify the error. If no source and | |
763 | * destination ports are specifed, but non-zero flowinfo and | |
764 | * local address match, notify the error. This is the case | |
765 | * when the error is delivered with an encrypted buffer | |
766 | * by ESP. Otherwise, just compare addresses and ports | |
767 | * as usual. | |
768 | */ | |
769 | if (lport == 0 && fport == 0 && flowinfo && | |
770 | inp->inp_socket != NULL && | |
771 | flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) && | |
772 | IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr)) | |
773 | goto do_notify; | |
774 | else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, | |
775 | &sa6_dst->sin6_addr) || | |
776 | inp->inp_socket == 0 || | |
777 | (lport && inp->inp_lport != lport) || | |
778 | (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && | |
779 | !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, | |
780 | &sa6_src.sin6_addr)) || | |
91447636 | 781 | (fport && inp->inp_fport != fport)) |
1c79356b | 782 | continue; |
91447636 | 783 | |
1c79356b | 784 | |
9bccf70c | 785 | do_notify: |
91447636 A |
786 | if (notify) { |
787 | if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) == WNT_STOPUSING) | |
788 | continue; | |
789 | socket_lock(inp->inp_socket, 1); | |
1c79356b | 790 | (*notify)(inp, errno); |
91447636 A |
791 | (void)in_pcb_checkstate(inp, WNT_RELEASE, 1); |
792 | socket_unlock(inp->inp_socket, 1); | |
793 | } | |
1c79356b | 794 | } |
91447636 | 795 | lck_rw_done(pcbinfo->mtx); |
1c79356b A |
796 | } |
797 | ||
798 | /* | |
799 | * Lookup a PCB based on the local address and port. | |
800 | */ | |
801 | struct inpcb * | |
802 | in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) | |
803 | struct inpcbinfo *pcbinfo; | |
804 | struct in6_addr *laddr; | |
805 | u_int lport_arg; | |
806 | int wild_okay; | |
807 | { | |
91447636 | 808 | struct inpcb *inp; |
1c79356b A |
809 | int matchwild = 3, wildcard; |
810 | u_short lport = lport_arg; | |
811 | ||
812 | if (!wild_okay) { | |
813 | struct inpcbhead *head; | |
814 | /* | |
815 | * Look for an unconnected (wildcard foreign addr) PCB that | |
816 | * matches the local address and port we're looking for. | |
817 | */ | |
818 | head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, | |
819 | pcbinfo->hashmask)]; | |
820 | LIST_FOREACH(inp, head, inp_hash) { | |
821 | if ((inp->inp_vflag & INP_IPV6) == 0) | |
822 | continue; | |
823 | if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && | |
824 | IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && | |
825 | inp->inp_lport == lport) { | |
826 | /* | |
827 | * Found. | |
828 | */ | |
829 | return (inp); | |
830 | } | |
831 | } | |
832 | /* | |
833 | * Not found. | |
834 | */ | |
835 | return (NULL); | |
836 | } else { | |
837 | struct inpcbporthead *porthash; | |
838 | struct inpcbport *phd; | |
839 | struct inpcb *match = NULL; | |
840 | /* | |
841 | * Best fit PCB lookup. | |
842 | * | |
843 | * First see if this local port is in use by looking on the | |
844 | * port hash list. | |
845 | */ | |
846 | porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, | |
847 | pcbinfo->porthashmask)]; | |
848 | LIST_FOREACH(phd, porthash, phd_hash) { | |
849 | if (phd->phd_port == lport) | |
850 | break; | |
851 | } | |
852 | if (phd != NULL) { | |
853 | /* | |
854 | * Port is in use by one or more PCBs. Look for best | |
855 | * fit. | |
856 | */ | |
857 | LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { | |
858 | wildcard = 0; | |
859 | if ((inp->inp_vflag & INP_IPV6) == 0) | |
860 | continue; | |
861 | if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) | |
862 | wildcard++; | |
863 | if (!IN6_IS_ADDR_UNSPECIFIED( | |
864 | &inp->in6p_laddr)) { | |
865 | if (IN6_IS_ADDR_UNSPECIFIED(laddr)) | |
866 | wildcard++; | |
867 | else if (!IN6_ARE_ADDR_EQUAL( | |
868 | &inp->in6p_laddr, laddr)) | |
869 | continue; | |
870 | } else { | |
871 | if (!IN6_IS_ADDR_UNSPECIFIED(laddr)) | |
872 | wildcard++; | |
873 | } | |
874 | if (wildcard < matchwild) { | |
875 | match = inp; | |
876 | matchwild = wildcard; | |
877 | if (matchwild == 0) { | |
878 | break; | |
879 | } | |
880 | } | |
881 | } | |
882 | } | |
883 | return (match); | |
884 | } | |
885 | } | |
91447636 A |
886 | #ifndef APPLE |
887 | /* this is not used in Darwin */ | |
9bccf70c | 888 | void |
91447636 A |
889 | in6_pcbpurgeif0( |
890 | struct in6pcb *head, | |
891 | struct ifnet *ifp) | |
9bccf70c A |
892 | { |
893 | struct in6pcb *in6p; | |
894 | struct ip6_moptions *im6o; | |
895 | struct in6_multi_mship *imm, *nimm; | |
896 | ||
897 | for (in6p = head; in6p != NULL; in6p = LIST_NEXT(in6p, inp_list)) { | |
898 | im6o = in6p->in6p_moptions; | |
899 | if ((in6p->inp_vflag & INP_IPV6) && | |
900 | im6o) { | |
901 | /* | |
902 | * Unselect the outgoing interface if it is being | |
903 | * detached. | |
904 | */ | |
905 | if (im6o->im6o_multicast_ifp == ifp) | |
906 | im6o->im6o_multicast_ifp = NULL; | |
907 | ||
908 | /* | |
909 | * Drop multicast group membership if we joined | |
910 | * through the interface being detached. | |
911 | * XXX controversial - is it really legal for kernel | |
912 | * to force this? | |
913 | */ | |
914 | for (imm = im6o->im6o_memberships.lh_first; | |
915 | imm != NULL; imm = nimm) { | |
916 | nimm = imm->i6mm_chain.le_next; | |
917 | if (imm->i6mm_maddr->in6m_ifp == ifp) { | |
918 | LIST_REMOVE(imm, i6mm_chain); | |
919 | in6_delmulti(imm->i6mm_maddr); | |
920 | FREE(imm, M_IPMADDR); | |
921 | } | |
922 | } | |
923 | } | |
924 | } | |
925 | } | |
91447636 | 926 | #endif |
9bccf70c | 927 | |
1c79356b A |
928 | /* |
929 | * Check for alternatives when higher level complains | |
930 | * about service problems. For now, invalidate cached | |
931 | * routing information. If the route was created dynamically | |
932 | * (by a redirect), time to try a default gateway again. | |
933 | */ | |
934 | void | |
935 | in6_losing(in6p) | |
936 | struct inpcb *in6p; | |
937 | { | |
938 | struct rtentry *rt; | |
939 | struct rt_addrinfo info; | |
940 | ||
941 | if ((rt = in6p->in6p_route.ro_rt) != NULL) { | |
b0d623f7 A |
942 | in6p->in6p_route.ro_rt = NULL; |
943 | RT_LOCK(rt); | |
1c79356b A |
944 | bzero((caddr_t)&info, sizeof(info)); |
945 | info.rti_info[RTAX_DST] = | |
946 | (struct sockaddr *)&in6p->in6p_route.ro_dst; | |
947 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; | |
948 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); | |
949 | rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); | |
b0d623f7 A |
950 | if (rt->rt_flags & RTF_DYNAMIC) { |
951 | /* | |
952 | * Prevent another thread from modifying rt_key, | |
953 | * rt_gateway via rt_setgate() after the rt_lock | |
954 | * is dropped by marking the route as defunct. | |
955 | */ | |
956 | rt->rt_flags |= RTF_CONDEMNED; | |
957 | RT_UNLOCK(rt); | |
958 | (void) rtrequest(RTM_DELETE, rt_key(rt), | |
959 | rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); | |
960 | } else { | |
961 | RT_UNLOCK(rt); | |
962 | } | |
1c79356b A |
963 | /* |
964 | * A new route can be allocated | |
965 | * the next time output is attempted. | |
966 | */ | |
b0d623f7 | 967 | rtfree(rt); |
1c79356b A |
968 | } |
969 | } | |
970 | ||
971 | /* | |
972 | * After a routing change, flush old routing | |
973 | * and allocate a (hopefully) better one. | |
974 | */ | |
975 | void | |
91447636 A |
976 | in6_rtchange( |
977 | struct inpcb *inp, | |
2d21ac55 | 978 | __unused int errno) |
1c79356b A |
979 | { |
980 | if (inp->in6p_route.ro_rt) { | |
981 | rtfree(inp->in6p_route.ro_rt); | |
982 | inp->in6p_route.ro_rt = 0; | |
983 | /* | |
984 | * A new route can be allocated the next time | |
985 | * output is attempted. | |
986 | */ | |
987 | } | |
988 | } | |
989 | ||
990 | /* | |
991 | * Lookup PCB in hash list. | |
992 | */ | |
993 | struct inpcb * | |
91447636 A |
994 | in6_pcblookup_hash( |
995 | struct inpcbinfo *pcbinfo, | |
996 | struct in6_addr *faddr, | |
997 | u_int fport_arg, | |
998 | struct in6_addr *laddr, | |
999 | u_int lport_arg, | |
1000 | int wildcard, | |
2d21ac55 | 1001 | __unused struct ifnet *ifp) |
1c79356b A |
1002 | { |
1003 | struct inpcbhead *head; | |
91447636 | 1004 | struct inpcb *inp; |
1c79356b | 1005 | u_short fport = fport_arg, lport = lport_arg; |
9bccf70c A |
1006 | int faith; |
1007 | ||
1008 | #if defined(NFAITH) && NFAITH > 0 | |
1009 | faith = faithprefix(laddr); | |
1010 | #else | |
1011 | faith = 0; | |
1012 | #endif | |
1c79356b | 1013 | |
91447636 A |
1014 | lck_rw_lock_shared(pcbinfo->mtx); |
1015 | ||
1c79356b A |
1016 | /* |
1017 | * First look for an exact match. | |
1018 | */ | |
1019 | head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, | |
1020 | lport, fport, | |
1021 | pcbinfo->hashmask)]; | |
9bccf70c | 1022 | LIST_FOREACH(inp, head, inp_hash) { |
1c79356b A |
1023 | if ((inp->inp_vflag & INP_IPV6) == 0) |
1024 | continue; | |
1025 | if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) && | |
1026 | IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && | |
1027 | inp->inp_fport == fport && | |
1028 | inp->inp_lport == lport) { | |
1029 | /* | |
91447636 A |
1030 | * Found. Check if pcb is still valid |
1031 | */ | |
1032 | if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) != WNT_STOPUSING) { | |
1033 | lck_rw_done(pcbinfo->mtx); | |
1034 | return (inp); | |
1035 | } | |
1036 | else { /* it's there but dead, say it isn't found */ | |
1037 | lck_rw_done(pcbinfo->mtx); | |
1038 | return(NULL); | |
1039 | } | |
1c79356b A |
1040 | } |
1041 | } | |
1042 | if (wildcard) { | |
1043 | struct inpcb *local_wild = NULL; | |
1044 | ||
1045 | head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, | |
1046 | pcbinfo->hashmask)]; | |
9bccf70c | 1047 | LIST_FOREACH(inp, head, inp_hash) { |
1c79356b A |
1048 | if ((inp->inp_vflag & INP_IPV6) == 0) |
1049 | continue; | |
1050 | if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && | |
1051 | inp->inp_lport == lport) { | |
9bccf70c | 1052 | if (faith && (inp->inp_flags & INP_FAITH) == 0) |
1c79356b | 1053 | continue; |
1c79356b | 1054 | if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, |
91447636 A |
1055 | laddr)) { |
1056 | if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) != WNT_STOPUSING) { | |
1057 | lck_rw_done(pcbinfo->mtx); | |
1058 | return (inp); | |
1059 | } | |
1060 | else { /* it's there but dead, say it isn't found */ | |
1061 | lck_rw_done(pcbinfo->mtx); | |
1062 | return(NULL); | |
1063 | } | |
1064 | } | |
1c79356b A |
1065 | else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) |
1066 | local_wild = inp; | |
1067 | } | |
1068 | } | |
91447636 A |
1069 | if (local_wild && in_pcb_checkstate(local_wild, WNT_ACQUIRE, 0) != WNT_STOPUSING) { |
1070 | lck_rw_done(pcbinfo->mtx); | |
1071 | return (local_wild); | |
1072 | } | |
1073 | else { | |
1074 | lck_rw_done(pcbinfo->mtx); | |
1075 | return (NULL); | |
1076 | } | |
1c79356b A |
1077 | } |
1078 | ||
1079 | /* | |
1080 | * Not found. | |
1081 | */ | |
91447636 | 1082 | lck_rw_done(pcbinfo->mtx); |
1c79356b A |
1083 | return (NULL); |
1084 | } | |
1085 | ||
1086 | void | |
1087 | init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m) | |
1088 | { | |
1089 | struct ip6_hdr *ip; | |
1090 | ||
1091 | ip = mtod(m, struct ip6_hdr *); | |
1092 | bzero(sin6, sizeof(*sin6)); | |
1093 | sin6->sin6_len = sizeof(*sin6); | |
1094 | sin6->sin6_family = AF_INET6; | |
1095 | sin6->sin6_addr = ip->ip6_src; | |
1096 | if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) | |
1097 | sin6->sin6_addr.s6_addr16[1] = 0; | |
1098 | sin6->sin6_scope_id = | |
1099 | (m->m_pkthdr.rcvif && IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) | |
1100 | ? m->m_pkthdr.rcvif->if_index : 0; | |
1101 | ||
1102 | return; | |
1103 | } |