]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/udp6_output.c
xnu-1504.9.37.tar.gz
[apple/xnu.git] / bsd / netinet6 / udp6_output.c
1 /*
2 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
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
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
134 extern 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
150 static __inline__ u_int16_t
151 get_socket_id(struct socket * s)
152 {
153 u_int16_t val;
154
155 if (s == NULL) {
156 return (0);
157 }
158 val = (u_int16_t)(((uintptr_t)s) / sizeof(struct socket));
159 if (val == 0) {
160 val = 0xffff;
161 }
162 return (val);
163 }
164
165 int
166 udp6_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;
185 struct in6_addr storage;
186 #if PKT_PRIORITY
187 mbuf_traffic_class_t mtc = MBUF_TC_NONE;
188 #endif /* PKT_PRIORITY */
189
190 priv = (proc_suser(p) == 0);
191
192 if (control) {
193 #if PKT_PRIORITY
194 mtc = mbuf_traffic_class_from_control(control);
195 #endif /* PKT_PRIORITY */
196
197 if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
198 goto release;
199 in6p->in6p_outputopts = &opt;
200 }
201
202 if (addr6) {
203 /*
204 * IPv4 version of udp_output calls in_pcbconnect in this case,
205 * which needs splnet and affects performance.
206 * Since we saw no essential reason for calling in_pcbconnect,
207 * we get rid of such kind of logic, and call in6_selectsrc
208 * and in6_pcbsetport in order to fill in the local address
209 * and the local port.
210 */
211 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr6;
212 if (sin6->sin6_port == 0) {
213 error = EADDRNOTAVAIL;
214 goto release;
215 }
216
217 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
218 /* how about ::ffff:0.0.0.0 case? */
219 error = EISCONN;
220 goto release;
221 }
222
223 /* protect *sin6 from overwrites */
224 tmp = *sin6;
225 sin6 = &tmp;
226
227 faddr = &sin6->sin6_addr;
228 fport = sin6->sin6_port; /* allow 0 port */
229
230 if (IN6_IS_ADDR_V4MAPPED(faddr)) {
231 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
232 /*
233 * I believe we should explicitly discard the
234 * packet when mapped addresses are disabled,
235 * rather than send the packet as an IPv6 one.
236 * If we chose the latter approach, the packet
237 * might be sent out on the wire based on the
238 * default route, the situation which we'd
239 * probably want to avoid.
240 * (20010421 jinmei@kame.net)
241 */
242 error = EINVAL;
243 goto release;
244 } else
245 af = AF_INET;
246 }
247
248 /* KAME hack: embed scopeid */
249 if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
250 error = EINVAL;
251 goto release;
252 }
253
254 if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
255 laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
256 in6p->in6p_moptions,
257 &in6p->in6p_route,
258 &in6p->in6p_laddr, &storage, &error);
259 } else
260 laddr = &in6p->in6p_laddr; /* XXX */
261 if (laddr == NULL) {
262 if (error == 0)
263 error = EADDRNOTAVAIL;
264 goto release;
265 }
266 if (in6p->in6p_lport == 0 &&
267 (error = in6_pcbsetport(laddr, in6p, p, 0)) != 0)
268 goto release;
269 } else {
270 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
271 error = ENOTCONN;
272 goto release;
273 }
274 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
275 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
276 /*
277 * XXX: this case would happen when the
278 * application sets the V6ONLY flag after
279 * connecting the foreign address.
280 * Such applications should be fixed,
281 * so we bark here.
282 */
283 log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
284 "option was set for a connected socket\n");
285 error = EINVAL;
286 goto release;
287 } else
288 af = AF_INET;
289 }
290 laddr = &in6p->in6p_laddr;
291 faddr = &in6p->in6p_faddr;
292 fport = in6p->in6p_fport;
293 }
294
295 if (af == AF_INET)
296 hlen = sizeof(struct ip);
297
298 /*
299 * Calculate data length and get a mbuf
300 * for UDP and IP6 headers.
301 */
302 M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
303 if (m == 0) {
304 error = ENOBUFS;
305 goto release;
306 }
307
308 /*
309 * Stuff checksum and output datagram.
310 */
311 udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
312 udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
313 udp6->uh_dport = fport;
314 if (plen <= 0xffff)
315 udp6->uh_ulen = htons((u_short)plen);
316 else
317 udp6->uh_ulen = 0;
318 udp6->uh_sum = 0;
319
320 switch (af) {
321 case AF_INET6:
322 ip6 = mtod(m, struct ip6_hdr *);
323 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
324 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
325 ip6->ip6_vfc |= IPV6_VERSION;
326 #if 0 /* ip6_plen will be filled in ip6_output. */
327 ip6->ip6_plen = htons((u_short)plen);
328 #endif
329 ip6->ip6_nxt = IPPROTO_UDP;
330 ip6->ip6_hlim = in6_selecthlim(in6p,
331 in6p->in6p_route.ro_rt ?
332 in6p->in6p_route.ro_rt->rt_ifp : NULL);
333 ip6->ip6_src = *laddr;
334 ip6->ip6_dst = *faddr;
335
336 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
337 sizeof(struct ip6_hdr), plen)) == 0) {
338 udp6->uh_sum = 0xffff;
339 }
340
341 flags = 0;
342
343 udp6stat.udp6s_opackets++;
344 #ifdef IPSEC
345 if (ipsec_bypass == 0 && ipsec_setsocket(m, in6p->in6p_socket) != 0) {
346 error = ENOBUFS;
347 goto release;
348 }
349 #endif /*IPSEC*/
350 m->m_pkthdr.socket_id = get_socket_id(in6p->in6p_socket);
351
352 #if PKT_PRIORITY
353 set_traffic_class(m, in6p->in6p_socket, mtc);
354 #endif /* PKT_PRIORITY */
355 error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
356 flags, in6p->in6p_moptions, NULL, 0);
357
358 #if IFNET_ROUTE_REFCNT
359 /*
360 * Always discard the cached route for unconnected socket
361 * or if it is a multicast route.
362 */
363 if (in6p->in6p_route.ro_rt != NULL &&
364 ((in6p->in6p_route.ro_rt->rt_flags & RTF_MULTICAST) ||
365 in6p->in6p_socket == NULL ||
366 in6p->in6p_socket->so_state != SS_ISCONNECTED)) {
367 rtfree(in6p->in6p_route.ro_rt);
368 in6p->in6p_route.ro_rt = NULL;
369 }
370 #endif /* IFNET_ROUTE_REFCNT */
371 break;
372 case AF_INET:
373 error = EAFNOSUPPORT;
374 goto release;
375 }
376 goto releaseopt;
377
378 release:
379 m_freem(m);
380
381 releaseopt:
382 if (control) {
383 ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
384 in6p->in6p_outputopts = stickyopt;
385 m_freem(control);
386 }
387 return(error);
388 }