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