1 /* $NetBSD: udp6_usrreq.c,v 1.13 1999/09/13 12:15:56 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1989, 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 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 65 */ 66 67 #ifdef __NetBSD__ /*XXX*/ 68 #include "opt_ipsec.h" 69 #endif 70 71 #include <sys/param.h> 72 #include <sys/malloc.h> 73 #include <sys/mbuf.h> 74 #include <sys/protosw.h> 75 #include <sys/socket.h> 76 #include <sys/socketvar.h> 77 #include <sys/errno.h> 78 #include <sys/stat.h> 79 #include <sys/systm.h> 80 #ifdef __NetBSD__ 81 #include <sys/proc.h> 82 #endif 83 #include <sys/syslog.h> 84 85 #include <net/if.h> 86 #include <net/route.h> 87 #include <net/if_types.h> 88 89 #include <netinet/in.h> 90 #include <netinet/in_var.h> 91 #include <netinet6/ip6.h> 92 #include <netinet6/in6_pcb.h> 93 #include <netinet6/ip6_var.h> 94 #include <netinet6/icmp6.h> 95 #include <netinet6/udp6.h> 96 #include <netinet6/udp6_var.h> 97 98 #ifdef IPSEC 99 #include <netinet6/ipsec.h> 100 #endif /*IPSEC*/ 101 102 #include "faith.h" 103 104 /* 105 * UDP protocol inplementation. 106 * Per RFC 768, August, 1980. 107 */ 108 109 struct in6pcb *udp6_last_in6pcb = &udb6; 110 111 static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, struct ifnet *)); 112 static void udp6_detach __P((struct in6pcb *)); 113 static void udp6_notify __P((struct in6pcb *, int)); 114 115 void 116 udp6_init() 117 { 118 udb6.in6p_next = udb6.in6p_prev = &udb6; 119 } 120 121 static int 122 in6_mcmatch(in6p, ia6, ifp) 123 struct in6pcb *in6p; 124 register struct in6_addr *ia6; 125 struct ifnet *ifp; 126 { 127 struct ip6_moptions *im6o = in6p->in6p_moptions; 128 struct in6_multi_mship *imm; 129 130 if (im6o == NULL) 131 return 0; 132 133 for (imm = im6o->im6o_memberships.lh_first; imm != NULL; 134 imm = imm->i6mm_chain.le_next) { 135 if ((ifp == NULL || 136 imm->i6mm_maddr->in6m_ifp == ifp) && 137 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, 138 ia6)) 139 return 1; 140 } 141 return 0; 142 } 143 144 int 145 udp6_input(mp, offp, proto) 146 struct mbuf **mp; 147 int *offp, proto; 148 { 149 struct mbuf *m = *mp; 150 register struct ip6_hdr *ip6; 151 register struct udphdr *uh; 152 register struct in6pcb *in6p; 153 struct mbuf *opts = 0; 154 int off = *offp; 155 int plen, ulen; 156 struct sockaddr_in6 udp_in6; 157 158 #if defined(NFAITH) && 0 < NFAITH 159 if (m->m_pkthdr.rcvif) { 160 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 161 /* send icmp6 host unreach? */ 162 m_freem(m); 163 return IPPROTO_DONE; 164 } 165 } 166 #endif 167 udp6stat.udp6s_ipackets++; 168 169 IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 170 171 ip6 = mtod(m, struct ip6_hdr *); 172 plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 173 uh = (struct udphdr *)((caddr_t)ip6 + off); 174 ulen = ntohs((u_short)uh->uh_ulen); 175 176 if (plen != ulen) { 177 udp6stat.udp6s_badlen++; 178 goto bad; 179 } 180 181 /* 182 * Checksum extended UDP header and data. 183 */ 184 if (uh->uh_sum == 0) 185 udp6stat.udp6s_nosum++; 186 else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { 187 udp6stat.udp6s_badsum++; 188 goto bad; 189 } 190 191 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 192 struct in6pcb *last; 193 194 /* 195 * Deliver a multicast datagram to all sockets 196 * for which the local and remote addresses and ports match 197 * those of the incoming datagram. This allows more than 198 * one process to receive multicasts on the same port. 199 * (This really ought to be done for unicast datagrams as 200 * well, but that would cause problems with existing 201 * applications that open both address-specific sockets and 202 * a wildcard socket listening to the same port -- they would 203 * end up receiving duplicates of every unicast datagram. 204 * Those applications open the multiple sockets to overcome an 205 * inadequacy of the UDP socket interface, but for backwards 206 * compatibility we avoid the problem here rather than 207 * fixing the interface. Maybe 4.5BSD will remedy this?) 208 */ 209 210 /* 211 * In a case that laddr should be set to the link-local 212 * address (this happens in RIPng), the multicast address 213 * specified in the received packet does not match with 214 * laddr. To cure this situation, the matching is relaxed 215 * if the receiving interface is the same as one specified 216 * in the socket and if the destination multicast address 217 * matches one of the multicast groups specified in the socket. 218 */ 219 220 /* 221 * Construct sockaddr format source address. 222 */ 223 bzero(&udp_in6, sizeof(udp_in6)); 224 udp_in6.sin6_len = sizeof(struct sockaddr_in6); 225 udp_in6.sin6_family = AF_INET6; 226 udp_in6.sin6_port = uh->uh_sport; 227 udp_in6.sin6_addr = ip6->ip6_src; 228 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) 229 udp_in6.sin6_addr.s6_addr16[1] = 0; 230 if (m->m_pkthdr.rcvif) { 231 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) { 232 udp_in6.sin6_scope_id = 233 m->m_pkthdr.rcvif->if_index; 234 } else 235 udp_in6.sin6_scope_id = 0; 236 } else 237 udp_in6.sin6_scope_id = 0; 238 /* 239 * KAME note: usually we drop udphdr from mbuf here. 240 * We need udphdr for IPsec processing so we do that later. 241 */ 242 243 /* 244 * Locate pcb(s) for datagram. 245 * (Algorithm copied from raw_intr().) 246 */ 247 last = NULL; 248 for (in6p = udb6.in6p_next; 249 in6p != &udb6; 250 in6p = in6p->in6p_next) { 251 if (in6p->in6p_lport != uh->uh_dport) 252 continue; 253 if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) { 254 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, 255 &ip6->ip6_dst) && 256 !in6_mcmatch(in6p, &ip6->ip6_dst, 257 m->m_pkthdr.rcvif)) 258 continue; 259 } 260 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { 261 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, 262 &ip6->ip6_src) || 263 in6p->in6p_fport != uh->uh_sport) 264 continue; 265 } 266 267 if (last != NULL) { 268 struct mbuf *n; 269 270 #ifdef IPSEC 271 /* 272 * Check AH/ESP integrity. 273 */ 274 if (last != NULL && ipsec6_in_reject(m, last)) { 275 ipsec6stat.in_polvio++; 276 /* do not inject data into pcb */ 277 } else 278 #endif /*IPSEC*/ 279 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 280 /* 281 * KAME NOTE: do not 282 * m_copy(m, offset, ...) above. 283 * sbappendaddr() expects M_PKTHDR, 284 * and m_copy() will copy M_PKTHDR 285 * only if offset is 0. 286 */ 287 if (last->in6p_flags & IN6P_CONTROLOPTS 288 || last->in6p_socket->so_options & SO_TIMESTAMP) { 289 ip6_savecontrol(last, &opts, 290 ip6, n); 291 } 292 293 m_adj(n, off + sizeof(struct udphdr)); 294 if (sbappendaddr(&last->in6p_socket->so_rcv, 295 (struct sockaddr *)&udp_in6, 296 n, opts) == 0) { 297 m_freem(n); 298 if (opts) 299 m_freem(opts); 300 udp6stat.udp6s_fullsock++; 301 } else 302 sorwakeup(last->in6p_socket); 303 opts = 0; 304 } 305 } 306 last = in6p; 307 /* 308 * Don't look for additional matches if this one does 309 * not have either the SO_REUSEPORT or SO_REUSEADDR 310 * socket options set. This heuristic avoids searching 311 * through all pcbs in the common case of a non-shared 312 * port. It assumes that an application will never 313 * clear these options after setting them. 314 */ 315 if ((last->in6p_socket->so_options & 316 (SO_REUSEPORT|SO_REUSEADDR)) == 0) 317 break; 318 } 319 320 if (last == NULL) { 321 /* 322 * No matching pcb found; discard datagram. 323 * (No need to send an ICMP Port Unreachable 324 * for a broadcast or multicast datgram.) 325 */ 326 udp6stat.udp6s_noport++; 327 udp6stat.udp6s_noportmcast++; 328 goto bad; 329 } 330 #ifdef IPSEC 331 /* 332 * Check AH/ESP integrity. 333 */ 334 if (last != NULL && ipsec6_in_reject(m, last)) { 335 ipsec6stat.in_polvio++; 336 goto bad; 337 } 338 #endif /*IPSEC*/ 339 if (last->in6p_flags & IN6P_CONTROLOPTS 340 || last->in6p_socket->so_options & SO_TIMESTAMP) { 341 ip6_savecontrol(last, &opts, ip6, m); 342 } 343 344 m_adj(m, off + sizeof(struct udphdr)); 345 if (sbappendaddr(&last->in6p_socket->so_rcv, 346 (struct sockaddr *)&udp_in6, 347 m, opts) == 0) { 348 udp6stat.udp6s_fullsock++; 349 goto bad; 350 } 351 sorwakeup(last->in6p_socket); 352 return IPPROTO_DONE; 353 } 354 /* 355 * Locate pcb for datagram. 356 */ 357 in6p = udp6_last_in6pcb; 358 if (in6p->in6p_lport != uh->uh_dport || 359 in6p->in6p_fport != uh->uh_sport || 360 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) || 361 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) { 362 in6p = in6_pcblookup(&udb6, 363 &ip6->ip6_src, uh->uh_sport, 364 &ip6->ip6_dst, uh->uh_dport, 365 IN6PLOOKUP_WILDCARD); 366 if (in6p) 367 udp6_last_in6pcb = in6p; 368 udp6stat.udp6ps_pcbcachemiss++; 369 } 370 if (in6p == 0) { 371 udp6stat.udp6s_noport++; 372 if (m->m_flags & M_MCAST) { 373 printf("UDP6: M_MCAST is set in a unicast packet.\n"); 374 udp6stat.udp6s_noportmcast++; 375 goto bad; 376 } 377 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 378 return IPPROTO_DONE; 379 } 380 #ifdef IPSEC 381 /* 382 * Check AH/ESP integrity. 383 */ 384 if (in6p != NULL && ipsec6_in_reject(m, in6p)) { 385 ipsec6stat.in_polvio++; 386 goto bad; 387 } 388 #endif /*IPSEC*/ 389 390 /* 391 * Construct sockaddr format source address. 392 * Stuff source address and datagram in user buffer. 393 */ 394 bzero(&udp_in6, sizeof(udp_in6)); 395 udp_in6.sin6_len = sizeof(struct sockaddr_in6); 396 udp_in6.sin6_family = AF_INET6; 397 udp_in6.sin6_port = uh->uh_sport; 398 udp_in6.sin6_addr = ip6->ip6_src; 399 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) 400 udp_in6.sin6_addr.s6_addr16[1] = 0; 401 if (m->m_pkthdr.rcvif) { 402 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) 403 udp_in6.sin6_scope_id = m->m_pkthdr.rcvif->if_index; 404 else 405 udp_in6.sin6_scope_id = 0; 406 } else 407 udp_in6.sin6_scope_id = 0; 408 if (in6p->in6p_flags & IN6P_CONTROLOPTS 409 || in6p->in6p_socket->so_options & SO_TIMESTAMP) { 410 ip6_savecontrol(in6p, &opts, ip6, m); 411 } 412 413 m_adj(m, off + sizeof(struct udphdr)); 414 if (sbappendaddr(&in6p->in6p_socket->so_rcv, 415 (struct sockaddr *)&udp_in6, 416 m, opts) == 0) { 417 udp6stat.udp6s_fullsock++; 418 goto bad; 419 } 420 sorwakeup(in6p->in6p_socket); 421 return IPPROTO_DONE; 422 bad: 423 if (m) 424 m_freem(m); 425 if (opts) 426 m_freem(opts); 427 return IPPROTO_DONE; 428 } 429 430 /* 431 * Notify a udp user of an asynchronous error; 432 * just wake up so tat he can collect error status. 433 */ 434 static void 435 udp6_notify(in6p, errno) 436 register struct in6pcb *in6p; 437 int errno; 438 { 439 in6p->in6p_socket->so_error = errno; 440 sorwakeup(in6p->in6p_socket); 441 sowwakeup(in6p->in6p_socket); 442 } 443 444 void 445 udp6_ctlinput(cmd, sa, ip6, m, off) 446 int cmd; 447 struct sockaddr *sa; 448 register struct ip6_hdr *ip6; 449 struct mbuf *m; 450 int off; 451 { 452 register struct udphdr *uhp; 453 struct udphdr uh; 454 struct sockaddr_in6 sa6; 455 456 if (sa->sa_family != AF_INET6 || 457 sa->sa_len != sizeof(struct sockaddr_in6)) 458 return; 459 #if 0 460 if (cmd == PRC_IFNEWADDR) 461 in6_mrejoin(&udb6); 462 else 463 #endif 464 if (!PRC_IS_REDIRECT(cmd) && 465 ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) 466 return; 467 468 /* translate addresses into internal form */ 469 sa6 = *(struct sockaddr_in6 *)sa; 470 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) 471 sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 472 473 if (ip6) { 474 /* 475 * XXX: We assume that when IPV6 is non NULL, 476 * M and OFF are valid. 477 */ 478 struct in6_addr s; 479 480 /* translate addresses into internal form */ 481 memcpy(&s, &ip6->ip6_src, sizeof(s)); 482 if (IN6_IS_ADDR_LINKLOCAL(&s)) 483 s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 484 485 if (m->m_len < off + sizeof(uh)) { 486 /* 487 * this should be rare case, 488 * so we compromise on this copy... 489 */ 490 m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 491 uhp = &uh; 492 } else 493 uhp = (struct udphdr *)(mtod(m, caddr_t) + off); 494 (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 495 uhp->uh_dport, &s, 496 uhp->uh_sport, cmd, udp6_notify); 497 } else { 498 (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 0, 499 &zeroin6_addr, 0, cmd, udp6_notify); 500 } 501 } 502 503 int 504 udp6_output(in6p, m, addr6, control) 505 register struct in6pcb *in6p; 506 register struct mbuf *m; 507 struct mbuf *addr6, *control; 508 { 509 register int ulen = m->m_pkthdr.len; 510 int plen = sizeof(struct udphdr) + ulen; 511 struct ip6_hdr *ip6; 512 struct udphdr *udp6; 513 struct in6_addr laddr6; 514 int s = 0, error = 0; 515 struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; 516 int priv = 0; 517 struct proc *p = curproc; /* XXX */ 518 519 if (p && !suser(p->p_ucred, &p->p_acflag)) 520 priv = 1; 521 if (control) { 522 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) 523 goto release; 524 in6p->in6p_outputopts = &opt; 525 } 526 527 if (addr6) { 528 laddr6 = in6p->in6p_laddr; 529 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { 530 error = EISCONN; 531 goto release; 532 } 533 /* 534 * Must block input while temporarily connected. 535 */ 536 s = splsoftnet(); 537 error = in6_pcbconnect(in6p, addr6); 538 if (error) { 539 splx(s); 540 goto release; 541 } 542 } else { 543 if (IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { 544 error = ENOTCONN; 545 goto release; 546 } 547 } 548 /* 549 * Calculate data length and get a mbuf 550 * for UDP and IP6 headers. 551 */ 552 M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), M_DONTWAIT); 553 if (m == 0) { 554 error = ENOBUFS; 555 if (addr6) 556 splx(s); 557 goto release; 558 } 559 560 /* 561 * Stuff checksum and output datagram. 562 */ 563 ip6 = mtod(m, struct ip6_hdr *); 564 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; 565 ip6->ip6_vfc = IPV6_VERSION; 566 #if 0 /* ip6_plen will be filled in ip6_output. */ 567 ip6->ip6_plen = htons((u_short)plen); 568 #endif 569 ip6->ip6_nxt = IPPROTO_UDP; 570 ip6->ip6_hlim = in6p->in6p_ip6.ip6_hlim; /* XXX */ 571 ip6->ip6_src = in6p->in6p_laddr; 572 ip6->ip6_dst = in6p->in6p_faddr; 573 574 udp6 = (struct udphdr *)(ip6 + 1); 575 udp6->uh_sport = in6p->in6p_lport; 576 udp6->uh_dport = in6p->in6p_fport; 577 udp6->uh_ulen = htons((u_short)plen); 578 udp6->uh_sum = 0; 579 580 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, 581 sizeof(struct ip6_hdr), plen)) == 0) { 582 udp6->uh_sum = 0xffff; 583 } 584 585 udp6stat.udp6s_opackets++; 586 587 #ifdef IPSEC 588 m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket; 589 #endif /*IPSEC*/ 590 error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, 591 0, in6p->in6p_moptions); 592 593 if (addr6) { 594 in6_pcbdisconnect(in6p); 595 in6p->in6p_laddr = laddr6; 596 splx(s); 597 } 598 goto releaseopt; 599 600 release: 601 m_freem(m); 602 603 releaseopt: 604 if (control) { 605 in6p->in6p_outputopts = stickyopt; 606 m_freem(control); 607 } 608 return(error); 609 } 610 611 extern int udp6_sendspace; 612 extern int udp6_recvspace; 613 614 int 615 udp6_usrreq(so, req, m, addr6, control, p) 616 struct socket *so; 617 int req; 618 struct mbuf *m, *addr6, *control; 619 struct proc *p; 620 { 621 struct in6pcb *in6p = sotoin6pcb(so); 622 int error = 0; 623 int s; 624 625 /* 626 * MAPPED_ADDR implementation info: 627 * Mapped addr support for PRU_CONTROL is not necessary. 628 * Because typical user of PRU_CONTROL is such as ifconfig, 629 * and they don't associate any addr to their socket. Then 630 * socket family is only hint about the PRU_CONTROL'ed address 631 * family, especially when getting addrs from kernel. 632 * So AF_INET socket need to be used to control AF_INET addrs, 633 * and AF_INET6 socket for AF_INET6 addrs. 634 */ 635 if (req == PRU_CONTROL) 636 return(in6_control(so, (u_long)m, (caddr_t)addr6, 637 (struct ifnet *)control, p)); 638 639 if (in6p == NULL && req != PRU_ATTACH) { 640 error = EINVAL; 641 goto release; 642 } 643 644 switch (req) { 645 case PRU_ATTACH: 646 /* 647 * MAPPED_ADDR implementation spec: 648 * Always attach for IPv6, 649 * and only when necessary for IPv4. 650 */ 651 if (in6p != NULL) { 652 error = EINVAL; 653 break; 654 } 655 s = splsoftnet(); 656 error = in6_pcballoc(so, &udb6); 657 splx(s); 658 if (error) 659 break; 660 error = soreserve(so, udp6_sendspace, udp6_recvspace); 661 if (error) 662 break; 663 in6p = sotoin6pcb(so); 664 in6p->in6p_ip6.ip6_hlim = ip6_defhlim; 665 in6p->in6p_cksum = -1; /* just to be sure */ 666 #ifdef IPSEC 667 if ((error = ipsec_init_policy(&in6p->in6p_sp)) != 0) 668 in6_pcbdetach(in6p); 669 #endif /*IPSEC*/ 670 break; 671 672 case PRU_DETACH: 673 udp6_detach(in6p); 674 break; 675 676 case PRU_BIND: 677 s = splsoftnet(); 678 error = in6_pcbbind(in6p, addr6); 679 splx(s); 680 break; 681 682 case PRU_LISTEN: 683 error = EOPNOTSUPP; 684 break; 685 686 case PRU_CONNECT: 687 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { 688 error = EISCONN; 689 break; 690 } 691 s = splsoftnet(); 692 error = in6_pcbconnect(in6p, addr6); 693 if (ip6_auto_flowlabel) { 694 in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; 695 in6p->in6p_flowinfo |= 696 (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); 697 } 698 splx(s); 699 if (error == 0) 700 soisconnected(so); 701 break; 702 703 case PRU_CONNECT2: 704 error = EOPNOTSUPP; 705 break; 706 707 case PRU_ACCEPT: 708 error = EOPNOTSUPP; 709 break; 710 711 case PRU_DISCONNECT: 712 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 713 error = ENOTCONN; 714 break; 715 } 716 s = splsoftnet(); 717 in6_pcbdisconnect(in6p); 718 bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr)); 719 splx(s); 720 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 721 break; 722 723 case PRU_SHUTDOWN: 724 socantsendmore(so); 725 break; 726 727 case PRU_SEND: 728 return(udp6_output(in6p, m, addr6, control)); 729 730 case PRU_ABORT: 731 soisdisconnected(so); 732 udp6_detach(in6p); 733 break; 734 735 case PRU_SOCKADDR: 736 in6_setsockaddr(in6p, addr6); 737 break; 738 739 case PRU_PEERADDR: 740 in6_setpeeraddr(in6p, addr6); 741 break; 742 743 case PRU_SENSE: 744 /* 745 * stat: don't bother with a blocksize 746 */ 747 return(0); 748 749 case PRU_SENDOOB: 750 case PRU_FASTTIMO: 751 case PRU_SLOWTIMO: 752 case PRU_PROTORCV: 753 case PRU_PROTOSEND: 754 error = EOPNOTSUPP; 755 break; 756 757 case PRU_RCVD: 758 case PRU_RCVOOB: 759 return(EOPNOTSUPP); /* do not free mbuf's */ 760 761 default: 762 panic("udp6_usrreq"); 763 } 764 765 release: 766 if (control) { 767 printf("udp control data unexpectedly retained\n"); 768 m_freem(control); 769 } 770 if (m) 771 m_freem(m); 772 return(error); 773 } 774 775 static void 776 udp6_detach(in6p) 777 struct in6pcb *in6p; 778 { 779 int s = splsoftnet(); 780 781 if (in6p == udp6_last_in6pcb) 782 udp6_last_in6pcb = &udb6; 783 in6_pcbdetach(in6p); 784 splx(s); 785 } 786 787 #ifdef __bsdi__ 788 int *udp6_sysvars[] = UDP6CTL_VARS; 789 790 int 791 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 792 int *name; 793 u_int namelen; 794 void *oldp; 795 size_t *oldlenp; 796 void *newp; 797 size_t newlen; 798 { 799 if (name[0] >= UDP6CTL_MAXID) 800 return (EOPNOTSUPP); 801 switch (name[0]) { 802 case UDP6CTL_STATS: 803 return sysctl_rdtrunc(oldp, oldlenp, newp, &udp6stat, 804 sizeof(udp6stat)); 805 806 default: 807 return (sysctl_int_arr(udp6_sysvars, name, namelen, 808 oldp, oldlenp, newp, newlen)); 809 } 810 } 811 #endif /*__bsdi__*/ 812 813 #ifdef __NetBSD__ 814 #include <vm/vm.h> 815 #include <sys/sysctl.h> 816 817 int 818 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 819 int *name; 820 u_int namelen; 821 void *oldp; 822 size_t *oldlenp; 823 void *newp; 824 size_t newlen; 825 { 826 /* All sysctl names at this level are terminal. */ 827 if (namelen != 1) 828 return ENOTDIR; 829 830 switch (name[0]) { 831 832 case UDP6CTL_SENDMAX: 833 return sysctl_int(oldp, oldlenp, newp, newlen, 834 &udp6_sendspace); 835 case UDP6CTL_RECVSPACE: 836 return sysctl_int(oldp, oldlenp, newp, newlen, 837 &udp6_recvspace); 838 default: 839 return ENOPROTOOPT; 840 } 841 /* NOTREACHED */ 842 } 843 #endif 844