]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/raw_ip6.c
xnu-2782.40.9.tar.gz
[apple/xnu.git] / bsd / netinet6 / raw_ip6.c
CommitLineData
b0d623f7 1/*
fe8ab488 2 * Copyright (c) 2000-2014 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 */
1c79356b
A
28/*
29 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
30 * All rights reserved.
9bccf70c 31 *
1c79356b
A
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. Neither the name of the project nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
9bccf70c 43 *
1c79356b
A
44 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
9bccf70c
A
55 *
56 * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.4 2001/07/29 19:32:40 ume Exp $
1c79356b
A
57 */
58
59/*
60 * Copyright (c) 1982, 1986, 1988, 1993
61 * The Regents of the University of California. All rights reserved.
62 *
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
65 * are met:
66 * 1. Redistributions of source code must retain the above copyright
67 * notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 * notice, this list of conditions and the following disclaimer in the
70 * documentation and/or other materials provided with the distribution.
71 * 3. All advertising materials mentioning features or use of this software
72 * must display the following acknowledgement:
73 * This product includes software developed by the University of
74 * California, Berkeley and its contributors.
75 * 4. Neither the name of the University nor the names of its contributors
76 * may be used to endorse or promote products derived from this software
77 * without specific prior written permission.
78 *
79 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 * SUCH DAMAGE.
90 *
91 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
92 */
1c79356b
A
93#include <sys/param.h>
94#include <sys/malloc.h>
95#include <sys/proc.h>
316670eb 96#include <sys/mcache.h>
1c79356b
A
97#include <sys/mbuf.h>
98#include <sys/socket.h>
99#include <sys/protosw.h>
100#include <sys/socketvar.h>
101#include <sys/errno.h>
102#include <sys/systm.h>
103
104#include <net/if.h>
105#include <net/route.h>
106#include <net/if_types.h>
107
108#include <netinet/in.h>
109#include <netinet/in_var.h>
110#include <netinet/in_systm.h>
111#include <netinet/ip6.h>
112#include <netinet6/ip6_var.h>
1c79356b 113#include <netinet/icmp6.h>
1c79356b 114#include <netinet/in_pcb.h>
1c79356b
A
115#include <netinet6/in6_pcb.h>
116#include <netinet6/nd6.h>
117#include <netinet6/ip6protosw.h>
9bccf70c 118#include <netinet6/scope6_var.h>
9bccf70c 119#include <netinet6/raw_ip6.h>
91447636 120#include <netinet6/ip6_fw.h>
1c79356b
A
121
122#if IPSEC
123#include <netinet6/ipsec.h>
9bccf70c 124#include <netinet6/ipsec6.h>
1c79356b
A
125#endif /*IPSEC*/
126
fe8ab488
A
127#if NECP
128#include <net/necp.h>
129#endif
130
1c79356b
A
131/*
132 * Raw interface to IP6 protocol.
133 */
134
9bccf70c
A
135extern struct inpcbhead ripcb;
136extern struct inpcbinfo ripcbinfo;
b0d623f7
A
137extern u_int32_t rip_sendspace;
138extern u_int32_t rip_recvspace;
1c79356b 139
9bccf70c
A
140struct rip6stat rip6stat;
141
1c79356b
A
142/*
143 * Setup generic address and protocol structures
144 * for raw_input routine, then pass them along with
145 * mbuf chain.
146 */
147int
91447636
A
148rip6_input(
149 struct mbuf **mp,
6d2010ae
A
150 int *offp,
151 int proto)
1c79356b
A
152{
153 struct mbuf *m = *mp;
39236c6e
A
154 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
155 struct inpcb *in6p;
1c79356b 156 struct inpcb *last = 0;
9bccf70c 157 struct mbuf *opts = NULL;
1c79356b 158 struct sockaddr_in6 rip6src;
6d2010ae 159 int ret;
39236c6e 160 struct ifnet *ifp = m->m_pkthdr.rcvif;
9bccf70c 161
316670eb
A
162 /* Expect 32-bit aligned data pointer on strict-align platforms */
163 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
1c79356b 164
316670eb 165 rip6stat.rip6s_ipackets++;
9bccf70c 166
1c79356b 167 init_sin6(&rip6src, m); /* general init */
1c79356b 168
39236c6e 169 lck_rw_lock_shared(ripcbinfo.ipi_lock);
1c79356b 170 LIST_FOREACH(in6p, &ripcb, inp_list) {
9bccf70c 171 if ((in6p->in6p_vflag & INP_IPV6) == 0)
1c79356b
A
172 continue;
173 if (in6p->in6p_ip6_nxt &&
174 in6p->in6p_ip6_nxt != proto)
175 continue;
176 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
177 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
178 continue;
179 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
180 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
181 continue;
39236c6e 182
fe8ab488 183 if (inp_restricted_recv(in6p, ifp))
39236c6e
A
184 continue;
185
316670eb 186 if (proto == IPPROTO_ICMPV6 || in6p->in6p_cksum != -1) {
9bccf70c
A
187 rip6stat.rip6s_isum++;
188 if (in6_cksum(m, ip6->ip6_nxt, *offp,
189 m->m_pkthdr.len - *offp)) {
190 rip6stat.rip6s_badsum++;
191 continue;
192 }
1c79356b
A
193 }
194 if (last) {
195 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
9bccf70c 196
fe8ab488
A
197#if NECP
198 if (n && !necp_socket_is_allowed_to_send_recv_v6(in6p, 0, 0, &ip6->ip6_dst, &ip6->ip6_src, ifp, NULL)) {
199 m_freem(n);
200 /* do not inject data into pcb */
9bccf70c 201 } else
fe8ab488 202#endif /* NECP */
1c79356b 203 if (n) {
39236c6e 204 if ((last->in6p_flags & INP_CONTROLOPTS) != 0 ||
6d2010ae
A
205 (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
206 (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
207 ret = ip6_savecontrol(last, n, &opts);
208 if (ret != 0) {
209 m_freem(n);
210 m_freem(opts);
211 last = in6p;
212 continue;
213 }
214 }
1c79356b
A
215 /* strip intermediate headers */
216 m_adj(n, *offp);
6d2010ae 217 so_recv_data_stat(last->in6p_socket, m, 0);
1c79356b
A
218 if (sbappendaddr(&last->in6p_socket->so_rcv,
219 (struct sockaddr *)&rip6src,
91447636 220 n, opts, NULL) == 0) {
9bccf70c 221 rip6stat.rip6s_fullsock++;
1c79356b
A
222 } else
223 sorwakeup(last->in6p_socket);
9bccf70c 224 opts = NULL;
1c79356b
A
225 }
226 }
227 last = in6p;
228 }
6d2010ae 229
fe8ab488
A
230#if NECP
231 if (last && !necp_socket_is_allowed_to_send_recv_v6(in6p, 0, 0, &ip6->ip6_dst, &ip6->ip6_src, ifp, NULL)) {
232 m_freem(m);
233 ip6stat.ip6s_delivered--;
234 /* do not inject data into pcb */
9bccf70c 235 } else
fe8ab488 236#endif /* NECP */
1c79356b 237 if (last) {
39236c6e 238 if ((last->in6p_flags & INP_CONTROLOPTS) != 0 ||
6d2010ae
A
239 (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
240 (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
241 ret = ip6_savecontrol(last, m, &opts);
242 if (ret != 0) {
243 m_freem(m);
244 m_freem(opts);
245 ip6stat.ip6s_delivered--;
246 goto unlock;
247 }
248
249 }
1c79356b
A
250 /* strip intermediate headers */
251 m_adj(m, *offp);
6d2010ae 252 so_recv_data_stat(last->in6p_socket, m, 0);
1c79356b 253 if (sbappendaddr(&last->in6p_socket->so_rcv,
91447636 254 (struct sockaddr *)&rip6src, m, opts, NULL) == 0) {
9bccf70c 255 rip6stat.rip6s_fullsock++;
1c79356b
A
256 } else
257 sorwakeup(last->in6p_socket);
258 } else {
9bccf70c
A
259 rip6stat.rip6s_nosock++;
260 if (m->m_flags & M_MCAST)
261 rip6stat.rip6s_nosockmcast++;
1c79356b
A
262 if (proto == IPPROTO_NONE)
263 m_freem(m);
264 else {
265 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
266 icmp6_error(m, ICMP6_PARAM_PROB,
267 ICMP6_PARAMPROB_NEXTHEADER,
268 prvnxtp - mtod(m, char *));
269 }
270 ip6stat.ip6s_delivered--;
271 }
6d2010ae
A
272
273unlock:
39236c6e 274 lck_rw_done(ripcbinfo.ipi_lock);
6d2010ae 275
1c79356b
A
276 return IPPROTO_DONE;
277}
278
279void
91447636
A
280rip6_ctlinput(
281 int cmd,
282 struct sockaddr *sa,
283 void *d)
1c79356b 284{
1c79356b
A
285 struct ip6_hdr *ip6;
286 struct mbuf *m;
6d2010ae 287 void *cmdarg = NULL;
1c79356b 288 int off = 0;
9bccf70c
A
289 struct ip6ctlparam *ip6cp = NULL;
290 const struct sockaddr_in6 *sa6_src = NULL;
91447636 291 void (*notify)(struct inpcb *, int) = in6_rtchange;
1c79356b
A
292
293 if (sa->sa_family != AF_INET6 ||
294 sa->sa_len != sizeof(struct sockaddr_in6))
295 return;
296
297 if ((unsigned)cmd >= PRC_NCMDS)
298 return;
299 if (PRC_IS_REDIRECT(cmd))
300 notify = in6_rtchange, d = NULL;
301 else if (cmd == PRC_HOSTDEAD)
302 d = NULL;
303 else if (inet6ctlerrmap[cmd] == 0)
304 return;
305
306 /* if the parameter is from icmp6, decode it. */
307 if (d != NULL) {
9bccf70c 308 ip6cp = (struct ip6ctlparam *)d;
1c79356b
A
309 m = ip6cp->ip6c_m;
310 ip6 = ip6cp->ip6c_ip6;
311 off = ip6cp->ip6c_off;
6d2010ae 312 cmdarg = ip6cp->ip6c_cmdarg;
9bccf70c 313 sa6_src = ip6cp->ip6c_src;
1c79356b
A
314 } else {
315 m = NULL;
316 ip6 = NULL;
9bccf70c 317 sa6_src = &sa6_any;
1c79356b
A
318 }
319
2d21ac55 320 (void) in6_pcbnotify(&ripcbinfo, sa, 0, (const struct sockaddr *)sa6_src,
6d2010ae 321 0, cmd, cmdarg, notify);
1c79356b
A
322}
323
324/*
325 * Generate IPv6 header and pass packet to ip6_output.
326 * Tack on options user may have setup with control call.
327 */
328int
91447636 329rip6_output(
39236c6e 330 struct mbuf *m,
91447636
A
331 struct socket *so,
332 struct sockaddr_in6 *dstsock,
6d2010ae
A
333 struct mbuf *control,
334 int israw)
1c79356b
A
335{
336 struct in6_addr *dst;
337 struct ip6_hdr *ip6;
338 struct inpcb *in6p;
339 u_int plen = m->m_pkthdr.len;
340 int error = 0;
39236c6e 341 struct ip6_pktopts opt, *optp = NULL;
6d2010ae 342 struct ip6_moptions *im6o = NULL;
1c79356b
A
343 struct ifnet *oifp = NULL;
344 int type = 0, code = 0; /* for ICMPv6 output statistics only */
316670eb
A
345 mbuf_svc_class_t msc = MBUF_SC_UNSPEC;
346 struct ip6_out_args ip6oa =
39236c6e 347 { IFSCOPE_NONE, { 0 }, IP6OAF_SELECT_SRCIF, 0 };
6d2010ae
A
348 int flags = IPV6_OUTARGS;
349
1c79356b
A
350 in6p = sotoin6pcb(so);
351
fe8ab488
A
352 if (in6p == NULL
353#if NECP
354 || (necp_socket_should_use_flow_divert(in6p))
355#endif /* NECP */
356 ) {
357 if (in6p == NULL)
358 error = EINVAL;
359 else
360 error = EPROTOTYPE;
39236c6e
A
361 goto bad;
362 }
363 if (dstsock != NULL && IN6_IS_ADDR_V4MAPPED(&dstsock->sin6_addr)) {
364 error = EINVAL;
365 goto bad;
366 }
367
316670eb
A
368 if (in6p->inp_flags & INP_BOUND_IF) {
369 ip6oa.ip6oa_boundif = in6p->inp_boundifp->if_index;
370 ip6oa.ip6oa_flags |= IP6OAF_BOUND_IF;
371 }
fe8ab488 372 if (INP_NO_CELLULAR(in6p))
316670eb 373 ip6oa.ip6oa_flags |= IP6OAF_NO_CELLULAR;
fe8ab488
A
374 if (INP_NO_EXPENSIVE(in6p))
375 ip6oa.ip6oa_flags |= IP6OAF_NO_EXPENSIVE;
376 if (INP_AWDL_UNRESTRICTED(in6p))
377 ip6oa.ip6oa_flags |= IP6OAF_AWDL_UNRESTRICTED;
6d2010ae 378
1c79356b
A
379 dst = &dstsock->sin6_addr;
380 if (control) {
316670eb 381 msc = mbuf_service_class_from_control(control);
d41d1dae 382
39236c6e
A
383 if ((error = ip6_setpktopts(control, &opt, NULL,
384 SOCK_PROTO(so))) != 0)
1c79356b
A
385 goto bad;
386 optp = &opt;
387 } else
388 optp = in6p->in6p_outputopts;
389
390 /*
391 * For an ICMPv6 packet, we should know its type and code
392 * to update statistics.
393 */
39236c6e 394 if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
1c79356b
A
395 struct icmp6_hdr *icmp6;
396 if (m->m_len < sizeof(struct icmp6_hdr) &&
397 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
398 error = ENOBUFS;
399 goto bad;
400 }
401 icmp6 = mtod(m, struct icmp6_hdr *);
402 type = icmp6->icmp6_type;
403 code = icmp6->icmp6_code;
404 }
405
316670eb
A
406 if (in6p->inp_flowhash == 0)
407 in6p->inp_flowhash = inp_calc_flowhash(in6p);
39236c6e
A
408 /* update flowinfo - RFC 6437 */
409 if (in6p->inp_flow == 0 && in6p->in6p_flags & IN6P_AUTOFLOWLABEL) {
410 in6p->inp_flow &= ~IPV6_FLOWLABEL_MASK;
411 in6p->inp_flow |=
412 (htonl(in6p->inp_flowhash) & IPV6_FLOWLABEL_MASK);
413 }
316670eb 414
1c79356b 415 M_PREPEND(m, sizeof(*ip6), M_WAIT);
b0d623f7
A
416 if (m == NULL) {
417 error = ENOBUFS;
418 goto bad;
419 }
1c79356b
A
420 ip6 = mtod(m, struct ip6_hdr *);
421
422 /*
423 * Next header might not be ICMP6 but use its pseudo header anyway.
424 */
425 ip6->ip6_dst = *dst;
426
6d2010ae
A
427 im6o = in6p->in6p_moptions;
428
1c79356b
A
429 /*
430 * If the scope of the destination is link-local, embed the interface
431 * index in the address.
432 *
9bccf70c 433 * XXX advanced-api value overrides sin6_scope_id
1c79356b
A
434 */
435 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
436 struct in6_pktinfo *pi;
6d2010ae 437 struct ifnet *im6o_multicast_ifp = NULL;
1c79356b 438
6d2010ae
A
439 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && im6o != NULL) {
440 IM6O_LOCK(im6o);
441 im6o_multicast_ifp = im6o->im6o_multicast_ifp;
442 IM6O_UNLOCK(im6o);
443 }
1c79356b
A
444 /*
445 * XXX Boundary check is assumed to be already done in
446 * ip6_setpktoptions().
447 */
b0d623f7 448 ifnet_head_lock_shared();
1c79356b
A
449 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
450 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
451 oifp = ifindex2ifnet[pi->ipi6_ifindex];
6d2010ae
A
452 if (oifp != NULL)
453 ifnet_reference(oifp);
9bccf70c 454 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
6d2010ae
A
455 im6o != NULL && im6o_multicast_ifp != NULL) {
456 oifp = im6o_multicast_ifp;
457 ifnet_reference(oifp);
1c79356b
A
458 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
459 } else if (dstsock->sin6_scope_id) {
b0d623f7
A
460 /*
461 * boundary check
462 *
463 * Sinced stsock->sin6_scope_id is unsigned, we don't
464 * need to check if it's < 0
465 */
466 if (if_index < dstsock->sin6_scope_id) {
1c79356b 467 error = ENXIO; /* XXX EINVAL? */
b0d623f7 468 ifnet_head_done();
1c79356b
A
469 goto bad;
470 }
471 ip6->ip6_dst.s6_addr16[1]
472 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
473 }
b0d623f7 474 ifnet_head_done();
1c79356b
A
475 }
476
477 /*
478 * Source address selection.
479 */
480 {
481 struct in6_addr *in6a;
91447636 482 struct in6_addr storage;
b0d623f7 483 u_short index = 0;
316670eb 484
6d2010ae
A
485 if (israw != 0 && optp && optp->ip6po_pktinfo && !IN6_IS_ADDR_UNSPECIFIED(&optp->ip6po_pktinfo->ipi6_addr)) {
486 in6a = &optp->ip6po_pktinfo->ipi6_addr;
487 flags |= IPV6_FLAG_NOSRCIFSEL;
488 } else if ((in6a = in6_selectsrc(dstsock, optp, in6p,
489 &in6p->in6p_route, NULL, &storage, ip6oa.ip6oa_boundif,
490 &error)) == 0) {
1c79356b
A
491 if (error == 0)
492 error = EADDRNOTAVAIL;
493 goto bad;
316670eb
A
494 } else {
495 ip6oa.ip6oa_flags |= IP6OAF_BOUND_SRCADDR;
1c79356b
A
496 }
497 ip6->ip6_src = *in6a;
b0d623f7
A
498 if (in6p->in6p_route.ro_rt != NULL) {
499 RT_LOCK(in6p->in6p_route.ro_rt);
500 if (in6p->in6p_route.ro_rt->rt_ifp != NULL)
501 index = in6p->in6p_route.ro_rt->rt_ifp->if_index;
502 RT_UNLOCK(in6p->in6p_route.ro_rt);
6d2010ae
A
503 if (oifp != NULL)
504 ifnet_release(oifp);
b0d623f7
A
505 ifnet_head_lock_shared();
506 if (index == 0 || if_index < index) {
507 panic("bad if_index on interface from route");
508 }
509 oifp = ifindex2ifnet[index];
6d2010ae
A
510 if (oifp != NULL)
511 ifnet_reference(oifp);
b0d623f7
A
512 ifnet_head_done();
513 }
1c79356b 514 }
9bccf70c 515 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
39236c6e 516 (in6p->inp_flow & IPV6_FLOWINFO_MASK);
9bccf70c
A
517 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
518 (IPV6_VERSION & IPV6_VERSION_MASK);
519 /* ip6_plen will be filled in ip6_output, so not fill it here. */
1c79356b
A
520 ip6->ip6_nxt = in6p->in6p_ip6_nxt;
521 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
522
39236c6e 523 if (SOCK_PROTO(so) == IPPROTO_ICMPV6 || in6p->in6p_cksum != -1) {
1c79356b
A
524 struct mbuf *n;
525 int off;
526 u_int16_t *p;
527
1c79356b 528 /* compute checksum */
39236c6e 529 if (SOCK_PROTO(so) == IPPROTO_ICMPV6)
1c79356b
A
530 off = offsetof(struct icmp6_hdr, icmp6_cksum);
531 else
532 off = in6p->in6p_cksum;
6d2010ae 533 if (plen < (unsigned int)(off + 1)) {
1c79356b
A
534 error = EINVAL;
535 goto bad;
536 }
537 off += sizeof(struct ip6_hdr);
538
539 n = m;
540 while (n && n->m_len <= off) {
541 off -= n->m_len;
542 n = n->m_next;
543 }
544 if (!n)
545 goto bad;
316670eb 546 p = (u_int16_t *)(void *)(mtod(n, caddr_t) + off);
1c79356b
A
547 *p = 0;
548 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
549 }
fe8ab488
A
550
551#if NECP
552 {
553 necp_kernel_policy_id policy_id;
554 if (!necp_socket_is_allowed_to_send_recv_v6(in6p, 0, 0, &ip6->ip6_src, &ip6->ip6_dst, NULL, &policy_id)) {
555 error = EHOSTUNREACH;
556 goto bad;
557 }
1c79356b 558
fe8ab488
A
559 necp_mark_packet_from_socket(m, in6p, policy_id);
560 }
561#endif /* NECP */
562
1c79356b 563#if IPSEC
fe8ab488 564 if (in6p->in6p_sp != NULL && ipsec_setsocket(m, so) != 0) {
9bccf70c
A
565 error = ENOBUFS;
566 goto bad;
567 }
1c79356b
A
568#endif /*IPSEC*/
569
39236c6e
A
570 if (ROUTE_UNUSABLE(&in6p->in6p_route))
571 ROUTE_RELEASE(&in6p->in6p_route);
91447636 572
6d2010ae
A
573 if (oifp != NULL) {
574 ifnet_release(oifp);
575 oifp = NULL;
576 }
d1ecb069 577
316670eb 578 set_packet_service_class(m, so, msc, PKT_SCF_IPV6);
39236c6e
A
579 m->m_pkthdr.pkt_flowsrc = FLOWSRC_INPCB;
580 m->m_pkthdr.pkt_flowid = in6p->inp_flowhash;
581 m->m_pkthdr.pkt_flags |= (PKTF_FLOW_ID | PKTF_FLOW_LOCALSRC |
582 PKTF_FLOW_RAWSOCK);
583 m->m_pkthdr.pkt_proto = in6p->in6p_ip6_nxt;
316670eb 584
6d2010ae
A
585 if (im6o != NULL)
586 IM6O_ADDREF(im6o);
d1ecb069 587
6d2010ae
A
588 error = ip6_output(m, optp, &in6p->in6p_route, flags, im6o,
589 &oifp, &ip6oa);
590
591 if (im6o != NULL)
592 IM6O_REMREF(im6o);
593
594 if (in6p->in6p_route.ro_rt != NULL) {
595 struct rtentry *rt = in6p->in6p_route.ro_rt;
316670eb 596 struct ifnet *outif;
6d2010ae
A
597
598 if ((rt->rt_flags & RTF_MULTICAST) ||
599 in6p->in6p_socket == NULL ||
600 !(in6p->in6p_socket->so_state & SS_ISCONNECTED)) {
601 rt = NULL; /* unusable */
602 }
603 /*
604 * Always discard the cached route for unconnected
605 * socket or if it is a multicast route.
606 */
39236c6e
A
607 if (rt == NULL)
608 ROUTE_RELEASE(&in6p->in6p_route);
609
6d2010ae
A
610 /*
611 * If this is a connected socket and the destination
612 * route is not multicast, update outif with that of
613 * the route interface index used by IP.
614 */
615 if (rt != NULL &&
316670eb
A
616 (outif = rt->rt_ifp) != in6p->in6p_last_outifp)
617 in6p->in6p_last_outifp = outif;
39236c6e
A
618 } else {
619 ROUTE_RELEASE(&in6p->in6p_route);
d1ecb069 620 }
d1ecb069 621
39236c6e 622 /*
fe8ab488
A
623 * If output interface was cellular/expensive, and this socket is
624 * denied access to it, generate an event.
39236c6e
A
625 */
626 if (error != 0 && (ip6oa.ip6oa_retflags & IP6OARF_IFDENIED) &&
fe8ab488 627 (INP_NO_CELLULAR(in6p) || INP_NO_EXPENSIVE(in6p)))
39236c6e
A
628 soevent(in6p->inp_socket, (SO_FILT_HINT_LOCKED|
629 SO_FILT_HINT_IFDENIED));
630
631 if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
1c79356b
A
632 if (oifp)
633 icmp6_ifoutstat_inc(oifp, type, code);
634 icmp6stat.icp6s_outhist[type]++;
9bccf70c
A
635 } else
636 rip6stat.rip6s_opackets++;
1c79356b
A
637
638 goto freectl;
639
39236c6e
A
640bad:
641 if (m != NULL)
1c79356b
A
642 m_freem(m);
643
39236c6e
A
644freectl:
645 if (optp == &opt && optp->ip6po_rthdr)
646 ROUTE_RELEASE(&optp->ip6po_route);
647
648 if (control != NULL) {
1c79356b 649 if (optp == &opt)
6d2010ae 650 ip6_clearpktopts(optp, -1);
1c79356b
A
651 m_freem(control);
652 }
6d2010ae
A
653 if (oifp != NULL)
654 ifnet_release(oifp);
1c79356b
A
655 return(error);
656}
657
7e4a7d39 658#if IPFW2
060df5ea 659__private_extern__ void
2d21ac55 660load_ip6fw(void)
91447636
A
661{
662 ip6_fw_init();
663}
7e4a7d39 664#endif
91447636 665
1c79356b
A
666/*
667 * Raw IPv6 socket option processing.
668 */
669int
91447636
A
670rip6_ctloutput(
671 struct socket *so,
672 struct sockopt *sopt)
1c79356b 673{
316670eb 674 int error, optval;
1c79356b 675
316670eb 676 /* Allow <SOL_SOCKET,SO_FLUSH> at this level */
1c79356b
A
677 if (sopt->sopt_level == IPPROTO_ICMPV6)
678 /*
679 * XXX: is it better to call icmp6_ctloutput() directly
680 * from protosw?
681 */
682 return(icmp6_ctloutput(so, sopt));
316670eb
A
683 else if (sopt->sopt_level != IPPROTO_IPV6 &&
684 !(sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_FLUSH))
1c79356b
A
685 return (EINVAL);
686
687 error = 0;
688
689 switch (sopt->sopt_dir) {
690 case SOPT_GET:
691 switch (sopt->sopt_name) {
7e4a7d39 692#if IPFW2
91447636
A
693 case IPV6_FW_ADD:
694 case IPV6_FW_GET:
695 if (ip6_fw_ctl_ptr == 0)
696 load_ip6fw();
697 if (ip6_fw_ctl_ptr)
698 error = ip6_fw_ctl_ptr(sopt);
699 else
700 error = ENOPROTOOPT;
701 break;
7e4a7d39 702#endif
6d2010ae
A
703 case IPV6_CHECKSUM:
704 error = ip6_raw_ctloutput(so, sopt);
1c79356b
A
705 break;
706 default:
707 error = ip6_ctloutput(so, sopt);
708 break;
709 }
710 break;
711
712 case SOPT_SET:
713 switch (sopt->sopt_name) {
7e4a7d39 714#if IPFW2
91447636
A
715 case IPV6_FW_ADD:
716 case IPV6_FW_DEL:
717 case IPV6_FW_FLUSH:
718 case IPV6_FW_ZERO:
719 if (ip6_fw_ctl_ptr == 0)
720 load_ip6fw();
721 if (ip6_fw_ctl_ptr)
722 error = ip6_fw_ctl_ptr(sopt);
723 else
724 error = ENOPROTOOPT;
725 break;
7e4a7d39 726#endif
91447636 727
6d2010ae
A
728 case IPV6_CHECKSUM:
729 error = ip6_raw_ctloutput(so, sopt);
730 break;
316670eb
A
731
732 case SO_FLUSH:
733 if ((error = sooptcopyin(sopt, &optval, sizeof (optval),
734 sizeof (optval))) != 0)
735 break;
736
737 error = inp_flush(sotoinpcb(so), optval);
738 break;
739
1c79356b
A
740 default:
741 error = ip6_ctloutput(so, sopt);
742 break;
743 }
744 break;
745 }
746
747 return (error);
748}
749
750static int
b0d623f7 751rip6_attach(struct socket *so, int proto, struct proc *p)
1c79356b
A
752{
753 struct inpcb *inp;
2d21ac55 754 int error;
1c79356b
A
755
756 inp = sotoinpcb(so);
757 if (inp)
758 panic("rip6_attach");
b0d623f7 759 if ((error = proc_suser(p)) != 0)
1c79356b
A
760 return error;
761
9bccf70c
A
762 error = soreserve(so, rip_sendspace, rip_recvspace);
763 if (error)
764 return error;
1c79356b 765 error = in_pcballoc(so, &ripcbinfo, p);
1c79356b
A
766 if (error)
767 return error;
768 inp = (struct inpcb *)so->so_pcb;
769 inp->inp_vflag |= INP_IPV6;
b0d623f7 770 inp->in6p_ip6_nxt = (char)proto;
1c79356b
A
771 inp->in6p_hops = -1; /* use kernel default */
772 inp->in6p_cksum = -1;
1c79356b 773 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
55e303ae
A
774 sizeof(struct icmp6_filter), M_PCB, M_WAITOK);
775 if (inp->in6p_icmp6filt == NULL)
776 return (ENOMEM);
1c79356b
A
777 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
778 return 0;
779}
780
781static int
782rip6_detach(struct socket *so)
783{
784 struct inpcb *inp;
785
786 inp = sotoinpcb(so);
787 if (inp == 0)
788 panic("rip6_detach");
9bccf70c 789 /* xxx: RSVP */
1c79356b
A
790 if (inp->in6p_icmp6filt) {
791 FREE(inp->in6p_icmp6filt, M_PCB);
792 inp->in6p_icmp6filt = NULL;
793 }
794 in6_pcbdetach(inp);
795 return 0;
796}
797
798static int
799rip6_abort(struct socket *so)
800{
801 soisdisconnected(so);
802 return rip6_detach(so);
803}
804
805static int
806rip6_disconnect(struct socket *so)
807{
808 struct inpcb *inp = sotoinpcb(so);
809
810 if ((so->so_state & SS_ISCONNECTED) == 0)
811 return ENOTCONN;
812 inp->in6p_faddr = in6addr_any;
813 return rip6_abort(so);
814}
815
816static int
39236c6e 817rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
1c79356b 818{
39236c6e 819#pragma unused(p)
1c79356b 820 struct inpcb *inp = sotoinpcb(so);
39236c6e 821 struct sockaddr_in6 sin6;
6d2010ae 822 struct ifaddr *ifa = NULL;
316670eb 823 struct ifnet *outif = NULL;
39236c6e 824 int error;
1c79356b 825
fe8ab488
A
826 if (inp == NULL
827#if NECP
828 || (necp_socket_should_use_flow_divert(inp))
829#endif /* NECP */
830 )
39236c6e 831 return (inp == NULL ? EINVAL : EPROTOTYPE);
1c79356b 832
39236c6e
A
833 if (nam->sa_len != sizeof (struct sockaddr_in6))
834 return (EINVAL);
835
836 if (TAILQ_EMPTY(&ifnet_head) || SIN6(nam)->sin6_family != AF_INET6)
837 return (EADDRNOTAVAIL);
838
839 bzero(&sin6, sizeof (sin6));
840 *(&sin6) = *SIN6(nam);
841
842 if ((error = sa6_embedscope(&sin6, ip6_use_defzone)) != 0)
843 return (error);
844
845 /* Sanitize local copy for address searches */
846 sin6.sin6_flowinfo = 0;
847 sin6.sin6_scope_id = 0;
848 sin6.sin6_port = 0;
849
850 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) &&
851 (ifa = ifa_ifwithaddr(SA(&sin6))) == 0)
852 return (EADDRNOTAVAIL);
6d2010ae
A
853 if (ifa != NULL) {
854 IFA_LOCK(ifa);
855 if (((struct in6_ifaddr *)ifa)->ia6_flags &
856 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
857 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
858 IFA_UNLOCK(ifa);
859 IFA_REMREF(ifa);
39236c6e 860 return (EADDRNOTAVAIL);
6d2010ae 861 }
316670eb 862 outif = ifa->ifa_ifp;
6d2010ae
A
863 IFA_UNLOCK(ifa);
864 IFA_REMREF(ifa);
1c79356b 865 }
39236c6e 866 inp->in6p_laddr = sin6.sin6_addr;
316670eb 867 inp->in6p_last_outifp = outif;
39236c6e 868 return (0);
1c79356b
A
869}
870
871static int
2d21ac55 872rip6_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
1c79356b
A
873{
874 struct inpcb *inp = sotoinpcb(so);
316670eb 875 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(void *)nam;
1c79356b 876 struct in6_addr *in6a = NULL;
91447636 877 struct in6_addr storage;
1c79356b 878 int error = 0;
9bccf70c
A
879#if ENABLE_DEFAULT_SCOPE
880 struct sockaddr_in6 tmp;
881#endif
316670eb
A
882 unsigned int ifscope;
883 struct ifnet *outif = NULL;
1c79356b 884
fe8ab488
A
885 if (inp == NULL
886#if NECP
887 || (necp_socket_should_use_flow_divert(inp))
888#endif /* NECP */
889 )
39236c6e 890 return (inp == NULL ? EINVAL : EPROTOTYPE);
1c79356b
A
891 if (nam->sa_len != sizeof(*addr))
892 return EINVAL;
91447636 893 if (TAILQ_EMPTY(&ifnet_head))
1c79356b
A
894 return EADDRNOTAVAIL;
895 if (addr->sin6_family != AF_INET6)
896 return EAFNOSUPPORT;
9bccf70c
A
897#if ENABLE_DEFAULT_SCOPE
898 if (addr->sin6_scope_id == 0) { /* not change if specified */
899 /* avoid overwrites */
900 tmp = *addr;
901 addr = &tmp;
902 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
903 }
904#endif
6d2010ae
A
905
906 ifscope = (inp->inp_flags & INP_BOUND_IF) ?
316670eb 907 inp->inp_boundifp->if_index : IFSCOPE_NONE;
6d2010ae 908
1c79356b 909 /* Source address selection. XXX: need pcblookup? */
6d2010ae
A
910 in6a = in6_selectsrc(addr, inp->in6p_outputopts, inp, &inp->in6p_route,
911 NULL, &storage, ifscope, &error);
1c79356b
A
912 if (in6a == NULL)
913 return (error ? error : EADDRNOTAVAIL);
914 inp->in6p_laddr = *in6a;
915 inp->in6p_faddr = addr->sin6_addr;
6d2010ae 916 if (inp->in6p_route.ro_rt != NULL)
316670eb
A
917 outif = inp->in6p_route.ro_rt->rt_ifp;
918 inp->in6p_last_outifp = outif;
1c79356b
A
919 soisconnected(so);
920 return 0;
921}
922
923static int
924rip6_shutdown(struct socket *so)
925{
926 socantsendmore(so);
927 return 0;
928}
929
930static int
6d2010ae 931rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
39236c6e 932 struct mbuf *control, struct proc *p)
1c79356b 933{
6d2010ae 934#pragma unused(flags, p)
1c79356b
A
935 struct inpcb *inp = sotoinpcb(so);
936 struct sockaddr_in6 tmp;
316670eb 937 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)(void *)nam;
39236c6e
A
938 int error = 0;
939
fe8ab488
A
940 if (inp == NULL
941#if NECP
942 || (necp_socket_should_use_flow_divert(inp))
943#endif /* NECP */
944 ) {
945 if (inp == NULL)
946 error = EINVAL;
947 else
948 error = EPROTOTYPE;
39236c6e
A
949 goto bad;
950 }
1c79356b 951
9bccf70c 952 /* always copy sockaddr to avoid overwrites */
1c79356b 953 if (so->so_state & SS_ISCONNECTED) {
39236c6e
A
954 if (nam != NULL) {
955 error = EISCONN;
956 goto bad;
1c79356b
A
957 }
958 /* XXX */
959 bzero(&tmp, sizeof(tmp));
960 tmp.sin6_family = AF_INET6;
961 tmp.sin6_len = sizeof(struct sockaddr_in6);
962 bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
963 sizeof(struct in6_addr));
964 dst = &tmp;
965 } else {
966 if (nam == NULL) {
39236c6e
A
967 error = ENOTCONN;
968 goto bad;
1c79356b 969 }
316670eb 970 tmp = *(struct sockaddr_in6 *)(void *)nam;
9bccf70c 971 dst = &tmp;
1c79356b 972 }
9bccf70c
A
973#if ENABLE_DEFAULT_SCOPE
974 if (dst->sin6_scope_id == 0) { /* not change if specified */
975 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr);
976 }
977#endif
39236c6e
A
978 return (rip6_output(m, so, dst, control, 1));
979
980bad:
981 VERIFY(error != 0);
982
983 if (m != NULL)
984 m_freem(m);
985 if (control != NULL)
986 m_freem(control);
987
988 return (error);
1c79356b
A
989}
990
991struct pr_usrreqs rip6_usrreqs = {
39236c6e
A
992 .pru_abort = rip6_abort,
993 .pru_attach = rip6_attach,
994 .pru_bind = rip6_bind,
995 .pru_connect = rip6_connect,
996 .pru_control = in6_control,
997 .pru_detach = rip6_detach,
998 .pru_disconnect = rip6_disconnect,
999 .pru_peeraddr = in6_getpeeraddr,
1000 .pru_send = rip6_send,
1001 .pru_shutdown = rip6_shutdown,
1002 .pru_sockaddr = in6_getsockaddr,
1003 .pru_sosend = sosend,
1004 .pru_soreceive = soreceive,
1c79356b 1005};
2d21ac55
A
1006
1007__private_extern__ struct pr_usrreqs icmp6_dgram_usrreqs = {
39236c6e
A
1008 .pru_abort = rip6_abort,
1009 .pru_attach = icmp6_dgram_attach,
1010 .pru_bind = rip6_bind,
1011 .pru_connect = rip6_connect,
1012 .pru_control = in6_control,
1013 .pru_detach = rip6_detach,
1014 .pru_disconnect = rip6_disconnect,
1015 .pru_peeraddr = in6_getpeeraddr,
1016 .pru_send = icmp6_dgram_send,
1017 .pru_shutdown = rip6_shutdown,
1018 .pru_sockaddr = in6_getsockaddr,
1019 .pru_sosend = sosend,
1020 .pru_soreceive = soreceive,
2d21ac55 1021};