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