raw_ip6.c revision 166938
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: head/sys/netinet6/raw_ip6.c 166938 2007-02-24 11:38:47Z bms $ 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 * 4. 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/errno.h> 68#include <sys/lock.h> 69#include <sys/malloc.h> 70#include <sys/mbuf.h> 71#include <sys/proc.h> 72#include <sys/protosw.h> 73#include <sys/signalvar.h> 74#include <sys/socket.h> 75#include <sys/socketvar.h> 76#include <sys/sx.h> 77#include <sys/systm.h> 78#include <sys/syslog.h> 79 80#include <net/if.h> 81#include <net/if_types.h> 82#include <net/route.h> 83 84#include <netinet/in.h> 85#include <netinet/in_var.h> 86#include <netinet/in_systm.h> 87#include <netinet/icmp6.h> 88#include <netinet/in_pcb.h> 89#include <netinet/ip6.h> 90#include <netinet6/ip6protosw.h> 91#include <netinet6/ip6_mroute.h> 92#include <netinet6/in6_pcb.h> 93#include <netinet6/ip6_var.h> 94#include <netinet6/nd6.h> 95#include <netinet6/raw_ip6.h> 96#include <netinet6/scope6_var.h> 97 98#ifdef IPSEC 99#include <netinet6/ipsec.h> 100#include <netinet6/ipsec6.h> 101#endif /*IPSEC*/ 102 103#ifdef FAST_IPSEC 104#include <netipsec/ipsec.h> 105#include <netipsec/ipsec6.h> 106#endif /* FAST_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 117extern struct inpcbhead ripcb; 118extern struct inpcbinfo ripcbinfo; 119extern u_long rip_sendspace; 120extern u_long rip_recvspace; 121 122struct rip6stat rip6stat; 123 124/* 125 * Hooks for multicast forwarding. 126 */ 127 128struct socket *ip6_mrouter; 129 130int (*ip6_mrouter_set)(struct socket *, struct sockopt *); 131int (*ip6_mrouter_get)(struct socket *, struct sockopt *); 132int (*ip6_mrouter_done)(void); 133int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *); 134int (*mrt6_ioctl)(int, caddr_t); 135 136/* 137 * Setup generic address and protocol structures 138 * for raw_input routine, then pass them along with 139 * mbuf chain. 140 */ 141int 142rip6_input(mp, offp, proto) 143 struct mbuf **mp; 144 int *offp, proto; 145{ 146 struct mbuf *m = *mp; 147 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 148 register struct inpcb *in6p; 149 struct inpcb *last = 0; 150 struct mbuf *opts = NULL; 151 struct sockaddr_in6 fromsa; 152 153 rip6stat.rip6s_ipackets++; 154 155 if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 156 /* XXX send icmp6 host/port unreach? */ 157 m_freem(m); 158 return IPPROTO_DONE; 159 } 160 161 init_sin6(&fromsa, m); /* general init */ 162 163 INP_INFO_RLOCK(&ripcbinfo); 164 LIST_FOREACH(in6p, &ripcb, inp_list) { 165 INP_LOCK(in6p); 166 if ((in6p->in6p_vflag & INP_IPV6) == 0) { 167docontinue: 168 INP_UNLOCK(in6p); 169 continue; 170 } 171 if (in6p->in6p_ip6_nxt && 172 in6p->in6p_ip6_nxt != proto) 173 goto docontinue; 174 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 175 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 176 goto docontinue; 177 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 178 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 179 goto docontinue; 180 if (in6p->in6p_cksum != -1) { 181 rip6stat.rip6s_isum++; 182 if (in6_cksum(m, proto, *offp, 183 m->m_pkthdr.len - *offp)) { 184 rip6stat.rip6s_badsum++; 185 goto docontinue; 186 } 187 } 188 if (last) { 189 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 190 191#if defined(IPSEC) || defined(FAST_IPSEC) 192 /* 193 * Check AH/ESP integrity. 194 */ 195 if (n && ipsec6_in_reject(n, last)) { 196 m_freem(n); 197#ifdef IPSEC 198 ipsec6stat.in_polvio++; 199#endif /*IPSEC*/ 200 /* do not inject data into pcb */ 201 } else 202#endif /*IPSEC || FAST_IPSEC*/ 203 if (n) { 204 if (last->in6p_flags & IN6P_CONTROLOPTS || 205 last->in6p_socket->so_options & SO_TIMESTAMP) 206 ip6_savecontrol(last, n, &opts); 207 /* strip intermediate headers */ 208 m_adj(n, *offp); 209 if (sbappendaddr(&last->in6p_socket->so_rcv, 210 (struct sockaddr *)&fromsa, 211 n, opts) == 0) { 212 m_freem(n); 213 if (opts) 214 m_freem(opts); 215 rip6stat.rip6s_fullsock++; 216 } else 217 sorwakeup(last->in6p_socket); 218 opts = NULL; 219 } 220 INP_UNLOCK(last); 221 } 222 last = in6p; 223 } 224#if defined(IPSEC) || defined(FAST_IPSEC) 225 /* 226 * Check AH/ESP integrity. 227 */ 228 if (last && ipsec6_in_reject(m, last)) { 229 m_freem(m); 230#ifdef IPSEC 231 ipsec6stat.in_polvio++; 232#endif /*IPSEC*/ 233 ip6stat.ip6s_delivered--; 234 /* do not inject data into pcb */ 235 INP_UNLOCK(last); 236 } else 237#endif /*IPSEC || FAST_IPSEC*/ 238 if (last) { 239 if (last->in6p_flags & IN6P_CONTROLOPTS || 240 last->in6p_socket->so_options & SO_TIMESTAMP) 241 ip6_savecontrol(last, m, &opts); 242 /* strip intermediate headers */ 243 m_adj(m, *offp); 244 if (sbappendaddr(&last->in6p_socket->so_rcv, 245 (struct sockaddr *)&fromsa, m, opts) == 0) { 246 m_freem(m); 247 if (opts) 248 m_freem(opts); 249 rip6stat.rip6s_fullsock++; 250 } else 251 sorwakeup(last->in6p_socket); 252 INP_UNLOCK(last); 253 } else { 254 rip6stat.rip6s_nosock++; 255 if (m->m_flags & M_MCAST) 256 rip6stat.rip6s_nosockmcast++; 257 if (proto == IPPROTO_NONE) 258 m_freem(m); 259 else { 260 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 261 icmp6_error(m, ICMP6_PARAM_PROB, 262 ICMP6_PARAMPROB_NEXTHEADER, 263 prvnxtp - mtod(m, char *)); 264 } 265 ip6stat.ip6s_delivered--; 266 } 267 INP_INFO_RUNLOCK(&ripcbinfo); 268 return IPPROTO_DONE; 269} 270 271void 272rip6_ctlinput(cmd, sa, d) 273 int cmd; 274 struct sockaddr *sa; 275 void *d; 276{ 277 struct ip6_hdr *ip6; 278 struct mbuf *m; 279 int off = 0; 280 struct ip6ctlparam *ip6cp = NULL; 281 const struct sockaddr_in6 *sa6_src = NULL; 282 void *cmdarg; 283 struct inpcb *(*notify) __P((struct inpcb *, int)) = in6_rtchange; 284 285 if (sa->sa_family != AF_INET6 || 286 sa->sa_len != sizeof(struct sockaddr_in6)) 287 return; 288 289 if ((unsigned)cmd >= PRC_NCMDS) 290 return; 291 if (PRC_IS_REDIRECT(cmd)) 292 notify = in6_rtchange, d = NULL; 293 else if (cmd == PRC_HOSTDEAD) 294 d = NULL; 295 else if (inet6ctlerrmap[cmd] == 0) 296 return; 297 298 /* if the parameter is from icmp6, decode it. */ 299 if (d != NULL) { 300 ip6cp = (struct ip6ctlparam *)d; 301 m = ip6cp->ip6c_m; 302 ip6 = ip6cp->ip6c_ip6; 303 off = ip6cp->ip6c_off; 304 cmdarg = ip6cp->ip6c_cmdarg; 305 sa6_src = ip6cp->ip6c_src; 306 } else { 307 m = NULL; 308 ip6 = NULL; 309 cmdarg = NULL; 310 sa6_src = &sa6_any; 311 } 312 313 (void) in6_pcbnotify(&ripcbinfo, sa, 0, 314 (const struct sockaddr *)sa6_src, 315 0, cmd, cmdarg, notify); 316} 317 318/* 319 * Generate IPv6 header and pass packet to ip6_output. 320 * Tack on options user may have setup with control call. 321 */ 322int 323#if __STDC__ 324rip6_output(struct mbuf *m, ...) 325#else 326rip6_output(m, va_alist) 327 struct mbuf *m; 328 va_dcl 329#endif 330{ 331 struct mbuf *control; 332 struct socket *so; 333 struct sockaddr_in6 *dstsock; 334 struct in6_addr *dst; 335 struct ip6_hdr *ip6; 336 struct inpcb *in6p; 337 u_int plen = m->m_pkthdr.len; 338 int error = 0; 339 struct ip6_pktopts opt, *optp; 340 struct ifnet *oifp = NULL; 341 int type = 0, code = 0; /* for ICMPv6 output statistics only */ 342 int priv = 0; 343 int scope_ambiguous = 0; 344 struct in6_addr *in6a; 345 va_list ap; 346 347 va_start(ap, m); 348 so = va_arg(ap, struct socket *); 349 dstsock = va_arg(ap, struct sockaddr_in6 *); 350 control = va_arg(ap, struct mbuf *); 351 va_end(ap); 352 353 in6p = sotoin6pcb(so); 354 INP_LOCK(in6p); 355 356 priv = 0; 357 if (suser_cred(so->so_cred, SUSER_ALLOWJAIL) == 0) 358 priv = 1; 359 dst = &dstsock->sin6_addr; 360 if (control) { 361 if ((error = ip6_setpktopts(control, &opt, 362 in6p->in6p_outputopts, priv, so->so_proto->pr_protocol)) 363 != 0) { 364 goto bad; 365 } 366 optp = &opt; 367 } else 368 optp = in6p->in6p_outputopts; 369 370 /* 371 * Check and convert scope zone ID into internal form. 372 * XXX: we may still need to determine the zone later. 373 */ 374 if (!(so->so_state & SS_ISCONNECTED)) { 375 if (dstsock->sin6_scope_id == 0 && !ip6_use_defzone) 376 scope_ambiguous = 1; 377 if ((error = sa6_embedscope(dstsock, ip6_use_defzone)) != 0) 378 goto bad; 379 } 380 381 /* 382 * For an ICMPv6 packet, we should know its type and code 383 * to update statistics. 384 */ 385 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 386 struct icmp6_hdr *icmp6; 387 if (m->m_len < sizeof(struct icmp6_hdr) && 388 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 389 error = ENOBUFS; 390 goto bad; 391 } 392 icmp6 = mtod(m, struct icmp6_hdr *); 393 type = icmp6->icmp6_type; 394 code = icmp6->icmp6_code; 395 } 396 397 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT); 398 if (m == NULL) { 399 error = ENOBUFS; 400 goto bad; 401 } 402 ip6 = mtod(m, struct ip6_hdr *); 403 404 /* 405 * Source address selection. 406 */ 407 if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions, NULL, 408 &in6p->in6p_laddr, &oifp, &error)) == NULL) { 409 if (error == 0) 410 error = EADDRNOTAVAIL; 411 goto bad; 412 } 413 ip6->ip6_src = *in6a; 414 415 if (oifp && scope_ambiguous) { 416 /* 417 * Application should provide a proper zone ID or the use of 418 * default zone IDs should be enabled. Unfortunately, some 419 * applications do not behave as it should, so we need a 420 * workaround. Even if an appropriate ID is not determined 421 * (when it's required), if we can determine the outgoing 422 * interface. determine the zone ID based on the interface. 423 */ 424 error = in6_setscope(&dstsock->sin6_addr, oifp, NULL); 425 if (error != 0) 426 goto bad; 427 } 428 ip6->ip6_dst = dstsock->sin6_addr; 429 430 /* fill in the rest of the IPv6 header fields */ 431 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | 432 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); 433 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | 434 (IPV6_VERSION & IPV6_VERSION_MASK); 435 /* ip6_plen will be filled in ip6_output, so not fill it here. */ 436 ip6->ip6_nxt = in6p->in6p_ip6_nxt; 437 ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 438 439 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 440 in6p->in6p_cksum != -1) { 441 struct mbuf *n; 442 int off; 443 u_int16_t *p; 444 445 /* compute checksum */ 446 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 447 off = offsetof(struct icmp6_hdr, icmp6_cksum); 448 else 449 off = in6p->in6p_cksum; 450 if (plen < off + 1) { 451 error = EINVAL; 452 goto bad; 453 } 454 off += sizeof(struct ip6_hdr); 455 456 n = m; 457 while (n && n->m_len <= off) { 458 off -= n->m_len; 459 n = n->m_next; 460 } 461 if (!n) 462 goto bad; 463 p = (u_int16_t *)(mtod(n, caddr_t) + off); 464 *p = 0; 465 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 466 } 467 468 error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p); 469 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 470 if (oifp) 471 icmp6_ifoutstat_inc(oifp, type, code); 472 icmp6stat.icp6s_outhist[type]++; 473 } else 474 rip6stat.rip6s_opackets++; 475 476 goto freectl; 477 478 bad: 479 if (m) 480 m_freem(m); 481 482 freectl: 483 if (control) { 484 ip6_clearpktopts(&opt, -1); 485 m_freem(control); 486 } 487 INP_UNLOCK(in6p); 488 return (error); 489} 490 491/* 492 * Raw IPv6 socket option processing. 493 */ 494int 495rip6_ctloutput(so, sopt) 496 struct socket *so; 497 struct sockopt *sopt; 498{ 499 int error; 500 501 if (sopt->sopt_level == IPPROTO_ICMPV6) 502 /* 503 * XXX: is it better to call icmp6_ctloutput() directly 504 * from protosw? 505 */ 506 return (icmp6_ctloutput(so, sopt)); 507 else if (sopt->sopt_level != IPPROTO_IPV6) 508 return (EINVAL); 509 510 error = 0; 511 512 switch (sopt->sopt_dir) { 513 case SOPT_GET: 514 switch (sopt->sopt_name) { 515 case MRT6_INIT: 516 case MRT6_DONE: 517 case MRT6_ADD_MIF: 518 case MRT6_DEL_MIF: 519 case MRT6_ADD_MFC: 520 case MRT6_DEL_MFC: 521 case MRT6_PIM: 522 error = ip6_mrouter_get ? ip6_mrouter_get(so, sopt) : 523 EOPNOTSUPP; 524 break; 525 case IPV6_CHECKSUM: 526 error = ip6_raw_ctloutput(so, sopt); 527 break; 528 default: 529 error = ip6_ctloutput(so, sopt); 530 break; 531 } 532 break; 533 534 case SOPT_SET: 535 switch (sopt->sopt_name) { 536 case MRT6_INIT: 537 case MRT6_DONE: 538 case MRT6_ADD_MIF: 539 case MRT6_DEL_MIF: 540 case MRT6_ADD_MFC: 541 case MRT6_DEL_MFC: 542 case MRT6_PIM: 543 error = ip6_mrouter_set ? ip6_mrouter_set(so, sopt) : 544 EOPNOTSUPP; 545 break; 546 case IPV6_CHECKSUM: 547 error = ip6_raw_ctloutput(so, sopt); 548 break; 549 default: 550 error = ip6_ctloutput(so, sopt); 551 break; 552 } 553 break; 554 } 555 556 return (error); 557} 558 559static int 560rip6_attach(struct socket *so, int proto, struct thread *td) 561{ 562 struct inpcb *inp; 563 struct icmp6_filter *filter; 564 int error; 565 566 inp = sotoinpcb(so); 567 KASSERT(inp == NULL, ("rip6_attach: inp != NULL")); 568 if (td && (error = suser(td)) != 0) 569 return error; 570 error = soreserve(so, rip_sendspace, rip_recvspace); 571 if (error) 572 return error; 573 MALLOC(filter, struct icmp6_filter *, 574 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); 575 if (filter == NULL) 576 return ENOMEM; 577 INP_INFO_WLOCK(&ripcbinfo); 578 error = in_pcballoc(so, &ripcbinfo); 579 if (error) { 580 INP_INFO_WUNLOCK(&ripcbinfo); 581 FREE(filter, M_PCB); 582 return error; 583 } 584 inp = (struct inpcb *)so->so_pcb; 585 INP_INFO_WUNLOCK(&ripcbinfo); 586 inp->inp_vflag |= INP_IPV6; 587 inp->in6p_ip6_nxt = (long)proto; 588 inp->in6p_hops = -1; /* use kernel default */ 589 inp->in6p_cksum = -1; 590 inp->in6p_icmp6filt = filter; 591 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); 592 INP_UNLOCK(inp); 593 return 0; 594} 595 596static void 597rip6_detach(struct socket *so) 598{ 599 struct inpcb *inp; 600 601 inp = sotoinpcb(so); 602 KASSERT(inp != NULL, ("rip6_detach: inp == NULL")); 603 604 if (so == ip6_mrouter && ip6_mrouter_done) 605 ip6_mrouter_done(); 606 /* xxx: RSVP */ 607 INP_INFO_WLOCK(&ripcbinfo); 608 INP_LOCK(inp); 609 if (inp->in6p_icmp6filt) { 610 FREE(inp->in6p_icmp6filt, M_PCB); 611 inp->in6p_icmp6filt = NULL; 612 } 613 in6_pcbdetach(inp); 614 in6_pcbfree(inp); 615 INP_INFO_WUNLOCK(&ripcbinfo); 616} 617 618/* XXXRW: This can't ever be called. */ 619static void 620rip6_abort(struct socket *so) 621{ 622 struct inpcb *inp; 623 624 inp = sotoinpcb(so); 625 KASSERT(inp != NULL, ("rip6_abort: inp == NULL")); 626 627 soisdisconnected(so); 628} 629 630static void 631rip6_close(struct socket *so) 632{ 633 struct inpcb *inp; 634 635 inp = sotoinpcb(so); 636 KASSERT(inp != NULL, ("rip6_close: inp == NULL")); 637 638 soisdisconnected(so); 639} 640 641static int 642rip6_disconnect(struct socket *so) 643{ 644 struct inpcb *inp = sotoinpcb(so); 645 646 if ((so->so_state & SS_ISCONNECTED) == 0) 647 return ENOTCONN; 648 inp->in6p_faddr = in6addr_any; 649 rip6_abort(so); 650 return (0); 651} 652 653static int 654rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 655{ 656 struct inpcb *inp = sotoinpcb(so); 657 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 658 struct ifaddr *ia = NULL; 659 int error = 0; 660 661 KASSERT(inp != NULL, ("rip6_bind: inp == NULL")); 662 if (nam->sa_len != sizeof(*addr)) 663 return EINVAL; 664 if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) 665 return EADDRNOTAVAIL; 666 if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) 667 return(error); 668 669 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 670 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) 671 return EADDRNOTAVAIL; 672 if (ia && 673 ((struct in6_ifaddr *)ia)->ia6_flags & 674 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 675 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 676 return (EADDRNOTAVAIL); 677 } 678 INP_INFO_WLOCK(&ripcbinfo); 679 INP_LOCK(inp); 680 inp->in6p_laddr = addr->sin6_addr; 681 INP_UNLOCK(inp); 682 INP_INFO_WUNLOCK(&ripcbinfo); 683 return 0; 684} 685 686static int 687rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 688{ 689 struct inpcb *inp = sotoinpcb(so); 690 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 691 struct in6_addr *in6a = NULL; 692 struct ifnet *ifp = NULL; 693 int error = 0, scope_ambiguous = 0; 694 695 KASSERT(inp != NULL, ("rip6_connect: inp == NULL")); 696 if (nam->sa_len != sizeof(*addr)) 697 return EINVAL; 698 if (TAILQ_EMPTY(&ifnet)) 699 return EADDRNOTAVAIL; 700 if (addr->sin6_family != AF_INET6) 701 return EAFNOSUPPORT; 702 703 /* 704 * Application should provide a proper zone ID or the use of 705 * default zone IDs should be enabled. Unfortunately, some 706 * applications do not behave as it should, so we need a 707 * workaround. Even if an appropriate ID is not determined, 708 * we'll see if we can determine the outgoing interface. If we 709 * can, determine the zone ID based on the interface below. 710 */ 711 if (addr->sin6_scope_id == 0 && !ip6_use_defzone) 712 scope_ambiguous = 1; 713 if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) 714 return(error); 715 716 INP_INFO_WLOCK(&ripcbinfo); 717 INP_LOCK(inp); 718 /* Source address selection. XXX: need pcblookup? */ 719 in6a = in6_selectsrc(addr, inp->in6p_outputopts, 720 inp->in6p_moptions, NULL, 721 &inp->in6p_laddr, &ifp, &error); 722 if (in6a == NULL) { 723 INP_UNLOCK(inp); 724 INP_INFO_WUNLOCK(&ripcbinfo); 725 return (error ? error : EADDRNOTAVAIL); 726 } 727 728 /* XXX: see above */ 729 if (ifp && scope_ambiguous && 730 (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) { 731 INP_UNLOCK(inp); 732 INP_INFO_WUNLOCK(&ripcbinfo); 733 return(error); 734 } 735 inp->in6p_faddr = addr->sin6_addr; 736 inp->in6p_laddr = *in6a; 737 soisconnected(so); 738 INP_UNLOCK(inp); 739 INP_INFO_WUNLOCK(&ripcbinfo); 740 return 0; 741} 742 743static int 744rip6_shutdown(struct socket *so) 745{ 746 struct inpcb *inp; 747 748 inp = sotoinpcb(so); 749 KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL")); 750 INP_LOCK(inp); 751 socantsendmore(so); 752 INP_UNLOCK(inp); 753 return 0; 754} 755 756static int 757rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 758 struct mbuf *control, struct thread *td) 759{ 760 struct inpcb *inp = sotoinpcb(so); 761 struct sockaddr_in6 tmp; 762 struct sockaddr_in6 *dst; 763 int ret; 764 765 KASSERT(inp != NULL, ("rip6_send: inp == NULL")); 766 INP_INFO_WLOCK(&ripcbinfo); 767 /* always copy sockaddr to avoid overwrites */ 768 /* Unlocked read. */ 769 if (so->so_state & SS_ISCONNECTED) { 770 if (nam) { 771 INP_INFO_WUNLOCK(&ripcbinfo); 772 m_freem(m); 773 return EISCONN; 774 } 775 /* XXX */ 776 bzero(&tmp, sizeof(tmp)); 777 tmp.sin6_family = AF_INET6; 778 tmp.sin6_len = sizeof(struct sockaddr_in6); 779 bcopy(&inp->in6p_faddr, &tmp.sin6_addr, 780 sizeof(struct in6_addr)); 781 dst = &tmp; 782 } else { 783 if (nam == NULL) { 784 INP_INFO_WUNLOCK(&ripcbinfo); 785 m_freem(m); 786 return ENOTCONN; 787 } 788 if (nam->sa_len != sizeof(struct sockaddr_in6)) { 789 INP_INFO_WUNLOCK(&ripcbinfo); 790 m_freem(m); 791 return(EINVAL); 792 } 793 tmp = *(struct sockaddr_in6 *)nam; 794 dst = &tmp; 795 796 if (dst->sin6_family == AF_UNSPEC) { 797 /* 798 * XXX: we allow this case for backward 799 * compatibility to buggy applications that 800 * rely on old (and wrong) kernel behavior. 801 */ 802 log(LOG_INFO, "rip6 SEND: address family is " 803 "unspec. Assume AF_INET6\n"); 804 dst->sin6_family = AF_INET6; 805 } else if (dst->sin6_family != AF_INET6) { 806 INP_INFO_WUNLOCK(&ripcbinfo); 807 m_freem(m); 808 return(EAFNOSUPPORT); 809 } 810 } 811 ret = rip6_output(m, so, dst, control); 812 INP_INFO_WUNLOCK(&ripcbinfo); 813 return (ret); 814} 815 816struct pr_usrreqs rip6_usrreqs = { 817 .pru_abort = rip6_abort, 818 .pru_attach = rip6_attach, 819 .pru_bind = rip6_bind, 820 .pru_connect = rip6_connect, 821 .pru_control = in6_control, 822 .pru_detach = rip6_detach, 823 .pru_disconnect = rip6_disconnect, 824 .pru_peeraddr = in6_setpeeraddr, 825 .pru_send = rip6_send, 826 .pru_shutdown = rip6_shutdown, 827 .pru_sockaddr = in6_setsockaddr, 828 .pru_close = rip6_close, 829}; 830