1 /* $NetBSD: raw_ip6.c,v 1.75 2006/01/21 00:15:37 rpaulo Exp $ */ 2 /* $KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1988, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 62 */ 63 64 #include <sys/cdefs.h> 65 __KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.75 2006/01/21 00:15:37 rpaulo Exp $"); 66 67 #include "opt_ipsec.h" 68 69 #include <sys/param.h> 70 #include <sys/sysctl.h> 71 #include <sys/malloc.h> 72 #include <sys/mbuf.h> 73 #include <sys/socket.h> 74 #include <sys/protosw.h> 75 #include <sys/socketvar.h> 76 #include <sys/errno.h> 77 #include <sys/systm.h> 78 #include <sys/proc.h> 79 80 #include <net/if.h> 81 #include <net/route.h> 82 #include <net/if_types.h> 83 84 #include <netinet/in.h> 85 #include <netinet/in_var.h> 86 #include <netinet/ip6.h> 87 #include <netinet6/ip6_var.h> 88 #include <netinet6/ip6_mroute.h> 89 #include <netinet/icmp6.h> 90 #include <netinet6/in6_pcb.h> 91 #include <netinet6/nd6.h> 92 #include <netinet6/ip6protosw.h> 93 #include <netinet6/scope6_var.h> 94 #include <netinet6/raw_ip6.h> 95 96 #ifdef IPSEC 97 #include <netinet6/ipsec.h> 98 #endif /* IPSEC */ 99 100 #include <machine/stdarg.h> 101 102 #include "faith.h" 103 #if defined(NFAITH) && 0 < NFAITH 104 #include <net/if_faith.h> 105 #endif 106 107 extern struct inpcbtable rawcbtable; 108 struct inpcbtable raw6cbtable; 109 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) 110 111 /* 112 * Raw interface to IP6 protocol. 113 */ 114 115 struct rip6stat rip6stat; 116 117 /* 118 * Initialize raw connection block queue. 119 */ 120 void 121 rip6_init() 122 { 123 124 in6_pcbinit(&raw6cbtable, 1, 1); 125 } 126 127 /* 128 * Setup generic address and protocol structures 129 * for raw_input routine, then pass them along with 130 * mbuf chain. 131 */ 132 int 133 rip6_input(mp, offp, proto) 134 struct mbuf **mp; 135 int *offp, proto; 136 { 137 struct mbuf *m = *mp; 138 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 139 struct inpcb_hdr *inph; 140 struct in6pcb *in6p; 141 struct in6pcb *last = NULL; 142 struct sockaddr_in6 rip6src; 143 struct mbuf *opts = NULL; 144 145 rip6stat.rip6s_ipackets++; 146 147 #if defined(NFAITH) && 0 < NFAITH 148 if (faithprefix(&ip6->ip6_dst)) { 149 /* send icmp6 host unreach? */ 150 m_freem(m); 151 return IPPROTO_DONE; 152 } 153 #endif 154 155 /* Be proactive about malicious use of IPv4 mapped address */ 156 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 157 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 158 /* XXX stat */ 159 m_freem(m); 160 return IPPROTO_DONE; 161 } 162 163 bzero(&rip6src, sizeof(rip6src)); 164 rip6src.sin6_len = sizeof(struct sockaddr_in6); 165 rip6src.sin6_family = AF_INET6; 166 rip6src.sin6_addr = ip6->ip6_src; 167 if (sa6_recoverscope(&rip6src) != 0) { 168 /* XXX: should be impossible. */ 169 m_freem(m); 170 return IPPROTO_DONE; 171 } 172 173 CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) { 174 in6p = (struct in6pcb *)inph; 175 if (in6p->in6p_af != AF_INET6) 176 continue; 177 if (in6p->in6p_ip6.ip6_nxt && 178 in6p->in6p_ip6.ip6_nxt != proto) 179 continue; 180 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 181 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 182 continue; 183 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 184 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 185 continue; 186 if (in6p->in6p_cksum != -1) { 187 rip6stat.rip6s_isum++; 188 if (in6_cksum(m, proto, *offp, 189 m->m_pkthdr.len - *offp)) { 190 rip6stat.rip6s_badsum++; 191 continue; 192 } 193 } 194 if (last) { 195 struct mbuf *n; 196 197 #ifdef IPSEC 198 /* 199 * Check AH/ESP integrity. 200 */ 201 if (ipsec6_in_reject(m, last)) { 202 ipsec6stat.in_polvio++; 203 /* do not inject data into pcb */ 204 } else 205 #endif /* IPSEC */ 206 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 207 if (last->in6p_flags & IN6P_CONTROLOPTS) 208 ip6_savecontrol(last, &opts, ip6, n); 209 /* strip intermediate headers */ 210 m_adj(n, *offp); 211 if (sbappendaddr(&last->in6p_socket->so_rcv, 212 (struct sockaddr *)&rip6src, n, opts) == 0) { 213 /* should notify about lost packet */ 214 m_freem(n); 215 if (opts) 216 m_freem(opts); 217 rip6stat.rip6s_fullsock++; 218 } else 219 sorwakeup(last->in6p_socket); 220 opts = NULL; 221 } 222 } 223 last = in6p; 224 } 225 #ifdef IPSEC 226 /* 227 * Check AH/ESP integrity. 228 */ 229 if (last && ipsec6_in_reject(m, last)) { 230 m_freem(m); 231 ipsec6stat.in_polvio++; 232 ip6stat.ip6s_delivered--; 233 /* do not inject data into pcb */ 234 } else 235 #endif /* IPSEC */ 236 if (last) { 237 if (last->in6p_flags & IN6P_CONTROLOPTS) 238 ip6_savecontrol(last, &opts, ip6, m); 239 /* strip intermediate headers */ 240 m_adj(m, *offp); 241 if (sbappendaddr(&last->in6p_socket->so_rcv, 242 (struct sockaddr *)&rip6src, m, opts) == 0) { 243 m_freem(m); 244 if (opts) 245 m_freem(opts); 246 rip6stat.rip6s_fullsock++; 247 } else 248 sorwakeup(last->in6p_socket); 249 } else { 250 rip6stat.rip6s_nosock++; 251 if (m->m_flags & M_MCAST) 252 rip6stat.rip6s_nosockmcast++; 253 if (proto == IPPROTO_NONE) 254 m_freem(m); 255 else { 256 u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 257 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown); 258 icmp6_error(m, ICMP6_PARAM_PROB, 259 ICMP6_PARAMPROB_NEXTHEADER, 260 prvnxtp - mtod(m, u_int8_t *)); 261 } 262 ip6stat.ip6s_delivered--; 263 } 264 return IPPROTO_DONE; 265 } 266 267 void 268 rip6_ctlinput(cmd, sa, d) 269 int cmd; 270 struct sockaddr *sa; 271 void *d; 272 { 273 struct ip6_hdr *ip6; 274 struct ip6ctlparam *ip6cp = NULL; 275 const struct sockaddr_in6 *sa6_src = NULL; 276 void *cmdarg; 277 void (*notify) __P((struct in6pcb *, int)) = in6_rtchange; 278 int nxt; 279 280 if (sa->sa_family != AF_INET6 || 281 sa->sa_len != sizeof(struct sockaddr_in6)) 282 return; 283 284 if ((unsigned)cmd >= PRC_NCMDS) 285 return; 286 if (PRC_IS_REDIRECT(cmd)) 287 notify = in6_rtchange, d = NULL; 288 else if (cmd == PRC_HOSTDEAD) 289 d = NULL; 290 else if (cmd == PRC_MSGSIZE) 291 ; /* special code is present, see below */ 292 else if (inet6ctlerrmap[cmd] == 0) 293 return; 294 295 /* if the parameter is from icmp6, decode it. */ 296 if (d != NULL) { 297 ip6cp = (struct ip6ctlparam *)d; 298 ip6 = ip6cp->ip6c_ip6; 299 cmdarg = ip6cp->ip6c_cmdarg; 300 sa6_src = ip6cp->ip6c_src; 301 nxt = ip6cp->ip6c_nxt; 302 } else { 303 ip6 = NULL; 304 cmdarg = NULL; 305 sa6_src = &sa6_any; 306 nxt = -1; 307 } 308 309 if (ip6 && cmd == PRC_MSGSIZE) { 310 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 311 int valid = 0; 312 struct in6pcb *in6p; 313 314 /* 315 * Check to see if we have a valid raw IPv6 socket 316 * corresponding to the address in the ICMPv6 message 317 * payload, and the protocol (ip6_nxt) meets the socket. 318 * XXX chase extension headers, or pass final nxt value 319 * from icmp6_notify_error() 320 */ 321 in6p = NULL; 322 in6p = in6_pcblookup_connect(&raw6cbtable, &sa6->sin6_addr, 0, 323 (const struct in6_addr *)&sa6_src->sin6_addr, 0, 0); 324 #if 0 325 if (!in6p) { 326 /* 327 * As the use of sendto(2) is fairly popular, 328 * we may want to allow non-connected pcb too. 329 * But it could be too weak against attacks... 330 * We should at least check if the local 331 * address (= s) is really ours. 332 */ 333 in6p = in6_pcblookup_bind(&raw6cbtable, 334 &sa6->sin6_addr, 0, 0); 335 } 336 #endif 337 338 if (in6p && in6p->in6p_ip6.ip6_nxt && 339 in6p->in6p_ip6.ip6_nxt == nxt) 340 valid++; 341 342 /* 343 * Depending on the value of "valid" and routing table 344 * size (mtudisc_{hi,lo}wat), we will: 345 * - recalculate the new MTU and create the 346 * corresponding routing entry, or 347 * - ignore the MTU change notification. 348 */ 349 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 350 351 /* 352 * regardless of if we called icmp6_mtudisc_update(), 353 * we need to call in6_pcbnotify(), to notify path 354 * MTU change to the userland (2292bis-02), because 355 * some unconnected sockets may share the same 356 * destination and want to know the path MTU. 357 */ 358 } 359 360 (void) in6_pcbnotify(&raw6cbtable, sa, 0, 361 (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify); 362 } 363 364 /* 365 * Generate IPv6 header and pass packet to ip6_output. 366 * Tack on options user may have setup with control call. 367 */ 368 int 369 #if __STDC__ 370 rip6_output(struct mbuf *m, ...) 371 #else 372 rip6_output(m, va_alist) 373 struct mbuf *m; 374 va_dcl 375 #endif 376 { 377 struct socket *so; 378 struct sockaddr_in6 *dstsock; 379 struct mbuf *control; 380 struct in6_addr *dst; 381 struct ip6_hdr *ip6; 382 struct in6pcb *in6p; 383 u_int plen = m->m_pkthdr.len; 384 int error = 0; 385 struct ip6_pktopts opt, *optp = NULL; 386 struct ifnet *oifp = NULL; 387 int type, code; /* for ICMPv6 output statistics only */ 388 int priv = 0; 389 int scope_ambiguous = 0; 390 struct in6_addr *in6a; 391 va_list ap; 392 int flags; 393 394 va_start(ap, m); 395 so = va_arg(ap, struct socket *); 396 dstsock = va_arg(ap, struct sockaddr_in6 *); 397 control = va_arg(ap, struct mbuf *); 398 va_end(ap); 399 400 in6p = sotoin6pcb(so); 401 402 priv = 0; 403 if (curproc && !suser(curproc->p_ucred, &curproc->p_acflag)) 404 priv = 1; 405 406 dst = &dstsock->sin6_addr; 407 if (control) { 408 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) 409 goto bad; 410 optp = &opt; 411 } else 412 optp = in6p->in6p_outputopts; 413 414 /* 415 * Check and convert scope zone ID into internal form. 416 * XXX: we may still need to determine the zone later. 417 */ 418 if (!(so->so_state & SS_ISCONNECTED)) { 419 if (dstsock->sin6_scope_id == 0 && !ip6_use_defzone) 420 scope_ambiguous = 1; 421 if ((error = sa6_embedscope(dstsock, ip6_use_defzone)) != 0) 422 goto bad; 423 } 424 425 /* 426 * For an ICMPv6 packet, we should know its type and code 427 * to update statistics. 428 */ 429 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 430 struct icmp6_hdr *icmp6; 431 if (m->m_len < sizeof(struct icmp6_hdr) && 432 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 433 error = ENOBUFS; 434 goto bad; 435 } 436 icmp6 = mtod(m, struct icmp6_hdr *); 437 type = icmp6->icmp6_type; 438 code = icmp6->icmp6_code; 439 } else { 440 type = 0; 441 code = 0; 442 } 443 444 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT); 445 if (!m) { 446 error = ENOBUFS; 447 goto bad; 448 } 449 ip6 = mtod(m, struct ip6_hdr *); 450 451 /* 452 * Next header might not be ICMP6 but use its pseudo header anyway. 453 */ 454 ip6->ip6_dst = *dst; 455 456 /* 457 * Source address selection. 458 */ 459 if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions, 460 &in6p->in6p_route, &in6p->in6p_laddr, &oifp, &error)) == 0) { 461 if (error == 0) 462 error = EADDRNOTAVAIL; 463 goto bad; 464 } 465 ip6->ip6_src = *in6a; 466 467 if (oifp && scope_ambiguous) { 468 /* 469 * Application should provide a proper zone ID or the use of 470 * default zone IDs should be enabled. Unfortunately, some 471 * applications do not behave as it should, so we need a 472 * workaround. Even if an appropriate ID is not determined 473 * (when it's required), if we can determine the outgoing 474 * interface. determine the zone ID based on the interface. 475 */ 476 error = in6_setscope(&dstsock->sin6_addr, oifp, NULL); 477 if (error != 0) 478 goto bad; 479 } 480 ip6->ip6_dst = dstsock->sin6_addr; 481 482 /* fill in the rest of the IPv6 header fields */ 483 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; 484 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 485 ip6->ip6_vfc |= IPV6_VERSION; 486 /* ip6_plen will be filled in ip6_output, so not fill it here. */ 487 ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt; 488 ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 489 490 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 491 in6p->in6p_cksum != -1) { 492 int off; 493 u_int16_t sum; 494 495 /* compute checksum */ 496 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 497 off = offsetof(struct icmp6_hdr, icmp6_cksum); 498 else 499 off = in6p->in6p_cksum; 500 if (plen < off + 1) { 501 error = EINVAL; 502 goto bad; 503 } 504 off += sizeof(struct ip6_hdr); 505 506 sum = 0; 507 m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum, 508 M_DONTWAIT); 509 if (m == NULL) { 510 error = ENOBUFS; 511 goto bad; 512 } 513 sum = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 514 m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum, 515 M_DONTWAIT); 516 if (m == NULL) { 517 error = ENOBUFS; 518 goto bad; 519 } 520 } 521 522 flags = 0; 523 if (in6p->in6p_flags & IN6P_MINMTU) 524 flags |= IPV6_MINMTU; 525 526 error = ip6_output(m, optp, &in6p->in6p_route, flags, 527 in6p->in6p_moptions, so, &oifp); 528 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 529 if (oifp) 530 icmp6_ifoutstat_inc(oifp, type, code); 531 icmp6stat.icp6s_outhist[type]++; 532 } else 533 rip6stat.rip6s_opackets++; 534 535 goto freectl; 536 537 bad: 538 if (m) 539 m_freem(m); 540 541 freectl: 542 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) 543 RTFREE(optp->ip6po_route.ro_rt); 544 if (control) 545 m_freem(control); 546 return (error); 547 } 548 549 /* 550 * Raw IPv6 socket option processing. 551 */ 552 int 553 rip6_ctloutput(op, so, level, optname, mp) 554 int op; 555 struct socket *so; 556 int level, optname; 557 struct mbuf **mp; 558 { 559 int error = 0; 560 561 switch (level) { 562 case IPPROTO_IPV6: 563 switch (optname) { 564 case MRT6_INIT: 565 case MRT6_DONE: 566 case MRT6_ADD_MIF: 567 case MRT6_DEL_MIF: 568 case MRT6_ADD_MFC: 569 case MRT6_DEL_MFC: 570 case MRT6_PIM: 571 if (op == PRCO_SETOPT) { 572 error = ip6_mrouter_set(optname, so, *mp); 573 if (*mp) 574 (void)m_free(*mp); 575 } else if (op == PRCO_GETOPT) 576 error = ip6_mrouter_get(optname, so, mp); 577 else 578 error = EINVAL; 579 return (error); 580 case IPV6_CHECKSUM: 581 return (ip6_raw_ctloutput(op, so, level, optname, mp)); 582 default: 583 return (ip6_ctloutput(op, so, level, optname, mp)); 584 } 585 586 case IPPROTO_ICMPV6: 587 /* 588 * XXX: is it better to call icmp6_ctloutput() directly 589 * from protosw? 590 */ 591 return (icmp6_ctloutput(op, so, level, optname, mp)); 592 593 default: 594 if (op == PRCO_SETOPT && *mp) 595 m_free(*mp); 596 return EINVAL; 597 } 598 } 599 600 extern u_long rip6_sendspace; 601 extern u_long rip6_recvspace; 602 603 int 604 rip6_usrreq(so, req, m, nam, control, l) 605 struct socket *so; 606 int req; 607 struct mbuf *m, *nam, *control; 608 struct lwp *l; 609 { 610 struct in6pcb *in6p = sotoin6pcb(so); 611 struct proc *p; 612 int s; 613 int error = 0; 614 int priv; 615 616 priv = 0; 617 p = l ? l->l_proc : NULL; 618 if (p && !suser(p->p_ucred, &p->p_acflag)) 619 priv++; 620 621 if (req == PRU_CONTROL) 622 return (in6_control(so, (u_long)m, (caddr_t)nam, 623 (struct ifnet *)control, p)); 624 625 if (req == PRU_PURGEIF) { 626 in6_pcbpurgeif0(&raw6cbtable, (struct ifnet *)control); 627 in6_purgeif((struct ifnet *)control); 628 in6_pcbpurgeif(&raw6cbtable, (struct ifnet *)control); 629 return (0); 630 } 631 632 switch (req) { 633 case PRU_ATTACH: 634 if (in6p) 635 panic("rip6_attach"); 636 if (!priv) { 637 error = EACCES; 638 break; 639 } 640 s = splsoftnet(); 641 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) { 642 splx(s); 643 break; 644 } 645 if ((error = in6_pcballoc(so, &raw6cbtable)) != 0) 646 { 647 splx(s); 648 break; 649 } 650 splx(s); 651 in6p = sotoin6pcb(so); 652 in6p->in6p_ip6.ip6_nxt = (long)nam; 653 in6p->in6p_cksum = -1; 654 655 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *, 656 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); 657 if (in6p->in6p_icmp6filt == NULL) { 658 in6_pcbdetach(in6p); 659 error = ENOMEM; 660 break; 661 } 662 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt); 663 break; 664 665 case PRU_DISCONNECT: 666 if ((so->so_state & SS_ISCONNECTED) == 0) { 667 error = ENOTCONN; 668 break; 669 } 670 in6p->in6p_faddr = in6addr_any; 671 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 672 break; 673 674 case PRU_ABORT: 675 soisdisconnected(so); 676 /* Fallthrough */ 677 case PRU_DETACH: 678 if (in6p == 0) 679 panic("rip6_detach"); 680 if (so == ip6_mrouter) 681 ip6_mrouter_done(); 682 /* xxx: RSVP */ 683 if (in6p->in6p_icmp6filt) { 684 FREE(in6p->in6p_icmp6filt, M_PCB); 685 in6p->in6p_icmp6filt = NULL; 686 } 687 in6_pcbdetach(in6p); 688 break; 689 690 case PRU_BIND: 691 { 692 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); 693 struct ifaddr *ia = NULL; 694 695 if (nam->m_len != sizeof(*addr)) { 696 error = EINVAL; 697 break; 698 } 699 if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) { 700 error = EADDRNOTAVAIL; 701 break; 702 } 703 if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) 704 break; 705 706 /* 707 * we don't support mapped address here, it would confuse 708 * users so reject it 709 */ 710 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 711 error = EADDRNOTAVAIL; 712 break; 713 } 714 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 715 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) { 716 error = EADDRNOTAVAIL; 717 break; 718 } 719 if (ia && ((struct in6_ifaddr *)ia)->ia6_flags & 720 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 721 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 722 error = EADDRNOTAVAIL; 723 break; 724 } 725 in6p->in6p_laddr = addr->sin6_addr; 726 break; 727 } 728 729 case PRU_CONNECT: 730 { 731 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); 732 struct in6_addr *in6a = NULL; 733 struct ifnet *ifp = NULL; 734 int scope_ambiguous = 0; 735 736 if (nam->m_len != sizeof(*addr)) { 737 error = EINVAL; 738 break; 739 } 740 if (ifnet.tqh_first == 0) 741 { 742 error = EADDRNOTAVAIL; 743 break; 744 } 745 if (addr->sin6_family != AF_INET6) { 746 error = EAFNOSUPPORT; 747 break; 748 } 749 750 /* 751 * Application should provide a proper zone ID or the use of 752 * default zone IDs should be enabled. Unfortunately, some 753 * applications do not behave as it should, so we need a 754 * workaround. Even if an appropriate ID is not determined, 755 * we'll see if we can determine the outgoing interface. If we 756 * can, determine the zone ID based on the interface below. 757 */ 758 if (addr->sin6_scope_id == 0 && !ip6_use_defzone) 759 scope_ambiguous = 1; 760 if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) 761 return(error); 762 763 /* Source address selection. XXX: need pcblookup? */ 764 in6a = in6_selectsrc(addr, in6p->in6p_outputopts, 765 in6p->in6p_moptions, &in6p->in6p_route, 766 &in6p->in6p_laddr, &ifp, &error); 767 if (in6a == NULL) { 768 if (error == 0) 769 error = EADDRNOTAVAIL; 770 break; 771 } 772 /* XXX: see above */ 773 if (ifp && scope_ambiguous && 774 (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) { 775 break; 776 } 777 in6p->in6p_laddr = *in6a; 778 in6p->in6p_faddr = addr->sin6_addr; 779 soisconnected(so); 780 break; 781 } 782 783 case PRU_CONNECT2: 784 error = EOPNOTSUPP; 785 break; 786 787 /* 788 * Mark the connection as being incapable of futther input. 789 */ 790 case PRU_SHUTDOWN: 791 socantsendmore(so); 792 break; 793 /* 794 * Ship a packet out. The appropriate raw output 795 * routine handles any messaging necessary. 796 */ 797 case PRU_SEND: 798 { 799 struct sockaddr_in6 tmp; 800 struct sockaddr_in6 *dst; 801 802 /* always copy sockaddr to avoid overwrites */ 803 if (so->so_state & SS_ISCONNECTED) { 804 if (nam) { 805 error = EISCONN; 806 break; 807 } 808 /* XXX */ 809 bzero(&tmp, sizeof(tmp)); 810 tmp.sin6_family = AF_INET6; 811 tmp.sin6_len = sizeof(struct sockaddr_in6); 812 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr, 813 sizeof(struct in6_addr)); 814 dst = &tmp; 815 } else { 816 if (nam == NULL) { 817 error = ENOTCONN; 818 break; 819 } 820 if (nam->m_len != sizeof(tmp)) { 821 error = EINVAL; 822 break; 823 } 824 825 tmp = *mtod(nam, struct sockaddr_in6 *); 826 dst = &tmp; 827 828 if (dst->sin6_family != AF_INET6) { 829 error = EAFNOSUPPORT; 830 break; 831 } 832 } 833 error = rip6_output(m, so, dst, control); 834 m = NULL; 835 break; 836 } 837 838 case PRU_SENSE: 839 /* 840 * stat: don't bother with a blocksize 841 */ 842 return (0); 843 /* 844 * Not supported. 845 */ 846 case PRU_RCVOOB: 847 case PRU_RCVD: 848 case PRU_LISTEN: 849 case PRU_ACCEPT: 850 case PRU_SENDOOB: 851 error = EOPNOTSUPP; 852 break; 853 854 case PRU_SOCKADDR: 855 in6_setsockaddr(in6p, nam); 856 break; 857 858 case PRU_PEERADDR: 859 in6_setpeeraddr(in6p, nam); 860 break; 861 862 default: 863 panic("rip6_usrreq"); 864 } 865 if (m != NULL) 866 m_freem(m); 867 return (error); 868 } 869 870 SYSCTL_SETUP(sysctl_net_inet6_raw6_setup, "sysctl net.inet6.raw6 subtree setup") 871 { 872 873 sysctl_createv(clog, 0, NULL, NULL, 874 CTLFLAG_PERMANENT, 875 CTLTYPE_NODE, "net", NULL, 876 NULL, 0, NULL, 0, 877 CTL_NET, CTL_EOL); 878 sysctl_createv(clog, 0, NULL, NULL, 879 CTLFLAG_PERMANENT, 880 CTLTYPE_NODE, "inet6", NULL, 881 NULL, 0, NULL, 0, 882 CTL_NET, PF_INET6, CTL_EOL); 883 sysctl_createv(clog, 0, NULL, NULL, 884 CTLFLAG_PERMANENT, 885 CTLTYPE_NODE, "raw6", 886 SYSCTL_DESCR("Raw IPv6 settings"), 887 NULL, 0, NULL, 0, 888 CTL_NET, PF_INET6, IPPROTO_RAW, CTL_EOL); 889 890 sysctl_createv(clog, 0, NULL, NULL, 891 CTLFLAG_PERMANENT, 892 CTLTYPE_STRUCT, "pcblist", 893 SYSCTL_DESCR("Raw IPv6 control block list"), 894 sysctl_inpcblist, 0, &raw6cbtable, 0, 895 CTL_NET, PF_INET6, IPPROTO_RAW, 896 CTL_CREATE, CTL_EOL); 897 sysctl_createv(clog, 0, NULL, NULL, 898 CTLFLAG_PERMANENT, 899 CTLTYPE_STRUCT, "stats", 900 SYSCTL_DESCR("Raw IPv6 statistics"), 901 NULL, 0, &rip6stat, sizeof(rip6stat), 902 CTL_NET, PF_INET6, IPPROTO_RAW, RAW6CTL_STATS, 903 CTL_EOL); 904 } 905