]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/raw_ip6.c
xnu-2782.40.9.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, &ip6->ip6_dst, &ip6->ip6_src, ifp, NULL)) {
199 m_freem(n);
200 /* do not inject data into pcb */
201 } else
202 #endif /* NECP */
203 if (n) {
204 if ((last->in6p_flags & INP_CONTROLOPTS) != 0 ||
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 }
215 /* strip intermediate headers */
216 m_adj(n, *offp);
217 so_recv_data_stat(last->in6p_socket, m, 0);
218 if (sbappendaddr(&last->in6p_socket->so_rcv,
219 (struct sockaddr *)&rip6src,
220 n, opts, NULL) == 0) {
221 rip6stat.rip6s_fullsock++;
222 } else
223 sorwakeup(last->in6p_socket);
224 opts = NULL;
225 }
226 }
227 last = in6p;
228 }
229
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 */
235 } else
236 #endif /* NECP */
237 if (last) {
238 if ((last->in6p_flags & INP_CONTROLOPTS) != 0 ||
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 }
250 /* strip intermediate headers */
251 m_adj(m, *offp);
252 so_recv_data_stat(last->in6p_socket, m, 0);
253 if (sbappendaddr(&last->in6p_socket->so_rcv,
254 (struct sockaddr *)&rip6src, m, opts, NULL) == 0) {
255 rip6stat.rip6s_fullsock++;
256 } else
257 sorwakeup(last->in6p_socket);
258 } else {
259 rip6stat.rip6s_nosock++;
260 if (m->m_flags & M_MCAST)
261 rip6stat.rip6s_nosockmcast++;
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 }
272
273 unlock:
274 lck_rw_done(ripcbinfo.ipi_lock);
275
276 return IPPROTO_DONE;
277 }
278
279 void
280 rip6_ctlinput(
281 int cmd,
282 struct sockaddr *sa,
283 void *d)
284 {
285 struct ip6_hdr *ip6;
286 struct mbuf *m;
287 void *cmdarg = NULL;
288 int off = 0;
289 struct ip6ctlparam *ip6cp = NULL;
290 const struct sockaddr_in6 *sa6_src = NULL;
291 void (*notify)(struct inpcb *, int) = in6_rtchange;
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) {
308 ip6cp = (struct ip6ctlparam *)d;
309 m = ip6cp->ip6c_m;
310 ip6 = ip6cp->ip6c_ip6;
311 off = ip6cp->ip6c_off;
312 cmdarg = ip6cp->ip6c_cmdarg;
313 sa6_src = ip6cp->ip6c_src;
314 } else {
315 m = NULL;
316 ip6 = NULL;
317 sa6_src = &sa6_any;
318 }
319
320 (void) in6_pcbnotify(&ripcbinfo, sa, 0, (const struct sockaddr *)sa6_src,
321 0, cmd, cmdarg, notify);
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 */
328 int
329 rip6_output(
330 struct mbuf *m,
331 struct socket *so,
332 struct sockaddr_in6 *dstsock,
333 struct mbuf *control,
334 int israw)
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;
341 struct ip6_pktopts opt, *optp = NULL;
342 struct ip6_moptions *im6o = NULL;
343 struct ifnet *oifp = NULL;
344 int type = 0, code = 0; /* for ICMPv6 output statistics only */
345 mbuf_svc_class_t msc = MBUF_SC_UNSPEC;
346 struct ip6_out_args ip6oa =
347 { IFSCOPE_NONE, { 0 }, IP6OAF_SELECT_SRCIF, 0 };
348 int flags = IPV6_OUTARGS;
349
350 in6p = sotoin6pcb(so);
351
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;
361 goto bad;
362 }
363 if (dstsock != NULL && IN6_IS_ADDR_V4MAPPED(&dstsock->sin6_addr)) {
364 error = EINVAL;
365 goto bad;
366 }
367
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 }
372 if (INP_NO_CELLULAR(in6p))
373 ip6oa.ip6oa_flags |= IP6OAF_NO_CELLULAR;
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;
378
379 dst = &dstsock->sin6_addr;
380 if (control) {
381 msc = mbuf_service_class_from_control(control);
382
383 if ((error = ip6_setpktopts(control, &opt, NULL,
384 SOCK_PROTO(so))) != 0)
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 */
394 if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
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
406 if (in6p->inp_flowhash == 0)
407 in6p->inp_flowhash = inp_calc_flowhash(in6p);
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 }
414
415 M_PREPEND(m, sizeof(*ip6), M_WAIT);
416 if (m == NULL) {
417 error = ENOBUFS;
418 goto bad;
419 }
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
427 im6o = in6p->in6p_moptions;
428
429 /*
430 * If the scope of the destination is link-local, embed the interface
431 * index in the address.
432 *
433 * XXX advanced-api value overrides sin6_scope_id
434 */
435 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
436 struct in6_pktinfo *pi;
437 struct ifnet *im6o_multicast_ifp = NULL;
438
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 }
444 /*
445 * XXX Boundary check is assumed to be already done in
446 * ip6_setpktoptions().
447 */
448 ifnet_head_lock_shared();
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];
452 if (oifp != NULL)
453 ifnet_reference(oifp);
454 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
455 im6o != NULL && im6o_multicast_ifp != NULL) {
456 oifp = im6o_multicast_ifp;
457 ifnet_reference(oifp);
458 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
459 } else if (dstsock->sin6_scope_id) {
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) {
467 error = ENXIO; /* XXX EINVAL? */
468 ifnet_head_done();
469 goto bad;
470 }
471 ip6->ip6_dst.s6_addr16[1]
472 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
473 }
474 ifnet_head_done();
475 }
476
477 /*
478 * Source address selection.
479 */
480 {
481 struct in6_addr *in6a;
482 struct in6_addr storage;
483 u_short index = 0;
484
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) {
491 if (error == 0)
492 error = EADDRNOTAVAIL;
493 goto bad;
494 } else {
495 ip6oa.ip6oa_flags |= IP6OAF_BOUND_SRCADDR;
496 }
497 ip6->ip6_src = *in6a;
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);
503 if (oifp != NULL)
504 ifnet_release(oifp);
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];
510 if (oifp != NULL)
511 ifnet_reference(oifp);
512 ifnet_head_done();
513 }
514 }
515 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
516 (in6p->inp_flow & IPV6_FLOWINFO_MASK);
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. */
520 ip6->ip6_nxt = in6p->in6p_ip6_nxt;
521 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
522
523 if (SOCK_PROTO(so) == IPPROTO_ICMPV6 || in6p->in6p_cksum != -1) {
524 struct mbuf *n;
525 int off;
526 u_int16_t *p;
527
528 /* compute checksum */
529 if (SOCK_PROTO(so) == IPPROTO_ICMPV6)
530 off = offsetof(struct icmp6_hdr, icmp6_cksum);
531 else
532 off = in6p->in6p_cksum;
533 if (plen < (unsigned int)(off + 1)) {
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;
546 p = (u_int16_t *)(void *)(mtod(n, caddr_t) + off);
547 *p = 0;
548 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
549 }
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 }
558
559 necp_mark_packet_from_socket(m, in6p, policy_id);
560 }
561 #endif /* NECP */
562
563 #if IPSEC
564 if (in6p->in6p_sp != NULL && ipsec_setsocket(m, so) != 0) {
565 error = ENOBUFS;
566 goto bad;
567 }
568 #endif /*IPSEC*/
569
570 if (ROUTE_UNUSABLE(&in6p->in6p_route))
571 ROUTE_RELEASE(&in6p->in6p_route);
572
573 if (oifp != NULL) {
574 ifnet_release(oifp);
575 oifp = NULL;
576 }
577
578 set_packet_service_class(m, so, msc, PKT_SCF_IPV6);
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;
584
585 if (im6o != NULL)
586 IM6O_ADDREF(im6o);
587
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;
596 struct ifnet *outif;
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 */
607 if (rt == NULL)
608 ROUTE_RELEASE(&in6p->in6p_route);
609
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 &&
616 (outif = rt->rt_ifp) != in6p->in6p_last_outifp)
617 in6p->in6p_last_outifp = outif;
618 } else {
619 ROUTE_RELEASE(&in6p->in6p_route);
620 }
621
622 /*
623 * If output interface was cellular/expensive, and this socket is
624 * denied access to it, generate an event.
625 */
626 if (error != 0 && (ip6oa.ip6oa_retflags & IP6OARF_IFDENIED) &&
627 (INP_NO_CELLULAR(in6p) || INP_NO_EXPENSIVE(in6p)))
628 soevent(in6p->inp_socket, (SO_FILT_HINT_LOCKED|
629 SO_FILT_HINT_IFDENIED));
630
631 if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
632 if (oifp)
633 icmp6_ifoutstat_inc(oifp, type, code);
634 icmp6stat.icp6s_outhist[type]++;
635 } else
636 rip6stat.rip6s_opackets++;
637
638 goto freectl;
639
640 bad:
641 if (m != NULL)
642 m_freem(m);
643
644 freectl:
645 if (optp == &opt && optp->ip6po_rthdr)
646 ROUTE_RELEASE(&optp->ip6po_route);
647
648 if (control != NULL) {
649 if (optp == &opt)
650 ip6_clearpktopts(optp, -1);
651 m_freem(control);
652 }
653 if (oifp != NULL)
654 ifnet_release(oifp);
655 return(error);
656 }
657
658 #if IPFW2
659 __private_extern__ void
660 load_ip6fw(void)
661 {
662 ip6_fw_init();
663 }
664 #endif
665
666 /*
667 * Raw IPv6 socket option processing.
668 */
669 int
670 rip6_ctloutput(
671 struct socket *so,
672 struct sockopt *sopt)
673 {
674 int error, optval;
675
676 /* Allow <SOL_SOCKET,SO_FLUSH> at this level */
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));
683 else if (sopt->sopt_level != IPPROTO_IPV6 &&
684 !(sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_FLUSH))
685 return (EINVAL);
686
687 error = 0;
688
689 switch (sopt->sopt_dir) {
690 case SOPT_GET:
691 switch (sopt->sopt_name) {
692 #if IPFW2
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;
702 #endif
703 case IPV6_CHECKSUM:
704 error = ip6_raw_ctloutput(so, sopt);
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) {
714 #if IPFW2
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;
726 #endif
727
728 case IPV6_CHECKSUM:
729 error = ip6_raw_ctloutput(so, sopt);
730 break;
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
740 default:
741 error = ip6_ctloutput(so, sopt);
742 break;
743 }
744 break;
745 }
746
747 return (error);
748 }
749
750 static int
751 rip6_attach(struct socket *so, int proto, struct proc *p)
752 {
753 struct inpcb *inp;
754 int error;
755
756 inp = sotoinpcb(so);
757 if (inp)
758 panic("rip6_attach");
759 if ((error = proc_suser(p)) != 0)
760 return error;
761
762 error = soreserve(so, rip_sendspace, rip_recvspace);
763 if (error)
764 return error;
765 error = in_pcballoc(so, &ripcbinfo, p);
766 if (error)
767 return error;
768 inp = (struct inpcb *)so->so_pcb;
769 inp->inp_vflag |= INP_IPV6;
770 inp->in6p_ip6_nxt = (char)proto;
771 inp->in6p_hops = -1; /* use kernel default */
772 inp->in6p_cksum = -1;
773 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
774 sizeof(struct icmp6_filter), M_PCB, M_WAITOK);
775 if (inp->in6p_icmp6filt == NULL)
776 return (ENOMEM);
777 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
778 return 0;
779 }
780
781 static int
782 rip6_detach(struct socket *so)
783 {
784 struct inpcb *inp;
785
786 inp = sotoinpcb(so);
787 if (inp == 0)
788 panic("rip6_detach");
789 /* xxx: RSVP */
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
798 static int
799 rip6_abort(struct socket *so)
800 {
801 soisdisconnected(so);
802 return rip6_detach(so);
803 }
804
805 static int
806 rip6_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
816 static int
817 rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
818 {
819 #pragma unused(p)
820 struct inpcb *inp = sotoinpcb(so);
821 struct sockaddr_in6 sin6;
822 struct ifaddr *ifa = NULL;
823 struct ifnet *outif = NULL;
824 int error;
825
826 if (inp == NULL
827 #if NECP
828 || (necp_socket_should_use_flow_divert(inp))
829 #endif /* NECP */
830 )
831 return (inp == NULL ? EINVAL : EPROTOTYPE);
832
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);
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);
860 return (EADDRNOTAVAIL);
861 }
862 outif = ifa->ifa_ifp;
863 IFA_UNLOCK(ifa);
864 IFA_REMREF(ifa);
865 }
866 inp->in6p_laddr = sin6.sin6_addr;
867 inp->in6p_last_outifp = outif;
868 return (0);
869 }
870
871 static int
872 rip6_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
873 {
874 struct inpcb *inp = sotoinpcb(so);
875 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(void *)nam;
876 struct in6_addr *in6a = NULL;
877 struct in6_addr storage;
878 int error = 0;
879 #if ENABLE_DEFAULT_SCOPE
880 struct sockaddr_in6 tmp;
881 #endif
882 unsigned int ifscope;
883 struct ifnet *outif = NULL;
884
885 if (inp == NULL
886 #if NECP
887 || (necp_socket_should_use_flow_divert(inp))
888 #endif /* NECP */
889 )
890 return (inp == NULL ? EINVAL : EPROTOTYPE);
891 if (nam->sa_len != sizeof(*addr))
892 return EINVAL;
893 if (TAILQ_EMPTY(&ifnet_head))
894 return EADDRNOTAVAIL;
895 if (addr->sin6_family != AF_INET6)
896 return EAFNOSUPPORT;
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
905
906 ifscope = (inp->inp_flags & INP_BOUND_IF) ?
907 inp->inp_boundifp->if_index : IFSCOPE_NONE;
908
909 /* Source address selection. XXX: need pcblookup? */
910 in6a = in6_selectsrc(addr, inp->in6p_outputopts, inp, &inp->in6p_route,
911 NULL, &storage, ifscope, &error);
912 if (in6a == NULL)
913 return (error ? error : EADDRNOTAVAIL);
914 inp->in6p_laddr = *in6a;
915 inp->in6p_faddr = addr->sin6_addr;
916 if (inp->in6p_route.ro_rt != NULL)
917 outif = inp->in6p_route.ro_rt->rt_ifp;
918 inp->in6p_last_outifp = outif;
919 soisconnected(so);
920 return 0;
921 }
922
923 static int
924 rip6_shutdown(struct socket *so)
925 {
926 socantsendmore(so);
927 return 0;
928 }
929
930 static int
931 rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
932 struct mbuf *control, struct proc *p)
933 {
934 #pragma unused(flags, p)
935 struct inpcb *inp = sotoinpcb(so);
936 struct sockaddr_in6 tmp;
937 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)(void *)nam;
938 int error = 0;
939
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;
949 goto bad;
950 }
951
952 /* always copy sockaddr to avoid overwrites */
953 if (so->so_state & SS_ISCONNECTED) {
954 if (nam != NULL) {
955 error = EISCONN;
956 goto bad;
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) {
967 error = ENOTCONN;
968 goto bad;
969 }
970 tmp = *(struct sockaddr_in6 *)(void *)nam;
971 dst = &tmp;
972 }
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
978 return (rip6_output(m, so, dst, control, 1));
979
980 bad:
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);
989 }
990
991 struct pr_usrreqs rip6_usrreqs = {
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,
1005 };
1006
1007 __private_extern__ struct pr_usrreqs icmp6_dgram_usrreqs = {
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,
1021 };