]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/udp6_output.c
xnu-1504.3.12.tar.gz
[apple/xnu.git] / bsd / netinet6 / udp6_output.c
1 /*
2 * Copyright (c) 2008 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
187 priv = (proc_suser(p) == 0);
188
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,
251 &in6p->in6p_laddr, &storage, &error);
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 &&
260 (error = in6_pcbsetport(laddr, in6p, p, 0)) != 0)
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*/
343 m->m_pkthdr.socket_id = get_socket_id(in6p->in6p_socket);
344 error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
345 flags, in6p->in6p_moptions, NULL, 0);
346 break;
347 case AF_INET:
348 error = EAFNOSUPPORT;
349 goto release;
350 }
351 goto releaseopt;
352
353 release:
354 m_freem(m);
355
356 releaseopt:
357 if (control) {
358 ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
359 in6p->in6p_outputopts = stickyopt;
360 m_freem(control);
361 }
362 return(error);
363 }