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/priv.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 = m_copy(m, 0, (int)M_COPYALL); 159 160 if (n) { 161 struct socket *so; 162 163 so = last->in6p_socket; 164 if ((last->in6p_flags & IN6P_CONTROLOPTS) || 165 (so->so_options & SO_TIMESTAMP)) { 166 ip6_savecontrol(last, &opts, ip6, n); 167 } 168 /* strip intermediate headers */ 169 m_adj(n, *offp); 170 lwkt_gettoken(&so->so_rcv.ssb_token); 171 if (ssb_appendaddr(&so->so_rcv, 172 (struct sockaddr *)&rip6src, 173 n, opts) == 0) { 174 m_freem(n); 175 if (opts) 176 m_freem(opts); 177 rip6stat.rip6s_fullsock++; 178 } else { 179 sorwakeup(so); 180 } 181 lwkt_reltoken(&so->so_rcv.ssb_token); 182 opts = NULL; 183 } 184 } 185 last = in6p; 186 } 187 if (last) { 188 struct socket *so; 189 190 so = last->in6p_socket; 191 if ((last->in6p_flags & IN6P_CONTROLOPTS) || 192 (so->so_options & SO_TIMESTAMP)) { 193 ip6_savecontrol(last, &opts, ip6, m); 194 } 195 /* strip intermediate headers */ 196 m_adj(m, *offp); 197 lwkt_gettoken(&so->so_rcv.ssb_token); 198 if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&rip6src, 199 m, opts) == 0) { 200 m_freem(m); 201 if (opts) 202 m_freem(opts); 203 rip6stat.rip6s_fullsock++; 204 } else { 205 sorwakeup(so); 206 } 207 lwkt_reltoken(&so->so_rcv.ssb_token); 208 } else { 209 rip6stat.rip6s_nosock++; 210 if (m->m_flags & M_MCAST) 211 rip6stat.rip6s_nosockmcast++; 212 if (proto == IPPROTO_NONE) 213 m_freem(m); 214 else { 215 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 216 icmp6_error(m, ICMP6_PARAM_PROB, 217 ICMP6_PARAMPROB_NEXTHEADER, 218 prvnxtp - mtod(m, char *)); 219 } 220 ip6stat.ip6s_delivered--; 221 } 222 return IPPROTO_DONE; 223 } 224 225 void 226 rip6_ctlinput(netmsg_t msg) 227 { 228 int cmd = msg->ctlinput.nm_cmd; 229 struct sockaddr *sa = msg->ctlinput.nm_arg; 230 void *d = msg->ctlinput.nm_extra; 231 struct ip6ctlparam *ip6cp = NULL; 232 const struct sockaddr_in6 *sa6_src = NULL; 233 inp_notify_t notify = in6_rtchange; 234 235 if (sa->sa_family != AF_INET6 || 236 sa->sa_len != sizeof(struct sockaddr_in6)) 237 goto out; 238 239 if ((unsigned)cmd >= PRC_NCMDS) 240 goto out; 241 if (PRC_IS_REDIRECT(cmd)) 242 notify = in6_rtchange, d = NULL; 243 else if (cmd == PRC_HOSTDEAD) 244 d = NULL; 245 else if (inet6ctlerrmap[cmd] == 0) 246 goto out; 247 248 /* if the parameter is from icmp6, decode it. */ 249 if (d != NULL) { 250 ip6cp = (struct ip6ctlparam *)d; 251 sa6_src = ip6cp->ip6c_src; 252 } else { 253 sa6_src = &sa6_any; 254 } 255 256 in6_pcbnotify(&ripcbinfo, sa, 0, 257 (const struct sockaddr *)sa6_src, 0, cmd, 0, notify); 258 out: 259 lwkt_replymsg(&msg->ctlinput.base.lmsg, 0); 260 } 261 262 /* 263 * Generate IPv6 header and pass packet to ip6_output. 264 * Tack on options user may have setup with control call. 265 */ 266 int 267 rip6_output(struct mbuf *m, struct socket *so, ...) 268 { 269 struct sockaddr_in6 *dstsock; 270 struct mbuf *control; 271 struct in6_addr *dst; 272 struct ip6_hdr *ip6; 273 struct inpcb *in6p; 274 u_int plen = m->m_pkthdr.len; 275 int error = 0; 276 struct ip6_pktopts opt, *optp = NULL; 277 struct ifnet *oifp = NULL; 278 int type = 0, code = 0; /* for ICMPv6 output statistics only */ 279 int priv = 0; 280 __va_list ap; 281 282 __va_start(ap, so); 283 dstsock = __va_arg(ap, struct sockaddr_in6 *); 284 control = __va_arg(ap, struct mbuf *); 285 __va_end(ap); 286 287 if (IN6_IS_ADDR_V4MAPPED(&dstsock->sin6_addr)) { 288 error = EADDRNOTAVAIL; 289 goto bad; 290 } 291 292 in6p = so->so_pcb; 293 294 priv = 0; 295 if (so->so_cred->cr_uid == 0) 296 priv = 1; 297 dst = &dstsock->sin6_addr; 298 if (control) { 299 if ((error = ip6_setpktoptions(control, &opt, 300 in6p->in6p_outputopts, 301 so->so_proto->pr_protocol, priv)) != 0) 302 goto bad; 303 optp = &opt; 304 } else 305 optp = in6p->in6p_outputopts; 306 307 /* 308 * For an ICMPv6 packet, we should know its type and code 309 * to update statistics. 310 */ 311 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 312 struct icmp6_hdr *icmp6; 313 if (m->m_len < sizeof(struct icmp6_hdr) && 314 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 315 error = ENOBUFS; 316 goto bad; 317 } 318 icmp6 = mtod(m, struct icmp6_hdr *); 319 type = icmp6->icmp6_type; 320 code = icmp6->icmp6_code; 321 } 322 323 M_PREPEND(m, sizeof(*ip6), M_WAITOK); 324 ip6 = mtod(m, struct ip6_hdr *); 325 326 /* 327 * Next header might not be ICMP6 but use its pseudo header anyway. 328 */ 329 ip6->ip6_dst = *dst; 330 331 /* 332 * If the scope of the destination is link-local, embed the interface 333 * index in the address. 334 * 335 * XXX advanced-api value overrides sin6_scope_id 336 */ 337 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 338 struct in6_pktinfo *pi; 339 340 /* 341 * XXX Boundary check is assumed to be already done in 342 * ip6_setpktoptions(). 343 */ 344 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { 345 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); 346 oifp = ifindex2ifnet[pi->ipi6_ifindex]; 347 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 348 in6p->in6p_moptions && 349 in6p->in6p_moptions->im6o_multicast_ifp) { 350 oifp = in6p->in6p_moptions->im6o_multicast_ifp; 351 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); 352 } else if (dstsock->sin6_scope_id) { 353 /* boundary check */ 354 if (dstsock->sin6_scope_id < 0 || 355 if_index < dstsock->sin6_scope_id) { 356 error = ENXIO; /* XXX EINVAL? */ 357 goto bad; 358 } 359 ip6->ip6_dst.s6_addr16[1] = 360 htons(dstsock->sin6_scope_id & 0xffff); /* XXX */ 361 } 362 } 363 364 /* 365 * Source address selection. 366 */ 367 { 368 struct in6_addr *in6a; 369 370 if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions, 371 &in6p->in6p_route, &in6p->in6p_laddr, &error, NULL)) 372 == NULL) { 373 if (error == 0) 374 error = EADDRNOTAVAIL; 375 goto bad; 376 } 377 ip6->ip6_src = *in6a; 378 if (in6p->in6p_route.ro_rt) 379 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; 380 } 381 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | 382 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); 383 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | 384 (IPV6_VERSION & IPV6_VERSION_MASK); 385 /* ip6_plen will be filled in ip6_output, so not fill it here. */ 386 ip6->ip6_nxt = in6p->in6p_ip6_nxt; 387 ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 388 389 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 390 in6p->in6p_cksum != -1) { 391 struct mbuf *n; 392 int off; 393 u_int16_t *p; 394 395 /* compute checksum */ 396 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 397 off = offsetof(struct icmp6_hdr, icmp6_cksum); 398 else 399 off = in6p->in6p_cksum; 400 if (plen < off + 1) { 401 error = EINVAL; 402 goto bad; 403 } 404 off += sizeof(struct ip6_hdr); 405 406 n = m; 407 while (n && n->m_len <= off) { 408 off -= n->m_len; 409 n = n->m_next; 410 } 411 if (!n) 412 goto bad; 413 p = (u_int16_t *)(mtod(n, caddr_t) + off); 414 *p = 0; 415 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 416 } 417 418 error = ip6_output(m, optp, &in6p->in6p_route, 0, 419 in6p->in6p_moptions, &oifp, in6p); 420 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 421 if (oifp) 422 icmp6_ifoutstat_inc(oifp, type, code); 423 icmp6stat.icp6s_outhist[type]++; 424 } else 425 rip6stat.rip6s_opackets++; 426 427 goto freectl; 428 429 bad: 430 if (m) 431 m_freem(m); 432 433 freectl: 434 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) 435 RTFREE(optp->ip6po_route.ro_rt); 436 if (control) { 437 if (optp == &opt) 438 ip6_clearpktopts(optp, -1); 439 m_freem(control); 440 } 441 return (error); 442 } 443 444 /* 445 * Raw IPv6 socket option processing. 446 */ 447 void 448 rip6_ctloutput(netmsg_t msg) 449 { 450 struct socket *so = msg->ctloutput.base.nm_so; 451 struct sockopt *sopt = msg->ctloutput.nm_sopt; 452 int error; 453 454 if (sopt->sopt_level == IPPROTO_ICMPV6) { 455 /* 456 * XXX: is it better to call icmp6_ctloutput() directly 457 * from protosw? 458 */ 459 icmp6_ctloutput(msg); 460 /* msg invalid now */ 461 return; 462 } 463 if (sopt->sopt_level != IPPROTO_IPV6) { 464 error = EINVAL; 465 goto out; 466 } 467 468 error = 0; 469 470 switch (sopt->sopt_dir) { 471 case SOPT_GET: 472 switch (sopt->sopt_name) { 473 case MRT6_INIT: 474 case MRT6_DONE: 475 case MRT6_ADD_MIF: 476 case MRT6_DEL_MIF: 477 case MRT6_ADD_MFC: 478 case MRT6_DEL_MFC: 479 case MRT6_PIM: 480 error = ip6_mrouter_get(so, sopt); 481 break; 482 case IPV6_CHECKSUM: 483 error = ip6_raw_ctloutput(so, sopt); 484 break; 485 default: 486 error = ip6_ctloutput(so, sopt); 487 break; 488 } 489 break; 490 491 case SOPT_SET: 492 switch (sopt->sopt_name) { 493 case MRT6_INIT: 494 case MRT6_DONE: 495 case MRT6_ADD_MIF: 496 case MRT6_DEL_MIF: 497 case MRT6_ADD_MFC: 498 case MRT6_DEL_MFC: 499 case MRT6_PIM: 500 error = ip6_mrouter_set(so, sopt); 501 break; 502 case IPV6_CHECKSUM: 503 error = ip6_raw_ctloutput(so, sopt); 504 break; 505 default: 506 error = ip6_ctloutput(so, sopt); 507 break; 508 } 509 break; 510 } 511 out: 512 lwkt_replymsg(&msg->ctloutput.base.lmsg, error); 513 } 514 515 static void 516 rip6_attach(netmsg_t msg) 517 { 518 struct socket *so = msg->attach.base.nm_so; 519 int proto = msg->attach.nm_proto; 520 struct pru_attach_info *ai = msg->attach.nm_ai; 521 struct inpcb *inp; 522 int error; 523 524 inp = so->so_pcb; 525 if (inp) 526 panic("rip6_attach"); 527 error = priv_check_cred(ai->p_ucred, PRIV_NETINET_RAW, NULL_CRED_OKAY); 528 if (error) 529 goto out; 530 531 error = soreserve(so, rip_sendspace, rip_recvspace, ai->sb_rlimit); 532 if (error) 533 goto out; 534 crit_enter(); 535 error = in_pcballoc(so, &ripcbinfo); 536 crit_exit(); 537 if (error) 538 goto out; 539 inp = (struct inpcb *)so->so_pcb; 540 inp->in6p_ip6_nxt = (long)proto; 541 inp->in6p_hops = -1; /* use kernel default */ 542 inp->in6p_cksum = -1; 543 inp->in6p_icmp6filt = kmalloc(sizeof(struct icmp6_filter), M_PCB, 544 M_NOWAIT); 545 if (inp->in6p_icmp6filt != NULL) 546 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); 547 error = 0; 548 out: 549 lwkt_replymsg(&msg->attach.base.lmsg, error); 550 } 551 552 static void 553 rip6_detach(netmsg_t msg) 554 { 555 struct socket *so = msg->detach.base.nm_so; 556 struct inpcb *inp; 557 558 inp = so->so_pcb; 559 if (inp == NULL) 560 panic("rip6_detach"); 561 /* xxx: RSVP */ 562 if (so == ip6_mrouter) 563 ip6_mrouter_done(); 564 if (inp->in6p_icmp6filt) { 565 kfree(inp->in6p_icmp6filt, M_PCB); 566 inp->in6p_icmp6filt = NULL; 567 } 568 in6_pcbdetach(inp); 569 lwkt_replymsg(&msg->detach.base.lmsg, 0); 570 } 571 572 /* 573 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 574 * will sofree() it when we return. 575 */ 576 static void 577 rip6_abort(netmsg_t msg) 578 { 579 soisdisconnected(msg->abort.base.nm_so); 580 rip6_detach(msg); 581 /* msg invalid now */ 582 } 583 584 static void 585 rip6_disconnect(netmsg_t msg) 586 { 587 struct socket *so = msg->disconnect.base.nm_so; 588 struct inpcb *inp = so->so_pcb; 589 590 if (so->so_state & SS_ISCONNECTED) { 591 inp->in6p_faddr = kin6addr_any; 592 soreference(so); 593 rip6_abort(msg); 594 /* msg invalid now */ 595 sofree(so); 596 return; 597 } 598 lwkt_replymsg(&msg->disconnect.base.lmsg, ENOTCONN); 599 } 600 601 static void 602 rip6_bind(netmsg_t msg) 603 { 604 struct socket *so = msg->bind.base.nm_so; 605 struct sockaddr *nam = msg->bind.nm_nam; 606 struct inpcb *inp = so->so_pcb; 607 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 608 struct ifaddr *ia = NULL; 609 int error; 610 611 if (nam->sa_len != sizeof(*addr)) { 612 error = EINVAL; 613 goto out; 614 } 615 if (ifnet_array_isempty() || addr->sin6_family != AF_INET6) { 616 error = EADDRNOTAVAIL; 617 goto out; 618 } 619 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 620 error = EADDRNOTAVAIL; 621 goto out; 622 } 623 #ifdef ENABLE_DEFAULT_SCOPE 624 if (addr->sin6_scope_id == 0) { /* not change if specified */ 625 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 626 } 627 #endif 628 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 629 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL) { 630 error = EADDRNOTAVAIL; 631 goto out; 632 } 633 if (ia && 634 ((struct in6_ifaddr *)ia)->ia6_flags & 635 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 636 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 637 error = EADDRNOTAVAIL; 638 goto out; 639 } 640 inp->in6p_laddr = addr->sin6_addr; 641 error = 0; 642 out: 643 lwkt_replymsg(&msg->bind.base.lmsg, error); 644 } 645 646 static void 647 rip6_connect(netmsg_t msg) 648 { 649 struct socket *so = msg->connect.base.nm_so; 650 struct sockaddr *nam = msg->connect.nm_nam; 651 struct inpcb *inp = so->so_pcb; 652 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 653 struct in6_addr *in6a = NULL; 654 int error = 0; 655 #ifdef ENABLE_DEFAULT_SCOPE 656 struct sockaddr_in6 tmp; 657 #endif 658 659 if (nam->sa_len != sizeof(*addr)) { 660 error = EINVAL; 661 goto out; 662 } 663 if (ifnet_array_isempty()) { 664 error = EADDRNOTAVAIL; 665 goto out; 666 } 667 if (addr->sin6_family != AF_INET6) { 668 error = EAFNOSUPPORT; 669 goto out; 670 } 671 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { 672 error = EADDRNOTAVAIL; 673 goto out; 674 } 675 #ifdef ENABLE_DEFAULT_SCOPE 676 if (addr->sin6_scope_id == 0) { /* not change if specified */ 677 /* avoid overwrites */ 678 tmp = *addr; 679 addr = &tmp; 680 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 681 } 682 #endif 683 /* Source address selection. XXX: need pcblookup? */ 684 in6a = in6_selectsrc(addr, inp->in6p_outputopts, 685 inp->in6p_moptions, &inp->in6p_route, 686 &inp->in6p_laddr, &error, NULL); 687 if (in6a == NULL) { 688 if (error == 0) 689 error = EADDRNOTAVAIL; 690 } else { 691 inp->in6p_laddr = *in6a; 692 inp->in6p_faddr = addr->sin6_addr; 693 soisconnected(so); 694 error = 0; 695 } 696 out: 697 lwkt_replymsg(&msg->connect.base.lmsg, error); 698 } 699 700 static void 701 rip6_shutdown(netmsg_t msg) 702 { 703 socantsendmore(msg->shutdown.base.nm_so); 704 lwkt_replymsg(&msg->shutdown.base.lmsg, 0); 705 } 706 707 static void 708 rip6_send(netmsg_t msg) 709 { 710 struct socket *so = msg->send.base.nm_so; 711 struct mbuf *m = msg->send.nm_m; 712 struct sockaddr *nam = msg->send.nm_addr; 713 struct mbuf *control = msg->send.nm_control; 714 struct inpcb *inp = so->so_pcb; 715 struct sockaddr_in6 tmp; 716 struct sockaddr_in6 *dst; 717 int error; 718 719 /* always copy sockaddr to avoid overwrites */ 720 if (so->so_state & SS_ISCONNECTED) { 721 if (nam) { 722 m_freem(m); 723 error = EISCONN; 724 goto out; 725 } 726 /* XXX */ 727 bzero(&tmp, sizeof(tmp)); 728 tmp.sin6_family = AF_INET6; 729 tmp.sin6_len = sizeof(struct sockaddr_in6); 730 bcopy(&inp->in6p_faddr, &tmp.sin6_addr, 731 sizeof(struct in6_addr)); 732 dst = &tmp; 733 } else { 734 if (nam == NULL) { 735 m_freem(m); 736 error = ENOTCONN; 737 goto out; 738 } 739 tmp = *(struct sockaddr_in6 *)nam; 740 dst = &tmp; 741 } 742 #ifdef ENABLE_DEFAULT_SCOPE 743 if (dst->sin6_scope_id == 0) { /* not change if specified */ 744 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); 745 } 746 #endif 747 error = rip6_output(m, so, dst, control); 748 out: 749 lwkt_replymsg(&msg->send.base.lmsg, error); 750 } 751 752 struct pr_usrreqs rip6_usrreqs = { 753 .pru_abort = rip6_abort, 754 .pru_accept = pr_generic_notsupp, 755 .pru_attach = rip6_attach, 756 .pru_bind = rip6_bind, 757 .pru_connect = rip6_connect, 758 .pru_connect2 = pr_generic_notsupp, 759 .pru_control = in6_control_dispatch, 760 .pru_detach = rip6_detach, 761 .pru_disconnect = rip6_disconnect, 762 .pru_listen = pr_generic_notsupp, 763 .pru_peeraddr = in6_setpeeraddr_dispatch, 764 .pru_rcvd = pr_generic_notsupp, 765 .pru_rcvoob = pr_generic_notsupp, 766 .pru_send = rip6_send, 767 .pru_sense = pru_sense_null, 768 .pru_shutdown = rip6_shutdown, 769 .pru_sockaddr = in6_setsockaddr_dispatch, 770 .pru_sosend = sosend, 771 .pru_soreceive = soreceive 772 }; 773