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