X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8f6c56a50524aa785f7e596d52dddfb331e18961..ca66cea69e6e866fd781ae2260d9474bdd48f2ca:/bsd/netinet6/in6_pcb.c diff --git a/bsd/netinet6/in6_pcb.c b/bsd/netinet6/in6_pcb.c index 3c28774df..f98b3d35f 100644 --- a/bsd/netinet6/in6_pcb.c +++ b/bsd/netinet6/in6_pcb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2003-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -121,11 +121,6 @@ #include #include -#include "faith.h" -#if defined(NFAITH) && NFAITH > 0 -#include -#endif - #if IPSEC #include #if INET6 @@ -136,11 +131,48 @@ #include #endif #include -extern lck_mtx_t *sadb_mutex; #endif /* IPSEC */ struct in6_addr zeroin6_addr; +/* + in6_pcblookup_local_and_cleanup does everything + in6_pcblookup_local does but it checks for a socket + that's going away. Since we know that the lock is + held read+write when this function is called, we + can safely dispose of this socket like the slow + timer would usually do and return NULL. This is + great for bind. +*/ +static struct inpcb* +in6_pcblookup_local_and_cleanup( + struct inpcbinfo *pcbinfo, + struct in6_addr *laddr, + u_int lport_arg, + int wild_okay) +{ + struct inpcb *inp; + + /* Perform normal lookup */ + inp = in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay); + + /* Check if we found a match but it's waiting to be disposed */ + if (inp && inp->inp_wantcnt == WNT_STOPUSING) { + struct socket *so = inp->inp_socket; + + lck_mtx_lock(inp->inpcb_mtx); + + if (so->so_usecount == 0) { + in_pcbdispose(inp); + inp = NULL; + } + else { + lck_mtx_unlock(inp->inpcb_mtx); + } + } + + return inp; +} int in6_pcbbind( struct inpcb *inp, @@ -237,7 +269,7 @@ in6_pcbbind( if (so->so_uid && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { - t = in6_pcblookup_local(pcbinfo, + t = in6_pcblookup_local_and_cleanup(pcbinfo, &sin6->sin6_addr, lport, INPLOOKUP_WILDCARD); if (t && @@ -245,7 +277,8 @@ in6_pcbbind( !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || (t->inp_socket->so_options & SO_REUSEPORT) == 0) && - so->so_uid != t->inp_socket->so_uid) { + (so->so_uid != t->inp_socket->so_uid) && + ((t->inp_socket->so_flags & SOF_REUSESHAREUID) == 0)) { lck_rw_done(pcbinfo->mtx); socket_lock(so, 0); return (EADDRINUSE); @@ -255,10 +288,10 @@ in6_pcbbind( struct sockaddr_in sin; in6_sin6_2_sin(&sin, sin6); - t = in_pcblookup_local(pcbinfo, + t = in_pcblookup_local_and_cleanup(pcbinfo, sin.sin_addr, lport, INPLOOKUP_WILDCARD); - if (t && + if (t && (t->inp_socket->so_options & SO_REUSEPORT) == 0 && (so->so_uid != t->inp_socket->so_uid) && (ntohl(t->inp_laddr.s_addr) != @@ -272,7 +305,7 @@ in6_pcbbind( } } } - t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, + t = in6_pcblookup_local_and_cleanup(pcbinfo, &sin6->sin6_addr, lport, wild); if (t && (reuseport & t->inp_socket->so_options) == 0) { lck_rw_done(pcbinfo->mtx); @@ -284,7 +317,7 @@ in6_pcbbind( struct sockaddr_in sin; in6_sin6_2_sin(&sin, sin6); - t = in_pcblookup_local(pcbinfo, sin.sin_addr, + t = in_pcblookup_local_and_cleanup(pcbinfo, sin.sin_addr, lport, wild); if (t && (reuseport & t->inp_socket->so_options) @@ -319,6 +352,7 @@ in6_pcbbind( } } lck_rw_done(pcbinfo->mtx); + sflt_notify(so, sock_evt_bound, NULL); return(0); } @@ -558,7 +592,7 @@ in6_selectsrc( struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL; if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) { - ifp = &loif[0]; + ifp = lo_ifp; } if (ifp) { @@ -623,8 +657,8 @@ in6_selectsrc( dst6->sin6_len = sizeof(struct sockaddr_in6); dst6->sin6_addr = *dst; if (IN6_IS_ADDR_MULTICAST(dst)) { - ro->ro_rt = rtalloc1(&((struct route *)ro) - ->ro_dst, 0, 0UL); + ro->ro_rt = + rtalloc1(&((struct route *)ro)->ro_dst, 0, 0UL); } else { rtalloc((struct route *)ro); } @@ -707,14 +741,12 @@ in6_pcbdetach(inp) #if IPSEC if (inp->in6p_sp != NULL) { - lck_mtx_lock(sadb_mutex); ipsec6_delete_pcbpolicy(inp); - lck_mtx_unlock(sadb_mutex); } #endif /* IPSEC */ if (in_pcb_checkstate(inp, WNT_STOPUSING, 1) != WNT_STOPUSING) - printf("in6_pcbdetach so=%x can't be marked dead ok\n", so); + printf("in6_pcbdetach so=%p can't be marked dead ok\n", so); inp->inp_state = INPCB_STATE_DEAD; @@ -1144,7 +1176,7 @@ in6_losing(in6p) void in6_rtchange( struct inpcb *inp, - int errno) + __unused int errno) { if (inp->in6p_route.ro_rt) { rtfree(inp->in6p_route.ro_rt); @@ -1167,7 +1199,7 @@ in6_pcblookup_hash( struct in6_addr *laddr, u_int lport_arg, int wildcard, - struct ifnet *ifp) + __unused struct ifnet *ifp) { struct inpcbhead *head; struct inpcb *inp;