1 /* $NetBSD: raw_ip6.c,v 1.24 2000/07/07 15:54:19 itojun Exp $ */ 2 /* $KAME: raw_ip6.c,v 1.35 2000/06/21 18:35:23 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. 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 105 struct in6pcb rawin6pcb; 106 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) 107 108 /* 109 * Raw interface to IP6 protocol. 110 */ 111 112 /* 113 * Initialize raw connection block queue. 114 */ 115 void 116 rip6_init() 117 { 118 rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb; 119 } 120 121 /* 122 * Setup generic address and protocol structures 123 * for raw_input routine, then pass them along with 124 * mbuf chain. 125 */ 126 int 127 rip6_input(mp, offp, proto) 128 struct mbuf **mp; 129 int *offp, proto; 130 { 131 struct mbuf *m = *mp; 132 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 133 register struct in6pcb *in6p; 134 struct in6pcb *last = NULL; 135 struct sockaddr_in6 rip6src; 136 struct mbuf *opts = NULL; 137 138 #if defined(NFAITH) && 0 < NFAITH 139 if (m->m_pkthdr.rcvif) { 140 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 141 /* send icmp6 host unreach? */ 142 m_freem(m); 143 return IPPROTO_DONE; 144 } 145 } 146 #endif 147 148 /* Be proactive about malicious use of IPv4 mapped address */ 149 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 150 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 151 /* XXX stat */ 152 m_freem(m); 153 return IPPROTO_DONE; 154 } 155 156 bzero(&rip6src, sizeof(rip6src)); 157 rip6src.sin6_len = sizeof(struct sockaddr_in6); 158 rip6src.sin6_family = AF_INET6; 159 #if 0 /*XXX inbound flowlabel */ 160 rip6src.sin6_flowinfo = ip6->ip6_flow & IPV6_FLOWINFO_MASK; 161 #endif 162 /* KAME hack: recover scopeid */ 163 (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif); 164 165 for (in6p = rawin6pcb.in6p_next; 166 in6p != &rawin6pcb; in6p = in6p->in6p_next) { 167 if (in6p->in6p_ip6.ip6_nxt && 168 in6p->in6p_ip6.ip6_nxt != proto) 169 continue; 170 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 171 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 172 continue; 173 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 174 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 175 continue; 176 if (in6p->in6p_cksum != -1 177 && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp)) 178 { 179 /* XXX bark something */ 180 continue; 181 } 182 if (last) { 183 struct mbuf *n; 184 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 185 if (last->in6p_flags & IN6P_CONTROLOPTS) 186 ip6_savecontrol(last, &opts, ip6, n); 187 /* strip intermediate headers */ 188 m_adj(n, *offp); 189 if (sbappendaddr(&last->in6p_socket->so_rcv, 190 (struct sockaddr *)&rip6src, 191 n, opts) == 0) { 192 /* should notify about lost packet */ 193 m_freem(n); 194 if (opts) 195 m_freem(opts); 196 } else 197 sorwakeup(last->in6p_socket); 198 opts = NULL; 199 } 200 } 201 last = in6p; 202 } 203 if (last) { 204 if (last->in6p_flags & IN6P_CONTROLOPTS) 205 ip6_savecontrol(last, &opts, ip6, m); 206 /* strip intermediate headers */ 207 m_adj(m, *offp); 208 if (sbappendaddr(&last->in6p_socket->so_rcv, 209 (struct sockaddr *)&rip6src, m, opts) == 0) { 210 m_freem(m); 211 if (opts) 212 m_freem(opts); 213 } else 214 sorwakeup(last->in6p_socket); 215 } else { 216 if (proto == IPPROTO_NONE) 217 m_freem(m); 218 else { 219 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 220 icmp6_error(m, ICMP6_PARAM_PROB, 221 ICMP6_PARAMPROB_NEXTHEADER, 222 prvnxtp - mtod(m, char *)); 223 } 224 ip6stat.ip6s_delivered--; 225 } 226 return IPPROTO_DONE; 227 } 228 229 void 230 rip6_ctlinput(cmd, sa, d) 231 int cmd; 232 struct sockaddr *sa; 233 void *d; 234 { 235 struct sockaddr_in6 sa6; 236 register struct ip6_hdr *ip6; 237 struct mbuf *m; 238 int off; 239 void (*notify) __P((struct in6pcb *, int)) = in6_rtchange; 240 241 if (sa->sa_family != AF_INET6 || 242 sa->sa_len != sizeof(struct sockaddr_in6)) 243 return; 244 245 if ((unsigned)cmd >= PRC_NCMDS) 246 return; 247 if (PRC_IS_REDIRECT(cmd)) 248 notify = in6_rtchange, d = NULL; 249 else if (cmd == PRC_HOSTDEAD) 250 d = NULL; 251 else if (inet6ctlerrmap[cmd] == 0) 252 return; 253 254 /* if the parameter is from icmp6, decode it. */ 255 if (d != NULL) { 256 struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; 257 m = ip6cp->ip6c_m; 258 ip6 = ip6cp->ip6c_ip6; 259 off = ip6cp->ip6c_off; 260 } else { 261 m = NULL; 262 ip6 = NULL; 263 } 264 265 /* translate addresses into internal form */ 266 sa6 = *(struct sockaddr_in6 *)sa; 267 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) 268 sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 269 270 if (ip6) { 271 /* 272 * XXX: We assume that when IPV6 is non NULL, 273 * M and OFF are valid. 274 */ 275 struct in6_addr s; 276 277 /* translate addresses into internal form */ 278 memcpy(&s, &ip6->ip6_src, sizeof(s)); 279 if (IN6_IS_ADDR_LINKLOCAL(&s)) 280 s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 281 282 (void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6, 283 0, &s, 0, cmd, notify); 284 } else { 285 (void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6, 0, 286 &zeroin6_addr, 0, cmd, notify); 287 } 288 } 289 290 /* 291 * Generate IPv6 header and pass packet to ip6_output. 292 * Tack on options user may have setup with control call. 293 */ 294 int 295 #if __STDC__ 296 rip6_output(struct mbuf *m, ...) 297 #else 298 rip6_output(m, va_alist) 299 struct mbuf *m; 300 va_dcl 301 #endif 302 { 303 struct socket *so; 304 struct sockaddr_in6 *dstsock; 305 struct mbuf *control; 306 struct in6_addr *dst; 307 struct ip6_hdr *ip6; 308 struct in6pcb *in6p; 309 u_int plen = m->m_pkthdr.len; 310 int error = 0; 311 struct ip6_pktopts opt, *optp = NULL, *origoptp; 312 struct ifnet *oifp = NULL; 313 int type, code; /* for ICMPv6 output statistics only */ 314 int priv = 0; 315 va_list ap; 316 317 va_start(ap, m); 318 so = va_arg(ap, struct socket *); 319 dstsock = va_arg(ap, struct sockaddr_in6 *); 320 control = va_arg(ap, struct mbuf *); 321 va_end(ap); 322 323 in6p = sotoin6pcb(so); 324 325 priv = 0; 326 { 327 struct proc *p = curproc; /* XXX */ 328 329 if (p && !suser(p->p_ucred, &p->p_acflag)) 330 priv = 1; 331 } 332 dst = &dstsock->sin6_addr; 333 if (control) { 334 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) 335 goto bad; 336 optp = &opt; 337 } else 338 optp = in6p->in6p_outputopts; 339 340 /* 341 * For an ICMPv6 packet, we should know its type and code 342 * to update statistics. 343 */ 344 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 345 struct icmp6_hdr *icmp6; 346 if (m->m_len < sizeof(struct icmp6_hdr) && 347 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 348 error = ENOBUFS; 349 goto bad; 350 } 351 icmp6 = mtod(m, struct icmp6_hdr *); 352 type = icmp6->icmp6_type; 353 code = icmp6->icmp6_code; 354 } 355 356 M_PREPEND(m, sizeof(*ip6), M_WAIT); 357 ip6 = mtod(m, struct ip6_hdr *); 358 359 /* 360 * Next header might not be ICMP6 but use its pseudo header anyway. 361 */ 362 ip6->ip6_dst = *dst; 363 364 /* KAME hack: embed scopeid */ 365 origoptp = in6p->in6p_outputopts; 366 in6p->in6p_outputopts = optp; 367 if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p, &oifp) != 0) { 368 error = EINVAL; 369 goto bad; 370 } 371 in6p->in6p_outputopts = origoptp; 372 373 /* 374 * Source address selection. 375 */ 376 { 377 struct in6_addr *in6a; 378 379 if ((in6a = in6_selectsrc(dstsock, optp, 380 in6p->in6p_moptions, 381 &in6p->in6p_route, 382 &in6p->in6p_laddr, 383 &error)) == 0) { 384 if (error == 0) 385 error = EADDRNOTAVAIL; 386 goto bad; 387 } 388 ip6->ip6_src = *in6a; 389 if (in6p->in6p_route.ro_rt) { 390 /* what if oifp contradicts ? */ 391 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; 392 } 393 } 394 395 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; 396 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 397 ip6->ip6_vfc |= IPV6_VERSION; 398 #if 0 /* ip6_plen will be filled in ip6_output. */ 399 ip6->ip6_plen = htons((u_short)plen); 400 #endif 401 ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt; 402 ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 403 404 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 405 in6p->in6p_cksum != -1) { 406 struct mbuf *n; 407 int off; 408 u_int16_t *p; 409 410 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */ 411 412 /* compute checksum */ 413 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 414 off = offsetof(struct icmp6_hdr, icmp6_cksum); 415 else 416 off = in6p->in6p_cksum; 417 if (plen < off + 1) { 418 error = EINVAL; 419 goto bad; 420 } 421 off += sizeof(struct ip6_hdr); 422 423 n = m; 424 while (n && n->m_len <= off) { 425 off -= n->m_len; 426 n = n->m_next; 427 } 428 if (!n) 429 goto bad; 430 p = (u_int16_t *)(mtod(n, caddr_t) + off); 431 *p = 0; 432 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 433 } 434 435 #ifdef IPSEC 436 ipsec_setsocket(m, so); 437 #endif /*IPSEC*/ 438 439 error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions, 440 &oifp); 441 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 442 if (oifp) 443 icmp6_ifoutstat_inc(oifp, type, code); 444 icmp6stat.icp6s_outhist[type]++; 445 } 446 447 goto freectl; 448 449 bad: 450 if (m) 451 m_freem(m); 452 453 freectl: 454 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) 455 RTFREE(optp->ip6po_route.ro_rt); 456 if (control) 457 m_freem(control); 458 return(error); 459 } 460 461 /* 462 * Raw IPv6 socket option processing. 463 */ 464 int 465 rip6_ctloutput(op, so, level, optname, m) 466 int op; 467 struct socket *so; 468 int level, optname; 469 struct mbuf **m; 470 { 471 int error = 0; 472 473 switch(level) { 474 case IPPROTO_IPV6: 475 switch(optname) { 476 case MRT6_INIT: 477 case MRT6_DONE: 478 case MRT6_ADD_MIF: 479 case MRT6_DEL_MIF: 480 case MRT6_ADD_MFC: 481 case MRT6_DEL_MFC: 482 case MRT6_PIM: 483 if (op == PRCO_SETOPT) { 484 error = ip6_mrouter_set(optname, so, *m); 485 if (*m) 486 (void)m_free(*m); 487 } else if (op == PRCO_GETOPT) { 488 error = ip6_mrouter_get(optname, so, m); 489 } else 490 error = EINVAL; 491 return (error); 492 } 493 return (ip6_ctloutput(op, so, level, optname, m)); 494 /* NOTREACHED */ 495 496 case IPPROTO_ICMPV6: 497 /* 498 * XXX: is it better to call icmp6_ctloutput() directly 499 * from protosw? 500 */ 501 return(icmp6_ctloutput(op, so, level, optname, m)); 502 503 default: 504 if (op == PRCO_SETOPT && *m) 505 (void)m_free(*m); 506 return(EINVAL); 507 } 508 } 509 510 extern u_long rip6_sendspace; 511 extern u_long rip6_recvspace; 512 513 int 514 rip6_usrreq(so, req, m, nam, control, p) 515 register struct socket *so; 516 int req; 517 struct mbuf *m, *nam, *control; 518 struct proc *p; 519 { 520 register struct in6pcb *in6p = sotoin6pcb(so); 521 int s; 522 int error = 0; 523 /* extern struct socket *ip6_mrouter; */ /* xxx */ 524 int priv; 525 526 priv = 0; 527 if (p && !suser(p->p_ucred, &p->p_acflag)) 528 priv++; 529 530 if (req == PRU_CONTROL) 531 return (in6_control(so, (u_long)m, (caddr_t)nam, 532 (struct ifnet *)control, p)); 533 534 if (req == PRU_PURGEIF) { 535 in6_purgeif((struct ifnet *)control); 536 in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control); 537 return (0); 538 } 539 540 switch (req) { 541 case PRU_ATTACH: 542 if (in6p) 543 panic("rip6_attach"); 544 if (!priv) { 545 error = EACCES; 546 break; 547 } 548 s = splsoftnet(); 549 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) || 550 (error = in6_pcballoc(so, &rawin6pcb))) { 551 splx(s); 552 break; 553 } 554 splx(s); 555 in6p = sotoin6pcb(so); 556 in6p->in6p_ip6.ip6_nxt = (long)nam; 557 in6p->in6p_cksum = -1; 558 #ifdef IPSEC 559 error = ipsec_init_policy(so, &in6p->in6p_sp); 560 if (error != 0) { 561 in6_pcbdetach(in6p); 562 break; 563 } 564 #endif /*IPSEC*/ 565 566 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *, 567 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); 568 if (in6p->in6p_icmp6filt == NULL) { 569 in6_pcbdetach(in6p); 570 error = ENOMEM; 571 break; 572 } 573 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt); 574 break; 575 576 case PRU_DISCONNECT: 577 if ((so->so_state & SS_ISCONNECTED) == 0) { 578 error = ENOTCONN; 579 break; 580 } 581 in6p->in6p_faddr = in6addr_any; 582 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 583 break; 584 585 case PRU_ABORT: 586 soisdisconnected(so); 587 /* Fallthrough */ 588 case PRU_DETACH: 589 if (in6p == 0) 590 panic("rip6_detach"); 591 if (so == ip6_mrouter) 592 ip6_mrouter_done(); 593 /* xxx: RSVP */ 594 if (in6p->in6p_icmp6filt) { 595 FREE(in6p->in6p_icmp6filt, M_PCB); 596 in6p->in6p_icmp6filt = NULL; 597 } 598 in6_pcbdetach(in6p); 599 break; 600 601 case PRU_BIND: 602 { 603 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); 604 struct ifaddr *ia = NULL; 605 606 if (nam->m_len != sizeof(*addr)) { 607 error = EINVAL; 608 break; 609 } 610 if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) { 611 error = EADDRNOTAVAIL; 612 break; 613 } 614 #ifdef ENABLE_DEFAULT_SCOPE 615 if (addr->sin6_scope_id == 0) /* not change if specified */ 616 addr->sin6_scope_id = 617 scope6_addr2default(&addr->sin6_addr); 618 #endif 619 /* 620 * we don't support mapped address here, it would confuse 621 * users so reject it 622 */ 623 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 624 error = EADDRNOTAVAIL; 625 break; 626 } 627 /* 628 * Currently, ifa_ifwithaddr tends to fail for a link-local 629 * address, since it implicitly expects that the link ID 630 * for the address is embedded in the sin6_addr part. 631 * For now, we'd rather keep this "as is". We'll eventually fix 632 * this in a more natural way. 633 */ 634 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 635 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) { 636 error = EADDRNOTAVAIL; 637 break; 638 } 639 if (ia && 640 ((struct in6_ifaddr *)ia)->ia6_flags & 641 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 642 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 643 error = EADDRNOTAVAIL; 644 break; 645 } 646 in6p->in6p_laddr = addr->sin6_addr; 647 break; 648 } 649 650 case PRU_CONNECT: 651 { 652 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); 653 struct in6_addr *in6a = NULL; 654 #ifdef ENABLE_DEFAULT_SCOPE 655 struct sockaddr_in6 sin6; 656 #endif 657 658 if (nam->m_len != sizeof(*addr)) { 659 error = EINVAL; 660 break; 661 } 662 if (ifnet.tqh_first == 0) 663 { 664 error = EADDRNOTAVAIL; 665 break; 666 } 667 if (addr->sin6_family != AF_INET6) { 668 error = EAFNOSUPPORT; 669 break; 670 } 671 672 #ifdef ENABLE_DEFAULT_SCOPE 673 if (addr->sin6_scope_id == 0) { 674 /* protect *addr */ 675 sin6 = *addr; 676 addr = &sin6; 677 addr->sin6_scope_id = 678 scope6_addr2default(&addr->sin6_addr); 679 } 680 #endif 681 682 /* Source address selection. XXX: need pcblookup? */ 683 in6a = in6_selectsrc(addr, in6p->in6p_outputopts, 684 in6p->in6p_moptions, 685 &in6p->in6p_route, 686 &in6p->in6p_laddr, 687 &error); 688 if (in6a == NULL) { 689 if (error == 0) 690 error = EADDRNOTAVAIL; 691 break; 692 } 693 in6p->in6p_laddr = *in6a; 694 in6p->in6p_faddr = addr->sin6_addr; 695 soisconnected(so); 696 break; 697 } 698 699 case PRU_CONNECT2: 700 error = EOPNOTSUPP; 701 break; 702 703 /* 704 * Mark the connection as being incapable of futther input. 705 */ 706 case PRU_SHUTDOWN: 707 socantsendmore(so); 708 break; 709 /* 710 * Ship a packet out. The appropriate raw output 711 * routine handles any messaging necessary. 712 */ 713 case PRU_SEND: 714 { 715 struct sockaddr_in6 tmp; 716 struct sockaddr_in6 *dst; 717 718 /* always copy sockaddr to avoid overwrites */ 719 if (so->so_state & SS_ISCONNECTED) { 720 if (nam) { 721 error = EISCONN; 722 break; 723 } 724 /* XXX */ 725 bzero(&tmp, sizeof(tmp)); 726 tmp.sin6_family = AF_INET6; 727 tmp.sin6_len = sizeof(struct sockaddr_in6); 728 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr, 729 sizeof(struct in6_addr)); 730 dst = &tmp; 731 } else { 732 if (nam == NULL) { 733 error = ENOTCONN; 734 break; 735 } 736 tmp = *mtod(nam, struct sockaddr_in6 *); 737 dst = &tmp; 738 } 739 #ifdef ENABLE_DEFAULT_SCOPE 740 if (dst->sin6_scope_id == 0) { 741 dst->sin6_scope_id = 742 scope6_addr2default(&dst->sin6_addr); 743 } 744 #endif 745 error = rip6_output(m, so, dst, control); 746 m = NULL; 747 break; 748 } 749 750 case PRU_SENSE: 751 /* 752 * stat: don't bother with a blocksize 753 */ 754 return(0); 755 /* 756 * Not supported. 757 */ 758 case PRU_RCVOOB: 759 case PRU_RCVD: 760 case PRU_LISTEN: 761 case PRU_ACCEPT: 762 case PRU_SENDOOB: 763 error = EOPNOTSUPP; 764 break; 765 766 case PRU_SOCKADDR: 767 in6_setsockaddr(in6p, nam); 768 break; 769 770 case PRU_PEERADDR: 771 in6_setpeeraddr(in6p, nam); 772 break; 773 774 default: 775 panic("rip6_usrreq"); 776 } 777 if (m != NULL) 778 m_freem(m); 779 return(error); 780 } 781