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