1 /* $OpenBSD: raw_ip6.c,v 1.93 2016/07/22 11:14:41 mpi Exp $ */ 2 /* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun 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 "pf.h" 65 66 #include <sys/param.h> 67 #include <sys/malloc.h> 68 #include <sys/mbuf.h> 69 #include <sys/socket.h> 70 #include <sys/protosw.h> 71 #include <sys/socketvar.h> 72 #include <sys/errno.h> 73 #include <sys/systm.h> 74 #include <sys/sysctl.h> 75 76 #include <net/if.h> 77 #include <net/if_var.h> 78 #include <net/route.h> 79 80 #include <netinet/in.h> 81 #include <netinet6/in6_var.h> 82 #include <netinet/ip6.h> 83 #include <netinet6/ip6_var.h> 84 #ifdef MROUTING 85 #include <netinet6/ip6_mroute.h> 86 #endif 87 #include <netinet/icmp6.h> 88 #include <netinet/ip.h> 89 #include <netinet/in_pcb.h> 90 #include <netinet6/nd6.h> 91 #include <netinet6/ip6protosw.h> 92 #include <netinet6/raw_ip6.h> 93 94 #if NPF > 0 95 #include <net/pfvar.h> 96 #endif 97 98 #include <sys/stdarg.h> 99 100 /* 101 * Raw interface to IP6 protocol. 102 */ 103 104 struct inpcbtable rawin6pcbtable; 105 106 struct rip6stat rip6stat; 107 108 /* 109 * Initialize raw connection block queue. 110 */ 111 void 112 rip6_init(void) 113 { 114 115 in_pcbinit(&rawin6pcbtable, 1); 116 } 117 118 /* 119 * Setup generic address and protocol structures 120 * for raw_input routine, then pass them along with 121 * mbuf chain. 122 */ 123 int 124 rip6_input(struct mbuf **mp, int *offp, int proto) 125 { 126 struct mbuf *m = *mp; 127 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 128 struct inpcb *in6p; 129 struct inpcb *last = NULL; 130 struct sockaddr_in6 rip6src; 131 struct mbuf *opts = NULL; 132 133 rip6stat.rip6s_ipackets++; 134 135 /* Be proactive about malicious use of IPv4 mapped address */ 136 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 137 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 138 /* XXX stat */ 139 m_freem(m); 140 return IPPROTO_DONE; 141 } 142 143 bzero(&rip6src, sizeof(rip6src)); 144 rip6src.sin6_len = sizeof(struct sockaddr_in6); 145 rip6src.sin6_family = AF_INET6; 146 /* KAME hack: recover scopeid */ 147 in6_recoverscope(&rip6src, &ip6->ip6_src); 148 149 TAILQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) { 150 if (in6p->inp_socket->so_state & SS_CANTRCVMORE) 151 continue; 152 if (!(in6p->inp_flags & INP_IPV6)) 153 continue; 154 if (in6p->inp_ipv6.ip6_nxt && 155 in6p->inp_ipv6.ip6_nxt != proto) 156 continue; 157 #if NPF > 0 158 if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) { 159 struct pf_divert *divert; 160 161 /* XXX rdomain support */ 162 if ((divert = pf_find_divert(m)) == NULL) 163 continue; 164 if (IN6_IS_ADDR_UNSPECIFIED(&divert->addr.v6)) 165 goto divert_reply; 166 if (!IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, 167 &divert->addr.v6)) 168 continue; 169 } else 170 divert_reply: 171 #endif 172 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_laddr6) && 173 !IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, &ip6->ip6_dst)) 174 continue; 175 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6) && 176 !IN6_ARE_ADDR_EQUAL(&in6p->inp_faddr6, &ip6->ip6_src)) 177 continue; 178 if (in6p->inp_cksum6 != -1) { 179 rip6stat.rip6s_isum++; 180 if (in6_cksum(m, proto, *offp, 181 m->m_pkthdr.len - *offp)) { 182 rip6stat.rip6s_badsum++; 183 continue; 184 } 185 } 186 if (last) { 187 struct mbuf *n; 188 if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) { 189 if (last->inp_flags & IN6P_CONTROLOPTS) 190 ip6_savecontrol(last, n, &opts); 191 /* strip intermediate headers */ 192 m_adj(n, *offp); 193 if (sbappendaddr(&last->inp_socket->so_rcv, 194 sin6tosa(&rip6src), n, opts) == 0) { 195 /* should notify about lost packet */ 196 m_freem(n); 197 m_freem(opts); 198 rip6stat.rip6s_fullsock++; 199 } else 200 sorwakeup(last->inp_socket); 201 opts = NULL; 202 } 203 } 204 last = in6p; 205 } 206 if (last) { 207 if (last->inp_flags & IN6P_CONTROLOPTS) 208 ip6_savecontrol(last, m, &opts); 209 /* strip intermediate headers */ 210 m_adj(m, *offp); 211 if (sbappendaddr(&last->inp_socket->so_rcv, 212 sin6tosa(&rip6src), m, opts) == 0) { 213 m_freem(m); 214 m_freem(opts); 215 rip6stat.rip6s_fullsock++; 216 } else 217 sorwakeup(last->inp_socket); 218 } else { 219 rip6stat.rip6s_nosock++; 220 if (m->m_flags & M_MCAST) 221 rip6stat.rip6s_nosockmcast++; 222 if (proto == IPPROTO_NONE) 223 m_freem(m); 224 else { 225 u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 226 icmp6_error(m, ICMP6_PARAM_PROB, 227 ICMP6_PARAMPROB_NEXTHEADER, 228 prvnxtp - mtod(m, u_int8_t *)); 229 } 230 ip6stat.ip6s_delivered--; 231 } 232 return IPPROTO_DONE; 233 } 234 235 void 236 rip6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) 237 { 238 struct ip6_hdr *ip6; 239 struct ip6ctlparam *ip6cp = NULL; 240 struct sockaddr_in6 *sa6 = satosin6(sa); 241 const struct sockaddr_in6 *sa6_src = NULL; 242 void *cmdarg; 243 void (*notify)(struct inpcb *, int) = in_rtchange; 244 int nxt; 245 246 if (sa->sa_family != AF_INET6 || 247 sa->sa_len != sizeof(struct sockaddr_in6)) 248 return; 249 250 if ((unsigned)cmd >= PRC_NCMDS) 251 return; 252 if (PRC_IS_REDIRECT(cmd)) 253 notify = in_rtchange, d = NULL; 254 else if (cmd == PRC_HOSTDEAD) 255 d = NULL; 256 else if (cmd == PRC_MSGSIZE) 257 ; /* special code is present, see below */ 258 else if (inet6ctlerrmap[cmd] == 0) 259 return; 260 261 /* if the parameter is from icmp6, decode it. */ 262 if (d != NULL) { 263 ip6cp = (struct ip6ctlparam *)d; 264 ip6 = ip6cp->ip6c_ip6; 265 cmdarg = ip6cp->ip6c_cmdarg; 266 sa6_src = ip6cp->ip6c_src; 267 nxt = ip6cp->ip6c_nxt; 268 } else { 269 ip6 = NULL; 270 cmdarg = NULL; 271 sa6_src = &sa6_any; 272 nxt = -1; 273 } 274 275 if (ip6 && cmd == PRC_MSGSIZE) { 276 int valid = 0; 277 struct inpcb *in6p; 278 279 /* 280 * Check to see if we have a valid raw IPv6 socket 281 * corresponding to the address in the ICMPv6 message 282 * payload, and the protocol (ip6_nxt) meets the socket. 283 * XXX chase extension headers, or pass final nxt value 284 * from icmp6_notify_error() 285 */ 286 in6p = in6_pcbhashlookup(&rawin6pcbtable, &sa6->sin6_addr, 0, 287 &sa6_src->sin6_addr, 0, rdomain); 288 289 if (in6p && in6p->inp_ipv6.ip6_nxt && 290 in6p->inp_ipv6.ip6_nxt == nxt) 291 valid++; 292 293 /* 294 * Depending on the value of "valid" and routing table 295 * size (mtudisc_{hi,lo}wat), we will: 296 * - recalculate the new MTU and create the 297 * corresponding routing entry, or 298 * - ignore the MTU change notification. 299 */ 300 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 301 302 /* 303 * regardless of if we called icmp6_mtudisc_update(), 304 * we need to call in6_pcbnotify(), to notify path 305 * MTU change to the userland (2292bis-02), because 306 * some unconnected sockets may share the same 307 * destination and want to know the path MTU. 308 */ 309 } 310 311 (void) in6_pcbnotify(&rawin6pcbtable, sa6, 0, 312 sa6_src, 0, rdomain, cmd, cmdarg, notify); 313 } 314 315 /* 316 * Generate IPv6 header and pass packet to ip6_output. 317 * Tack on options user may have setup with control call. 318 */ 319 int 320 rip6_output(struct mbuf *m, ...) 321 { 322 struct socket *so; 323 struct sockaddr_in6 *dstsock; 324 struct mbuf *control; 325 struct in6_addr *dst; 326 struct ip6_hdr *ip6; 327 struct inpcb *in6p; 328 u_int plen = m->m_pkthdr.len; 329 int error = 0; 330 struct ip6_pktopts opt, *optp = NULL, *origoptp; 331 int type; /* for ICMPv6 output statistics only */ 332 int priv = 0; 333 va_list ap; 334 int flags; 335 336 va_start(ap, m); 337 so = va_arg(ap, struct socket *); 338 dstsock = va_arg(ap, struct sockaddr_in6 *); 339 control = va_arg(ap, struct mbuf *); 340 va_end(ap); 341 342 in6p = sotoinpcb(so); 343 344 priv = 0; 345 if ((so->so_state & SS_PRIV) != 0) 346 priv = 1; 347 dst = &dstsock->sin6_addr; 348 if (control) { 349 if ((error = ip6_setpktopts(control, &opt, 350 in6p->inp_outputopts6, 351 priv, so->so_proto->pr_protocol)) != 0) 352 goto bad; 353 optp = &opt; 354 } else 355 optp = in6p->inp_outputopts6; 356 357 /* 358 * For an ICMPv6 packet, we should know its type and code 359 * to update statistics. 360 */ 361 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 362 struct icmp6_hdr *icmp6; 363 if (m->m_len < sizeof(struct icmp6_hdr) && 364 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 365 error = ENOBUFS; 366 goto bad; 367 } 368 icmp6 = mtod(m, struct icmp6_hdr *); 369 type = icmp6->icmp6_type; 370 } 371 372 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT); 373 if (!m) { 374 error = ENOBUFS; 375 goto bad; 376 } 377 ip6 = mtod(m, struct ip6_hdr *); 378 379 /* 380 * Next header might not be ICMP6 but use its pseudo header anyway. 381 */ 382 ip6->ip6_dst = *dst; 383 384 /* KAME hack: embed scopeid */ 385 origoptp = in6p->inp_outputopts6; 386 in6p->inp_outputopts6 = optp; 387 if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p) != 0) { 388 error = EINVAL; 389 goto bad; 390 } 391 in6p->inp_outputopts6 = origoptp; 392 393 /* 394 * Source address selection. 395 */ 396 { 397 struct in6_addr *in6a; 398 399 error = in6_selectsrc(&in6a, dstsock, optp, 400 in6p->inp_moptions6, &in6p->inp_route6, &in6p->inp_laddr6, 401 in6p->inp_rtableid); 402 if (error) 403 goto bad; 404 405 ip6->ip6_src = *in6a; 406 } 407 408 ip6->ip6_flow = in6p->inp_flowinfo & IPV6_FLOWINFO_MASK; 409 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 410 ip6->ip6_vfc |= IPV6_VERSION; 411 #if 0 /* ip6_plen will be filled in ip6_output. */ 412 ip6->ip6_plen = htons((u_short)plen); 413 #endif 414 ip6->ip6_nxt = in6p->inp_ipv6.ip6_nxt; 415 ip6->ip6_hlim = in6_selecthlim(in6p); 416 417 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 418 in6p->inp_cksum6 != -1) { 419 struct mbuf *n; 420 int off; 421 u_int16_t *sump; 422 int sumoff; 423 424 /* compute checksum */ 425 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 426 off = offsetof(struct icmp6_hdr, icmp6_cksum); 427 else 428 off = in6p->inp_cksum6; 429 if (plen < off + 1) { 430 error = EINVAL; 431 goto bad; 432 } 433 off += sizeof(struct ip6_hdr); 434 435 n = m_pulldown(m, off, sizeof(*sump), &sumoff); 436 if (n == NULL) { 437 m = NULL; 438 error = ENOBUFS; 439 goto bad; 440 } 441 sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff); 442 *sump = 0; 443 *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 444 } 445 446 flags = 0; 447 if (in6p->inp_flags & IN6P_MINMTU) 448 flags |= IPV6_MINMTU; 449 450 /* force routing table */ 451 m->m_pkthdr.ph_rtableid = in6p->inp_rtableid; 452 453 #if NPF > 0 454 if (in6p->inp_socket->so_state & SS_ISCONNECTED && 455 so->so_proto->pr_protocol != IPPROTO_ICMPV6) 456 m->m_pkthdr.pf.inp = in6p; 457 #endif 458 459 error = ip6_output(m, optp, &in6p->inp_route6, flags, 460 in6p->inp_moptions6, in6p); 461 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 462 icmp6stat.icp6s_outhist[type]++; 463 } else 464 rip6stat.rip6s_opackets++; 465 466 goto freectl; 467 468 bad: 469 m_freem(m); 470 471 freectl: 472 if (control) { 473 ip6_clearpktopts(&opt, -1); 474 m_freem(control); 475 } 476 return (error); 477 } 478 479 /* 480 * Raw IPv6 socket option processing. 481 */ 482 int 483 rip6_ctloutput(int op, struct socket *so, int level, int optname, 484 struct mbuf **mp) 485 { 486 struct inpcb *inp = sotoinpcb(so); 487 int error = 0; 488 int dir; 489 490 switch (level) { 491 case IPPROTO_IPV6: 492 switch (optname) { 493 494 case IP_DIVERTFL: 495 switch (op) { 496 case PRCO_SETOPT: 497 if (*mp == NULL || (*mp)->m_len < sizeof(int)) { 498 error = EINVAL; 499 break; 500 } 501 dir = *mtod(*mp, int *); 502 if (inp->inp_divertfl > 0) 503 error = ENOTSUP; 504 else if ((dir & IPPROTO_DIVERT_RESP) || 505 (dir & IPPROTO_DIVERT_INIT)) 506 inp->inp_divertfl = dir; 507 else 508 error = EINVAL; 509 break; 510 511 case PRCO_GETOPT: 512 *mp = m_get(M_WAIT, M_SOOPTS); 513 (*mp)->m_len = sizeof(int); 514 *mtod(*mp, int *) = inp->inp_divertfl; 515 break; 516 517 default: 518 error = EINVAL; 519 break; 520 } 521 522 if (op == PRCO_SETOPT) 523 (void)m_free(*mp); 524 return (error); 525 526 #ifdef MROUTING 527 case MRT6_INIT: 528 case MRT6_DONE: 529 case MRT6_ADD_MIF: 530 case MRT6_DEL_MIF: 531 case MRT6_ADD_MFC: 532 case MRT6_DEL_MFC: 533 case MRT6_PIM: 534 if (op == PRCO_SETOPT) { 535 error = ip6_mrouter_set(optname, so, *mp); 536 if (*mp) 537 (void)m_free(*mp); 538 } else if (op == PRCO_GETOPT) 539 error = ip6_mrouter_get(optname, so, mp); 540 else 541 error = EINVAL; 542 return (error); 543 #endif 544 case IPV6_CHECKSUM: 545 return (ip6_raw_ctloutput(op, so, level, optname, mp)); 546 default: 547 return (ip6_ctloutput(op, so, level, optname, mp)); 548 } 549 550 case IPPROTO_ICMPV6: 551 /* 552 * XXX: is it better to call icmp6_ctloutput() directly 553 * from protosw? 554 */ 555 return (icmp6_ctloutput(op, so, level, optname, mp)); 556 557 default: 558 if (op == PRCO_SETOPT) 559 m_free(*mp); 560 return EINVAL; 561 } 562 } 563 564 extern u_long rip6_sendspace; 565 extern u_long rip6_recvspace; 566 567 int 568 rip6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 569 struct mbuf *control, struct proc *p) 570 { 571 struct inpcb *in6p = sotoinpcb(so); 572 int error = 0; 573 int s; 574 int priv; 575 576 priv = 0; 577 if ((so->so_state & SS_PRIV) != 0) 578 priv++; 579 580 if (req == PRU_CONTROL) 581 return (in6_control(so, (u_long)m, (caddr_t)nam, 582 (struct ifnet *)control)); 583 584 switch (req) { 585 case PRU_ATTACH: 586 if (in6p) 587 panic("rip6_attach"); 588 if (!priv) { 589 error = EACCES; 590 break; 591 } 592 if ((long)nam < 0 || (long)nam >= IPPROTO_MAX) { 593 error = EPROTONOSUPPORT; 594 break; 595 } 596 s = splsoftnet(); 597 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) || 598 (error = in_pcballoc(so, &rawin6pcbtable))) { 599 splx(s); 600 break; 601 } 602 splx(s); 603 in6p = sotoinpcb(so); 604 in6p->inp_ipv6.ip6_nxt = (long)nam; 605 in6p->inp_cksum6 = -1; 606 607 in6p->inp_icmp6filt = malloc(sizeof(struct icmp6_filter), 608 M_PCB, M_NOWAIT); 609 if (in6p->inp_icmp6filt == NULL) { 610 in_pcbdetach(in6p); 611 error = ENOMEM; 612 break; 613 } 614 ICMP6_FILTER_SETPASSALL(in6p->inp_icmp6filt); 615 break; 616 617 case PRU_DISCONNECT: 618 if ((so->so_state & SS_ISCONNECTED) == 0) { 619 error = ENOTCONN; 620 break; 621 } 622 in6p->inp_faddr6 = in6addr_any; 623 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 624 break; 625 626 case PRU_ABORT: 627 soisdisconnected(so); 628 /* FALLTHROUGH */ 629 case PRU_DETACH: 630 if (in6p == NULL) 631 panic("rip6_detach"); 632 #ifdef MROUTING 633 if (so == ip6_mrouter) 634 ip6_mrouter_done(); 635 #endif 636 if (in6p->inp_icmp6filt) { 637 free(in6p->inp_icmp6filt, M_PCB, 0); 638 in6p->inp_icmp6filt = NULL; 639 } 640 in_pcbdetach(in6p); 641 break; 642 643 case PRU_BIND: 644 { 645 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); 646 struct ifaddr *ifa = NULL; 647 648 if (nam->m_len != sizeof(*addr)) { 649 error = EINVAL; 650 break; 651 } 652 if (addr->sin6_family != AF_INET6) { 653 error = EADDRNOTAVAIL; 654 break; 655 } 656 /* 657 * we don't support mapped address here, it would confuse 658 * users so reject it 659 */ 660 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 661 error = EADDRNOTAVAIL; 662 break; 663 } 664 /* 665 * Currently, ifa_ifwithaddr tends to fail for a link-local 666 * address, since it implicitly expects that the link ID 667 * for the address is embedded in the sin6_addr part. 668 * For now, we'd rather keep this "as is". We'll eventually fix 669 * this in a more natural way. 670 */ 671 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 672 !(so->so_options & SO_BINDANY) && 673 (ifa = ifa_ifwithaddr(sin6tosa(addr), 674 in6p->inp_rtableid)) == 0) { 675 error = EADDRNOTAVAIL; 676 break; 677 } 678 if (ifa && ifatoia6(ifa)->ia6_flags & 679 (IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED| 680 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 681 error = EADDRNOTAVAIL; 682 break; 683 } 684 in6p->inp_laddr6 = addr->sin6_addr; 685 break; 686 } 687 688 case PRU_CONNECT: 689 { 690 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); 691 struct in6_addr *in6a = NULL; 692 693 if (nam->m_len != sizeof(*addr)) { 694 error = EINVAL; 695 break; 696 } 697 if (addr->sin6_family != AF_INET6) { 698 error = EAFNOSUPPORT; 699 break; 700 } 701 702 /* Source address selection. XXX: need pcblookup? */ 703 error = in6_selectsrc(&in6a, addr, in6p->inp_outputopts6, 704 in6p->inp_moptions6, &in6p->inp_route6, 705 &in6p->inp_laddr6, in6p->inp_rtableid); 706 if (error) 707 break; 708 in6p->inp_laddr6 = *in6a; 709 in6p->inp_faddr6 = addr->sin6_addr; 710 soisconnected(so); 711 break; 712 } 713 714 case PRU_CONNECT2: 715 error = EOPNOTSUPP; 716 break; 717 718 /* 719 * Mark the connection as being incapable of futther input. 720 */ 721 case PRU_SHUTDOWN: 722 socantsendmore(so); 723 break; 724 /* 725 * Ship a packet out. The appropriate raw output 726 * routine handles any messaging necessary. 727 */ 728 case PRU_SEND: 729 { 730 struct sockaddr_in6 tmp; 731 struct sockaddr_in6 *dst; 732 733 /* always copy sockaddr to avoid overwrites */ 734 if (so->so_state & SS_ISCONNECTED) { 735 if (nam) { 736 error = EISCONN; 737 break; 738 } 739 /* XXX */ 740 bzero(&tmp, sizeof(tmp)); 741 tmp.sin6_family = AF_INET6; 742 tmp.sin6_len = sizeof(struct sockaddr_in6); 743 bcopy(&in6p->inp_faddr6, &tmp.sin6_addr, 744 sizeof(struct in6_addr)); 745 dst = &tmp; 746 } else { 747 if (nam == NULL) { 748 error = ENOTCONN; 749 break; 750 } 751 if (nam->m_len != sizeof(tmp)) { 752 error = EINVAL; 753 break; 754 } 755 756 tmp = *mtod(nam, struct sockaddr_in6 *); 757 dst = &tmp; 758 759 if (dst->sin6_family != AF_INET6) { 760 error = EAFNOSUPPORT; 761 break; 762 } 763 } 764 error = rip6_output(m, so, dst, control); 765 m = NULL; 766 break; 767 } 768 769 case PRU_SENSE: 770 /* 771 * stat: don't bother with a blocksize 772 */ 773 return (0); 774 /* 775 * Not supported. 776 */ 777 case PRU_RCVOOB: 778 case PRU_RCVD: 779 case PRU_LISTEN: 780 case PRU_ACCEPT: 781 case PRU_SENDOOB: 782 error = EOPNOTSUPP; 783 break; 784 785 case PRU_SOCKADDR: 786 in6_setsockaddr(in6p, nam); 787 break; 788 789 case PRU_PEERADDR: 790 in6_setpeeraddr(in6p, nam); 791 break; 792 793 default: 794 panic("rip6_usrreq"); 795 } 796 m_freem(m); 797 return (error); 798 } 799 800 int 801 rip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 802 void *newp, size_t newlen) 803 { 804 /* All sysctl names at this level are terminal. */ 805 if (namelen != 1) 806 return ENOTDIR; 807 808 switch (name[0]) { 809 case RIPV6CTL_STATS: 810 if (newp != NULL) 811 return (EPERM); 812 return (sysctl_struct(oldp, oldlenp, newp, newlen, 813 &rip6stat, sizeof(rip6stat))); 814 default: 815 return (EOPNOTSUPP); 816 } 817 /* NOTREACHED */ 818 } 819