1 /* $OpenBSD: udp_usrreq.c,v 1.302 2022/09/05 14:56:09 bluhm Exp $ */ 2 /* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1988, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 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 University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 33 * 34 * NRL grants permission for redistribution and use in source and binary 35 * forms, with or without modification, of the software and documentation 36 * created at NRL provided that the following conditions are met: 37 * 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. All advertising materials mentioning features or use of this software 44 * must display the following acknowledgements: 45 * This product includes software developed by the University of 46 * California, Berkeley and its contributors. 47 * This product includes software developed at the Information 48 * Technology Division, US Naval Research Laboratory. 49 * 4. Neither the name of the NRL nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS 54 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 56 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR 57 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 58 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 59 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 60 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 61 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 62 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 63 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 64 * 65 * The views and conclusions contained in the software and documentation 66 * are those of the authors and should not be interpreted as representing 67 * official policies, either expressed or implied, of the US Naval 68 * Research Laboratory (NRL). 69 */ 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/mbuf.h> 74 #include <sys/protosw.h> 75 #include <sys/socket.h> 76 #include <sys/socketvar.h> 77 #include <sys/sysctl.h> 78 #include <sys/domain.h> 79 80 #include <net/if.h> 81 #include <net/if_var.h> 82 #include <net/if_media.h> 83 #include <net/route.h> 84 85 #include <netinet/in.h> 86 #include <netinet/in_var.h> 87 #include <netinet/ip.h> 88 #include <netinet/in_pcb.h> 89 #include <netinet/ip_var.h> 90 #include <netinet/ip_icmp.h> 91 #include <netinet/udp.h> 92 #include <netinet/udp_var.h> 93 94 #ifdef IPSEC 95 #include <netinet/ip_ipsp.h> 96 #include <netinet/ip_esp.h> 97 #endif 98 99 #ifdef INET6 100 #include <netinet6/in6_var.h> 101 #include <netinet6/ip6_var.h> 102 #include <netinet6/ip6protosw.h> 103 #endif /* INET6 */ 104 105 #include "pf.h" 106 #if NPF > 0 107 #include <net/pfvar.h> 108 #endif 109 110 #ifdef PIPEX 111 #include <netinet/if_ether.h> 112 #include <net/pipex.h> 113 #endif 114 115 /* 116 * UDP protocol implementation. 117 * Per RFC 768, August, 1980. 118 */ 119 int udpcksum = 1; 120 121 u_int udp_sendspace = 9216; /* really max datagram size */ 122 u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 123 /* 40 1K datagrams */ 124 125 const struct pr_usrreqs udp_usrreqs = { 126 .pru_attach = udp_attach, 127 .pru_detach = udp_detach, 128 .pru_lock = udp_lock, 129 .pru_unlock = udp_unlock, 130 .pru_bind = udp_bind, 131 .pru_connect = udp_connect, 132 .pru_disconnect = udp_disconnect, 133 .pru_shutdown = udp_shutdown, 134 .pru_send = udp_send, 135 .pru_abort = udp_abort, 136 .pru_control = in_control, 137 .pru_sockaddr = in_sockaddr, 138 .pru_peeraddr = in_peeraddr, 139 }; 140 141 #ifdef INET6 142 const struct pr_usrreqs udp6_usrreqs = { 143 .pru_attach = udp_attach, 144 .pru_detach = udp_detach, 145 .pru_lock = udp_lock, 146 .pru_unlock = udp_unlock, 147 .pru_bind = udp_bind, 148 .pru_connect = udp_connect, 149 .pru_disconnect = udp_disconnect, 150 .pru_shutdown = udp_shutdown, 151 .pru_send = udp_send, 152 .pru_abort = udp_abort, 153 .pru_control = in6_control, 154 .pru_sockaddr = in6_sockaddr, 155 .pru_peeraddr = in6_peeraddr, 156 }; 157 #endif 158 159 const struct sysctl_bounded_args udpctl_vars[] = { 160 { UDPCTL_CHECKSUM, &udpcksum, 0, 1 }, 161 { UDPCTL_RECVSPACE, &udp_recvspace, 0, INT_MAX }, 162 { UDPCTL_SENDSPACE, &udp_sendspace, 0, INT_MAX }, 163 }; 164 165 struct inpcbtable udbtable; 166 struct cpumem *udpcounters; 167 168 void udp_sbappend(struct inpcb *, struct mbuf *, struct ip *, 169 struct ip6_hdr *, int, struct udphdr *, struct sockaddr *, 170 u_int32_t); 171 int udp_output(struct inpcb *, struct mbuf *, struct mbuf *, struct mbuf *); 172 void udp_notify(struct inpcb *, int); 173 int udp_sysctl_udpstat(void *, size_t *, void *); 174 175 #ifndef UDB_INITIAL_HASH_SIZE 176 #define UDB_INITIAL_HASH_SIZE 128 177 #endif 178 179 void 180 udp_init(void) 181 { 182 udpcounters = counters_alloc(udps_ncounters); 183 in_pcbinit(&udbtable, UDB_INITIAL_HASH_SIZE); 184 } 185 186 int 187 udp_input(struct mbuf **mp, int *offp, int proto, int af) 188 { 189 struct mbuf *m = *mp; 190 int iphlen = *offp; 191 struct ip *ip = NULL; 192 struct udphdr *uh; 193 struct inpcb *inp = NULL; 194 struct ip save_ip; 195 int len; 196 u_int16_t savesum; 197 union { 198 struct sockaddr sa; 199 struct sockaddr_in sin; 200 #ifdef INET6 201 struct sockaddr_in6 sin6; 202 #endif /* INET6 */ 203 } srcsa, dstsa; 204 struct ip6_hdr *ip6 = NULL; 205 u_int32_t ipsecflowinfo = 0; 206 207 udpstat_inc(udps_ipackets); 208 209 IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); 210 if (!uh) { 211 udpstat_inc(udps_hdrops); 212 return IPPROTO_DONE; 213 } 214 215 /* Check for illegal destination port 0 */ 216 if (uh->uh_dport == 0) { 217 udpstat_inc(udps_noport); 218 goto bad; 219 } 220 221 /* 222 * Make mbuf data length reflect UDP length. 223 * If not enough data to reflect UDP length, drop. 224 */ 225 len = ntohs((u_int16_t)uh->uh_ulen); 226 switch (af) { 227 case AF_INET: 228 if (m->m_pkthdr.len - iphlen != len) { 229 if (len > (m->m_pkthdr.len - iphlen) || 230 len < sizeof(struct udphdr)) { 231 udpstat_inc(udps_badlen); 232 goto bad; 233 } 234 m_adj(m, len - (m->m_pkthdr.len - iphlen)); 235 } 236 ip = mtod(m, struct ip *); 237 /* 238 * Save a copy of the IP header in case we want restore it 239 * for sending an ICMP error message in response. 240 */ 241 save_ip = *ip; 242 break; 243 #ifdef INET6 244 case AF_INET6: 245 /* jumbograms */ 246 if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff) 247 len = m->m_pkthdr.len - iphlen; 248 if (len != m->m_pkthdr.len - iphlen) { 249 udpstat_inc(udps_badlen); 250 goto bad; 251 } 252 ip6 = mtod(m, struct ip6_hdr *); 253 break; 254 #endif /* INET6 */ 255 default: 256 unhandled_af(af); 257 } 258 259 /* 260 * Checksum extended UDP header and data. 261 * from W.R.Stevens: check incoming udp cksums even if 262 * udpcksum is not set. 263 */ 264 savesum = uh->uh_sum; 265 if (uh->uh_sum == 0) { 266 udpstat_inc(udps_nosum); 267 #ifdef INET6 268 /* 269 * In IPv6, the UDP checksum is ALWAYS used. 270 */ 271 if (ip6) 272 goto bad; 273 #endif /* INET6 */ 274 } else { 275 if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) { 276 if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) { 277 udpstat_inc(udps_badsum); 278 goto bad; 279 } 280 udpstat_inc(udps_inswcsum); 281 282 if (ip) 283 uh->uh_sum = in4_cksum(m, IPPROTO_UDP, 284 iphlen, len); 285 #ifdef INET6 286 else if (ip6) 287 uh->uh_sum = in6_cksum(m, IPPROTO_UDP, 288 iphlen, len); 289 #endif /* INET6 */ 290 if (uh->uh_sum != 0) { 291 udpstat_inc(udps_badsum); 292 goto bad; 293 } 294 } 295 } 296 297 #ifdef IPSEC 298 if (udpencap_enable && udpencap_port && esp_enable && 299 #if NPF > 0 300 !(m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) && 301 #endif 302 uh->uh_dport == htons(udpencap_port)) { 303 u_int32_t spi; 304 int skip = iphlen + sizeof(struct udphdr); 305 306 if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) { 307 /* packet too short */ 308 m_freem(m); 309 return IPPROTO_DONE; 310 } 311 m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); 312 /* 313 * decapsulate if the SPI is not zero, otherwise pass 314 * to userland 315 */ 316 if (spi != 0) { 317 int protoff; 318 319 if ((m = *mp = m_pullup(m, skip)) == NULL) { 320 udpstat_inc(udps_hdrops); 321 return IPPROTO_DONE; 322 } 323 324 /* remove the UDP header */ 325 bcopy(mtod(m, u_char *), 326 mtod(m, u_char *) + sizeof(struct udphdr), iphlen); 327 m_adj(m, sizeof(struct udphdr)); 328 skip -= sizeof(struct udphdr); 329 330 espstat_inc(esps_udpencin); 331 protoff = af == AF_INET ? offsetof(struct ip, ip_p) : 332 offsetof(struct ip6_hdr, ip6_nxt); 333 return ipsec_common_input(mp, skip, protoff, 334 af, IPPROTO_ESP, 1); 335 } 336 } 337 #endif /* IPSEC */ 338 339 switch (af) { 340 case AF_INET: 341 bzero(&srcsa, sizeof(struct sockaddr_in)); 342 srcsa.sin.sin_len = sizeof(struct sockaddr_in); 343 srcsa.sin.sin_family = AF_INET; 344 srcsa.sin.sin_port = uh->uh_sport; 345 srcsa.sin.sin_addr = ip->ip_src; 346 347 bzero(&dstsa, sizeof(struct sockaddr_in)); 348 dstsa.sin.sin_len = sizeof(struct sockaddr_in); 349 dstsa.sin.sin_family = AF_INET; 350 dstsa.sin.sin_port = uh->uh_dport; 351 dstsa.sin.sin_addr = ip->ip_dst; 352 break; 353 #ifdef INET6 354 case AF_INET6: 355 bzero(&srcsa, sizeof(struct sockaddr_in6)); 356 srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6); 357 srcsa.sin6.sin6_family = AF_INET6; 358 srcsa.sin6.sin6_port = uh->uh_sport; 359 #if 0 /*XXX inbound flowinfo */ 360 srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow; 361 #endif 362 /* KAME hack: recover scopeid */ 363 in6_recoverscope(&srcsa.sin6, &ip6->ip6_src); 364 365 bzero(&dstsa, sizeof(struct sockaddr_in6)); 366 dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6); 367 dstsa.sin6.sin6_family = AF_INET6; 368 dstsa.sin6.sin6_port = uh->uh_dport; 369 #if 0 /*XXX inbound flowinfo */ 370 dstsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow; 371 #endif 372 /* KAME hack: recover scopeid */ 373 in6_recoverscope(&dstsa.sin6, &ip6->ip6_dst); 374 break; 375 #endif /* INET6 */ 376 } 377 378 if (m->m_flags & (M_BCAST|M_MCAST)) { 379 SIMPLEQ_HEAD(, inpcb) inpcblist; 380 381 /* 382 * Deliver a multicast or broadcast datagram to *all* sockets 383 * for which the local and remote addresses and ports match 384 * those of the incoming datagram. This allows more than 385 * one process to receive multi/broadcasts on the same port. 386 * (This really ought to be done for unicast datagrams as 387 * well, but that would cause problems with existing 388 * applications that open both address-specific sockets and 389 * a wildcard socket listening to the same port -- they would 390 * end up receiving duplicates of every unicast datagram. 391 * Those applications open the multiple sockets to overcome an 392 * inadequacy of the UDP socket interface, but for backwards 393 * compatibility we avoid the problem here rather than 394 * fixing the interface. Maybe 4.5BSD will remedy this?) 395 */ 396 397 /* 398 * Locate pcb(s) for datagram. 399 * (Algorithm copied from raw_intr().) 400 */ 401 SIMPLEQ_INIT(&inpcblist); 402 rw_enter_write(&udbtable.inpt_notify); 403 mtx_enter(&udbtable.inpt_mtx); 404 TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) { 405 if (inp->inp_socket->so_state & SS_CANTRCVMORE) 406 continue; 407 #ifdef INET6 408 /* don't accept it if AF does not match */ 409 if (ip6 && !(inp->inp_flags & INP_IPV6)) 410 continue; 411 if (!ip6 && (inp->inp_flags & INP_IPV6)) 412 continue; 413 #endif 414 if (rtable_l2(inp->inp_rtableid) != 415 rtable_l2(m->m_pkthdr.ph_rtableid)) 416 continue; 417 if (inp->inp_lport != uh->uh_dport) 418 continue; 419 #ifdef INET6 420 if (ip6) { 421 if (inp->inp_ip6_minhlim && 422 inp->inp_ip6_minhlim > ip6->ip6_hlim) 423 continue; 424 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) 425 if (!IN6_ARE_ADDR_EQUAL( 426 &inp->inp_laddr6, &ip6->ip6_dst)) 427 continue; 428 } else 429 #endif /* INET6 */ 430 { 431 if (inp->inp_ip_minttl && 432 inp->inp_ip_minttl > ip->ip_ttl) 433 continue; 434 435 if (inp->inp_laddr.s_addr != INADDR_ANY) { 436 if (inp->inp_laddr.s_addr != 437 ip->ip_dst.s_addr) 438 continue; 439 } 440 } 441 #ifdef INET6 442 if (ip6) { 443 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) 444 if (!IN6_ARE_ADDR_EQUAL( 445 &inp->inp_faddr6, &ip6->ip6_src) || 446 inp->inp_fport != uh->uh_sport) 447 continue; 448 } else 449 #endif /* INET6 */ 450 if (inp->inp_faddr.s_addr != INADDR_ANY) { 451 if (inp->inp_faddr.s_addr != 452 ip->ip_src.s_addr || 453 inp->inp_fport != uh->uh_sport) 454 continue; 455 } 456 457 in_pcbref(inp); 458 SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify); 459 460 /* 461 * Don't look for additional matches if this one does 462 * not have either the SO_REUSEPORT or SO_REUSEADDR 463 * socket options set. This heuristic avoids searching 464 * through all pcbs in the common case of a non-shared 465 * port. It assumes that an application will never 466 * clear these options after setting them. 467 */ 468 if ((inp->inp_socket->so_options & (SO_REUSEPORT | 469 SO_REUSEADDR)) == 0) 470 break; 471 } 472 mtx_leave(&udbtable.inpt_mtx); 473 474 if (SIMPLEQ_EMPTY(&inpcblist)) { 475 rw_exit_write(&udbtable.inpt_notify); 476 477 /* 478 * No matching pcb found; discard datagram. 479 * (No need to send an ICMP Port Unreachable 480 * for a broadcast or multicast datgram.) 481 */ 482 udpstat_inc(udps_noportbcast); 483 goto bad; 484 } 485 486 while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) { 487 struct mbuf *n; 488 489 SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify); 490 if (SIMPLEQ_EMPTY(&inpcblist)) 491 n = m; 492 else 493 n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 494 if (n != NULL) { 495 udp_sbappend(inp, n, ip, ip6, iphlen, uh, 496 &srcsa.sa, 0); 497 } 498 in_pcbunref(inp); 499 } 500 rw_exit_write(&udbtable.inpt_notify); 501 502 return IPPROTO_DONE; 503 } 504 /* 505 * Locate pcb for datagram. 506 */ 507 #if NPF > 0 508 inp = pf_inp_lookup(m); 509 #endif 510 if (inp == NULL) { 511 #ifdef INET6 512 if (ip6) 513 inp = in6_pcblookup(&udbtable, &ip6->ip6_src, 514 uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 515 m->m_pkthdr.ph_rtableid); 516 else 517 #endif /* INET6 */ 518 inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport, 519 ip->ip_dst, uh->uh_dport, m->m_pkthdr.ph_rtableid); 520 } 521 if (inp == NULL) { 522 udpstat_inc(udps_pcbhashmiss); 523 #ifdef INET6 524 if (ip6) { 525 inp = in6_pcblookup_listen(&udbtable, &ip6->ip6_dst, 526 uh->uh_dport, m, m->m_pkthdr.ph_rtableid); 527 } else 528 #endif /* INET6 */ 529 inp = in_pcblookup_listen(&udbtable, ip->ip_dst, 530 uh->uh_dport, m, m->m_pkthdr.ph_rtableid); 531 } 532 533 #ifdef IPSEC 534 if (ipsec_in_use) { 535 struct m_tag *mtag; 536 struct tdb_ident *tdbi; 537 struct tdb *tdb; 538 int error; 539 540 mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 541 if (mtag != NULL) { 542 tdbi = (struct tdb_ident *)(mtag + 1); 543 tdb = gettdb(tdbi->rdomain, tdbi->spi, 544 &tdbi->dst, tdbi->proto); 545 } else 546 tdb = NULL; 547 error = ipsp_spd_lookup(m, af, iphlen, IPSP_DIRECTION_IN, 548 tdb, inp, NULL, NULL); 549 if (error) { 550 udpstat_inc(udps_nosec); 551 tdb_unref(tdb); 552 goto bad; 553 } 554 /* create ipsec options, id is not modified after creation */ 555 if (tdb && tdb->tdb_ids) 556 ipsecflowinfo = tdb->tdb_ids->id_flow; 557 tdb_unref(tdb); 558 } 559 #endif /*IPSEC */ 560 561 if (inp == NULL) { 562 udpstat_inc(udps_noport); 563 if (m->m_flags & (M_BCAST | M_MCAST)) { 564 udpstat_inc(udps_noportbcast); 565 goto bad; 566 } 567 #ifdef INET6 568 if (ip6) { 569 uh->uh_sum = savesum; 570 icmp6_error(m, ICMP6_DST_UNREACH, 571 ICMP6_DST_UNREACH_NOPORT,0); 572 } else 573 #endif /* INET6 */ 574 { 575 *ip = save_ip; 576 uh->uh_sum = savesum; 577 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 578 0, 0); 579 } 580 return IPPROTO_DONE; 581 } 582 583 KASSERT(sotoinpcb(inp->inp_socket) == inp); 584 soassertlocked(inp->inp_socket); 585 586 #ifdef INET6 587 if (ip6 && inp->inp_ip6_minhlim && 588 inp->inp_ip6_minhlim > ip6->ip6_hlim) { 589 goto bad; 590 } else 591 #endif 592 if (ip && inp->inp_ip_minttl && 593 inp->inp_ip_minttl > ip->ip_ttl) { 594 goto bad; 595 } 596 597 #if NPF > 0 598 if (inp->inp_socket->so_state & SS_ISCONNECTED) 599 pf_inp_link(m, inp); 600 #endif 601 602 #ifdef PIPEX 603 if (pipex_enable && inp->inp_pipex) { 604 struct pipex_session *session; 605 int off = iphlen + sizeof(struct udphdr); 606 607 if ((session = pipex_l2tp_lookup_session(m, off)) != NULL) { 608 m = *mp = pipex_l2tp_input(m, off, session, 609 ipsecflowinfo); 610 pipex_rele_session(session); 611 if (m == NULL) { 612 in_pcbunref(inp); 613 return IPPROTO_DONE; 614 } 615 } 616 } 617 #endif 618 619 udp_sbappend(inp, m, ip, ip6, iphlen, uh, &srcsa.sa, ipsecflowinfo); 620 in_pcbunref(inp); 621 return IPPROTO_DONE; 622 bad: 623 m_freem(m); 624 in_pcbunref(inp); 625 return IPPROTO_DONE; 626 } 627 628 void 629 udp_sbappend(struct inpcb *inp, struct mbuf *m, struct ip *ip, 630 struct ip6_hdr *ip6, int hlen, struct udphdr *uh, 631 struct sockaddr *srcaddr, u_int32_t ipsecflowinfo) 632 { 633 struct socket *so = inp->inp_socket; 634 struct mbuf *opts = NULL; 635 636 hlen += sizeof(*uh); 637 638 if (inp->inp_upcall != NULL) { 639 m = (*inp->inp_upcall)(inp->inp_upcall_arg, m, 640 ip, ip6, uh, hlen); 641 if (m == NULL) 642 return; 643 } 644 645 #ifdef INET6 646 if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS || 647 so->so_options & SO_TIMESTAMP)) 648 ip6_savecontrol(inp, m, &opts); 649 #endif /* INET6 */ 650 if (ip && (inp->inp_flags & INP_CONTROLOPTS || 651 so->so_options & SO_TIMESTAMP)) 652 ip_savecontrol(inp, &opts, ip, m); 653 #ifdef INET6 654 if (ip6 && (inp->inp_flags & IN6P_RECVDSTPORT)) { 655 struct mbuf **mp = &opts; 656 657 while (*mp) 658 mp = &(*mp)->m_next; 659 *mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t), 660 IPV6_RECVDSTPORT, IPPROTO_IPV6); 661 } 662 #endif /* INET6 */ 663 if (ip && (inp->inp_flags & INP_RECVDSTPORT)) { 664 struct mbuf **mp = &opts; 665 666 while (*mp) 667 mp = &(*mp)->m_next; 668 *mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t), 669 IP_RECVDSTPORT, IPPROTO_IP); 670 } 671 #ifdef IPSEC 672 if (ipsecflowinfo && (inp->inp_flags & INP_IPSECFLOWINFO)) { 673 struct mbuf **mp = &opts; 674 675 while (*mp) 676 mp = &(*mp)->m_next; 677 *mp = sbcreatecontrol((caddr_t)&ipsecflowinfo, 678 sizeof(u_int32_t), IP_IPSECFLOWINFO, IPPROTO_IP); 679 } 680 #endif 681 m_adj(m, hlen); 682 683 mtx_enter(&inp->inp_mtx); 684 if (sbappendaddr(so, &so->so_rcv, srcaddr, m, opts) == 0) { 685 mtx_leave(&inp->inp_mtx); 686 udpstat_inc(udps_fullsock); 687 m_freem(m); 688 m_freem(opts); 689 return; 690 } 691 mtx_leave(&inp->inp_mtx); 692 693 sorwakeup(so); 694 } 695 696 /* 697 * Notify a udp user of an asynchronous error; 698 * just wake up so that he can collect error status. 699 */ 700 void 701 udp_notify(struct inpcb *inp, int errno) 702 { 703 inp->inp_socket->so_error = errno; 704 sorwakeup(inp->inp_socket); 705 sowwakeup(inp->inp_socket); 706 } 707 708 #ifdef INET6 709 void 710 udp6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) 711 { 712 struct udphdr uh; 713 struct sockaddr_in6 sa6; 714 struct ip6_hdr *ip6; 715 struct mbuf *m; 716 int off; 717 void *cmdarg; 718 struct ip6ctlparam *ip6cp = NULL; 719 struct udp_portonly { 720 u_int16_t uh_sport; 721 u_int16_t uh_dport; 722 } *uhp; 723 struct inpcb *inp; 724 void (*notify)(struct inpcb *, int) = udp_notify; 725 726 if (sa == NULL) 727 return; 728 if (sa->sa_family != AF_INET6 || 729 sa->sa_len != sizeof(struct sockaddr_in6)) 730 return; 731 732 if ((unsigned)cmd >= PRC_NCMDS) 733 return; 734 if (PRC_IS_REDIRECT(cmd)) 735 notify = in_rtchange, d = NULL; 736 else if (cmd == PRC_HOSTDEAD) 737 d = NULL; 738 else if (cmd == PRC_MSGSIZE) 739 ; /* special code is present, see below */ 740 else if (inet6ctlerrmap[cmd] == 0) 741 return; 742 743 /* if the parameter is from icmp6, decode it. */ 744 if (d != NULL) { 745 ip6cp = (struct ip6ctlparam *)d; 746 m = ip6cp->ip6c_m; 747 ip6 = ip6cp->ip6c_ip6; 748 off = ip6cp->ip6c_off; 749 cmdarg = ip6cp->ip6c_cmdarg; 750 } else { 751 m = NULL; 752 ip6 = NULL; 753 cmdarg = NULL; 754 /* XXX: translate addresses into internal form */ 755 sa6 = *satosin6(sa); 756 if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL)) { 757 /* should be impossible */ 758 return; 759 } 760 } 761 762 if (ip6cp && ip6cp->ip6c_finaldst) { 763 bzero(&sa6, sizeof(sa6)); 764 sa6.sin6_family = AF_INET6; 765 sa6.sin6_len = sizeof(sa6); 766 sa6.sin6_addr = *ip6cp->ip6c_finaldst; 767 /* XXX: assuming M is valid in this case */ 768 sa6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx, 769 ip6cp->ip6c_finaldst); 770 if (in6_embedscope(ip6cp->ip6c_finaldst, &sa6, NULL)) { 771 /* should be impossible */ 772 return; 773 } 774 } else { 775 /* XXX: translate addresses into internal form */ 776 sa6 = *satosin6(sa); 777 if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL)) { 778 /* should be impossible */ 779 return; 780 } 781 } 782 783 if (ip6) { 784 /* 785 * XXX: We assume that when IPV6 is non NULL, 786 * M and OFF are valid. 787 */ 788 struct sockaddr_in6 sa6_src; 789 790 /* check if we can safely examine src and dst ports */ 791 if (m->m_pkthdr.len < off + sizeof(*uhp)) 792 return; 793 794 bzero(&uh, sizeof(uh)); 795 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 796 797 bzero(&sa6_src, sizeof(sa6_src)); 798 sa6_src.sin6_family = AF_INET6; 799 sa6_src.sin6_len = sizeof(sa6_src); 800 sa6_src.sin6_addr = ip6->ip6_src; 801 sa6_src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx, 802 &ip6->ip6_src); 803 if (in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL)) { 804 /* should be impossible */ 805 return; 806 } 807 808 if (cmd == PRC_MSGSIZE) { 809 /* 810 * Check to see if we have a valid UDP socket 811 * corresponding to the address in the ICMPv6 message 812 * payload. 813 */ 814 inp = in6_pcblookup(&udbtable, &sa6.sin6_addr, 815 uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport, 816 rdomain); 817 #if 0 818 /* 819 * As the use of sendto(2) is fairly popular, 820 * we may want to allow non-connected pcb too. 821 * But it could be too weak against attacks... 822 * We should at least check if the local address (= s) 823 * is really ours. 824 */ 825 if (inp == NULL) { 826 inp = in6_pcblookup_listen(&udbtable, 827 &sa6_src.sin6_addr, uh.uh_sport, NULL, 828 rdomain)) 829 } 830 #endif 831 832 /* 833 * Depending on the value of "valid" and routing table 834 * size (mtudisc_{hi,lo}wat), we will: 835 * - recalculate the new MTU and create the 836 * corresponding routing entry, or 837 * - ignore the MTU change notification. 838 */ 839 icmp6_mtudisc_update((struct ip6ctlparam *)d, 840 inp != NULL); 841 in_pcbunref(inp); 842 843 /* 844 * regardless of if we called icmp6_mtudisc_update(), 845 * we need to call in6_pcbnotify(), to notify path 846 * MTU change to the userland (2292bis-02), because 847 * some unconnected sockets may share the same 848 * destination and want to know the path MTU. 849 */ 850 } 851 852 in6_pcbnotify(&udbtable, &sa6, uh.uh_dport, 853 &sa6_src, uh.uh_sport, rdomain, cmd, cmdarg, notify); 854 } else { 855 in6_pcbnotify(&udbtable, &sa6, 0, 856 &sa6_any, 0, rdomain, cmd, cmdarg, notify); 857 } 858 } 859 #endif 860 861 void 862 udp_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) 863 { 864 struct ip *ip = v; 865 struct udphdr *uhp; 866 struct in_addr faddr; 867 struct inpcb *inp; 868 void (*notify)(struct inpcb *, int) = udp_notify; 869 int errno; 870 871 if (sa == NULL) 872 return; 873 if (sa->sa_family != AF_INET || 874 sa->sa_len != sizeof(struct sockaddr_in)) 875 return; 876 faddr = satosin(sa)->sin_addr; 877 if (faddr.s_addr == INADDR_ANY) 878 return; 879 880 if ((unsigned)cmd >= PRC_NCMDS) 881 return; 882 errno = inetctlerrmap[cmd]; 883 if (PRC_IS_REDIRECT(cmd)) 884 notify = in_rtchange, ip = 0; 885 else if (cmd == PRC_HOSTDEAD) 886 ip = 0; 887 else if (errno == 0) 888 return; 889 if (ip) { 890 uhp = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 891 892 #ifdef IPSEC 893 /* PMTU discovery for udpencap */ 894 if (cmd == PRC_MSGSIZE && ip_mtudisc && udpencap_enable && 895 udpencap_port && uhp->uh_sport == htons(udpencap_port)) { 896 udpencap_ctlinput(cmd, sa, rdomain, v); 897 return; 898 } 899 #endif 900 inp = in_pcblookup(&udbtable, 901 ip->ip_dst, uhp->uh_dport, ip->ip_src, uhp->uh_sport, 902 rdomain); 903 if (inp && inp->inp_socket != NULL) 904 notify(inp, errno); 905 in_pcbunref(inp); 906 } else 907 in_pcbnotifyall(&udbtable, sa, rdomain, errno, notify); 908 } 909 910 int 911 udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr, 912 struct mbuf *control) 913 { 914 struct sockaddr_in *sin = NULL; 915 struct udpiphdr *ui; 916 u_int32_t ipsecflowinfo = 0; 917 struct sockaddr_in src_sin; 918 int len = m->m_pkthdr.len; 919 struct in_addr laddr; 920 int error = 0; 921 922 #ifdef DIAGNOSTIC 923 if ((inp->inp_flags & INP_IPV6) != 0) 924 panic("IPv6 inpcb to %s", __func__); 925 #endif 926 927 /* 928 * Compute the packet length of the IP header, and 929 * punt if the length looks bogus. 930 */ 931 if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { 932 error = EMSGSIZE; 933 goto release; 934 } 935 936 memset(&src_sin, 0, sizeof(src_sin)); 937 938 if (control) { 939 u_int clen; 940 struct cmsghdr *cm; 941 caddr_t cmsgs; 942 943 /* 944 * XXX: Currently, we assume all the optional information is 945 * stored in a single mbuf. 946 */ 947 if (control->m_next) { 948 error = EINVAL; 949 goto release; 950 } 951 952 clen = control->m_len; 953 cmsgs = mtod(control, caddr_t); 954 do { 955 if (clen < CMSG_LEN(0)) { 956 error = EINVAL; 957 goto release; 958 } 959 cm = (struct cmsghdr *)cmsgs; 960 if (cm->cmsg_len < CMSG_LEN(0) || 961 CMSG_ALIGN(cm->cmsg_len) > clen) { 962 error = EINVAL; 963 goto release; 964 } 965 #ifdef IPSEC 966 if ((inp->inp_flags & INP_IPSECFLOWINFO) != 0 && 967 cm->cmsg_len == CMSG_LEN(sizeof(ipsecflowinfo)) && 968 cm->cmsg_level == IPPROTO_IP && 969 cm->cmsg_type == IP_IPSECFLOWINFO) { 970 ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm); 971 } else 972 #endif 973 if (cm->cmsg_len == CMSG_LEN(sizeof(struct in_addr)) && 974 cm->cmsg_level == IPPROTO_IP && 975 cm->cmsg_type == IP_SENDSRCADDR) { 976 memcpy(&src_sin.sin_addr, CMSG_DATA(cm), 977 sizeof(struct in_addr)); 978 src_sin.sin_family = AF_INET; 979 src_sin.sin_len = sizeof(src_sin); 980 /* no check on reuse when sin->sin_port == 0 */ 981 if ((error = in_pcbaddrisavail(inp, &src_sin, 982 0, curproc))) 983 goto release; 984 } 985 clen -= CMSG_ALIGN(cm->cmsg_len); 986 cmsgs += CMSG_ALIGN(cm->cmsg_len); 987 } while (clen); 988 } 989 990 if (addr) { 991 if ((error = in_nam2sin(addr, &sin))) 992 goto release; 993 if (sin->sin_port == 0) { 994 error = EADDRNOTAVAIL; 995 goto release; 996 } 997 if (inp->inp_faddr.s_addr != INADDR_ANY) { 998 error = EISCONN; 999 goto release; 1000 } 1001 error = in_pcbselsrc(&laddr, sin, inp); 1002 if (error) 1003 goto release; 1004 1005 if (inp->inp_lport == 0) { 1006 error = in_pcbbind(inp, NULL, curproc); 1007 if (error) 1008 goto release; 1009 } 1010 1011 if (src_sin.sin_len > 0 && 1012 src_sin.sin_addr.s_addr != INADDR_ANY && 1013 src_sin.sin_addr.s_addr != inp->inp_laddr.s_addr) { 1014 src_sin.sin_port = inp->inp_lport; 1015 if (inp->inp_laddr.s_addr != INADDR_ANY && 1016 (error = 1017 in_pcbaddrisavail(inp, &src_sin, 0, curproc))) 1018 goto release; 1019 laddr = src_sin.sin_addr; 1020 } 1021 } else { 1022 if (inp->inp_faddr.s_addr == INADDR_ANY) { 1023 error = ENOTCONN; 1024 goto release; 1025 } 1026 laddr = inp->inp_laddr; 1027 } 1028 1029 /* 1030 * Calculate data length and get a mbuf 1031 * for UDP and IP headers. 1032 */ 1033 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 1034 if (m == NULL) { 1035 error = ENOBUFS; 1036 goto bail; 1037 } 1038 1039 /* 1040 * Fill in mbuf with extended UDP header 1041 * and addresses and length put into network format. 1042 */ 1043 ui = mtod(m, struct udpiphdr *); 1044 bzero(ui->ui_x1, sizeof ui->ui_x1); 1045 ui->ui_pr = IPPROTO_UDP; 1046 ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); 1047 ui->ui_src = laddr; 1048 ui->ui_dst = sin ? sin->sin_addr : inp->inp_faddr; 1049 ui->ui_sport = inp->inp_lport; 1050 ui->ui_dport = sin ? sin->sin_port : inp->inp_fport; 1051 ui->ui_ulen = ui->ui_len; 1052 ((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len); 1053 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; 1054 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; 1055 if (udpcksum) 1056 m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; 1057 1058 udpstat_inc(udps_opackets); 1059 1060 /* force routing table */ 1061 m->m_pkthdr.ph_rtableid = inp->inp_rtableid; 1062 1063 #if NPF > 0 1064 if (inp->inp_socket->so_state & SS_ISCONNECTED) 1065 pf_mbuf_link_inpcb(m, inp); 1066 #endif 1067 1068 error = ip_output(m, inp->inp_options, &inp->inp_route, 1069 (inp->inp_socket->so_options & SO_BROADCAST), inp->inp_moptions, 1070 inp, ipsecflowinfo); 1071 1072 bail: 1073 m_freem(control); 1074 return (error); 1075 1076 release: 1077 m_freem(m); 1078 goto bail; 1079 } 1080 1081 int 1082 udp_attach(struct socket *so, int proto) 1083 { 1084 int error; 1085 1086 if (so->so_pcb != NULL) 1087 return EINVAL; 1088 1089 if ((error = soreserve(so, udp_sendspace, udp_recvspace))) 1090 return error; 1091 1092 NET_ASSERT_LOCKED(); 1093 if ((error = in_pcballoc(so, &udbtable))) 1094 return error; 1095 #ifdef INET6 1096 if (sotoinpcb(so)->inp_flags & INP_IPV6) 1097 sotoinpcb(so)->inp_ipv6.ip6_hlim = ip6_defhlim; 1098 else 1099 #endif /* INET6 */ 1100 sotoinpcb(so)->inp_ip.ip_ttl = ip_defttl; 1101 return 0; 1102 } 1103 1104 int 1105 udp_detach(struct socket *so) 1106 { 1107 struct inpcb *inp; 1108 1109 soassertlocked(so); 1110 1111 inp = sotoinpcb(so); 1112 if (inp == NULL) 1113 return (EINVAL); 1114 1115 in_pcbdetach(inp); 1116 return (0); 1117 } 1118 1119 void 1120 udp_lock(struct socket *so) 1121 { 1122 struct inpcb *inp = sotoinpcb(so); 1123 1124 NET_ASSERT_LOCKED(); 1125 mtx_enter(&inp->inp_mtx); 1126 } 1127 1128 void 1129 udp_unlock(struct socket *so) 1130 { 1131 struct inpcb *inp = sotoinpcb(so); 1132 1133 NET_ASSERT_LOCKED(); 1134 mtx_leave(&inp->inp_mtx); 1135 } 1136 1137 int 1138 udp_bind(struct socket *so, struct mbuf *addr, struct proc *p) 1139 { 1140 struct inpcb *inp = sotoinpcb(so); 1141 1142 soassertlocked(so); 1143 return in_pcbbind(inp, addr, p); 1144 } 1145 1146 int 1147 udp_connect(struct socket *so, struct mbuf *addr) 1148 { 1149 struct inpcb *inp = sotoinpcb(so); 1150 int error; 1151 1152 soassertlocked(so); 1153 1154 #ifdef INET6 1155 if (inp->inp_flags & INP_IPV6) { 1156 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) 1157 return (EISCONN); 1158 error = in6_pcbconnect(inp, addr); 1159 } else 1160 #endif /* INET6 */ 1161 { 1162 if (inp->inp_faddr.s_addr != INADDR_ANY) 1163 return (EISCONN); 1164 error = in_pcbconnect(inp, addr); 1165 } 1166 1167 if (error) 1168 return (error); 1169 1170 soisconnected(so); 1171 return (0); 1172 } 1173 1174 int 1175 udp_disconnect(struct socket *so) 1176 { 1177 struct inpcb *inp = sotoinpcb(so); 1178 1179 soassertlocked(so); 1180 1181 #ifdef INET6 1182 if (inp->inp_flags & INP_IPV6) { 1183 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) 1184 return (ENOTCONN); 1185 } else 1186 #endif /* INET6 */ 1187 { 1188 if (inp->inp_faddr.s_addr == INADDR_ANY) 1189 return (ENOTCONN); 1190 } 1191 1192 #ifdef INET6 1193 if (inp->inp_flags & INP_IPV6) 1194 inp->inp_laddr6 = in6addr_any; 1195 else 1196 #endif /* INET6 */ 1197 inp->inp_laddr.s_addr = INADDR_ANY; 1198 1199 in_pcbdisconnect(inp); 1200 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 1201 1202 return (0); 1203 } 1204 1205 int 1206 udp_shutdown(struct socket *so) 1207 { 1208 soassertlocked(so); 1209 socantsendmore(so); 1210 return (0); 1211 } 1212 1213 int 1214 udp_send(struct socket *so, struct mbuf *m, struct mbuf *addr, 1215 struct mbuf *control) 1216 { 1217 struct inpcb *inp = sotoinpcb(so); 1218 int error; 1219 1220 soassertlocked(so); 1221 1222 #ifdef PIPEX 1223 if (inp->inp_pipex) { 1224 struct pipex_session *session; 1225 1226 if (addr != NULL) 1227 session = 1228 pipex_l2tp_userland_lookup_session(m, 1229 mtod(addr, struct sockaddr *)); 1230 else 1231 #ifdef INET6 1232 if (inp->inp_flags & INP_IPV6) 1233 session = 1234 pipex_l2tp_userland_lookup_session_ipv6( 1235 m, inp->inp_faddr6); 1236 else 1237 #endif 1238 session = 1239 pipex_l2tp_userland_lookup_session_ipv4( 1240 m, inp->inp_faddr); 1241 if (session != NULL) { 1242 m = pipex_l2tp_userland_output(m, session); 1243 pipex_rele_session(session); 1244 1245 if (m == NULL) { 1246 m_freem(control); 1247 return (ENOMEM); 1248 } 1249 } 1250 } 1251 #endif 1252 1253 #ifdef INET6 1254 if (inp->inp_flags & INP_IPV6) 1255 error = udp6_output(inp, m, addr, control); 1256 else 1257 #endif 1258 error = udp_output(inp, m, addr, control); 1259 1260 return (error); 1261 } 1262 1263 int 1264 udp_abort(struct socket *so) 1265 { 1266 struct inpcb *inp = sotoinpcb(so); 1267 1268 soassertlocked(so); 1269 1270 soisdisconnected(so); 1271 in_pcbdetach(inp); 1272 1273 return (0); 1274 } 1275 1276 /* 1277 * Sysctl for udp variables. 1278 */ 1279 int 1280 udp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 1281 size_t newlen) 1282 { 1283 int error; 1284 1285 /* All sysctl names at this level are terminal. */ 1286 if (namelen != 1) 1287 return (ENOTDIR); 1288 1289 switch (name[0]) { 1290 case UDPCTL_BADDYNAMIC: 1291 NET_LOCK(); 1292 error = sysctl_struct(oldp, oldlenp, newp, newlen, 1293 baddynamicports.udp, sizeof(baddynamicports.udp)); 1294 NET_UNLOCK(); 1295 return (error); 1296 1297 case UDPCTL_ROOTONLY: 1298 if (newp && securelevel > 0) 1299 return (EPERM); 1300 NET_LOCK(); 1301 error = sysctl_struct(oldp, oldlenp, newp, newlen, 1302 rootonlyports.udp, sizeof(rootonlyports.udp)); 1303 NET_UNLOCK(); 1304 return (error); 1305 1306 case UDPCTL_STATS: 1307 if (newp != NULL) 1308 return (EPERM); 1309 1310 return (udp_sysctl_udpstat(oldp, oldlenp, newp)); 1311 1312 default: 1313 NET_LOCK(); 1314 error = sysctl_bounded_arr(udpctl_vars, nitems(udpctl_vars), 1315 name, namelen, oldp, oldlenp, newp, newlen); 1316 NET_UNLOCK(); 1317 return (error); 1318 } 1319 /* NOTREACHED */ 1320 } 1321 1322 int 1323 udp_sysctl_udpstat(void *oldp, size_t *oldlenp, void *newp) 1324 { 1325 uint64_t counters[udps_ncounters]; 1326 struct udpstat udpstat; 1327 u_long *words = (u_long *)&udpstat; 1328 int i; 1329 1330 CTASSERT(sizeof(udpstat) == (nitems(counters) * sizeof(u_long))); 1331 memset(&udpstat, 0, sizeof udpstat); 1332 counters_read(udpcounters, counters, nitems(counters)); 1333 1334 for (i = 0; i < nitems(counters); i++) 1335 words[i] = (u_long)counters[i]; 1336 1337 return (sysctl_rdstruct(oldp, oldlenp, newp, 1338 &udpstat, sizeof(udpstat))); 1339 } 1340