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> 128extern int ipsec_bypass; 129#endif /*IPSEC*/ 130 131/* 132 * Raw interface to IP6 protocol. 133 */ 134 135extern struct inpcbhead ripcb; 136extern struct inpcbinfo ripcbinfo; 137extern u_int32_t rip_sendspace; 138extern u_int32_t rip_recvspace; 139extern int ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt); 140 141struct 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 */ 148int 149rip6_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 277unlock: 278 lck_rw_done(ripcbinfo.mtx); 279 280 return IPPROTO_DONE; 281} 282 283void 284rip6_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 */ 332int 333rip6_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 622load_ip6fw(void) 623{ 624 ip6_fw_init(); 625} 626#endif 627 628/* 629 * Raw IPv6 socket option processing. 630 */ 631int 632rip6_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 739static int 740rip6_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 770static int 771rip6_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 791static int 792rip6_abort(struct socket *so) 793{ 794 soisdisconnected(so); 795 return rip6_detach(so); 796} 797 798static int 799rip6_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 809static int 810rip6_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 848static int 849rip6_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 894static int 895rip6_shutdown(struct socket *so) 896{ 897 socantsendmore(so); 898 return 0; 899} 900 901static int 902rip6_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 939struct 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 957