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