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