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