1 /* 2 * Copyright (c) 2004 Jeffrey M. Hsu. All rights reserved. 3 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 4 * 5 * This code is derived from software contributed to The DragonFly Project 6 * by Jeffrey M. Hsu. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of The DragonFly Project nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific, prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 36 * The Regents of the University of California. All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. Neither the name of the University nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 63 * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.18 2003/01/24 05:11:34 sam Exp $ 64 */ 65 66 #include "opt_ipsec.h" 67 #include "opt_inet6.h" 68 69 #include <sys/param.h> 70 #include <sys/systm.h> 71 #include <sys/kernel.h> 72 #include <sys/malloc.h> 73 #include <sys/mbuf.h> 74 #include <sys/domain.h> 75 #include <sys/proc.h> 76 #include <sys/priv.h> 77 #include <sys/protosw.h> 78 #include <sys/socket.h> 79 #include <sys/socketvar.h> 80 #include <sys/sysctl.h> 81 #include <sys/syslog.h> 82 #include <sys/in_cksum.h> 83 84 #include <sys/thread2.h> 85 #include <sys/socketvar2.h> 86 #include <sys/serialize.h> 87 88 #include <machine/stdarg.h> 89 90 #include <net/if.h> 91 #include <net/route.h> 92 #include <net/netmsg2.h> 93 #include <net/netisr2.h> 94 95 #include <netinet/in.h> 96 #include <netinet/in_systm.h> 97 #include <netinet/ip.h> 98 #ifdef INET6 99 #include <netinet/ip6.h> 100 #endif 101 #include <netinet/in_pcb.h> 102 #include <netinet/in_var.h> 103 #include <netinet/ip_var.h> 104 #ifdef INET6 105 #include <netinet6/ip6_var.h> 106 #endif 107 #include <netinet/ip_icmp.h> 108 #include <netinet/icmp_var.h> 109 #include <netinet/udp.h> 110 #include <netinet/udp_var.h> 111 112 #ifdef FAST_IPSEC 113 #include <netproto/ipsec/ipsec.h> 114 #endif 115 116 #ifdef IPSEC 117 #include <netinet6/ipsec.h> 118 #endif 119 120 /* 121 * UDP protocol implementation. 122 * Per RFC 768, August, 1980. 123 */ 124 #ifndef COMPAT_42 125 static int udpcksum = 1; 126 #else 127 static int udpcksum = 0; /* XXX */ 128 #endif 129 SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, 130 &udpcksum, 0, "Enable checksumming of UDP packets"); 131 132 int log_in_vain = 0; 133 SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, 134 &log_in_vain, 0, "Log all incoming UDP packets"); 135 136 static int blackhole = 0; 137 SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW, 138 &blackhole, 0, "Do not send port unreachables for refused connects"); 139 140 static int strict_mcast_mship = 1; 141 SYSCTL_INT(_net_inet_udp, OID_AUTO, strict_mcast_mship, CTLFLAG_RW, 142 &strict_mcast_mship, 0, "Only send multicast to member sockets"); 143 144 int udp_sosend_async = 1; 145 SYSCTL_INT(_net_inet_udp, OID_AUTO, sosend_async, CTLFLAG_RW, 146 &udp_sosend_async, 0, "UDP asynchronized pru_send"); 147 148 int udp_sosend_prepend = 1; 149 SYSCTL_INT(_net_inet_udp, OID_AUTO, sosend_prepend, CTLFLAG_RW, 150 &udp_sosend_prepend, 0, 151 "Prepend enough space for proto and link header in pru_send"); 152 153 static int udp_reuseport_ext = 1; 154 SYSCTL_INT(_net_inet_udp, OID_AUTO, reuseport_ext, CTLFLAG_RW, 155 &udp_reuseport_ext, 0, "SO_REUSEPORT extension"); 156 157 struct inpcbinfo udbinfo; 158 struct inpcbportinfo udbportinfo; 159 160 static struct netisr_barrier *udbinfo_br; 161 static struct lwkt_serialize udbinfo_slize = LWKT_SERIALIZE_INITIALIZER; 162 163 #ifndef UDBHASHSIZE 164 #define UDBHASHSIZE 16 165 #endif 166 167 struct udpstat udpstat_percpu[MAXCPU] __cachealign; 168 169 #ifdef INET6 170 struct udp_in6 { 171 struct sockaddr_in6 uin6_sin; 172 u_char uin6_init_done : 1; 173 }; 174 struct udp_ip6 { 175 struct ip6_hdr uip6_ip6; 176 u_char uip6_init_done : 1; 177 }; 178 #else 179 struct udp_in6; 180 struct udp_ip6; 181 #endif /* INET6 */ 182 183 static void udp_append (struct inpcb *last, struct ip *ip, 184 struct mbuf *n, int off, struct sockaddr_in *udp_in, 185 struct udp_in6 *, struct udp_ip6 *); 186 #ifdef INET6 187 static void ip_2_ip6_hdr (struct ip6_hdr *ip6, struct ip *ip); 188 #endif 189 190 static int udp_connect_oncpu(struct socket *so, struct thread *td, 191 struct sockaddr_in *sin, struct sockaddr_in *if_sin); 192 static int udp_output (struct inpcb *, struct mbuf *, struct sockaddr *, 193 struct thread *, int, boolean_t); 194 195 void 196 udp_init(void) 197 { 198 int cpu; 199 200 in_pcbinfo_init(&udbinfo); 201 in_pcbportinfo_init(&udbportinfo, UDBHASHSIZE, FALSE, 0); 202 203 udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); 204 udbinfo.portinfo = &udbportinfo; 205 udbinfo.wildcardhashbase = hashinit(UDBHASHSIZE, M_PCB, 206 &udbinfo.wildcardhashmask); 207 udbinfo.localgrphashbase = hashinit(UDBHASHSIZE, M_PCB, 208 &udbinfo.localgrphashmask); 209 udbinfo.ipi_size = sizeof(struct inpcb); 210 211 udbinfo_br = netisr_barrier_create(); 212 213 /* 214 * Initialize UDP statistics counters for each CPU. 215 */ 216 for (cpu = 0; cpu < ncpus; ++cpu) 217 bzero(&udpstat_percpu[cpu], sizeof(struct udpstat)); 218 } 219 220 static int 221 sysctl_udpstat(SYSCTL_HANDLER_ARGS) 222 { 223 int cpu, error = 0; 224 225 for (cpu = 0; cpu < ncpus; ++cpu) { 226 if ((error = SYSCTL_OUT(req, &udpstat_percpu[cpu], 227 sizeof(struct udpstat)))) 228 break; 229 if ((error = SYSCTL_IN(req, &udpstat_percpu[cpu], 230 sizeof(struct udpstat)))) 231 break; 232 } 233 234 return (error); 235 } 236 SYSCTL_PROC(_net_inet_udp, UDPCTL_STATS, stats, (CTLTYPE_OPAQUE | CTLFLAG_RW), 237 0, 0, sysctl_udpstat, "S,udpstat", "UDP statistics"); 238 239 /* 240 * Check multicast packets to make sure they are only sent to sockets with 241 * multicast memberships for the packet's destination address and arrival 242 * interface. Multicast packets to multicast-unaware sockets are also 243 * disallowed. 244 * 245 * Returns 0 if the packet is acceptable, -1 if it is not. 246 */ 247 static __inline int 248 check_multicast_membership(struct ip *ip, struct inpcb *inp, struct mbuf *m) 249 { 250 int mshipno; 251 struct ip_moptions *mopt; 252 253 if (strict_mcast_mship == 0 || 254 !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 255 return (0); 256 } 257 mopt = inp->inp_moptions; 258 if (mopt == NULL) 259 return (-1); 260 for (mshipno = 0; mshipno < mopt->imo_num_memberships; ++mshipno) { 261 struct in_multi *maddr = mopt->imo_membership[mshipno]; 262 263 if (ip->ip_dst.s_addr == maddr->inm_addr.s_addr && 264 m->m_pkthdr.rcvif == maddr->inm_ifp) { 265 return (0); 266 } 267 } 268 return (-1); 269 } 270 271 int 272 udp_input(struct mbuf **mp, int *offp, int proto) 273 { 274 struct sockaddr_in udp_in = { sizeof udp_in, AF_INET }; 275 #ifdef INET6 276 struct udp_in6 udp_in6 = { 277 { sizeof udp_in6.uin6_sin, AF_INET6 }, 0 278 }; 279 struct udp_ip6 udp_ip6; 280 #endif 281 282 int iphlen; 283 struct ip *ip; 284 struct udphdr *uh; 285 struct inpcb *inp; 286 struct mbuf *m; 287 struct mbuf *opts = NULL; 288 int len, off; 289 struct ip save_ip; 290 struct sockaddr *append_sa; 291 292 off = *offp; 293 m = *mp; 294 *mp = NULL; 295 296 iphlen = off; 297 udp_stat.udps_ipackets++; 298 299 /* 300 * Strip IP options, if any; should skip this, 301 * make available to user, and use on returned packets, 302 * but we don't yet have a way to check the checksum 303 * with options still present. 304 */ 305 if (iphlen > sizeof(struct ip)) { 306 ip_stripoptions(m); 307 iphlen = sizeof(struct ip); 308 } 309 310 /* 311 * IP and UDP headers are together in first mbuf. 312 * Already checked and pulled up in ip_demux(). 313 */ 314 KASSERT(m->m_len >= iphlen + sizeof(struct udphdr), 315 ("UDP header not in one mbuf")); 316 317 ip = mtod(m, struct ip *); 318 uh = (struct udphdr *)((caddr_t)ip + iphlen); 319 320 /* destination port of 0 is illegal, based on RFC768. */ 321 if (uh->uh_dport == 0) 322 goto bad; 323 324 /* 325 * Make mbuf data length reflect UDP length. 326 * If not enough data to reflect UDP length, drop. 327 */ 328 len = ntohs((u_short)uh->uh_ulen); 329 if (ip->ip_len != len) { 330 if (len > ip->ip_len || len < sizeof(struct udphdr)) { 331 udp_stat.udps_badlen++; 332 goto bad; 333 } 334 m_adj(m, len - ip->ip_len); 335 /* ip->ip_len = len; */ 336 } 337 /* 338 * Save a copy of the IP header in case we want restore it 339 * for sending an ICMP error message in response. 340 */ 341 save_ip = *ip; 342 343 /* 344 * Checksum extended UDP header and data. 345 */ 346 if (uh->uh_sum) { 347 if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 348 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 349 uh->uh_sum = m->m_pkthdr.csum_data; 350 else 351 uh->uh_sum = in_pseudo(ip->ip_src.s_addr, 352 ip->ip_dst.s_addr, htonl((u_short)len + 353 m->m_pkthdr.csum_data + IPPROTO_UDP)); 354 uh->uh_sum ^= 0xffff; 355 } else { 356 char b[9]; 357 358 bcopy(((struct ipovly *)ip)->ih_x1, b, 9); 359 bzero(((struct ipovly *)ip)->ih_x1, 9); 360 ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 361 uh->uh_sum = in_cksum(m, len + sizeof(struct ip)); 362 bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); 363 } 364 if (uh->uh_sum) { 365 udp_stat.udps_badsum++; 366 m_freem(m); 367 return(IPPROTO_DONE); 368 } 369 } else 370 udp_stat.udps_nosum++; 371 372 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 373 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 374 struct inpcb *last; 375 376 /* 377 * Deliver a multicast or broadcast datagram to *all* sockets 378 * for which the local and remote addresses and ports match 379 * those of the incoming datagram. This allows more than 380 * one process to receive multi/broadcasts on the same port. 381 * (This really ought to be done for unicast datagrams as 382 * well, but that would cause problems with existing 383 * applications that open both address-specific sockets and 384 * a wildcard socket listening to the same port -- they would 385 * end up receiving duplicates of every unicast datagram. 386 * Those applications open the multiple sockets to overcome an 387 * inadequacy of the UDP socket interface, but for backwards 388 * compatibility we avoid the problem here rather than 389 * fixing the interface. Maybe 4.5BSD will remedy this?) 390 */ 391 392 /* 393 * Construct sockaddr format source address. 394 */ 395 udp_in.sin_port = uh->uh_sport; 396 udp_in.sin_addr = ip->ip_src; 397 /* 398 * Locate pcb(s) for datagram. 399 * (Algorithm copied from raw_intr().) 400 */ 401 last = NULL; 402 #ifdef INET6 403 udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0; 404 #endif 405 LIST_FOREACH(inp, &udbinfo.pcblisthead, inp_list) { 406 KKASSERT((inp->inp_flags & INP_PLACEMARKER) == 0); 407 #ifdef INET6 408 if (!(inp->inp_vflag & INP_IPV4)) 409 continue; 410 #endif 411 if (inp->inp_lport != uh->uh_dport) 412 continue; 413 if (inp->inp_laddr.s_addr != INADDR_ANY) { 414 if (inp->inp_laddr.s_addr != 415 ip->ip_dst.s_addr) 416 continue; 417 } 418 if (inp->inp_faddr.s_addr != INADDR_ANY) { 419 if (inp->inp_faddr.s_addr != 420 ip->ip_src.s_addr || 421 inp->inp_fport != uh->uh_sport) 422 continue; 423 } 424 425 if (check_multicast_membership(ip, inp, m) < 0) 426 continue; 427 428 if (last != NULL) { 429 struct mbuf *n; 430 431 #ifdef IPSEC 432 /* check AH/ESP integrity. */ 433 if (ipsec4_in_reject_so(m, last->inp_socket)) 434 ipsecstat.in_polvio++; 435 /* do not inject data to pcb */ 436 else 437 #endif /*IPSEC*/ 438 #ifdef FAST_IPSEC 439 /* check AH/ESP integrity. */ 440 if (ipsec4_in_reject(m, last)) 441 ; 442 else 443 #endif /*FAST_IPSEC*/ 444 if ((n = m_copypacket(m, MB_DONTWAIT)) != NULL) 445 udp_append(last, ip, n, 446 iphlen + sizeof(struct udphdr), 447 &udp_in, 448 #ifdef INET6 449 &udp_in6, &udp_ip6 450 #else 451 NULL, NULL 452 #endif 453 ); 454 } 455 last = inp; 456 /* 457 * Don't look for additional matches if this one does 458 * not have either the SO_REUSEPORT or SO_REUSEADDR 459 * socket options set. This heuristic avoids searching 460 * through all pcbs in the common case of a non-shared 461 * port. It * assumes that an application will never 462 * clear these options after setting them. 463 */ 464 if (!(last->inp_socket->so_options & 465 (SO_REUSEPORT | SO_REUSEADDR))) 466 break; 467 } 468 469 if (last == NULL) { 470 /* 471 * No matching pcb found; discard datagram. 472 * (No need to send an ICMP Port Unreachable 473 * for a broadcast or multicast datgram.) 474 */ 475 udp_stat.udps_noportbcast++; 476 goto bad; 477 } 478 #ifdef IPSEC 479 /* check AH/ESP integrity. */ 480 if (ipsec4_in_reject_so(m, last->inp_socket)) { 481 ipsecstat.in_polvio++; 482 goto bad; 483 } 484 #endif /*IPSEC*/ 485 #ifdef FAST_IPSEC 486 /* check AH/ESP integrity. */ 487 if (ipsec4_in_reject(m, last)) 488 goto bad; 489 #endif /*FAST_IPSEC*/ 490 udp_append(last, ip, m, iphlen + sizeof(struct udphdr), 491 &udp_in, 492 #ifdef INET6 493 &udp_in6, &udp_ip6 494 #else 495 NULL, NULL 496 #endif 497 ); 498 return(IPPROTO_DONE); 499 } 500 /* 501 * Locate pcb for datagram. 502 */ 503 inp = in_pcblookup_pkthash(&udbinfo, ip->ip_src, uh->uh_sport, 504 ip->ip_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif, 505 udp_reuseport_ext ? m : NULL); 506 if (inp == NULL) { 507 if (log_in_vain) { 508 char buf[sizeof "aaa.bbb.ccc.ddd"]; 509 510 strcpy(buf, inet_ntoa(ip->ip_dst)); 511 log(LOG_INFO, 512 "Connection attempt to UDP %s:%d from %s:%d\n", 513 buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), 514 ntohs(uh->uh_sport)); 515 } 516 udp_stat.udps_noport++; 517 if (m->m_flags & (M_BCAST | M_MCAST)) { 518 udp_stat.udps_noportbcast++; 519 goto bad; 520 } 521 if (blackhole) 522 goto bad; 523 #ifdef ICMP_BANDLIM 524 if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0) 525 goto bad; 526 #endif 527 *ip = save_ip; 528 ip->ip_len += iphlen; 529 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 530 return(IPPROTO_DONE); 531 } 532 #ifdef IPSEC 533 if (ipsec4_in_reject_so(m, inp->inp_socket)) { 534 ipsecstat.in_polvio++; 535 goto bad; 536 } 537 #endif /*IPSEC*/ 538 #ifdef FAST_IPSEC 539 if (ipsec4_in_reject(m, inp)) 540 goto bad; 541 #endif /*FAST_IPSEC*/ 542 /* 543 * Check the minimum TTL for socket. 544 */ 545 if (ip->ip_ttl < inp->inp_ip_minttl) 546 goto bad; 547 548 /* 549 * Construct sockaddr format source address. 550 * Stuff source address and datagram in user buffer. 551 */ 552 udp_in.sin_port = uh->uh_sport; 553 udp_in.sin_addr = ip->ip_src; 554 if ((inp->inp_flags & INP_CONTROLOPTS) || 555 (inp->inp_socket->so_options & SO_TIMESTAMP)) { 556 #ifdef INET6 557 if (inp->inp_vflag & INP_IPV6) { 558 int savedflags; 559 560 ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip); 561 savedflags = inp->inp_flags; 562 inp->inp_flags &= ~INP_UNMAPPABLEOPTS; 563 ip6_savecontrol(inp, &opts, &udp_ip6.uip6_ip6, m); 564 inp->inp_flags = savedflags; 565 } else 566 #endif 567 ip_savecontrol(inp, &opts, ip, m); 568 } 569 m_adj(m, iphlen + sizeof(struct udphdr)); 570 #ifdef INET6 571 if (inp->inp_vflag & INP_IPV6) { 572 in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); 573 append_sa = (struct sockaddr *)&udp_in6; 574 } else 575 #endif 576 append_sa = (struct sockaddr *)&udp_in; 577 578 lwkt_gettoken(&inp->inp_socket->so_rcv.ssb_token); 579 if (ssb_appendaddr(&inp->inp_socket->so_rcv, append_sa, m, opts) == 0) { 580 udp_stat.udps_fullsock++; 581 lwkt_reltoken(&inp->inp_socket->so_rcv.ssb_token); 582 goto bad; 583 } 584 lwkt_reltoken(&inp->inp_socket->so_rcv.ssb_token); 585 sorwakeup(inp->inp_socket); 586 return(IPPROTO_DONE); 587 bad: 588 m_freem(m); 589 if (opts) 590 m_freem(opts); 591 return(IPPROTO_DONE); 592 } 593 594 #ifdef INET6 595 static void 596 ip_2_ip6_hdr(struct ip6_hdr *ip6, struct ip *ip) 597 { 598 bzero(ip6, sizeof *ip6); 599 600 ip6->ip6_vfc = IPV6_VERSION; 601 ip6->ip6_plen = ip->ip_len; 602 ip6->ip6_nxt = ip->ip_p; 603 ip6->ip6_hlim = ip->ip_ttl; 604 ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] = 605 IPV6_ADDR_INT32_SMP; 606 ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr; 607 ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr; 608 } 609 #endif 610 611 /* 612 * subroutine of udp_input(), mainly for source code readability. 613 * caller must properly init udp_ip6 and udp_in6 beforehand. 614 */ 615 static void 616 udp_append(struct inpcb *last, struct ip *ip, struct mbuf *n, int off, 617 struct sockaddr_in *udp_in, 618 struct udp_in6 *udp_in6, struct udp_ip6 *udp_ip6) 619 { 620 struct sockaddr *append_sa; 621 struct mbuf *opts = NULL; 622 623 if (last->inp_flags & INP_CONTROLOPTS || 624 last->inp_socket->so_options & SO_TIMESTAMP) { 625 #ifdef INET6 626 if (last->inp_vflag & INP_IPV6) { 627 int savedflags; 628 629 if (udp_ip6->uip6_init_done == 0) { 630 ip_2_ip6_hdr(&udp_ip6->uip6_ip6, ip); 631 udp_ip6->uip6_init_done = 1; 632 } 633 savedflags = last->inp_flags; 634 last->inp_flags &= ~INP_UNMAPPABLEOPTS; 635 ip6_savecontrol(last, &opts, &udp_ip6->uip6_ip6, n); 636 last->inp_flags = savedflags; 637 } else 638 #endif 639 ip_savecontrol(last, &opts, ip, n); 640 } 641 #ifdef INET6 642 if (last->inp_vflag & INP_IPV6) { 643 if (udp_in6->uin6_init_done == 0) { 644 in6_sin_2_v4mapsin6(udp_in, &udp_in6->uin6_sin); 645 udp_in6->uin6_init_done = 1; 646 } 647 append_sa = (struct sockaddr *)&udp_in6->uin6_sin; 648 } else 649 #endif 650 append_sa = (struct sockaddr *)udp_in; 651 m_adj(n, off); 652 lwkt_gettoken(&last->inp_socket->so_rcv.ssb_token); 653 if (ssb_appendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) { 654 m_freem(n); 655 if (opts) 656 m_freem(opts); 657 udp_stat.udps_fullsock++; 658 } else { 659 sorwakeup(last->inp_socket); 660 } 661 lwkt_reltoken(&last->inp_socket->so_rcv.ssb_token); 662 } 663 664 /* 665 * Notify a udp user of an asynchronous error; 666 * just wake up so that he can collect error status. 667 */ 668 void 669 udp_notify(struct inpcb *inp, int error) 670 { 671 inp->inp_socket->so_error = error; 672 sorwakeup(inp->inp_socket); 673 sowwakeup(inp->inp_socket); 674 } 675 676 struct netmsg_udp_notify { 677 struct netmsg_base base; 678 void (*nm_notify)(struct inpcb *, int); 679 struct in_addr nm_faddr; 680 int nm_arg; 681 }; 682 683 static void 684 udp_notifyall_oncpu(netmsg_t msg) 685 { 686 struct netmsg_udp_notify *nm = (struct netmsg_udp_notify *)msg; 687 #if 0 688 int nextcpu; 689 #endif 690 691 in_pcbnotifyall(&udbinfo.pcblisthead, nm->nm_faddr, 692 nm->nm_arg, nm->nm_notify); 693 lwkt_replymsg(&nm->base.lmsg, 0); 694 695 #if 0 696 /* XXX currently udp only runs on cpu 0 */ 697 nextcpu = mycpuid + 1; 698 if (nextcpu < ncpus2) 699 lwkt_forwardmsg(netisr_cpuport(nextcpu), &nm->base.lmsg); 700 else 701 lwkt_replymsg(&nmsg->base.lmsg, 0); 702 #endif 703 } 704 705 static void 706 udp_rtchange(struct inpcb *inp, int err) 707 { 708 /* XXX Nuke this, once UDP inpcbs are CPU localized */ 709 if (inp->inp_route.ro_rt && inp->inp_route.ro_rt->rt_cpuid == mycpuid) { 710 rtfree(inp->inp_route.ro_rt); 711 inp->inp_route.ro_rt = NULL; 712 /* 713 * A new route can be allocated the next time 714 * output is attempted. 715 */ 716 } 717 } 718 719 void 720 udp_ctlinput(netmsg_t msg) 721 { 722 struct sockaddr *sa = msg->ctlinput.nm_arg; 723 struct ip *ip = msg->ctlinput.nm_extra; 724 int cmd = msg->ctlinput.nm_cmd; 725 struct udphdr *uh; 726 void (*notify) (struct inpcb *, int) = udp_notify; 727 struct in_addr faddr; 728 struct inpcb *inp; 729 730 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 731 732 faddr = ((struct sockaddr_in *)sa)->sin_addr; 733 if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) 734 goto done; 735 736 if (PRC_IS_REDIRECT(cmd)) { 737 ip = NULL; 738 notify = udp_rtchange; 739 } else if (cmd == PRC_HOSTDEAD) { 740 ip = NULL; 741 } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 742 goto done; 743 } 744 745 if (ip) { 746 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 747 inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport, 748 ip->ip_src, uh->uh_sport, 0, NULL); 749 if (inp != NULL && inp->inp_socket != NULL) 750 (*notify)(inp, inetctlerrmap[cmd]); 751 } else if (PRC_IS_REDIRECT(cmd)) { 752 struct netmsg_udp_notify *nm; 753 754 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 755 nm = kmalloc(sizeof(*nm), M_LWKTMSG, M_INTWAIT); 756 netmsg_init(&nm->base, NULL, &netisr_afree_rport, 757 0, udp_notifyall_oncpu); 758 nm->nm_faddr = faddr; 759 nm->nm_arg = inetctlerrmap[cmd]; 760 nm->nm_notify = notify; 761 lwkt_sendmsg(netisr_cpuport(0), &nm->base.lmsg); 762 } else { 763 /* 764 * XXX We should forward msg upon PRC_HOSTHEAD and ip == NULL, 765 * once UDP inpcbs are CPU localized 766 */ 767 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 768 in_pcbnotifyall(&udbinfo.pcblisthead, faddr, inetctlerrmap[cmd], 769 notify); 770 } 771 done: 772 lwkt_replymsg(&msg->lmsg, 0); 773 } 774 775 static int 776 udp_pcblist(SYSCTL_HANDLER_ARGS) 777 { 778 struct xinpcb *xi; 779 int error, nxi, i; 780 781 udbinfo_lock(); 782 error = in_pcblist_global_nomarker(oidp, arg1, arg2, req, &xi, &nxi); 783 udbinfo_unlock(); 784 785 if (error) { 786 KKASSERT(xi == NULL); 787 return error; 788 } 789 if (nxi == 0) { 790 KKASSERT(xi == NULL); 791 return 0; 792 } 793 794 for (i = 0; i < nxi; ++i) { 795 error = SYSCTL_OUT(req, &xi[i], sizeof(xi[i])); 796 if (error) 797 break; 798 } 799 kfree(xi, M_TEMP); 800 801 return error; 802 } 803 SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, &udbinfo, 0, 804 udp_pcblist, "S,xinpcb", "List of active UDP sockets"); 805 806 static int 807 udp_getcred(SYSCTL_HANDLER_ARGS) 808 { 809 struct sockaddr_in addrs[2]; 810 struct ucred cred0, *cred = NULL; 811 struct inpcb *inp; 812 int error; 813 814 error = priv_check(req->td, PRIV_ROOT); 815 if (error) 816 return (error); 817 error = SYSCTL_IN(req, addrs, sizeof addrs); 818 if (error) 819 return (error); 820 821 udbinfo_lock(); 822 inp = in_pcblookup_hash(&udbinfo, addrs[1].sin_addr, addrs[1].sin_port, 823 addrs[0].sin_addr, addrs[0].sin_port, 1, NULL); 824 if (inp == NULL || inp->inp_socket == NULL) { 825 error = ENOENT; 826 } else { 827 if (inp->inp_socket->so_cred != NULL) { 828 cred0 = *(inp->inp_socket->so_cred); 829 cred = &cred0; 830 } 831 } 832 udbinfo_unlock(); 833 834 if (error) 835 return error; 836 837 return SYSCTL_OUT(req, cred, sizeof(struct ucred)); 838 } 839 840 SYSCTL_PROC(_net_inet_udp, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 841 0, 0, udp_getcred, "S,ucred", "Get the ucred of a UDP connection"); 842 843 static int 844 udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *dstaddr, 845 struct thread *td, int flags, boolean_t held_td) 846 { 847 struct udpiphdr *ui; 848 int len = m->m_pkthdr.len; 849 struct sockaddr_in *sin; /* really is initialized before use */ 850 int error = 0, lport_any = 0; 851 852 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { 853 error = EMSGSIZE; 854 goto release; 855 } 856 857 if (inp->inp_lport == 0) { /* unbound socket */ 858 error = in_pcbbind(inp, NULL, td); 859 if (error) 860 goto release; 861 862 udbinfo_barrier_set(); 863 in_pcbinswildcardhash(inp); 864 udbinfo_barrier_rem(); 865 lport_any = 1; 866 } 867 868 if (dstaddr != NULL) { /* destination address specified */ 869 if (inp->inp_faddr.s_addr != INADDR_ANY) { 870 /* already connected */ 871 error = EISCONN; 872 goto release; 873 } 874 sin = (struct sockaddr_in *)dstaddr; 875 if (!prison_remote_ip(td, (struct sockaddr *)&sin)) { 876 error = EAFNOSUPPORT; /* IPv6 only jail */ 877 goto release; 878 } 879 } else { 880 if (inp->inp_faddr.s_addr == INADDR_ANY) { 881 /* no destination specified and not already connected */ 882 error = ENOTCONN; 883 goto release; 884 } 885 sin = NULL; 886 } 887 888 /* 889 * Calculate data length and get a mbuf 890 * for UDP and IP headers. 891 */ 892 M_PREPEND(m, sizeof(struct udpiphdr), MB_DONTWAIT); 893 if (m == NULL) { 894 error = ENOBUFS; 895 goto release; 896 } 897 898 /* 899 * Fill in mbuf with extended UDP header 900 * and addresses and length put into network format. 901 */ 902 ui = mtod(m, struct udpiphdr *); 903 bzero(ui->ui_x1, sizeof ui->ui_x1); /* XXX still needed? */ 904 ui->ui_pr = IPPROTO_UDP; 905 906 /* 907 * Set destination address. 908 */ 909 if (dstaddr != NULL) { /* use specified destination */ 910 ui->ui_dst = sin->sin_addr; 911 ui->ui_dport = sin->sin_port; 912 } else { /* use connected destination */ 913 ui->ui_dst = inp->inp_faddr; 914 ui->ui_dport = inp->inp_fport; 915 } 916 917 /* 918 * Set source address. 919 */ 920 if (inp->inp_laddr.s_addr == INADDR_ANY || 921 IN_MULTICAST(ntohl(inp->inp_laddr.s_addr))) { 922 struct sockaddr_in *if_sin; 923 924 if (dstaddr == NULL) { 925 /* 926 * connect() had (or should have) failed because 927 * the interface had no IP address, but the 928 * application proceeded to call send() anyways. 929 */ 930 error = ENOTCONN; 931 goto release; 932 } 933 934 /* Look up outgoing interface. */ 935 error = in_pcbladdr_find(inp, dstaddr, &if_sin, td, 1); 936 if (error) 937 goto release; 938 ui->ui_src = if_sin->sin_addr; /* use address of interface */ 939 } else { 940 ui->ui_src = inp->inp_laddr; /* use non-null bound address */ 941 } 942 ui->ui_sport = inp->inp_lport; 943 KASSERT(inp->inp_lport != 0, ("inp lport should have been bound")); 944 945 /* 946 * Release the original thread, since it is no longer used 947 */ 948 if (held_td) { 949 lwkt_rele(td); 950 held_td = FALSE; 951 } 952 953 ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr)); 954 955 /* 956 * Set up checksum and output datagram. 957 */ 958 if (udpcksum) { 959 ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr, 960 htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP)); 961 m->m_pkthdr.csum_flags = CSUM_UDP; 962 m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); 963 m->m_pkthdr.csum_thlen = sizeof(struct udphdr); 964 } else { 965 ui->ui_sum = 0; 966 } 967 ((struct ip *)ui)->ip_len = sizeof(struct udpiphdr) + len; 968 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ 969 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ 970 udp_stat.udps_opackets++; 971 972 error = ip_output(m, inp->inp_options, &inp->inp_route, 973 (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)) | 974 flags | IP_DEBUGROUTE, 975 inp->inp_moptions, inp); 976 977 /* 978 * If this is the first data gram sent on an unbound and unconnected 979 * UDP socket, lport will be changed in this function. If target 980 * CPU after this lport changing is no longer the current CPU, then 981 * free the route entry allocated on the current CPU. 982 */ 983 if (lport_any) { 984 if (udp_addrcpu(inp->inp_faddr.s_addr, inp->inp_fport, 985 inp->inp_laddr.s_addr, inp->inp_lport) != mycpuid) { 986 #ifdef notyet 987 struct route *ro = &inp->inp_route; 988 989 if (ro->ro_rt != NULL) 990 RTFREE(ro->ro_rt); 991 bzero(ro, sizeof(*ro)); 992 #else 993 panic("UDP activity should only be in netisr0"); 994 #endif 995 } 996 } 997 return (error); 998 999 release: 1000 if (held_td) 1001 lwkt_rele(td); 1002 m_freem(m); 1003 return (error); 1004 } 1005 1006 u_long udp_sendspace = 9216; /* really max datagram size */ 1007 /* 40 1K datagrams */ 1008 SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, 1009 &udp_sendspace, 0, "Maximum outgoing UDP datagram size"); 1010 1011 u_long udp_recvspace = 40 * (1024 + 1012 #ifdef INET6 1013 sizeof(struct sockaddr_in6) 1014 #else 1015 sizeof(struct sockaddr_in) 1016 #endif 1017 ); 1018 SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, 1019 &udp_recvspace, 0, "Maximum incoming UDP datagram size"); 1020 1021 /* 1022 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 1023 * will sofree() it when we return. 1024 */ 1025 static void 1026 udp_abort(netmsg_t msg) 1027 { 1028 struct socket *so = msg->abort.base.nm_so; 1029 struct inpcb *inp; 1030 int error; 1031 1032 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1033 1034 inp = so->so_pcb; 1035 if (inp) { 1036 soisdisconnected(so); 1037 1038 udbinfo_barrier_set(); 1039 in_pcbdetach(inp); 1040 udbinfo_barrier_rem(); 1041 error = 0; 1042 } else { 1043 error = EINVAL; 1044 } 1045 lwkt_replymsg(&msg->abort.base.lmsg, error); 1046 } 1047 1048 static void 1049 udp_attach(netmsg_t msg) 1050 { 1051 struct socket *so = msg->attach.base.nm_so; 1052 struct pru_attach_info *ai = msg->attach.nm_ai; 1053 struct inpcb *inp; 1054 int error; 1055 1056 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1057 1058 inp = so->so_pcb; 1059 if (inp != NULL) { 1060 error = EINVAL; 1061 goto out; 1062 } 1063 error = soreserve(so, udp_sendspace, udp_recvspace, ai->sb_rlimit); 1064 if (error) 1065 goto out; 1066 1067 udbinfo_barrier_set(); 1068 error = in_pcballoc(so, &udbinfo); 1069 udbinfo_barrier_rem(); 1070 1071 if (error) 1072 goto out; 1073 1074 /* 1075 * Set default port for protocol processing prior to bind/connect. 1076 */ 1077 sosetport(so, netisr_cpuport(0)); 1078 1079 inp = (struct inpcb *)so->so_pcb; 1080 inp->inp_vflag |= INP_IPV4; 1081 inp->inp_ip_ttl = ip_defttl; 1082 error = 0; 1083 out: 1084 lwkt_replymsg(&msg->attach.base.lmsg, error); 1085 } 1086 1087 static void 1088 udp_bind(netmsg_t msg) 1089 { 1090 struct socket *so = msg->bind.base.nm_so; 1091 struct sockaddr *nam = msg->bind.nm_nam; 1092 struct thread *td = msg->bind.nm_td; 1093 struct sockaddr_in *sin = (struct sockaddr_in *)nam; 1094 struct inpcb *inp; 1095 int error; 1096 1097 inp = so->so_pcb; 1098 if (inp) { 1099 error = in_pcbbind(inp, nam, td); 1100 if (error == 0) { 1101 if (sin->sin_addr.s_addr != INADDR_ANY) 1102 inp->inp_flags |= INP_WASBOUND_NOTANY; 1103 1104 udbinfo_barrier_set(); 1105 in_pcbinswildcardhash(inp); 1106 udbinfo_barrier_rem(); 1107 } 1108 } else { 1109 error = EINVAL; 1110 } 1111 lwkt_replymsg(&msg->bind.base.lmsg, error); 1112 } 1113 1114 static void 1115 udp_connect(netmsg_t msg) 1116 { 1117 struct socket *so = msg->connect.base.nm_so; 1118 struct sockaddr *nam = msg->connect.nm_nam; 1119 struct thread *td = msg->connect.nm_td; 1120 struct inpcb *inp; 1121 struct sockaddr_in *sin = (struct sockaddr_in *)nam; 1122 struct sockaddr_in *if_sin; 1123 lwkt_port_t port; 1124 int error; 1125 1126 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1127 1128 inp = so->so_pcb; 1129 if (inp == NULL) { 1130 error = EINVAL; 1131 goto out; 1132 } 1133 1134 if (msg->connect.nm_flags & PRUC_RECONNECT) { 1135 panic("UDP does not support RECONNECT"); 1136 #ifdef notyet 1137 msg->connect.nm_flags &= ~PRUC_RECONNECT; 1138 in_pcblink(inp, &udbinfo); 1139 #endif 1140 } 1141 1142 if (inp->inp_faddr.s_addr != INADDR_ANY) { 1143 error = EISCONN; 1144 goto out; 1145 } 1146 error = 0; 1147 1148 /* 1149 * Bind if we have to 1150 */ 1151 if (td->td_proc && td->td_proc->p_ucred->cr_prison != NULL && 1152 inp->inp_laddr.s_addr == INADDR_ANY) { 1153 error = in_pcbbind(inp, NULL, td); 1154 if (error) 1155 goto out; 1156 } 1157 1158 /* 1159 * Calculate the correct protocol processing thread. The connect 1160 * operation must run there. 1161 */ 1162 error = in_pcbladdr(inp, nam, &if_sin, td); 1163 if (error) 1164 goto out; 1165 if (!prison_remote_ip(td, nam)) { 1166 error = EAFNOSUPPORT; /* IPv6 only jail */ 1167 goto out; 1168 } 1169 1170 port = udp_addrport(sin->sin_addr.s_addr, sin->sin_port, 1171 inp->inp_laddr.s_addr, inp->inp_lport); 1172 if (port != &curthread->td_msgport) { 1173 #ifdef notyet 1174 struct route *ro = &inp->inp_route; 1175 1176 /* 1177 * in_pcbladdr() may have allocated a route entry for us 1178 * on the current CPU, but we need a route entry on the 1179 * inpcb's owner CPU, so free it here. 1180 */ 1181 if (ro->ro_rt != NULL) 1182 RTFREE(ro->ro_rt); 1183 bzero(ro, sizeof(*ro)); 1184 1185 /* 1186 * We are moving the protocol processing port the socket 1187 * is on, we have to unlink here and re-link on the 1188 * target cpu. 1189 */ 1190 in_pcbunlink(so->so_pcb, &udbinfo); 1191 /* in_pcbunlink(so->so_pcb, &udbinfo[mycpu->gd_cpuid]); */ 1192 sosetport(so, port); 1193 msg->connect.nm_flags |= PRUC_RECONNECT; 1194 msg->connect.base.nm_dispatch = udp_connect; 1195 1196 lwkt_forwardmsg(port, &msg->connect.base.lmsg); 1197 /* msg invalid now */ 1198 return; 1199 #else 1200 panic("UDP activity should only be in netisr0"); 1201 #endif 1202 } 1203 KKASSERT(port == &curthread->td_msgport); 1204 error = udp_connect_oncpu(so, td, sin, if_sin); 1205 out: 1206 KKASSERT(msg->connect.nm_m == NULL); 1207 lwkt_replymsg(&msg->connect.base.lmsg, error); 1208 } 1209 1210 static int 1211 udp_connect_oncpu(struct socket *so, struct thread *td, 1212 struct sockaddr_in *sin, struct sockaddr_in *if_sin) 1213 { 1214 struct inpcb *inp; 1215 int error; 1216 1217 udbinfo_barrier_set(); 1218 1219 inp = so->so_pcb; 1220 if (inp->inp_flags & INP_WILDCARD) 1221 in_pcbremwildcardhash(inp); 1222 error = in_pcbconnect(inp, (struct sockaddr *)sin, td); 1223 1224 if (error == 0) { 1225 /* 1226 * No more errors can occur, finish adjusting the socket 1227 * and change the processing port to reflect the connected 1228 * socket. Once set we can no longer safely mess with the 1229 * socket. 1230 */ 1231 soisconnected(so); 1232 } else if (error == EAFNOSUPPORT) { /* connection dissolved */ 1233 /* 1234 * Follow traditional BSD behavior and retain 1235 * the local port binding. But, fix the old misbehavior 1236 * of overwriting any previously bound local address. 1237 */ 1238 if (!(inp->inp_flags & INP_WASBOUND_NOTANY)) 1239 inp->inp_laddr.s_addr = INADDR_ANY; 1240 in_pcbinswildcardhash(inp); 1241 } 1242 1243 udbinfo_barrier_rem(); 1244 return error; 1245 } 1246 1247 static void 1248 udp_detach(netmsg_t msg) 1249 { 1250 struct socket *so = msg->detach.base.nm_so; 1251 struct inpcb *inp; 1252 int error; 1253 1254 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1255 1256 inp = so->so_pcb; 1257 if (inp) { 1258 udbinfo_barrier_set(); 1259 in_pcbdetach(inp); 1260 udbinfo_barrier_rem(); 1261 error = 0; 1262 } else { 1263 error = EINVAL; 1264 } 1265 lwkt_replymsg(&msg->detach.base.lmsg, error); 1266 } 1267 1268 static void 1269 udp_disconnect(netmsg_t msg) 1270 { 1271 struct socket *so = msg->disconnect.base.nm_so; 1272 struct route *ro; 1273 struct inpcb *inp; 1274 int error; 1275 1276 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1277 1278 inp = so->so_pcb; 1279 if (inp == NULL) { 1280 error = EINVAL; 1281 goto out; 1282 } 1283 if (inp->inp_faddr.s_addr == INADDR_ANY) { 1284 error = ENOTCONN; 1285 goto out; 1286 } 1287 1288 soreference(so); 1289 1290 udbinfo_barrier_set(); 1291 in_pcbdisconnect(inp); 1292 udbinfo_barrier_rem(); 1293 1294 soclrstate(so, SS_ISCONNECTED); /* XXX */ 1295 sofree(so); 1296 1297 ro = &inp->inp_route; 1298 if (ro->ro_rt != NULL) 1299 RTFREE(ro->ro_rt); 1300 bzero(ro, sizeof(*ro)); 1301 error = 0; 1302 out: 1303 lwkt_replymsg(&msg->disconnect.base.lmsg, error); 1304 } 1305 1306 static void 1307 udp_send(netmsg_t msg) 1308 { 1309 struct socket *so = msg->send.base.nm_so; 1310 struct mbuf *m = msg->send.nm_m; 1311 struct sockaddr *addr = msg->send.nm_addr; 1312 int pru_flags = msg->send.nm_flags; 1313 struct inpcb *inp; 1314 int error; 1315 1316 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1317 KKASSERT(msg->send.nm_control == NULL); 1318 1319 inp = so->so_pcb; 1320 if (inp) { 1321 struct thread *td = msg->send.nm_td; 1322 int flags = 0; 1323 1324 if (pru_flags & PRUS_DONTROUTE) 1325 flags |= SO_DONTROUTE; 1326 error = udp_output(inp, m, addr, td, flags, 1327 (pru_flags & PRUS_HELDTD) ? TRUE : FALSE); 1328 } else { 1329 if (pru_flags & PRUS_HELDTD) 1330 lwkt_rele(msg->send.nm_td); 1331 m_freem(m); 1332 error = EINVAL; 1333 } 1334 1335 if (pru_flags & PRUS_FREEADDR) 1336 kfree(addr, M_SONAME); 1337 1338 if ((pru_flags & PRUS_NOREPLY) == 0) 1339 lwkt_replymsg(&msg->send.base.lmsg, error); 1340 } 1341 1342 void 1343 udp_shutdown(netmsg_t msg) 1344 { 1345 struct socket *so = msg->shutdown.base.nm_so; 1346 struct inpcb *inp; 1347 int error; 1348 1349 KKASSERT(&curthread->td_msgport == netisr_cpuport(0)); 1350 1351 inp = so->so_pcb; 1352 if (inp) { 1353 socantsendmore(so); 1354 error = 0; 1355 } else { 1356 error = EINVAL; 1357 } 1358 lwkt_replymsg(&msg->shutdown.base.lmsg, error); 1359 } 1360 1361 void 1362 udbinfo_lock(void) 1363 { 1364 lwkt_serialize_enter(&udbinfo_slize); 1365 } 1366 1367 void 1368 udbinfo_unlock(void) 1369 { 1370 lwkt_serialize_exit(&udbinfo_slize); 1371 } 1372 1373 void 1374 udbinfo_barrier_set(void) 1375 { 1376 netisr_barrier_set(udbinfo_br); 1377 udbinfo_lock(); 1378 } 1379 1380 void 1381 udbinfo_barrier_rem(void) 1382 { 1383 udbinfo_unlock(); 1384 netisr_barrier_rem(udbinfo_br); 1385 } 1386 1387 struct pr_usrreqs udp_usrreqs = { 1388 .pru_abort = udp_abort, 1389 .pru_accept = pr_generic_notsupp, 1390 .pru_attach = udp_attach, 1391 .pru_bind = udp_bind, 1392 .pru_connect = udp_connect, 1393 .pru_connect2 = pr_generic_notsupp, 1394 .pru_control = in_control_dispatch, 1395 .pru_detach = udp_detach, 1396 .pru_disconnect = udp_disconnect, 1397 .pru_listen = pr_generic_notsupp, 1398 .pru_peeraddr = in_setpeeraddr_dispatch, 1399 .pru_rcvd = pr_generic_notsupp, 1400 .pru_rcvoob = pr_generic_notsupp, 1401 .pru_send = udp_send, 1402 .pru_sense = pru_sense_null, 1403 .pru_shutdown = udp_shutdown, 1404 .pru_sockaddr = in_setsockaddr_dispatch, 1405 .pru_sosend = sosendudp, 1406 .pru_soreceive = soreceive 1407 }; 1408 1409