/*
- * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
if (inp != NULL && inp->inp_wantcnt == WNT_STOPUSING) {
struct socket *so = inp->inp_socket;
- lck_mtx_lock(&inp->inpcb_mtx);
+ socket_lock(so, 0);
if (so->so_usecount == 0) {
if (inp->inp_state != INPCB_STATE_DEAD)
in_pcbdispose(inp); /* will unlock & destroy */
inp = NULL;
} else {
- lck_mtx_unlock(&inp->inpcb_mtx);
+ socket_unlock(so, 0);
}
}
int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
struct ifnet *outif = NULL;
struct sockaddr_in6 sin6;
+#if !CONFIG_EMBEDDED
int error;
kauth_cred_t cred;
+#endif /* !CONFIG_EMBEDDED */
if (!in6_ifaddrs) /* XXX broken! */
return (EADDRNOTAVAIL);
- if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
- return (EINVAL);
if (!(so->so_options & (SO_REUSEADDR|SO_REUSEPORT)))
wild = 1;
+
socket_unlock(so, 0); /* keep reference */
lck_rw_lock_exclusive(pcbinfo->ipi_lock);
+ if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
+ /* another thread completed the bind */
+ lck_rw_done(pcbinfo->ipi_lock);
+ socket_lock(so, 0);
+ return (EINVAL);
+ }
bzero(&sin6, sizeof (sin6));
if (nam != NULL) {
*/
IFA_LOCK_SPIN(ifa);
if (((struct in6_ifaddr *)ifa)->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
- IN6_IFF_DETACHED)) {
+ (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY|
+ IN6_IFF_DETACHED | IN6_IFF_CLAT46)) {
IFA_UNLOCK(ifa);
IFA_REMREF(ifa);
lck_rw_done(pcbinfo->ipi_lock);
struct inpcb *t;
uid_t u;
- /* GROSS */
- if (ntohs(lport) < IPV6PORT_RESERVED) {
+#if !CONFIG_EMBEDDED
+ if (ntohs(lport) < IPV6PORT_RESERVED &&
+ !IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
cred = kauth_cred_proc_ref(p);
error = priv_check_cred(cred,
PRIV_NETINET_RESERVEDPORT, 0);
return (EACCES);
}
}
+#endif /* !CONFIG_EMBEDDED */
if (!IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr) &&
(u = kauth_cred_getuid(so->so_cred)) != 0) {
t = in6_pcblookup_local_and_cleanup(pcbinfo,
}
socket_lock(so, 0);
+ /*
+ * We unlocked socket's protocol lock for a long time.
+ * The socket might have been dropped/defuncted.
+ * Checking if world has changed since.
+ */
+ if (inp->inp_state == INPCB_STATE_DEAD) {
+ lck_rw_done(pcbinfo->ipi_lock);
+ return (ECONNABORTED);
+ }
+
/* check if the socket got bound when the lock was released */
if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
lck_rw_done(pcbinfo->ipi_lock);
struct ifnet *outif = NULL;
struct socket *so = inp->inp_socket;
+#if CONTENT_FILTER
+ if (so)
+ so->so_state_change_cnt++;
+#endif
+
+ if (so->so_proto->pr_protocol == IPPROTO_UDP &&
+ sin6->sin6_port == htons(53) && !(so->so_flags1 & SOF1_DNS_COUNTED)) {
+ so->so_flags1 |= SOF1_DNS_COUNTED;
+ INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_inet_dgram_dns);
+ }
+
/*
* Call inner routine, to assign local interface address.
* in6_pcbladdr() may automatically fill in sin6_scope_id.
{
struct socket *so = inp->inp_socket;
+#if CONTENT_FILTER
+ if (so)
+ so->so_state_change_cnt++;
+#endif
+
if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->ipi_lock)) {
/* lock inversion issue, mostly with udp multicast packets */
socket_unlock(so, 0);
inp, so, SOCK_PROTO(so));
/* NOTREACHED */
}
-
+
#if IPSEC
if (inp->in6p_sp != NULL) {
(void) ipsec6_delete_pcbpolicy(inp);
}
#endif /* IPSEC */
+ if (inp->inp_stat != NULL && SOCK_PROTO(so) == IPPROTO_UDP) {
+ if (inp->inp_stat->rxpackets == 0 && inp->inp_stat->txpackets == 0) {
+ INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_inet6_dgram_no_data);
+ }
+ }
+
/*
* Let NetworkStatistics know this PCB is going away
* before we detach it.
}
im6o = inp->in6p_moptions;
inp->in6p_moptions = NULL;
- if (im6o != NULL)
- IM6O_REMREF(im6o);
imo = inp->inp_moptions;
inp->inp_moptions = NULL;
- if (imo != NULL)
- IMO_REMREF(imo);
+
sofreelastref(so, 0);
inp->inp_state = INPCB_STATE_DEAD;
/* makes sure we're not called twice from so_close */
so->so_flags |= SOF_PCBCLEARING;
-
+
inpcb_gc_sched(inp->inp_pcbinfo, INPCB_TIMER_FAST);
+
+ /*
+ * See inp_join_group() for why we need to unlock
+ */
+ if (im6o != NULL || imo != NULL) {
+ socket_unlock(so, 0);
+ if (im6o != NULL)
+ IM6O_REMREF(im6o);
+ if (imo != NULL)
+ IMO_REMREF(imo);
+ socket_lock(so, 0);
+ }
}
}
}
int
-in6_getsockaddr_s(struct socket *so, struct sockaddr_storage *ss)
+in6_getsockaddr_s(struct socket *so, struct sockaddr_in6 *ss)
{
struct inpcb *inp;
struct in6_addr addr;
VERIFY(ss != NULL);
bzero(ss, sizeof (*ss));
- if ((inp = sotoinpcb(so)) == NULL
-#if NECP
- || (necp_socket_should_use_flow_divert(inp))
-#endif /* NECP */
- )
- return (inp == NULL ? EINVAL : EPROTOTYPE);
+ if ((inp = sotoinpcb(so)) == NULL)
+ return (EINVAL);
port = inp->inp_lport;
addr = inp->in6p_laddr;
- in6_sockaddr_s(port, &addr, SIN6(ss));
+ in6_sockaddr_s(port, &addr, ss);
return (0);
}
return (0);
}
-int
-in6_getpeeraddr_s(struct socket *so, struct sockaddr_storage *ss)
-{
- struct inpcb *inp;
- struct in6_addr addr;
- in_port_t port;
-
- VERIFY(ss != NULL);
- bzero(ss, sizeof (*ss));
-
- if ((inp = sotoinpcb(so)) == NULL
-#if NECP
- || (necp_socket_should_use_flow_divert(inp))
-#endif /* NECP */
- )
- return (inp == NULL ? EINVAL : EPROTOTYPE);
-
- port = inp->inp_fport;
- addr = inp->in6p_faddr;
-
- in6_sockaddr_s(port, &addr, SIN6(ss));
- return (0);
-}
-
int
in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam)
{
u_int32_t flowinfo;
int errno;
- if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
+ if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6)
return;
sa6_dst = (struct sockaddr_in6 *)(void *)dst;
* sockets disconnected.
* XXX: should we avoid to notify the value to TCP sockets?
*/
- if (cmd == PRC_MSGSIZE && (inp->inp_flags & IN6P_MTU) != 0 &&
- (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
- IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,
- &sa6_dst->sin6_addr))) {
+ if (cmd == PRC_MSGSIZE)
ip6_notify_pmtu(inp, (struct sockaddr_in6 *)(void *)dst,
(u_int32_t *)cmdarg);
- }
/*
* Detect if we should notify the error. If no source and
in6_losing(struct inpcb *in6p)
{
struct rtentry *rt;
- struct rt_addrinfo info;
if ((rt = in6p->in6p_route.ro_rt) != NULL) {
RT_LOCK(rt);
- bzero((caddr_t)&info, sizeof (info));
- info.rti_info[RTAX_DST] =
- (struct sockaddr *)&in6p->in6p_route.ro_dst;
- info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
- info.rti_info[RTAX_NETMASK] = rt_mask(rt);
- rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
if (rt->rt_flags & RTF_DYNAMIC) {
/*
* Prevent another thread from modifying rt_key,
{
struct route_in6 *src = &inp->in6p_route;
- lck_mtx_assert(&inp->inpcb_mtx, LCK_MTX_ASSERT_OWNED);
+ socket_lock_assert_owned(inp->inp_socket);
/* Minor sanity check */
if (src->ro_rt != NULL && rt_key(src->ro_rt)->sa_family != AF_INET6)
{
struct route_in6 *dst = &inp->in6p_route;
- lck_mtx_assert(&inp->inpcb_mtx, LCK_MTX_ASSERT_OWNED);
+ socket_lock_assert_owned(inp->inp_socket);
/* Minor sanity check */
if (src->ro_rt != NULL && rt_key(src->ro_rt)->sa_family != AF_INET6)