]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/udp6_output.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / bsd / netinet6 / udp6_output.c
CommitLineData
b0d623f7 1/*
d1ecb069 2 * Copyright (c) 2009 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
9bccf70c
A
30/* $FreeBSD: src/sys/netinet6/udp6_output.c,v 1.1.2.3 2001/08/31 13:49:58 jlemon Exp $ */
31/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */
32
33/*
34 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the project nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62/*
63 * Copyright (c) 1982, 1986, 1989, 1993
64 * The Regents of the University of California. All rights reserved.
65 *
66 * Redistribution and use in source and binary forms, with or without
67 * modification, are permitted provided that the following conditions
68 * are met:
69 * 1. Redistributions of source code must retain the above copyright
70 * notice, this list of conditions and the following disclaimer.
71 * 2. Redistributions in binary form must reproduce the above copyright
72 * notice, this list of conditions and the following disclaimer in the
73 * documentation and/or other materials provided with the distribution.
74 * 3. All advertising materials mentioning features or use of this software
75 * must display the following acknowledgement:
76 * This product includes software developed by the University of
77 * California, Berkeley and its contributors.
78 * 4. Neither the name of the University nor the names of its contributors
79 * may be used to endorse or promote products derived from this software
80 * without specific prior written permission.
81 *
82 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
83 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
84 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
85 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
86 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
87 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
88 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
90 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
91 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
92 * SUCH DAMAGE.
93 *
94 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
95 */
96
97#include <sys/param.h>
98#include <sys/malloc.h>
99#include <sys/mbuf.h>
100#include <sys/protosw.h>
101#include <sys/socket.h>
102#include <sys/socketvar.h>
103#include <sys/sysctl.h>
104#include <sys/errno.h>
105#include <sys/stat.h>
106#include <sys/systm.h>
107#include <sys/proc.h>
108#include <sys/syslog.h>
109
110#include <net/if.h>
111#include <net/route.h>
112#include <net/if_types.h>
113
114#include <netinet/in.h>
115#include <netinet/in_var.h>
116#include <netinet/in_systm.h>
117#include <netinet/ip.h>
118#include <netinet/ip_var.h>
119#include <netinet/in_pcb.h>
120#include <netinet/udp.h>
121#include <netinet/udp_var.h>
122#include <netinet/ip6.h>
123#include <netinet6/ip6_var.h>
124#include <netinet6/in6_pcb.h>
125#include <netinet6/udp6_var.h>
126#include <netinet/icmp6.h>
127#include <netinet6/ip6protosw.h>
128
129#ifdef IPSEC
130#include <netinet6/ipsec.h>
131#ifdef INET6
132#include <netinet6/ipsec6.h>
133#endif
134extern int ipsec_bypass;
135#endif /*IPSEC*/
136
137#include "faith.h"
138
139#include <net/net_osdep.h>
140
141/*
142 * UDP protocol inplementation.
143 * Per RFC 768, August, 1980.
144 */
145
146#define in6pcb inpcb
147#define udp6stat udpstat
148#define udp6s_opackets udps_opackets
149
91447636
A
150static __inline__ u_int16_t
151get_socket_id(struct socket * s)
152{
153 u_int16_t val;
154
155 if (s == NULL) {
156 return (0);
157 }
b0d623f7 158 val = (u_int16_t)(((uintptr_t)s) / sizeof(struct socket));
91447636
A
159 if (val == 0) {
160 val = 0xffff;
161 }
162 return (val);
163}
164
9bccf70c
A
165int
166udp6_output(in6p, m, addr6, control, p)
167 struct in6pcb *in6p;
168 struct mbuf *m;
169 struct mbuf *control;
170 struct sockaddr *addr6;
171 struct proc *p;
172{
173 u_int32_t ulen = m->m_pkthdr.len;
174 u_int32_t plen = sizeof(struct udphdr) + ulen;
175 struct ip6_hdr *ip6;
176 struct udphdr *udp6;
177 struct in6_addr *laddr, *faddr;
178 u_short fport;
179 int error = 0;
180 struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
181 int priv;
182 int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
183 int flags;
184 struct sockaddr_in6 tmp;
91447636 185 struct in6_addr storage;
9bccf70c 186
b0d623f7
A
187 priv = (proc_suser(p) == 0);
188
9bccf70c
A
189 if (control) {
190 if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
191 goto release;
192 in6p->in6p_outputopts = &opt;
193 }
194
195 if (addr6) {
196 /*
197 * IPv4 version of udp_output calls in_pcbconnect in this case,
198 * which needs splnet and affects performance.
199 * Since we saw no essential reason for calling in_pcbconnect,
200 * we get rid of such kind of logic, and call in6_selectsrc
201 * and in6_pcbsetport in order to fill in the local address
202 * and the local port.
203 */
204 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr6;
205 if (sin6->sin6_port == 0) {
206 error = EADDRNOTAVAIL;
207 goto release;
208 }
209
210 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
211 /* how about ::ffff:0.0.0.0 case? */
212 error = EISCONN;
213 goto release;
214 }
215
216 /* protect *sin6 from overwrites */
217 tmp = *sin6;
218 sin6 = &tmp;
219
220 faddr = &sin6->sin6_addr;
221 fport = sin6->sin6_port; /* allow 0 port */
222
223 if (IN6_IS_ADDR_V4MAPPED(faddr)) {
224 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
225 /*
226 * I believe we should explicitly discard the
227 * packet when mapped addresses are disabled,
228 * rather than send the packet as an IPv6 one.
229 * If we chose the latter approach, the packet
230 * might be sent out on the wire based on the
231 * default route, the situation which we'd
232 * probably want to avoid.
233 * (20010421 jinmei@kame.net)
234 */
235 error = EINVAL;
236 goto release;
237 } else
238 af = AF_INET;
239 }
240
241 /* KAME hack: embed scopeid */
242 if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
243 error = EINVAL;
244 goto release;
245 }
246
247 if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
248 laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
249 in6p->in6p_moptions,
250 &in6p->in6p_route,
91447636 251 &in6p->in6p_laddr, &storage, &error);
9bccf70c
A
252 } else
253 laddr = &in6p->in6p_laddr; /* XXX */
254 if (laddr == NULL) {
255 if (error == 0)
256 error = EADDRNOTAVAIL;
257 goto release;
258 }
259 if (in6p->in6p_lport == 0 &&
91447636 260 (error = in6_pcbsetport(laddr, in6p, p, 0)) != 0)
9bccf70c
A
261 goto release;
262 } else {
263 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
264 error = ENOTCONN;
265 goto release;
266 }
267 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
268 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
269 /*
270 * XXX: this case would happen when the
271 * application sets the V6ONLY flag after
272 * connecting the foreign address.
273 * Such applications should be fixed,
274 * so we bark here.
275 */
276 log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
277 "option was set for a connected socket\n");
278 error = EINVAL;
279 goto release;
280 } else
281 af = AF_INET;
282 }
283 laddr = &in6p->in6p_laddr;
284 faddr = &in6p->in6p_faddr;
285 fport = in6p->in6p_fport;
286 }
287
288 if (af == AF_INET)
289 hlen = sizeof(struct ip);
290
291 /*
292 * Calculate data length and get a mbuf
293 * for UDP and IP6 headers.
294 */
295 M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
296 if (m == 0) {
297 error = ENOBUFS;
298 goto release;
299 }
300
301 /*
302 * Stuff checksum and output datagram.
303 */
304 udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
305 udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
306 udp6->uh_dport = fport;
307 if (plen <= 0xffff)
308 udp6->uh_ulen = htons((u_short)plen);
309 else
310 udp6->uh_ulen = 0;
311 udp6->uh_sum = 0;
312
313 switch (af) {
314 case AF_INET6:
315 ip6 = mtod(m, struct ip6_hdr *);
316 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
317 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
318 ip6->ip6_vfc |= IPV6_VERSION;
319#if 0 /* ip6_plen will be filled in ip6_output. */
320 ip6->ip6_plen = htons((u_short)plen);
321#endif
322 ip6->ip6_nxt = IPPROTO_UDP;
323 ip6->ip6_hlim = in6_selecthlim(in6p,
324 in6p->in6p_route.ro_rt ?
325 in6p->in6p_route.ro_rt->rt_ifp : NULL);
326 ip6->ip6_src = *laddr;
327 ip6->ip6_dst = *faddr;
328
329 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
330 sizeof(struct ip6_hdr), plen)) == 0) {
331 udp6->uh_sum = 0xffff;
332 }
333
334 flags = 0;
335
336 udp6stat.udp6s_opackets++;
337#ifdef IPSEC
338 if (ipsec_bypass == 0 && ipsec_setsocket(m, in6p->in6p_socket) != 0) {
339 error = ENOBUFS;
340 goto release;
341 }
342#endif /*IPSEC*/
91447636 343 m->m_pkthdr.socket_id = get_socket_id(in6p->in6p_socket);
d1ecb069
A
344#if PKT_PRIORITY
345 if (soisbackground(in6p->in6p_socket))
346 m_prio_background(m);
347#endif /* PKT_PRIORITY */
9bccf70c 348 error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
91447636 349 flags, in6p->in6p_moptions, NULL, 0);
d1ecb069
A
350
351#if IFNET_ROUTE_REFCNT
352 /*
353 * Always discard the cached route for unconnected socket
354 * or if it is a multicast route.
355 */
356 if (in6p->in6p_route.ro_rt != NULL &&
357 ((in6p->in6p_route.ro_rt->rt_flags & RTF_MULTICAST) ||
358 in6p->in6p_socket == NULL ||
359 in6p->in6p_socket->so_state != SS_ISCONNECTED)) {
360 rtfree(in6p->in6p_route.ro_rt);
361 in6p->in6p_route.ro_rt = NULL;
362 }
363#endif /* IFNET_ROUTE_REFCNT */
9bccf70c
A
364 break;
365 case AF_INET:
366 error = EAFNOSUPPORT;
367 goto release;
368 }
369 goto releaseopt;
370
371release:
372 m_freem(m);
373
374releaseopt:
375 if (control) {
376 ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
377 in6p->in6p_outputopts = stickyopt;
378 m_freem(control);
379 }
380 return(error);
381}