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: src/sys/netinet6/raw_ip6.c,v 1.7.2.7 2003/01/24 05:11:35 sam Exp $ 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. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 61 */ 62 63 #include "opt_inet6.h" 64 65 #include <sys/param.h> 66 #include <sys/malloc.h> 67 #include <sys/proc.h> 68 #include <sys/caps.h> 69 #include <sys/mbuf.h> 70 #include <sys/socket.h> 71 #include <sys/jail.h> 72 #include <sys/protosw.h> 73 #include <sys/socketvar.h> 74 #include <sys/errno.h> 75 #include <sys/systm.h> 76 77 #include <sys/thread2.h> 78 #include <sys/socketvar2.h> 79 #include <sys/msgport2.h> 80 81 #include <net/if.h> 82 #include <net/route.h> 83 #include <net/if_types.h> 84 85 #include <netinet/in.h> 86 #include <netinet/in_var.h> 87 #include <netinet/in_systm.h> 88 #include <netinet/ip6.h> 89 #include <netinet6/ip6_var.h> 90 #include <netinet6/ip6_mroute.h> 91 #include <netinet/icmp6.h> 92 #include <netinet/in_pcb.h> 93 #include <netinet6/in6_pcb.h> 94 #include <netinet6/nd6.h> 95 #include <netinet6/ip6protosw.h> 96 #ifdef ENABLE_DEFAULT_SCOPE 97 #include <netinet6/scope6_var.h> 98 #endif 99 #include <netinet6/raw_ip6.h> 100 101 #include <machine/stdarg.h> 102 103 #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) 104 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) 105 106 /* 107 * Raw interface to IP6 protocol. 108 */ 109 110 extern struct inpcbinfo ripcbinfo; 111 extern u_long rip_sendspace; 112 extern u_long rip_recvspace; 113 114 struct rip6stat rip6stat; 115 116 /* 117 * Setup generic address and protocol structures 118 * for raw_input routine, then pass them along with 119 * mbuf chain. 120 */ 121 int 122 rip6_input(struct mbuf **mp, int *offp, int proto) 123 { 124 struct mbuf *m = *mp; 125 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 126 struct inpcb *in6p; 127 struct inpcb *last = NULL; 128 struct mbuf *opts = NULL; 129 struct sockaddr_in6 rip6src; 130 131 rip6stat.rip6s_ipackets++; 132 133 init_sin6(&rip6src, m); /* general init */ 134 135 LIST_FOREACH(in6p, &ripcbinfo.pcblisthead, inp_list) { 136 if (in6p->in6p_flags & INP_PLACEMARKER) 137 continue; 138 if (!INP_ISIPV6(in6p)) 139 continue; 140 if (in6p->in6p_ip6_nxt && 141 in6p->in6p_ip6_nxt != proto) 142 continue; 143 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 144 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 145 continue; 146 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 147 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 148 continue; 149 if (in6p->in6p_cksum != -1) { 150 rip6stat.rip6s_isum++; 151 if (in6_cksum(m, ip6->ip6_nxt, *offp, 152 m->m_pkthdr.len - *offp)) { 153 rip6stat.rip6s_badsum++; 154 continue; 155 } 156 } 157 if (last) { 158 struct mbuf *n; 159 160 n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 161 if (n != NULL) { 162 struct socket *so; 163 164 so = last->in6p_socket; 165 if ((last->in6p_flags & IN6P_CONTROLOPTS) || 166 (so->so_options & SO_TIMESTAMP)) { 167 ip6_savecontrol(last, &opts, ip6, n); 168 } 169 /* strip intermediate headers */ 170 m_adj(n, *offp); 171 lwkt_gettoken(&so->so_rcv.ssb_token); 172 if (ssb_appendaddr(&so->so_rcv, 173 (struct sockaddr *)&rip6src, 174 n, opts) == 0) { 175 m_freem(n); 176 if (opts) 177 m_freem(opts); 178 rip6stat.rip6s_fullsock++; 179 soroverflow(so); 180 } else { 181 sorwakeup(so); 182 } 183 lwkt_reltoken(&so->so_rcv.ssb_token); 184 opts = NULL; 185 } 186 } 187 last = in6p; 188 } 189 if (last) { 190 struct socket *so; 191 192 so = last->in6p_socket; 193 if ((last->in6p_flags & IN6P_CONTROLOPTS) || 194 (so->so_options & SO_TIMESTAMP)) { 195 ip6_savecontrol(last, &opts, ip6, m); 196 } 197 /* strip intermediate headers */ 198 m_adj(m, *offp); 199 lwkt_gettoken(&so->so_rcv.ssb_token); 200 if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&rip6src, 201 m, opts) == 0) { 202 m_freem(m); 203 if (opts) 204 m_freem(opts); 205 rip6stat.rip6s_fullsock++; 206 soroverflow(so); 207 } else { 208 sorwakeup(so); 209 } 210 lwkt_reltoken(&so->so_rcv.ssb_token); 211 } else { 212 rip6stat.rip6s_nosock++; 213 if (m->m_flags & M_MCAST) 214 rip6stat.rip6s_nosockmcast++; 215 if (proto == IPPROTO_NONE) 216 m_freem(m); 217 else { 218 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 219 icmp6_error(m, ICMP6_PARAM_PROB, 220 ICMP6_PARAMPROB_NEXTHEADER, 221 prvnxtp - mtod(m, char *)); 222 } 223 ip6stat.ip6s_delivered--; 224 } 225 return IPPROTO_DONE; 226 } 227 228 void 229 rip6_ctlinput(netmsg_t msg) 230 { 231 int cmd = msg->ctlinput.nm_cmd; 232 struct sockaddr *sa = msg->ctlinput.nm_arg; 233 void *d = msg->ctlinput.nm_extra; 234 struct ip6ctlparam *ip6cp = NULL; 235 const struct sockaddr_in6 *sa6_src = NULL; 236 inp_notify_t notify = in6_rtchange; 237 238 if (sa->sa_family != AF_INET6 || 239 sa->sa_len != sizeof(struct sockaddr_in6)) 240 goto out; 241 242 if ((unsigned)cmd >= PRC_NCMDS) 243 goto out; 244 if (PRC_IS_REDIRECT(cmd)) 245 notify = in6_rtchange, d = NULL; 246 else if (cmd == PRC_HOSTDEAD) 247 d = NULL; 248 else if (inet6ctlerrmap[cmd] == 0) 249 goto out; 250 251 /* if the parameter is from icmp6, decode it. */ 252 if (d != NULL) { 253 ip6cp = (struct ip6ctlparam *)d; 254 sa6_src = ip6cp->ip6c_src; 255 } else { 256 sa6_src = &sa6_any; 257 } 258 259 in6_pcbnotify(&ripcbinfo, sa, 0, 260 (const struct sockaddr *)sa6_src, 0, cmd, 0, notify); 261 out: 262 lwkt_replymsg(&msg->ctlinput.base.lmsg, 0); 263 } 264 265 /* 266 * Generate IPv6 header and pass packet to ip6_output. 267 * Tack on options user may have setup with control call. 268 */ 269 int 270 rip6_output(struct mbuf *m, struct socket *so, ...) 271 { 272 struct sockaddr_in6 *dstsock; 273 struct mbuf *control; 274 struct in6_addr *dst; 275 struct ip6_hdr *ip6; 276 struct inpcb *in6p; 277 u_int plen = m->m_pkthdr.len; 278 int error = 0; 279 struct ip6_pktopts opt, *optp = NULL; 280 struct ifnet *oifp = NULL; 281 int type = 0, code = 0; /* for ICMPv6 output statistics only */ 282 int priv = 0; 283 __va_list ap; 284 285 __va_start(ap, so); 286 dstsock = __va_arg(ap, struct sockaddr_in6 *); 287 control = __va_arg(ap, struct mbuf *); 288 __va_end(ap); 289 290 if (IN6_IS_ADDR_V4MAPPED(&dstsock->sin6_addr)) { 291 error = EADDRNOTAVAIL; 292 goto bad; 293 } 294 295 in6p = so->so_pcb; 296 297 priv = 0; 298 if (so->so_cred->cr_uid == 0) 299 priv = 1; 300 dst = &dstsock->sin6_addr; 301 if (control) { 302 if ((error = ip6_setpktoptions(control, &opt, 303 in6p->in6p_outputopts, 304 so->so_proto->pr_protocol, priv)) != 0) 305 goto bad; 306 optp = &opt; 307 } else 308 optp = in6p->in6p_outputopts; 309 310 /* 311 * For an ICMPv6 packet, we should know its type and code 312 * to update statistics. 313 */ 314 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 315 struct icmp6_hdr *icmp6; 316 if (m->m_len < sizeof(struct icmp6_hdr) && 317 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 318 error = ENOBUFS; 319 goto bad; 320 } 321 icmp6 = mtod(m, struct icmp6_hdr *); 322 type = icmp6->icmp6_type; 323 code = icmp6->icmp6_code; 324 } 325 326 M_PREPEND(m, sizeof(*ip6), M_WAITOK); 327 ip6 = mtod(m, struct ip6_hdr *); 328 329 /* 330 * Next header might not be ICMP6 but use its pseudo header anyway. 331 */ 332 ip6->ip6_dst = *dst; 333 334 /* 335 * If the scope of the destination is link-local, embed the interface 336 * index in the address. 337 * 338 * XXX advanced-api value overrides sin6_scope_id 339 */ 340 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 341 struct in6_pktinfo *pi; 342 343 /* 344 * XXX Boundary check is assumed to be already done in 345 * ip6_setpktoptions(). 346 */ 347 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { 348 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); 349 oifp = ifindex2ifnet[pi->ipi6_ifindex]; 350 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 351 in6p->in6p_moptions && 352 in6p->in6p_moptions->im6o_multicast_ifp) { 353 oifp = in6p->in6p_moptions->im6o_multicast_ifp; 354 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); 355 } else if (dstsock->sin6_scope_id) { 356 /* boundary check */ 357 if (dstsock->sin6_scope_id < 0 || 358 if_index < dstsock->sin6_scope_id) { 359 error = ENXIO; /* XXX EINVAL? */ 360 goto bad; 361 } 362 ip6->ip6_dst.s6_addr16[1] = 363 htons(dstsock->sin6_scope_id & 0xffff); /* XXX */ 364 } 365 } 366 367 /* 368 * Source address selection. 369 */ 370 { 371 struct in6_addr *in6a; 372 373 if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions, 374 &in6p->in6p_route, &in6p->in6p_laddr, &error, NULL)) 375 == NULL) { 376 if (error == 0) 377 error = EADDRNOTAVAIL; 378 goto bad; 379 } 380 ip6->ip6_src = *in6a; 381 if (in6p->in6p_route.ro_rt) 382 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; 383 } 384 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | 385 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); 386 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | 387 (IPV6_VERSION & IPV6_VERSION_MASK); 388 /* ip6_plen will be filled in ip6_output, so not fill it here. */ 389 ip6->ip6_nxt = in6p->in6p_ip6_nxt; 390 ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 391 392 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 393 in6p->in6p_cksum != -1) { 394 struct mbuf *n; 395 int off; 396 u_int16_t *p; 397 398 /* compute checksum */ 399 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 400 off = offsetof(struct icmp6_hdr, icmp6_cksum); 401 else 402 off = in6p->in6p_cksum; 403 if (plen < off + 1) { 404 error = EINVAL; 405 goto bad; 406 } 407 off += sizeof(struct ip6_hdr); 408 409 n = m; 410 while (n && n->m_len <= off) { 411 off -= n->m_len; 412 n = n->m_next; 413 } 414 if (!n) 415 goto bad; 416 p = (u_int16_t *)(mtod(n, caddr_t) + off); 417 *p = 0; 418 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 419 } 420 421 error = ip6_output(m, optp, &in6p->in6p_route, 0, 422 in6p->in6p_moptions, &oifp, in6p); 423 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 424 if (oifp) 425 icmp6_ifoutstat_inc(oifp, type, code); 426 icmp6stat.icp6s_outhist[type]++; 427 } else 428 rip6stat.rip6s_opackets++; 429 430 goto freectl; 431 432 bad: 433 if (m) 434 m_freem(m); 435 436 freectl: 437 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) 438 RTFREE(optp->ip6po_route.ro_rt); 439 if (control) { 440 if (optp == &opt) 441 ip6_clearpktopts(optp, -1); 442 m_freem(control); 443 } 444 return (error); 445 } 446 447 /* 448 * Raw IPv6 socket option processing. 449 */ 450 void 451 rip6_ctloutput(netmsg_t msg) 452 { 453 struct socket *so = msg->ctloutput.base.nm_so; 454 struct sockopt *sopt = msg->ctloutput.nm_sopt; 455 int error; 456 457 if (sopt->sopt_level == IPPROTO_ICMPV6) { 458 /* 459 * XXX: is it better to call icmp6_ctloutput() directly 460 * from protosw? 461 */ 462 icmp6_ctloutput(msg); 463 /* msg invalid now */ 464 return; 465 } 466 if (sopt->sopt_level != IPPROTO_IPV6) { 467 error = EINVAL; 468 goto out; 469 } 470 471 error = 0; 472 473 switch (sopt->sopt_dir) { 474 case SOPT_GET: 475 switch (sopt->sopt_name) { 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 error = ip6_mrouter_get(so, sopt); 484 break; 485 case IPV6_CHECKSUM: 486 error = ip6_raw_ctloutput(so, sopt); 487 break; 488 default: 489 error = ip6_ctloutput(so, sopt); 490 break; 491 } 492 break; 493 494 case SOPT_SET: 495 switch (sopt->sopt_name) { 496 case MRT6_INIT: 497 case MRT6_DONE: 498 case MRT6_ADD_MIF: 499 case MRT6_DEL_MIF: 500 case MRT6_ADD_MFC: 501 case MRT6_DEL_MFC: 502 case MRT6_PIM: 503 error = ip6_mrouter_set(so, sopt); 504 break; 505 case IPV6_CHECKSUM: 506 error = ip6_raw_ctloutput(so, sopt); 507 break; 508 default: 509 error = ip6_ctloutput(so, sopt); 510 break; 511 } 512 break; 513 } 514 out: 515 lwkt_replymsg(&msg->ctloutput.base.lmsg, error); 516 } 517 518 static void 519 rip6_attach(netmsg_t msg) 520 { 521 struct socket *so = msg->attach.base.nm_so; 522 int proto = msg->attach.nm_proto; 523 struct pru_attach_info *ai = msg->attach.nm_ai; 524 struct inpcb *inp; 525 int error; 526 527 inp = so->so_pcb; 528 if (inp) 529 panic("rip6_attach"); 530 error = caps_priv_check(ai->p_ucred, 531 SYSCAP_NONET_RAW | __SYSCAP_NULLCRED); 532 if (error) 533 goto out; 534 535 error = soreserve(so, rip_sendspace, rip_recvspace, ai->sb_rlimit); 536 if (error) 537 goto out; 538 crit_enter(); 539 error = in_pcballoc(so, &ripcbinfo); 540 crit_exit(); 541 if (error) 542 goto out; 543 inp = (struct inpcb *)so->so_pcb; 544 inp->in6p_ip6_nxt = (long)proto; 545 inp->in6p_hops = -1; /* use kernel default */ 546 inp->in6p_cksum = -1; 547 inp->in6p_icmp6filt = kmalloc(sizeof(struct icmp6_filter), M_PCB, 548 M_NOWAIT); 549 if (inp->in6p_icmp6filt != NULL) 550 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); 551 error = 0; 552 out: 553 lwkt_replymsg(&msg->attach.base.lmsg, error); 554 } 555 556 static void 557 rip6_detach(netmsg_t msg) 558 { 559 struct socket *so = msg->detach.base.nm_so; 560 struct inpcb *inp; 561 562 inp = so->so_pcb; 563 if (inp == NULL) 564 panic("rip6_detach"); 565 /* xxx: RSVP */ 566 if (so == ip6_mrouter) 567 ip6_mrouter_done(); 568 if (inp->in6p_icmp6filt) { 569 kfree(inp->in6p_icmp6filt, M_PCB); 570 inp->in6p_icmp6filt = NULL; 571 } 572 in6_pcbdetach(inp); 573 lwkt_replymsg(&msg->detach.base.lmsg, 0); 574 } 575 576 /* 577 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 578 * will sofree() it when we return. 579 */ 580 static void 581 rip6_abort(netmsg_t msg) 582 { 583 soisdisconnected(msg->abort.base.nm_so); 584 rip6_detach(msg); 585 /* msg invalid now */ 586 } 587 588 static void 589 rip6_disconnect(netmsg_t msg) 590 { 591 struct socket *so = msg->disconnect.base.nm_so; 592 struct inpcb *inp = so->so_pcb; 593 594 if (so->so_state & SS_ISCONNECTED) { 595 inp->in6p_faddr = kin6addr_any; 596 soreference(so); 597 rip6_abort(msg); 598 /* msg invalid now */ 599 sofree(so); 600 return; 601 } 602 lwkt_replymsg(&msg->disconnect.base.lmsg, ENOTCONN); 603 } 604 605 static void 606 rip6_bind(netmsg_t msg) 607 { 608 struct socket *so = msg->bind.base.nm_so; 609 struct sockaddr *nam = msg->bind.nm_nam; 610 struct inpcb *inp = so->so_pcb; 611 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 612 struct ifaddr *ia = NULL; 613 int error; 614 615 if (nam->sa_len != sizeof(*addr)) { 616 error = EINVAL; 617 goto out; 618 } 619 if (ifnet_array_isempty() || addr->sin6_family != AF_INET6) { 620 error = EADDRNOTAVAIL; 621 goto out; 622 } 623 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 624 error = EADDRNOTAVAIL; 625 goto out; 626 } 627 #ifdef ENABLE_DEFAULT_SCOPE 628 if (addr->sin6_scope_id == 0) { /* not change if specified */ 629 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 630 } 631 #endif 632 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 633 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL) { 634 error = EADDRNOTAVAIL; 635 goto out; 636 } 637 if (ia && 638 ((struct in6_ifaddr *)ia)->ia6_flags & 639 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 640 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 641 error = EADDRNOTAVAIL; 642 goto out; 643 } 644 inp->in6p_laddr = addr->sin6_addr; 645 error = 0; 646 out: 647 lwkt_replymsg(&msg->bind.base.lmsg, error); 648 } 649 650 static void 651 rip6_connect(netmsg_t msg) 652 { 653 struct socket *so = msg->connect.base.nm_so; 654 struct sockaddr *nam = msg->connect.nm_nam; 655 struct inpcb *inp = so->so_pcb; 656 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 657 struct in6_addr *in6a = NULL; 658 int error = 0; 659 #ifdef ENABLE_DEFAULT_SCOPE 660 struct sockaddr_in6 tmp; 661 #endif 662 663 if (nam->sa_len != sizeof(*addr)) { 664 error = EINVAL; 665 goto out; 666 } 667 if (ifnet_array_isempty()) { 668 error = EADDRNOTAVAIL; 669 goto out; 670 } 671 if (addr->sin6_family != AF_INET6) { 672 error = EAFNOSUPPORT; 673 goto out; 674 } 675 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 676 error = EADDRNOTAVAIL; 677 goto out; 678 } 679 #ifdef ENABLE_DEFAULT_SCOPE 680 if (addr->sin6_scope_id == 0) { /* not change if specified */ 681 /* avoid overwrites */ 682 tmp = *addr; 683 addr = &tmp; 684 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 685 } 686 #endif 687 /* Source address selection. XXX: need pcblookup? */ 688 in6a = in6_selectsrc(addr, inp->in6p_outputopts, 689 inp->in6p_moptions, &inp->in6p_route, 690 &inp->in6p_laddr, &error, NULL); 691 if (in6a == NULL) { 692 if (error == 0) 693 error = EADDRNOTAVAIL; 694 } else { 695 inp->in6p_laddr = *in6a; 696 inp->in6p_faddr = addr->sin6_addr; 697 soisconnected(so); 698 error = 0; 699 } 700 out: 701 lwkt_replymsg(&msg->connect.base.lmsg, error); 702 } 703 704 static void 705 rip6_shutdown(netmsg_t msg) 706 { 707 socantsendmore(msg->shutdown.base.nm_so); 708 lwkt_replymsg(&msg->shutdown.base.lmsg, 0); 709 } 710 711 static void 712 rip6_send(netmsg_t msg) 713 { 714 struct socket *so = msg->send.base.nm_so; 715 struct mbuf *m = msg->send.nm_m; 716 struct sockaddr *nam = msg->send.nm_addr; 717 struct mbuf *control = msg->send.nm_control; 718 struct inpcb *inp = so->so_pcb; 719 struct sockaddr_in6 tmp; 720 struct sockaddr_in6 *dst; 721 int error; 722 723 /* always copy sockaddr to avoid overwrites */ 724 if (so->so_state & SS_ISCONNECTED) { 725 if (nam) { 726 m_freem(m); 727 error = EISCONN; 728 goto out; 729 } 730 /* XXX */ 731 bzero(&tmp, sizeof(tmp)); 732 tmp.sin6_family = AF_INET6; 733 tmp.sin6_len = sizeof(struct sockaddr_in6); 734 bcopy(&inp->in6p_faddr, &tmp.sin6_addr, 735 sizeof(struct in6_addr)); 736 dst = &tmp; 737 } else { 738 if (nam == NULL) { 739 m_freem(m); 740 error = ENOTCONN; 741 goto out; 742 } 743 tmp = *(struct sockaddr_in6 *)nam; 744 dst = &tmp; 745 } 746 #ifdef ENABLE_DEFAULT_SCOPE 747 if (dst->sin6_scope_id == 0) { /* not change if specified */ 748 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); 749 } 750 #endif 751 error = rip6_output(m, so, dst, control); 752 out: 753 lwkt_replymsg(&msg->send.base.lmsg, error); 754 } 755 756 struct pr_usrreqs rip6_usrreqs = { 757 .pru_abort = rip6_abort, 758 .pru_accept = pr_generic_notsupp, 759 .pru_attach = rip6_attach, 760 .pru_bind = rip6_bind, 761 .pru_connect = rip6_connect, 762 .pru_connect2 = pr_generic_notsupp, 763 .pru_control = in6_control_dispatch, 764 .pru_detach = rip6_detach, 765 .pru_disconnect = rip6_disconnect, 766 .pru_listen = pr_generic_notsupp, 767 .pru_peeraddr = in6_setpeeraddr_dispatch, 768 .pru_rcvd = pr_generic_notsupp, 769 .pru_rcvoob = pr_generic_notsupp, 770 .pru_send = rip6_send, 771 .pru_sense = pru_sense_null, 772 .pru_shutdown = rip6_shutdown, 773 .pru_sockaddr = in6_setsockaddr_dispatch, 774 .pru_sosend = sosend, 775 .pru_soreceive = soreceive 776 }; 777