1 /* 2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1988, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 65 */ 66 67 #include "opt_ipsec.h" 68 69 #include <sys/param.h> 70 #include <sys/malloc.h> 71 #include <sys/proc.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 79 #include <net/if.h> 80 #include <net/route.h> 81 #include <net/if_types.h> 82 83 #include <netinet/in.h> 84 #include <netinet/in_var.h> 85 #include <netinet/in_systm.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 <netinet/in_pcb.h> 91 #include <netinet6/in6_pcb.h> 92 #include <netinet6/nd6.h> 93 #include <netinet6/ip6protosw.h> 94 #ifdef ENABLE_DEFAULT_SCOPE 95 #include <netinet6/scope6_var.h> 96 #endif 97 98 #ifdef IPSEC 99 #include <netinet6/ipsec.h> 100 #include <netinet6/ipsec6.h> 101 #endif /*IPSEC*/ 102 103 #include <machine/stdarg.h> 104 105 #include "faith.h" 106 107 #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) 108 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) 109 110 /* 111 * Raw interface to IP6 protocol. 112 */ 113 114 extern struct inpcbhead ripcb; 115 extern struct inpcbinfo ripcbinfo; 116 extern u_long rip_sendspace; 117 extern u_long rip_recvspace; 118 119 /* 120 * Setup generic address and protocol structures 121 * for raw_input routine, then pass them along with 122 * mbuf chain. 123 */ 124 int 125 rip6_input(mp, offp, proto) 126 struct mbuf **mp; 127 int *offp, proto; 128 { 129 struct mbuf *m = *mp; 130 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 131 register struct inpcb *in6p; 132 struct inpcb *last = 0; 133 struct mbuf *opts = 0; 134 struct sockaddr_in6 rip6src; 135 136 #if defined(NFAITH) && 0 < NFAITH 137 if (m->m_pkthdr.rcvif) { 138 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 139 /* XXX send icmp6 host/port unreach? */ 140 m_freem(m); 141 return IPPROTO_DONE; 142 } 143 } 144 #endif 145 init_sin6(&rip6src, m); /* general init */ 146 147 LIST_FOREACH(in6p, &ripcb, inp_list) { 148 if ((in6p->in6p_vflag & INP_IPV6) == 0) 149 continue; 150 if (in6p->in6p_ip6_nxt && 151 in6p->in6p_ip6_nxt != proto) 152 continue; 153 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 154 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 155 continue; 156 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 157 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 158 continue; 159 if (in6p->in6p_cksum != -1 160 && in6_cksum(m, ip6->ip6_nxt, *offp, 161 m->m_pkthdr.len - *offp)) { 162 /* XXX bark something */ 163 continue; 164 } 165 if (last) { 166 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 167 if (n) { 168 if (last->in6p_flags & IN6P_CONTROLOPTS || 169 last->in6p_socket->so_options & SO_TIMESTAMP) 170 ip6_savecontrol(last, &opts, ip6, n); 171 /* strip intermediate headers */ 172 m_adj(n, *offp); 173 if (sbappendaddr(&last->in6p_socket->so_rcv, 174 (struct sockaddr *)&rip6src, 175 n, opts) == 0) { 176 /* should notify about lost packet */ 177 m_freem(n); 178 if (opts) 179 m_freem(opts); 180 } else 181 sorwakeup(last->in6p_socket); 182 opts = NULL; 183 } 184 } 185 last = in6p; 186 } 187 if (last) { 188 if (last->in6p_flags & IN6P_CONTROLOPTS || 189 last->in6p_socket->so_options & SO_TIMESTAMP) 190 ip6_savecontrol(last, &opts, ip6, m); 191 /* strip intermediate headers */ 192 m_adj(m, *offp); 193 if (sbappendaddr(&last->in6p_socket->so_rcv, 194 (struct sockaddr *)&rip6src, m, opts) == 0) { 195 m_freem(m); 196 if (opts) 197 m_freem(opts); 198 } else 199 sorwakeup(last->in6p_socket); 200 } else { 201 if (proto == IPPROTO_NONE) 202 m_freem(m); 203 else { 204 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 205 icmp6_error(m, ICMP6_PARAM_PROB, 206 ICMP6_PARAMPROB_NEXTHEADER, 207 prvnxtp - mtod(m, char *)); 208 } 209 ip6stat.ip6s_delivered--; 210 } 211 return IPPROTO_DONE; 212 } 213 214 void 215 rip6_ctlinput(cmd, sa, d) 216 int cmd; 217 struct sockaddr *sa; 218 void *d; 219 { 220 struct sockaddr_in6 sa6; 221 struct ip6_hdr *ip6; 222 struct mbuf *m; 223 int off = 0; 224 void (*notify) __P((struct inpcb *, int)) = in6_rtchange; 225 226 if (sa->sa_family != AF_INET6 || 227 sa->sa_len != sizeof(struct sockaddr_in6)) 228 return; 229 230 if ((unsigned)cmd >= PRC_NCMDS) 231 return; 232 if (PRC_IS_REDIRECT(cmd)) 233 notify = in6_rtchange, d = NULL; 234 else if (cmd == PRC_HOSTDEAD) 235 d = NULL; 236 else if (inet6ctlerrmap[cmd] == 0) 237 return; 238 239 /* if the parameter is from icmp6, decode it. */ 240 if (d != NULL) { 241 struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; 242 m = ip6cp->ip6c_m; 243 ip6 = ip6cp->ip6c_ip6; 244 off = ip6cp->ip6c_off; 245 } else { 246 m = NULL; 247 ip6 = NULL; 248 } 249 250 /* translate addresses into internal form */ 251 sa6 = *(struct sockaddr_in6 *)sa; 252 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) 253 sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 254 255 if (ip6) { 256 /* 257 * XXX: We assume that when IPV6 is non NULL, 258 * M and OFF are valid. 259 */ 260 struct in6_addr s; 261 262 /* translate addresses into internal form */ 263 memcpy(&s, &ip6->ip6_src, sizeof(s)); 264 if (IN6_IS_ADDR_LINKLOCAL(&s)) 265 s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 266 267 (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, 268 0, &s, 0, cmd, notify); 269 } else 270 (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, 0, 271 &zeroin6_addr, 0, cmd, notify); 272 } 273 274 /* 275 * Generate IPv6 header and pass packet to ip6_output. 276 * Tack on options user may have setup with control call. 277 */ 278 int 279 #if __STDC__ 280 rip6_output(struct mbuf *m, ...) 281 #else 282 rip6_output(m, va_alist) 283 struct mbuf *m; 284 va_dcl 285 #endif 286 { 287 struct socket *so; 288 struct sockaddr_in6 *dstsock; 289 struct mbuf *control; 290 struct in6_addr *dst; 291 struct ip6_hdr *ip6; 292 struct inpcb *in6p; 293 u_int plen = m->m_pkthdr.len; 294 int error = 0; 295 struct ip6_pktopts opt, *optp = 0; 296 struct ifnet *oifp = NULL; 297 int type = 0, code = 0; /* for ICMPv6 output statistics only */ 298 int priv = 0; 299 va_list ap; 300 301 va_start(ap, m); 302 so = va_arg(ap, struct socket *); 303 dstsock = va_arg(ap, struct sockaddr_in6 *); 304 control = va_arg(ap, struct mbuf *); 305 va_end(ap); 306 307 in6p = sotoin6pcb(so); 308 309 priv = 0; 310 if (so->so_cred->cr_uid == 0) 311 priv = 1; 312 dst = &dstsock->sin6_addr; 313 if (control) { 314 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) 315 goto bad; 316 optp = &opt; 317 } else 318 optp = in6p->in6p_outputopts; 319 320 /* 321 * For an ICMPv6 packet, we should know its type and code 322 * to update statistics. 323 */ 324 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 325 struct icmp6_hdr *icmp6; 326 if (m->m_len < sizeof(struct icmp6_hdr) && 327 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 328 error = ENOBUFS; 329 goto bad; 330 } 331 icmp6 = mtod(m, struct icmp6_hdr *); 332 type = icmp6->icmp6_type; 333 code = icmp6->icmp6_code; 334 } 335 336 M_PREPEND(m, sizeof(*ip6), M_WAIT); 337 ip6 = mtod(m, struct ip6_hdr *); 338 339 /* 340 * Next header might not be ICMP6 but use its pseudo header anyway. 341 */ 342 ip6->ip6_dst = *dst; 343 344 /* 345 * If the scope of the destination is link-local, embed the interface 346 * index in the address. 347 * 348 * XXX advanced-api value overrides sin6_scope_id 349 */ 350 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 351 struct in6_pktinfo *pi; 352 353 /* 354 * XXX Boundary check is assumed to be already done in 355 * ip6_setpktoptions(). 356 */ 357 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { 358 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); 359 oifp = ifindex2ifnet[pi->ipi6_ifindex]; 360 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 361 in6p->in6p_moptions && 362 in6p->in6p_moptions->im6o_multicast_ifp) { 363 oifp = in6p->in6p_moptions->im6o_multicast_ifp; 364 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); 365 } else if (dstsock->sin6_scope_id) { 366 /* boundary check */ 367 if (dstsock->sin6_scope_id < 0 368 || if_index < dstsock->sin6_scope_id) { 369 error = ENXIO; /* XXX EINVAL? */ 370 goto bad; 371 } 372 ip6->ip6_dst.s6_addr16[1] 373 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/ 374 } 375 } 376 377 /* 378 * Source address selection. 379 */ 380 { 381 struct in6_addr *in6a; 382 383 if ((in6a = in6_selectsrc(dstsock, optp, 384 in6p->in6p_moptions, 385 &in6p->in6p_route, 386 &in6p->in6p_laddr, 387 &error)) == 0) { 388 if (error == 0) 389 error = EADDRNOTAVAIL; 390 goto bad; 391 } 392 ip6->ip6_src = *in6a; 393 if (in6p->in6p_route.ro_rt) 394 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; 395 } 396 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | 397 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); 398 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | 399 (IPV6_VERSION & IPV6_VERSION_MASK); 400 /* ip6_plen will be filled in ip6_output, so not fill it here. */ 401 ip6->ip6_nxt = in6p->in6p_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 /* compute checksum */ 411 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 412 off = offsetof(struct icmp6_hdr, icmp6_cksum); 413 else 414 off = in6p->in6p_cksum; 415 if (plen < off + 1) { 416 error = EINVAL; 417 goto bad; 418 } 419 off += sizeof(struct ip6_hdr); 420 421 n = m; 422 while (n && n->m_len <= off) { 423 off -= n->m_len; 424 n = n->m_next; 425 } 426 if (!n) 427 goto bad; 428 p = (u_int16_t *)(mtod(n, caddr_t) + off); 429 *p = 0; 430 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 431 } 432 433 #ifdef IPSEC 434 ipsec_setsocket(m, so); 435 #endif /*IPSEC*/ 436 437 error = ip6_output(m, optp, &in6p->in6p_route, 0, 438 in6p->in6p_moptions, &oifp); 439 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 440 if (oifp) 441 icmp6_ifoutstat_inc(oifp, type, code); 442 icmp6stat.icp6s_outhist[type]++; 443 } 444 445 goto freectl; 446 447 bad: 448 if (m) 449 m_freem(m); 450 451 freectl: 452 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) 453 RTFREE(optp->ip6po_route.ro_rt); 454 if (control) 455 m_freem(control); 456 return(error); 457 } 458 459 /* 460 * Raw IPv6 socket option processing. 461 */ 462 int 463 rip6_ctloutput(so, sopt) 464 struct socket *so; 465 struct sockopt *sopt; 466 { 467 int error; 468 469 if (sopt->sopt_level == IPPROTO_ICMPV6) 470 /* 471 * XXX: is it better to call icmp6_ctloutput() directly 472 * from protosw? 473 */ 474 return(icmp6_ctloutput(so, sopt)); 475 else if (sopt->sopt_level != IPPROTO_IPV6) 476 return (EINVAL); 477 478 error = 0; 479 480 switch (sopt->sopt_dir) { 481 case SOPT_GET: 482 switch (sopt->sopt_name) { 483 case MRT6_INIT: 484 case MRT6_DONE: 485 case MRT6_ADD_MIF: 486 case MRT6_DEL_MIF: 487 case MRT6_ADD_MFC: 488 case MRT6_DEL_MFC: 489 case MRT6_PIM: 490 error = ip6_mrouter_get(so, sopt); 491 break; 492 default: 493 error = ip6_ctloutput(so, sopt); 494 break; 495 } 496 break; 497 498 case SOPT_SET: 499 switch (sopt->sopt_name) { 500 case MRT6_INIT: 501 case MRT6_DONE: 502 case MRT6_ADD_MIF: 503 case MRT6_DEL_MIF: 504 case MRT6_ADD_MFC: 505 case MRT6_DEL_MFC: 506 case MRT6_PIM: 507 error = ip6_mrouter_set(so, sopt); 508 break; 509 default: 510 error = ip6_ctloutput(so, sopt); 511 break; 512 } 513 break; 514 } 515 516 return (error); 517 } 518 519 static int 520 rip6_attach(struct socket *so, int proto, struct proc *p) 521 { 522 struct inpcb *inp; 523 int error, s; 524 525 inp = sotoinpcb(so); 526 if (inp) 527 panic("rip6_attach"); 528 if (p && (error = suser(p)) != 0) 529 return error; 530 531 error = soreserve(so, rip_sendspace, rip_recvspace); 532 if (error) 533 return error; 534 s = splnet(); 535 error = in_pcballoc(so, &ripcbinfo, p); 536 splx(s); 537 if (error) 538 return error; 539 inp = (struct inpcb *)so->so_pcb; 540 inp->inp_vflag |= INP_IPV6; 541 inp->in6p_ip6_nxt = (long)proto; 542 inp->in6p_hops = -1; /* use kernel default */ 543 inp->in6p_cksum = -1; 544 #ifdef IPSEC 545 error = ipsec_init_policy(so, &inp->in6p_sp); 546 if (error != 0) { 547 in6_pcbdetach(inp); 548 return (error); 549 } 550 #endif /*IPSEC*/ 551 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *, 552 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); 553 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); 554 return 0; 555 } 556 557 static int 558 rip6_detach(struct socket *so) 559 { 560 struct inpcb *inp; 561 562 inp = sotoinpcb(so); 563 if (inp == 0) 564 panic("rip6_detach"); 565 /* xxx: RSVP */ 566 if (so == ip6_mrouter) 567 ip6_mrouter_done(); 568 if (inp->in6p_icmp6filt) { 569 FREE(inp->in6p_icmp6filt, M_PCB); 570 inp->in6p_icmp6filt = NULL; 571 } 572 in6_pcbdetach(inp); 573 return 0; 574 } 575 576 static int 577 rip6_abort(struct socket *so) 578 { 579 soisdisconnected(so); 580 return rip6_detach(so); 581 } 582 583 static int 584 rip6_disconnect(struct socket *so) 585 { 586 struct inpcb *inp = sotoinpcb(so); 587 588 if ((so->so_state & SS_ISCONNECTED) == 0) 589 return ENOTCONN; 590 inp->in6p_faddr = in6addr_any; 591 return rip6_abort(so); 592 } 593 594 static int 595 rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 596 { 597 struct inpcb *inp = sotoinpcb(so); 598 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 599 struct ifaddr *ia = NULL; 600 601 if (nam->sa_len != sizeof(*addr)) 602 return EINVAL; 603 604 if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) 605 return EADDRNOTAVAIL; 606 #ifdef ENABLE_DEFAULT_SCOPE 607 if (addr->sin6_scope_id == 0) { /* not change if specified */ 608 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 609 } 610 #endif 611 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 612 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) 613 return EADDRNOTAVAIL; 614 if (ia && 615 ((struct in6_ifaddr *)ia)->ia6_flags & 616 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 617 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 618 return(EADDRNOTAVAIL); 619 } 620 inp->in6p_laddr = addr->sin6_addr; 621 return 0; 622 } 623 624 static int 625 rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 626 { 627 struct inpcb *inp = sotoinpcb(so); 628 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 629 struct in6_addr *in6a = NULL; 630 int error = 0; 631 #ifdef ENABLE_DEFAULT_SCOPE 632 struct sockaddr_in6 tmp; 633 #endif 634 635 if (nam->sa_len != sizeof(*addr)) 636 return EINVAL; 637 if (TAILQ_EMPTY(&ifnet)) 638 return EADDRNOTAVAIL; 639 if (addr->sin6_family != AF_INET6) 640 return EAFNOSUPPORT; 641 #ifdef ENABLE_DEFAULT_SCOPE 642 if (addr->sin6_scope_id == 0) { /* not change if specified */ 643 /* avoid overwrites */ 644 tmp = *addr; 645 addr = &tmp; 646 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 647 } 648 #endif 649 /* Source address selection. XXX: need pcblookup? */ 650 in6a = in6_selectsrc(addr, inp->in6p_outputopts, 651 inp->in6p_moptions, &inp->in6p_route, 652 &inp->in6p_laddr, &error); 653 if (in6a == NULL) 654 return (error ? error : EADDRNOTAVAIL); 655 inp->in6p_laddr = *in6a; 656 inp->in6p_faddr = addr->sin6_addr; 657 soisconnected(so); 658 return 0; 659 } 660 661 static int 662 rip6_shutdown(struct socket *so) 663 { 664 socantsendmore(so); 665 return 0; 666 } 667 668 static int 669 rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 670 struct mbuf *control, struct proc *p) 671 { 672 struct inpcb *inp = sotoinpcb(so); 673 struct sockaddr_in6 tmp; 674 struct sockaddr_in6 *dst; 675 676 /* always copy sockaddr to avoid overwrites */ 677 if (so->so_state & SS_ISCONNECTED) { 678 if (nam) { 679 m_freem(m); 680 return EISCONN; 681 } 682 /* XXX */ 683 bzero(&tmp, sizeof(tmp)); 684 tmp.sin6_family = AF_INET6; 685 tmp.sin6_len = sizeof(struct sockaddr_in6); 686 bcopy(&inp->in6p_faddr, &tmp.sin6_addr, 687 sizeof(struct in6_addr)); 688 dst = &tmp; 689 } else { 690 if (nam == NULL) { 691 m_freem(m); 692 return ENOTCONN; 693 } 694 tmp = *(struct sockaddr_in6 *)nam; 695 dst = &tmp; 696 } 697 #ifdef ENABLE_DEFAULT_SCOPE 698 if (dst->sin6_scope_id == 0) { /* not change if specified */ 699 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); 700 } 701 #endif 702 return rip6_output(m, so, dst, control); 703 } 704 705 struct pr_usrreqs rip6_usrreqs = { 706 rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect, 707 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect, 708 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp, 709 pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, 710 in6_setsockaddr, sosend, soreceive, sopoll 711 }; 712