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