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