+/*
+ * 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 $ */
#include <sys/proc.h>
#include <sys/syslog.h>
+#include <machine/endian.h>
+
#include <net/if.h>
#include <net/route.h>
#include <net/if_types.h>
+#include <net/ntstat.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
if (s == NULL) {
return (0);
}
- val = (u_int16_t)(((u_int32_t)s) / sizeof(struct socket));
+ val = (u_int16_t)(((uintptr_t)s) / sizeof(struct socket));
if (val == 0) {
val = 0xffff;
}
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 && !proc_suser(p))
-#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) {
/*
}
/* 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, &storage, &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) {
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
}
#endif /*IPSEC*/
m->m_pkthdr.socket_id = get_socket_id(in6p->in6p_socket);
- error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
- flags, in6p->in6p_moptions, NULL, 0);
+
+ 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;
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);