1 /* $OpenBSD: udp_usrreq.c,v 1.277 2022/03/21 23:37: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 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 if ((session = pipex_l2tp_lookup_session(m, off)) != NULL) { 569 if ((m = *mp = pipex_l2tp_input(m, off, session, 570 ipsecflowinfo)) == NULL) { 571 /* the packet is handled by PIPEX */ 572 return IPPROTO_DONE; 573 } 574 } 575 } 576 #endif 577 578 udp_sbappend(inp, m, ip, ip6, iphlen, uh, &srcsa.sa, ipsecflowinfo); 579 return IPPROTO_DONE; 580 bad: 581 m_freem(m); 582 return IPPROTO_DONE; 583 } 584 585 void 586 udp_sbappend(struct inpcb *inp, struct mbuf *m, struct ip *ip, 587 struct ip6_hdr *ip6, int hlen, struct udphdr *uh, 588 struct sockaddr *srcaddr, u_int32_t ipsecflowinfo) 589 { 590 struct socket *so = inp->inp_socket; 591 struct mbuf *opts = NULL; 592 593 hlen += sizeof(*uh); 594 595 if (inp->inp_upcall != NULL) { 596 m = (*inp->inp_upcall)(inp->inp_upcall_arg, m, 597 ip, ip6, uh, hlen); 598 if (m == NULL) 599 return; 600 } 601 602 #ifdef INET6 603 if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS || 604 so->so_options & SO_TIMESTAMP)) 605 ip6_savecontrol(inp, m, &opts); 606 #endif /* INET6 */ 607 if (ip && (inp->inp_flags & INP_CONTROLOPTS || 608 so->so_options & SO_TIMESTAMP)) 609 ip_savecontrol(inp, &opts, ip, m); 610 #ifdef INET6 611 if (ip6 && (inp->inp_flags & IN6P_RECVDSTPORT)) { 612 struct mbuf **mp = &opts; 613 614 while (*mp) 615 mp = &(*mp)->m_next; 616 *mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t), 617 IPV6_RECVDSTPORT, IPPROTO_IPV6); 618 } 619 #endif /* INET6 */ 620 if (ip && (inp->inp_flags & INP_RECVDSTPORT)) { 621 struct mbuf **mp = &opts; 622 623 while (*mp) 624 mp = &(*mp)->m_next; 625 *mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t), 626 IP_RECVDSTPORT, IPPROTO_IP); 627 } 628 #ifdef IPSEC 629 if (ipsecflowinfo && (inp->inp_flags & INP_IPSECFLOWINFO)) { 630 struct mbuf **mp = &opts; 631 632 while (*mp) 633 mp = &(*mp)->m_next; 634 *mp = sbcreatecontrol((caddr_t)&ipsecflowinfo, 635 sizeof(u_int32_t), IP_IPSECFLOWINFO, IPPROTO_IP); 636 } 637 #endif 638 m_adj(m, hlen); 639 if (sbappendaddr(so, &so->so_rcv, srcaddr, m, opts) == 0) { 640 udpstat_inc(udps_fullsock); 641 m_freem(m); 642 m_freem(opts); 643 return; 644 } 645 sorwakeup(so); 646 } 647 648 /* 649 * Notify a udp user of an asynchronous error; 650 * just wake up so that he can collect error status. 651 */ 652 void 653 udp_notify(struct inpcb *inp, int errno) 654 { 655 inp->inp_socket->so_error = errno; 656 sorwakeup(inp->inp_socket); 657 sowwakeup(inp->inp_socket); 658 } 659 660 #ifdef INET6 661 void 662 udp6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) 663 { 664 struct udphdr uh; 665 struct sockaddr_in6 sa6; 666 struct ip6_hdr *ip6; 667 struct mbuf *m; 668 int off; 669 void *cmdarg; 670 struct ip6ctlparam *ip6cp = NULL; 671 struct udp_portonly { 672 u_int16_t uh_sport; 673 u_int16_t uh_dport; 674 } *uhp; 675 void (*notify)(struct inpcb *, int) = udp_notify; 676 677 if (sa == NULL) 678 return; 679 if (sa->sa_family != AF_INET6 || 680 sa->sa_len != sizeof(struct sockaddr_in6)) 681 return; 682 683 if ((unsigned)cmd >= PRC_NCMDS) 684 return; 685 if (PRC_IS_REDIRECT(cmd)) 686 notify = in_rtchange, d = NULL; 687 else if (cmd == PRC_HOSTDEAD) 688 d = NULL; 689 else if (cmd == PRC_MSGSIZE) 690 ; /* special code is present, see below */ 691 else if (inet6ctlerrmap[cmd] == 0) 692 return; 693 694 /* if the parameter is from icmp6, decode it. */ 695 if (d != NULL) { 696 ip6cp = (struct ip6ctlparam *)d; 697 m = ip6cp->ip6c_m; 698 ip6 = ip6cp->ip6c_ip6; 699 off = ip6cp->ip6c_off; 700 cmdarg = ip6cp->ip6c_cmdarg; 701 } else { 702 m = NULL; 703 ip6 = NULL; 704 cmdarg = NULL; 705 /* XXX: translate addresses into internal form */ 706 sa6 = *satosin6(sa); 707 if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL)) { 708 /* should be impossible */ 709 return; 710 } 711 } 712 713 if (ip6cp && ip6cp->ip6c_finaldst) { 714 bzero(&sa6, sizeof(sa6)); 715 sa6.sin6_family = AF_INET6; 716 sa6.sin6_len = sizeof(sa6); 717 sa6.sin6_addr = *ip6cp->ip6c_finaldst; 718 /* XXX: assuming M is valid in this case */ 719 sa6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx, 720 ip6cp->ip6c_finaldst); 721 if (in6_embedscope(ip6cp->ip6c_finaldst, &sa6, NULL)) { 722 /* should be impossible */ 723 return; 724 } 725 } else { 726 /* XXX: translate addresses into internal form */ 727 sa6 = *satosin6(sa); 728 if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL)) { 729 /* should be impossible */ 730 return; 731 } 732 } 733 734 if (ip6) { 735 /* 736 * XXX: We assume that when IPV6 is non NULL, 737 * M and OFF are valid. 738 */ 739 struct sockaddr_in6 sa6_src; 740 741 /* check if we can safely examine src and dst ports */ 742 if (m->m_pkthdr.len < off + sizeof(*uhp)) 743 return; 744 745 bzero(&uh, sizeof(uh)); 746 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 747 748 bzero(&sa6_src, sizeof(sa6_src)); 749 sa6_src.sin6_family = AF_INET6; 750 sa6_src.sin6_len = sizeof(sa6_src); 751 sa6_src.sin6_addr = ip6->ip6_src; 752 sa6_src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx, 753 &ip6->ip6_src); 754 if (in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL)) { 755 /* should be impossible */ 756 return; 757 } 758 759 if (cmd == PRC_MSGSIZE) { 760 int valid = 0; 761 762 /* 763 * Check to see if we have a valid UDP socket 764 * corresponding to the address in the ICMPv6 message 765 * payload. 766 */ 767 if (in6_pcbhashlookup(&udbtable, &sa6.sin6_addr, 768 uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport, 769 rdomain)) 770 valid = 1; 771 #if 0 772 /* 773 * As the use of sendto(2) is fairly popular, 774 * we may want to allow non-connected pcb too. 775 * But it could be too weak against attacks... 776 * We should at least check if the local address (= s) 777 * is really ours. 778 */ 779 else if (in6_pcblookup_listen(&udbtable, 780 &sa6_src.sin6_addr, uh.uh_sport, NULL, 781 rdomain)) 782 valid = 1; 783 #endif 784 785 /* 786 * Depending on the value of "valid" and routing table 787 * size (mtudisc_{hi,lo}wat), we will: 788 * - recalculate the new MTU and create the 789 * corresponding routing entry, or 790 * - ignore the MTU change notification. 791 */ 792 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 793 794 /* 795 * regardless of if we called icmp6_mtudisc_update(), 796 * we need to call in6_pcbnotify(), to notify path 797 * MTU change to the userland (2292bis-02), because 798 * some unconnected sockets may share the same 799 * destination and want to know the path MTU. 800 */ 801 } 802 803 in6_pcbnotify(&udbtable, &sa6, uh.uh_dport, 804 &sa6_src, uh.uh_sport, rdomain, cmd, cmdarg, notify); 805 } else { 806 in6_pcbnotify(&udbtable, &sa6, 0, 807 &sa6_any, 0, rdomain, cmd, cmdarg, notify); 808 } 809 } 810 #endif 811 812 void 813 udp_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) 814 { 815 struct ip *ip = v; 816 struct udphdr *uhp; 817 struct in_addr faddr; 818 struct inpcb *inp; 819 void (*notify)(struct inpcb *, int) = udp_notify; 820 int errno; 821 822 if (sa == NULL) 823 return; 824 if (sa->sa_family != AF_INET || 825 sa->sa_len != sizeof(struct sockaddr_in)) 826 return; 827 faddr = satosin(sa)->sin_addr; 828 if (faddr.s_addr == INADDR_ANY) 829 return; 830 831 if ((unsigned)cmd >= PRC_NCMDS) 832 return; 833 errno = inetctlerrmap[cmd]; 834 if (PRC_IS_REDIRECT(cmd)) 835 notify = in_rtchange, ip = 0; 836 else if (cmd == PRC_HOSTDEAD) 837 ip = 0; 838 else if (errno == 0) 839 return; 840 if (ip) { 841 uhp = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 842 843 #ifdef IPSEC 844 /* PMTU discovery for udpencap */ 845 if (cmd == PRC_MSGSIZE && ip_mtudisc && udpencap_enable && 846 udpencap_port && uhp->uh_sport == htons(udpencap_port)) { 847 udpencap_ctlinput(cmd, sa, rdomain, v); 848 return; 849 } 850 #endif 851 inp = in_pcbhashlookup(&udbtable, 852 ip->ip_dst, uhp->uh_dport, ip->ip_src, uhp->uh_sport, 853 rdomain); 854 if (inp && inp->inp_socket != NULL) 855 notify(inp, errno); 856 } else 857 in_pcbnotifyall(&udbtable, sa, rdomain, errno, notify); 858 } 859 860 int 861 udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr, 862 struct mbuf *control) 863 { 864 struct sockaddr_in *sin = NULL; 865 struct udpiphdr *ui; 866 u_int32_t ipsecflowinfo = 0; 867 struct sockaddr_in src_sin; 868 int len = m->m_pkthdr.len; 869 struct in_addr *laddr; 870 int error = 0; 871 872 #ifdef DIAGNOSTIC 873 if ((inp->inp_flags & INP_IPV6) != 0) 874 panic("IPv6 inpcb to %s", __func__); 875 #endif 876 877 /* 878 * Compute the packet length of the IP header, and 879 * punt if the length looks bogus. 880 */ 881 if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { 882 error = EMSGSIZE; 883 goto release; 884 } 885 886 memset(&src_sin, 0, sizeof(src_sin)); 887 888 if (control) { 889 u_int clen; 890 struct cmsghdr *cm; 891 caddr_t cmsgs; 892 893 /* 894 * XXX: Currently, we assume all the optional information is 895 * stored in a single mbuf. 896 */ 897 if (control->m_next) { 898 error = EINVAL; 899 goto release; 900 } 901 902 clen = control->m_len; 903 cmsgs = mtod(control, caddr_t); 904 do { 905 if (clen < CMSG_LEN(0)) { 906 error = EINVAL; 907 goto release; 908 } 909 cm = (struct cmsghdr *)cmsgs; 910 if (cm->cmsg_len < CMSG_LEN(0) || 911 CMSG_ALIGN(cm->cmsg_len) > clen) { 912 error = EINVAL; 913 goto release; 914 } 915 #ifdef IPSEC 916 if ((inp->inp_flags & INP_IPSECFLOWINFO) != 0 && 917 cm->cmsg_len == CMSG_LEN(sizeof(ipsecflowinfo)) && 918 cm->cmsg_level == IPPROTO_IP && 919 cm->cmsg_type == IP_IPSECFLOWINFO) { 920 ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm); 921 } else 922 #endif 923 if (cm->cmsg_len == CMSG_LEN(sizeof(struct in_addr)) && 924 cm->cmsg_level == IPPROTO_IP && 925 cm->cmsg_type == IP_SENDSRCADDR) { 926 memcpy(&src_sin.sin_addr, CMSG_DATA(cm), 927 sizeof(struct in_addr)); 928 src_sin.sin_family = AF_INET; 929 src_sin.sin_len = sizeof(src_sin); 930 /* no check on reuse when sin->sin_port == 0 */ 931 if ((error = in_pcbaddrisavail(inp, &src_sin, 932 0, curproc))) 933 goto release; 934 } 935 clen -= CMSG_ALIGN(cm->cmsg_len); 936 cmsgs += CMSG_ALIGN(cm->cmsg_len); 937 } while (clen); 938 } 939 940 if (addr) { 941 if ((error = in_nam2sin(addr, &sin))) 942 goto release; 943 if (sin->sin_port == 0) { 944 error = EADDRNOTAVAIL; 945 goto release; 946 } 947 if (inp->inp_faddr.s_addr != INADDR_ANY) { 948 error = EISCONN; 949 goto release; 950 } 951 error = in_pcbselsrc(&laddr, sin, inp); 952 if (error) 953 goto release; 954 955 if (inp->inp_lport == 0) { 956 error = in_pcbbind(inp, NULL, curproc); 957 if (error) 958 goto release; 959 } 960 961 if (src_sin.sin_len > 0 && 962 src_sin.sin_addr.s_addr != INADDR_ANY && 963 src_sin.sin_addr.s_addr != inp->inp_laddr.s_addr) { 964 src_sin.sin_port = inp->inp_lport; 965 if (inp->inp_laddr.s_addr != INADDR_ANY && 966 (error = 967 in_pcbaddrisavail(inp, &src_sin, 0, curproc))) 968 goto release; 969 laddr = &src_sin.sin_addr; 970 } 971 } else { 972 if (inp->inp_faddr.s_addr == INADDR_ANY) { 973 error = ENOTCONN; 974 goto release; 975 } 976 laddr = &inp->inp_laddr; 977 } 978 979 /* 980 * Calculate data length and get a mbuf 981 * for UDP and IP headers. 982 */ 983 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 984 if (m == NULL) { 985 error = ENOBUFS; 986 goto bail; 987 } 988 989 /* 990 * Fill in mbuf with extended UDP header 991 * and addresses and length put into network format. 992 */ 993 ui = mtod(m, struct udpiphdr *); 994 bzero(ui->ui_x1, sizeof ui->ui_x1); 995 ui->ui_pr = IPPROTO_UDP; 996 ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); 997 ui->ui_src = *laddr; 998 ui->ui_dst = sin ? sin->sin_addr : inp->inp_faddr; 999 ui->ui_sport = inp->inp_lport; 1000 ui->ui_dport = sin ? sin->sin_port : inp->inp_fport; 1001 ui->ui_ulen = ui->ui_len; 1002 ((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len); 1003 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; 1004 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; 1005 if (udpcksum) 1006 m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; 1007 1008 udpstat_inc(udps_opackets); 1009 1010 /* force routing table */ 1011 m->m_pkthdr.ph_rtableid = inp->inp_rtableid; 1012 1013 #if NPF > 0 1014 if (inp->inp_socket->so_state & SS_ISCONNECTED) 1015 pf_mbuf_link_inpcb(m, inp); 1016 #endif 1017 1018 error = ip_output(m, inp->inp_options, &inp->inp_route, 1019 (inp->inp_socket->so_options & SO_BROADCAST), inp->inp_moptions, 1020 inp, ipsecflowinfo); 1021 1022 bail: 1023 m_freem(control); 1024 return (error); 1025 1026 release: 1027 m_freem(m); 1028 goto bail; 1029 } 1030 1031 /*ARGSUSED*/ 1032 int 1033 udp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr, 1034 struct mbuf *control, struct proc *p) 1035 { 1036 struct inpcb *inp; 1037 int error = 0; 1038 1039 if (req == PRU_CONTROL) { 1040 #ifdef INET6 1041 if (sotopf(so) == PF_INET6) 1042 return (in6_control(so, (u_long)m, (caddr_t)addr, 1043 (struct ifnet *)control)); 1044 else 1045 #endif /* INET6 */ 1046 return (in_control(so, (u_long)m, (caddr_t)addr, 1047 (struct ifnet *)control)); 1048 } 1049 1050 soassertlocked(so); 1051 1052 inp = sotoinpcb(so); 1053 if (inp == NULL) { 1054 error = EINVAL; 1055 goto release; 1056 } 1057 1058 /* 1059 * Note: need to block udp_input while changing 1060 * the udp pcb queue and/or pcb addresses. 1061 */ 1062 switch (req) { 1063 1064 case PRU_BIND: 1065 error = in_pcbbind(inp, addr, p); 1066 break; 1067 1068 case PRU_LISTEN: 1069 error = EOPNOTSUPP; 1070 break; 1071 1072 case PRU_CONNECT: 1073 #ifdef INET6 1074 if (inp->inp_flags & INP_IPV6) { 1075 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) { 1076 error = EISCONN; 1077 break; 1078 } 1079 error = in6_pcbconnect(inp, addr); 1080 } else 1081 #endif /* INET6 */ 1082 { 1083 if (inp->inp_faddr.s_addr != INADDR_ANY) { 1084 error = EISCONN; 1085 break; 1086 } 1087 error = in_pcbconnect(inp, addr); 1088 } 1089 1090 if (error == 0) 1091 soisconnected(so); 1092 break; 1093 1094 case PRU_CONNECT2: 1095 error = EOPNOTSUPP; 1096 break; 1097 1098 case PRU_ACCEPT: 1099 error = EOPNOTSUPP; 1100 break; 1101 1102 case PRU_DISCONNECT: 1103 #ifdef INET6 1104 if (inp->inp_flags & INP_IPV6) { 1105 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) { 1106 error = ENOTCONN; 1107 break; 1108 } 1109 } else 1110 #endif /* INET6 */ 1111 { 1112 if (inp->inp_faddr.s_addr == INADDR_ANY) { 1113 error = ENOTCONN; 1114 break; 1115 } 1116 } 1117 1118 #ifdef INET6 1119 if (inp->inp_flags & INP_IPV6) 1120 inp->inp_laddr6 = in6addr_any; 1121 else 1122 #endif /* INET6 */ 1123 inp->inp_laddr.s_addr = INADDR_ANY; 1124 in_pcbdisconnect(inp); 1125 1126 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 1127 break; 1128 1129 case PRU_SHUTDOWN: 1130 socantsendmore(so); 1131 break; 1132 1133 case PRU_SEND: 1134 #ifdef PIPEX 1135 if (inp->inp_pipex) { 1136 struct pipex_session *session; 1137 1138 if (addr != NULL) 1139 session = 1140 pipex_l2tp_userland_lookup_session(m, 1141 mtod(addr, struct sockaddr *)); 1142 else 1143 #ifdef INET6 1144 if (inp->inp_flags & INP_IPV6) 1145 session = 1146 pipex_l2tp_userland_lookup_session_ipv6( 1147 m, inp->inp_faddr6); 1148 else 1149 #endif 1150 session = 1151 pipex_l2tp_userland_lookup_session_ipv4( 1152 m, inp->inp_faddr); 1153 if (session != NULL) 1154 if ((m = pipex_l2tp_userland_output( 1155 m, session)) == NULL) { 1156 error = ENOMEM; 1157 goto release; 1158 } 1159 } 1160 #endif 1161 1162 #ifdef INET6 1163 if (inp->inp_flags & INP_IPV6) 1164 error = udp6_output(inp, m, addr, control); 1165 else 1166 #endif 1167 error = udp_output(inp, m, addr, control); 1168 return (error); 1169 1170 case PRU_ABORT: 1171 soisdisconnected(so); 1172 in_pcbdetach(inp); 1173 break; 1174 1175 case PRU_SOCKADDR: 1176 #ifdef INET6 1177 if (inp->inp_flags & INP_IPV6) 1178 in6_setsockaddr(inp, addr); 1179 else 1180 #endif /* INET6 */ 1181 in_setsockaddr(inp, addr); 1182 break; 1183 1184 case PRU_PEERADDR: 1185 #ifdef INET6 1186 if (inp->inp_flags & INP_IPV6) 1187 in6_setpeeraddr(inp, addr); 1188 else 1189 #endif /* INET6 */ 1190 in_setpeeraddr(inp, addr); 1191 break; 1192 1193 case PRU_SENSE: 1194 /* 1195 * stat: don't bother with a blocksize. 1196 */ 1197 /* 1198 * Perhaps Path MTU might be returned for a connected 1199 * UDP socket in this case. 1200 */ 1201 break; 1202 1203 case PRU_SENDOOB: 1204 case PRU_FASTTIMO: 1205 case PRU_SLOWTIMO: 1206 case PRU_PROTORCV: 1207 case PRU_PROTOSEND: 1208 case PRU_RCVD: 1209 case PRU_RCVOOB: 1210 error = EOPNOTSUPP; 1211 break; 1212 1213 default: 1214 panic("udp_usrreq"); 1215 } 1216 release: 1217 if (req != PRU_RCVD && req != PRU_RCVOOB && req != PRU_SENSE) { 1218 m_freem(control); 1219 m_freem(m); 1220 } 1221 return (error); 1222 } 1223 1224 int 1225 udp_attach(struct socket *so, int proto) 1226 { 1227 int error; 1228 1229 if (so->so_pcb != NULL) 1230 return EINVAL; 1231 1232 if ((error = soreserve(so, udp_sendspace, udp_recvspace))) 1233 return error; 1234 1235 NET_ASSERT_LOCKED(); 1236 if ((error = in_pcballoc(so, &udbtable))) 1237 return error; 1238 #ifdef INET6 1239 if (sotoinpcb(so)->inp_flags & INP_IPV6) 1240 sotoinpcb(so)->inp_ipv6.ip6_hlim = ip6_defhlim; 1241 else 1242 #endif /* INET6 */ 1243 sotoinpcb(so)->inp_ip.ip_ttl = ip_defttl; 1244 return 0; 1245 } 1246 1247 int 1248 udp_detach(struct socket *so) 1249 { 1250 struct inpcb *inp; 1251 1252 soassertlocked(so); 1253 1254 inp = sotoinpcb(so); 1255 if (inp == NULL) 1256 return (EINVAL); 1257 1258 in_pcbdetach(inp); 1259 return (0); 1260 } 1261 1262 /* 1263 * Sysctl for udp variables. 1264 */ 1265 int 1266 udp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 1267 size_t newlen) 1268 { 1269 int error; 1270 1271 /* All sysctl names at this level are terminal. */ 1272 if (namelen != 1) 1273 return (ENOTDIR); 1274 1275 switch (name[0]) { 1276 case UDPCTL_BADDYNAMIC: 1277 NET_LOCK(); 1278 error = sysctl_struct(oldp, oldlenp, newp, newlen, 1279 baddynamicports.udp, sizeof(baddynamicports.udp)); 1280 NET_UNLOCK(); 1281 return (error); 1282 1283 case UDPCTL_ROOTONLY: 1284 if (newp && securelevel > 0) 1285 return (EPERM); 1286 NET_LOCK(); 1287 error = sysctl_struct(oldp, oldlenp, newp, newlen, 1288 rootonlyports.udp, sizeof(rootonlyports.udp)); 1289 NET_UNLOCK(); 1290 return (error); 1291 1292 case UDPCTL_STATS: 1293 if (newp != NULL) 1294 return (EPERM); 1295 1296 return (udp_sysctl_udpstat(oldp, oldlenp, newp)); 1297 1298 default: 1299 NET_LOCK(); 1300 error = sysctl_bounded_arr(udpctl_vars, nitems(udpctl_vars), 1301 name, namelen, oldp, oldlenp, newp, newlen); 1302 NET_UNLOCK(); 1303 return (error); 1304 } 1305 /* NOTREACHED */ 1306 } 1307 1308 int 1309 udp_sysctl_udpstat(void *oldp, size_t *oldlenp, void *newp) 1310 { 1311 uint64_t counters[udps_ncounters]; 1312 struct udpstat udpstat; 1313 u_long *words = (u_long *)&udpstat; 1314 int i; 1315 1316 CTASSERT(sizeof(udpstat) == (nitems(counters) * sizeof(u_long))); 1317 memset(&udpstat, 0, sizeof udpstat); 1318 counters_read(udpcounters, counters, nitems(counters)); 1319 1320 for (i = 0; i < nitems(counters); i++) 1321 words[i] = (u_long)counters[i]; 1322 1323 return (sysctl_rdstruct(oldp, oldlenp, newp, 1324 &udpstat, sizeof(udpstat))); 1325 } 1326