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