X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552..13f56ec4e58bf8687e2a68032c093c0213dd519b:/bsd/netinet6/udp6_output.c?ds=sidebyside diff --git a/bsd/netinet6/udp6_output.c b/bsd/netinet6/udp6_output.c index 8d8c6df34..0fb9a6993 100644 --- a/bsd/netinet6/udp6_output.c +++ b/bsd/netinet6/udp6_output.c @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2000-2011 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + + /* $FreeBSD: src/sys/netinet6/udp6_output.c,v 1.1.2.3 2001/08/31 13:49:58 jlemon Exp $ */ /* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */ @@ -78,9 +107,12 @@ #include #include +#include + #include #include #include +#include #include #include @@ -118,6 +150,21 @@ extern int ipsec_bypass; #define udp6stat udpstat #define udp6s_opackets udps_opackets +static __inline__ u_int16_t +get_socket_id(struct socket * s) +{ + u_int16_t val; + + if (s == NULL) { + return (0); + } + val = (u_int16_t)(((uintptr_t)s) / sizeof(struct socket)); + if (val == 0) { + val = 0xffff; + } + return (val); +} + int udp6_output(in6p, m, addr6, control, p) struct in6pcb *in6p; @@ -133,24 +180,28 @@ udp6_output(in6p, m, addr6, control, p) struct in6_addr *laddr, *faddr; u_short fport; int error = 0; - struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; - int priv; + struct ip6_pktopts opt, *optp = NULL; + struct ip6_moptions *im6o; int af = AF_INET6, hlen = sizeof(struct ip6_hdr); int flags; struct sockaddr_in6 tmp; + struct in6_addr storage; + mbuf_traffic_class_t mtc = MBUF_TC_UNSPEC; + struct ip6_out_args ip6oa = { IFSCOPE_NONE, 0 }; + + if (in6p->inp_flags & INP_BOUND_IF) + ip6oa.ip6oa_boundif = in6p->inp_boundif; + + ip6oa.ip6oa_nocell = (in6p->inp_flags & INP_NO_IFT_CELLULAR) ? 1 : 0; - priv = 0; -#ifdef __APPLE__ - if (p && !suser(p->p_ucred, &p->p_acflag)) -#else - if (p && !suser(p)) -#endif - priv = 1; if (control) { - if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) + mtc = mbuf_traffic_class_from_control(control); + + if ((error = ip6_setpktopts(control, &opt, NULL, IPPROTO_UDP)) != 0) goto release; - in6p->in6p_outputopts = &opt; - } + optp = &opt; + } else + optp = in6p->in6p_outputopts; if (addr6) { /* @@ -199,16 +250,16 @@ udp6_output(in6p, m, addr6, control, p) } /* KAME hack: embed scopeid */ - if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) { + if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL, + optp) != 0) { error = EINVAL; goto release; } if (!IN6_IS_ADDR_V4MAPPED(faddr)) { - laddr = in6_selectsrc(sin6, in6p->in6p_outputopts, - in6p->in6p_moptions, - &in6p->in6p_route, - &in6p->in6p_laddr, &error); + laddr = in6_selectsrc(sin6, optp, + in6p, &in6p->in6p_route, NULL, &storage, + ip6oa.ip6oa_boundif, &error); } else laddr = &in6p->in6p_laddr; /* XXX */ if (laddr == NULL) { @@ -217,7 +268,7 @@ udp6_output(in6p, m, addr6, control, p) goto release; } if (in6p->in6p_lport == 0 && - (error = in6_pcbsetport(laddr, in6p, p)) != 0) + (error = in6_pcbsetport(laddr, in6p, p, 0)) != 0) goto release; } else { if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { @@ -286,12 +337,12 @@ udp6_output(in6p, m, addr6, control, p) ip6->ip6_src = *laddr; ip6->ip6_dst = *faddr; - if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, - sizeof(struct ip6_hdr), plen)) == 0) { - udp6->uh_sum = 0xffff; - } + udp6->uh_sum = in6_cksum_phdr(laddr, faddr, + htonl(plen), htonl(IPPROTO_UDP)); + m->m_pkthdr.csum_flags = CSUM_UDPIPV6; + m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); - flags = 0; + flags = IPV6_OUTARGS; udp6stat.udp6s_opackets++; #ifdef IPSEC @@ -300,8 +351,51 @@ udp6_output(in6p, m, addr6, control, p) goto release; } #endif /*IPSEC*/ - error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, - flags, in6p->in6p_moptions, NULL); + m->m_pkthdr.socket_id = get_socket_id(in6p->in6p_socket); + + set_packet_tclass(m, in6p->in6p_socket, mtc, 1); + + im6o = in6p->in6p_moptions; + if (im6o != NULL) + IM6O_ADDREF(im6o); + + error = ip6_output(m, optp, &in6p->in6p_route, + flags, im6o, NULL, &ip6oa); + + if (im6o != NULL) + IM6O_REMREF(im6o); + + if (error == 0 && nstat_collect) { + locked_add_64(&in6p->inp_stat->txpackets, 1); + locked_add_64(&in6p->inp_stat->txbytes, ulen); + } + + if (in6p->in6p_route.ro_rt != NULL) { + struct rtentry *rt = in6p->in6p_route.ro_rt; + unsigned int outif; + + if ((rt->rt_flags & RTF_MULTICAST) || + in6p->in6p_socket == NULL || + !(in6p->in6p_socket->so_state & SS_ISCONNECTED)) { + rt = NULL; /* unusable */ + } + /* + * Always discard the cached route for unconnected + * socket or if it is a multicast route. + */ + if (rt == NULL) { + rtfree(in6p->in6p_route.ro_rt); + in6p->in6p_route.ro_rt = NULL; + } + /* + * If this is a connected socket and the destination + * route is not multicast, update outif with that of + * the route interface index used by IP. + */ + if (rt != NULL && (outif = rt->rt_ifp->if_index) != + in6p->in6p_last_outif) + in6p->in6p_last_outif = outif; + } break; case AF_INET: error = EAFNOSUPPORT; @@ -314,8 +408,8 @@ release: releaseopt: if (control) { - ip6_clearpktopts(in6p->in6p_outputopts, 0, -1); - in6p->in6p_outputopts = stickyopt; + if (optp == &opt) + ip6_clearpktopts(optp, -1); m_freem(control); } return(error);