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