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 #include "opt_inet6.h" 69 70 #include <sys/param.h> 71 #include <sys/errno.h> 72 #include <sys/lock.h> 73 #include <sys/malloc.h> 74 #include <sys/mbuf.h> 75 #include <sys/proc.h> 76 #include <sys/protosw.h> 77 #include <sys/signalvar.h> 78 #include <sys/socket.h> 79 #include <sys/socketvar.h> 80 #include <sys/sx.h> 81 #include <sys/systm.h> 82 83 #include <net/if.h> 84 #include <net/if_types.h> 85 #include <net/route.h> 86 87 #include <netinet/in.h> 88 #include <netinet/in_var.h> 89 #include <netinet/in_systm.h> 90 #include <netinet/icmp6.h> 91 #include <netinet/in_pcb.h> 92 #include <netinet/ip6.h> 93 #include <netinet6/ip6protosw.h> 94 #include <netinet6/ip6_mroute.h> 95 #include <netinet6/in6_pcb.h> 96 #include <netinet6/ip6_var.h> 97 #include <netinet6/nd6.h> 98 #include <netinet6/raw_ip6.h> 99 #ifdef ENABLE_DEFAULT_SCOPE 100 #include <netinet6/scope6_var.h> 101 #endif 102 103 #ifdef IPSEC 104 #include <netinet6/ipsec.h> 105 #include <netinet6/ipsec6.h> 106 #endif /*IPSEC*/ 107 108 #include <machine/stdarg.h> 109 110 #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) 111 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) 112 113 /* 114 * Raw interface to IP6 protocol. 115 */ 116 117 extern struct inpcbhead ripcb; 118 extern struct inpcbinfo ripcbinfo; 119 extern u_long rip_sendspace; 120 extern u_long rip_recvspace; 121 122 struct rip6stat rip6stat; 123 124 /* 125 * Setup generic address and protocol structures 126 * for raw_input routine, then pass them along with 127 * mbuf chain. 128 */ 129 int 130 rip6_input(mp, offp, proto) 131 struct mbuf **mp; 132 int *offp, proto; 133 { 134 struct mbuf *m = *mp; 135 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 136 register struct inpcb *in6p; 137 struct inpcb *last = 0; 138 struct mbuf *opts = NULL; 139 struct sockaddr_in6 rip6src; 140 141 rip6stat.rip6s_ipackets++; 142 143 if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 144 /* XXX send icmp6 host/port unreach? */ 145 m_freem(m); 146 return IPPROTO_DONE; 147 } 148 149 init_sin6(&rip6src, m); /* general init */ 150 151 LIST_FOREACH(in6p, &ripcb, inp_list) { 152 if ((in6p->in6p_vflag & INP_IPV6) == 0) 153 continue; 154 if (in6p->in6p_ip6_nxt && 155 in6p->in6p_ip6_nxt != proto) 156 continue; 157 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 158 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 159 continue; 160 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 161 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 162 continue; 163 if (in6p->in6p_cksum != -1) { 164 rip6stat.rip6s_isum++; 165 if (in6_cksum(m, ip6->ip6_nxt, *offp, 166 m->m_pkthdr.len - *offp)) { 167 rip6stat.rip6s_badsum++; 168 continue; 169 } 170 } 171 if (last) { 172 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 173 174 #ifdef IPSEC 175 /* 176 * Check AH/ESP integrity. 177 */ 178 if (n && ipsec6_in_reject_so(n, last->inp_socket)) { 179 m_freem(n); 180 ipsec6stat.in_polvio++; 181 /* do not inject data into pcb */ 182 } else 183 #endif /*IPSEC*/ 184 if (n) { 185 if (last->in6p_flags & IN6P_CONTROLOPTS || 186 last->in6p_socket->so_options & SO_TIMESTAMP) 187 ip6_savecontrol(last, &opts, ip6, n); 188 /* strip intermediate headers */ 189 m_adj(n, *offp); 190 if (sbappendaddr(&last->in6p_socket->so_rcv, 191 (struct sockaddr *)&rip6src, 192 n, opts) == 0) { 193 m_freem(n); 194 if (opts) 195 m_freem(opts); 196 rip6stat.rip6s_fullsock++; 197 } else 198 sorwakeup(last->in6p_socket); 199 opts = NULL; 200 } 201 } 202 last = in6p; 203 } 204 #ifdef IPSEC 205 /* 206 * Check AH/ESP integrity. 207 */ 208 if (last && ipsec6_in_reject_so(m, last->inp_socket)) { 209 m_freem(m); 210 ipsec6stat.in_polvio++; 211 ip6stat.ip6s_delivered--; 212 /* do not inject data into pcb */ 213 } else 214 #endif /*IPSEC*/ 215 if (last) { 216 if (last->in6p_flags & IN6P_CONTROLOPTS || 217 last->in6p_socket->so_options & SO_TIMESTAMP) 218 ip6_savecontrol(last, &opts, ip6, m); 219 /* strip intermediate headers */ 220 m_adj(m, *offp); 221 if (sbappendaddr(&last->in6p_socket->so_rcv, 222 (struct sockaddr *)&rip6src, m, opts) == 0) { 223 m_freem(m); 224 if (opts) 225 m_freem(opts); 226 rip6stat.rip6s_fullsock++; 227 } else 228 sorwakeup(last->in6p_socket); 229 } else { 230 rip6stat.rip6s_nosock++; 231 if (m->m_flags & M_MCAST) 232 rip6stat.rip6s_nosockmcast++; 233 if (proto == IPPROTO_NONE) 234 m_freem(m); 235 else { 236 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 237 icmp6_error(m, ICMP6_PARAM_PROB, 238 ICMP6_PARAMPROB_NEXTHEADER, 239 prvnxtp - mtod(m, char *)); 240 } 241 ip6stat.ip6s_delivered--; 242 } 243 return IPPROTO_DONE; 244 } 245 246 void 247 rip6_ctlinput(cmd, sa, d) 248 int cmd; 249 struct sockaddr *sa; 250 void *d; 251 { 252 struct ip6_hdr *ip6; 253 struct mbuf *m; 254 int off = 0; 255 struct ip6ctlparam *ip6cp = NULL; 256 const struct sockaddr_in6 *sa6_src = NULL; 257 struct inpcb *(*notify) __P((struct inpcb *, int)) = in6_rtchange; 258 259 if (sa->sa_family != AF_INET6 || 260 sa->sa_len != sizeof(struct sockaddr_in6)) 261 return; 262 263 if ((unsigned)cmd >= PRC_NCMDS) 264 return; 265 if (PRC_IS_REDIRECT(cmd)) 266 notify = in6_rtchange, d = NULL; 267 else if (cmd == PRC_HOSTDEAD) 268 d = NULL; 269 else if (inet6ctlerrmap[cmd] == 0) 270 return; 271 272 /* if the parameter is from icmp6, decode it. */ 273 if (d != NULL) { 274 ip6cp = (struct ip6ctlparam *)d; 275 m = ip6cp->ip6c_m; 276 ip6 = ip6cp->ip6c_ip6; 277 off = ip6cp->ip6c_off; 278 sa6_src = ip6cp->ip6c_src; 279 } else { 280 m = NULL; 281 ip6 = NULL; 282 sa6_src = &sa6_any; 283 } 284 285 (void) in6_pcbnotify(&ripcb, sa, 0, (const struct sockaddr *)sa6_src, 286 0, cmd, notify); 287 } 288 289 /* 290 * Generate IPv6 header and pass packet to ip6_output. 291 * Tack on options user may have setup with control call. 292 */ 293 int 294 #if __STDC__ 295 rip6_output(struct mbuf *m, ...) 296 #else 297 rip6_output(m, va_alist) 298 struct mbuf *m; 299 va_dcl 300 #endif 301 { 302 struct socket *so; 303 struct sockaddr_in6 *dstsock; 304 struct mbuf *control; 305 struct in6_addr *dst; 306 struct ip6_hdr *ip6; 307 struct inpcb *in6p; 308 u_int plen = m->m_pkthdr.len; 309 int error = 0; 310 struct ip6_pktopts opt, *optp = 0; 311 struct ifnet *oifp = NULL; 312 int type = 0, code = 0; /* for ICMPv6 output statistics only */ 313 int priv = 0; 314 va_list ap; 315 316 va_start(ap, m); 317 so = va_arg(ap, struct socket *); 318 dstsock = va_arg(ap, struct sockaddr_in6 *); 319 control = va_arg(ap, struct mbuf *); 320 va_end(ap); 321 322 in6p = sotoin6pcb(so); 323 324 priv = 0; 325 if (so->so_cred->cr_uid == 0) 326 priv = 1; 327 dst = &dstsock->sin6_addr; 328 if (control) { 329 if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) 330 goto bad; 331 optp = &opt; 332 } else 333 optp = in6p->in6p_outputopts; 334 335 /* 336 * For an ICMPv6 packet, we should know its type and code 337 * to update statistics. 338 */ 339 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 340 struct icmp6_hdr *icmp6; 341 if (m->m_len < sizeof(struct icmp6_hdr) && 342 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 343 error = ENOBUFS; 344 goto bad; 345 } 346 icmp6 = mtod(m, struct icmp6_hdr *); 347 type = icmp6->icmp6_type; 348 code = icmp6->icmp6_code; 349 } 350 351 M_PREPEND(m, sizeof(*ip6), M_TRYWAIT); 352 ip6 = mtod(m, struct ip6_hdr *); 353 354 /* 355 * Next header might not be ICMP6 but use its pseudo header anyway. 356 */ 357 ip6->ip6_dst = *dst; 358 359 /* 360 * If the scope of the destination is link-local, embed the interface 361 * index in the address. 362 * 363 * XXX advanced-api value overrides sin6_scope_id 364 */ 365 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 366 struct in6_pktinfo *pi; 367 368 /* 369 * XXX Boundary check is assumed to be already done in 370 * ip6_setpktoptions(). 371 */ 372 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { 373 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); 374 oifp = ifnet_byindex(pi->ipi6_ifindex); 375 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 376 in6p->in6p_moptions && 377 in6p->in6p_moptions->im6o_multicast_ifp) { 378 oifp = in6p->in6p_moptions->im6o_multicast_ifp; 379 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); 380 } else if (dstsock->sin6_scope_id) { 381 /* boundary check */ 382 if (dstsock->sin6_scope_id < 0 383 || if_index < dstsock->sin6_scope_id) { 384 error = ENXIO; /* XXX EINVAL? */ 385 goto bad; 386 } 387 ip6->ip6_dst.s6_addr16[1] 388 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/ 389 } 390 } 391 392 /* 393 * Source address selection. 394 */ 395 { 396 struct in6_addr *in6a; 397 398 if ((in6a = in6_selectsrc(dstsock, optp, 399 in6p->in6p_moptions, 400 &in6p->in6p_route, 401 &in6p->in6p_laddr, 402 &error)) == 0) { 403 if (error == 0) 404 error = EADDRNOTAVAIL; 405 goto bad; 406 } 407 ip6->ip6_src = *in6a; 408 if (in6p->in6p_route.ro_rt) 409 oifp = ifnet_byindex(in6p->in6p_route.ro_rt->rt_ifp->if_index); 410 } 411 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | 412 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); 413 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | 414 (IPV6_VERSION & IPV6_VERSION_MASK); 415 /* ip6_plen will be filled in ip6_output, so not fill it here. */ 416 ip6->ip6_nxt = in6p->in6p_ip6_nxt; 417 ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 418 419 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 420 in6p->in6p_cksum != -1) { 421 struct mbuf *n; 422 int off; 423 u_int16_t *p; 424 425 /* compute checksum */ 426 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 427 off = offsetof(struct icmp6_hdr, icmp6_cksum); 428 else 429 off = in6p->in6p_cksum; 430 if (plen < off + 1) { 431 error = EINVAL; 432 goto bad; 433 } 434 off += sizeof(struct ip6_hdr); 435 436 n = m; 437 while (n && n->m_len <= off) { 438 off -= n->m_len; 439 n = n->m_next; 440 } 441 if (!n) 442 goto bad; 443 p = (u_int16_t *)(mtod(n, caddr_t) + off); 444 *p = 0; 445 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 446 } 447 448 #ifdef IPSEC 449 if (ipsec_setsocket(m, so) != 0) { 450 error = ENOBUFS; 451 goto bad; 452 } 453 #endif /*IPSEC*/ 454 455 error = ip6_output(m, optp, &in6p->in6p_route, 0, 456 in6p->in6p_moptions, &oifp); 457 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 458 if (oifp) 459 icmp6_ifoutstat_inc(oifp, type, code); 460 icmp6stat.icp6s_outhist[type]++; 461 } else 462 rip6stat.rip6s_opackets++; 463 464 goto freectl; 465 466 bad: 467 if (m) 468 m_freem(m); 469 470 freectl: 471 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) 472 RTFREE(optp->ip6po_route.ro_rt); 473 if (control) { 474 if (optp == &opt) 475 ip6_clearpktopts(optp, 0, -1); 476 m_freem(control); 477 } 478 return(error); 479 } 480 481 /* 482 * Raw IPv6 socket option processing. 483 */ 484 int 485 rip6_ctloutput(so, sopt) 486 struct socket *so; 487 struct sockopt *sopt; 488 { 489 int error; 490 491 if (sopt->sopt_level == IPPROTO_ICMPV6) 492 /* 493 * XXX: is it better to call icmp6_ctloutput() directly 494 * from protosw? 495 */ 496 return(icmp6_ctloutput(so, sopt)); 497 else if (sopt->sopt_level != IPPROTO_IPV6) 498 return (EINVAL); 499 500 error = 0; 501 502 switch (sopt->sopt_dir) { 503 case SOPT_GET: 504 switch (sopt->sopt_name) { 505 case MRT6_INIT: 506 case MRT6_DONE: 507 case MRT6_ADD_MIF: 508 case MRT6_DEL_MIF: 509 case MRT6_ADD_MFC: 510 case MRT6_DEL_MFC: 511 case MRT6_PIM: 512 error = ip6_mrouter_get(so, sopt); 513 break; 514 default: 515 error = ip6_ctloutput(so, sopt); 516 break; 517 } 518 break; 519 520 case SOPT_SET: 521 switch (sopt->sopt_name) { 522 case MRT6_INIT: 523 case MRT6_DONE: 524 case MRT6_ADD_MIF: 525 case MRT6_DEL_MIF: 526 case MRT6_ADD_MFC: 527 case MRT6_DEL_MFC: 528 case MRT6_PIM: 529 error = ip6_mrouter_set(so, sopt); 530 break; 531 default: 532 error = ip6_ctloutput(so, sopt); 533 break; 534 } 535 break; 536 } 537 538 return (error); 539 } 540 541 static int 542 rip6_attach(struct socket *so, int proto, struct thread *td) 543 { 544 struct inpcb *inp; 545 int error, s; 546 547 inp = sotoinpcb(so); 548 if (inp) 549 panic("rip6_attach"); 550 if (td && (error = suser(td)) != 0) 551 return error; 552 553 error = soreserve(so, rip_sendspace, rip_recvspace); 554 if (error) 555 return error; 556 s = splnet(); 557 error = in_pcballoc(so, &ripcbinfo, td); 558 splx(s); 559 if (error) 560 return error; 561 inp = (struct inpcb *)so->so_pcb; 562 inp->inp_vflag |= INP_IPV6; 563 inp->in6p_ip6_nxt = (long)proto; 564 inp->in6p_hops = -1; /* use kernel default */ 565 inp->in6p_cksum = -1; 566 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *, 567 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); 568 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); 569 return 0; 570 } 571 572 static int 573 rip6_detach(struct socket *so) 574 { 575 struct inpcb *inp; 576 577 inp = sotoinpcb(so); 578 if (inp == 0) 579 panic("rip6_detach"); 580 /* xxx: RSVP */ 581 if (so == ip6_mrouter) 582 ip6_mrouter_done(); 583 if (inp->in6p_icmp6filt) { 584 FREE(inp->in6p_icmp6filt, M_PCB); 585 inp->in6p_icmp6filt = NULL; 586 } 587 in6_pcbdetach(inp); 588 return 0; 589 } 590 591 static int 592 rip6_abort(struct socket *so) 593 { 594 soisdisconnected(so); 595 return rip6_detach(so); 596 } 597 598 static int 599 rip6_disconnect(struct socket *so) 600 { 601 struct inpcb *inp = sotoinpcb(so); 602 603 if ((so->so_state & SS_ISCONNECTED) == 0) 604 return ENOTCONN; 605 inp->in6p_faddr = in6addr_any; 606 return rip6_abort(so); 607 } 608 609 static int 610 rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 611 { 612 struct inpcb *inp = sotoinpcb(so); 613 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 614 struct ifaddr *ia = NULL; 615 616 if (nam->sa_len != sizeof(*addr)) 617 return EINVAL; 618 619 if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) 620 return EADDRNOTAVAIL; 621 #ifdef ENABLE_DEFAULT_SCOPE 622 if (addr->sin6_scope_id == 0) { /* not change if specified */ 623 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 624 } 625 #endif 626 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 627 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) 628 return EADDRNOTAVAIL; 629 if (ia && 630 ((struct in6_ifaddr *)ia)->ia6_flags & 631 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 632 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 633 return(EADDRNOTAVAIL); 634 } 635 inp->in6p_laddr = addr->sin6_addr; 636 return 0; 637 } 638 639 static int 640 rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 641 { 642 struct inpcb *inp = sotoinpcb(so); 643 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 644 struct in6_addr *in6a = NULL; 645 int error = 0; 646 #ifdef ENABLE_DEFAULT_SCOPE 647 struct sockaddr_in6 tmp; 648 #endif 649 650 if (nam->sa_len != sizeof(*addr)) 651 return EINVAL; 652 if (TAILQ_EMPTY(&ifnet)) 653 return EADDRNOTAVAIL; 654 if (addr->sin6_family != AF_INET6) 655 return EAFNOSUPPORT; 656 #ifdef ENABLE_DEFAULT_SCOPE 657 if (addr->sin6_scope_id == 0) { /* not change if specified */ 658 /* avoid overwrites */ 659 tmp = *addr; 660 addr = &tmp; 661 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 662 } 663 #endif 664 /* Source address selection. XXX: need pcblookup? */ 665 in6a = in6_selectsrc(addr, inp->in6p_outputopts, 666 inp->in6p_moptions, &inp->in6p_route, 667 &inp->in6p_laddr, &error); 668 if (in6a == NULL) 669 return (error ? error : EADDRNOTAVAIL); 670 inp->in6p_laddr = *in6a; 671 inp->in6p_faddr = addr->sin6_addr; 672 soisconnected(so); 673 return 0; 674 } 675 676 static int 677 rip6_shutdown(struct socket *so) 678 { 679 socantsendmore(so); 680 return 0; 681 } 682 683 static int 684 rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 685 struct mbuf *control, struct thread *td) 686 { 687 struct inpcb *inp = sotoinpcb(so); 688 struct sockaddr_in6 tmp; 689 struct sockaddr_in6 *dst; 690 691 /* always copy sockaddr to avoid overwrites */ 692 if (so->so_state & SS_ISCONNECTED) { 693 if (nam) { 694 m_freem(m); 695 return EISCONN; 696 } 697 /* XXX */ 698 bzero(&tmp, sizeof(tmp)); 699 tmp.sin6_family = AF_INET6; 700 tmp.sin6_len = sizeof(struct sockaddr_in6); 701 bcopy(&inp->in6p_faddr, &tmp.sin6_addr, 702 sizeof(struct in6_addr)); 703 dst = &tmp; 704 } else { 705 if (nam == NULL) { 706 m_freem(m); 707 return ENOTCONN; 708 } 709 tmp = *(struct sockaddr_in6 *)nam; 710 dst = &tmp; 711 } 712 #ifdef ENABLE_DEFAULT_SCOPE 713 if (dst->sin6_scope_id == 0) { /* not change if specified */ 714 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); 715 } 716 #endif 717 return rip6_output(m, so, dst, control); 718 } 719 720 struct pr_usrreqs rip6_usrreqs = { 721 rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect, 722 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect, 723 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp, 724 pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, 725 in6_setsockaddr, sosend, soreceive, sopoll 726 }; 727