1 /* $OpenBSD: udp_usrreq.c,v 1.264 2021/11/11 18:08:18 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 #ifdef IPSEC 177 struct m_tag *mtag; 178 struct tdb_ident *tdbi; 179 struct tdb *tdb; 180 int error, protoff; 181 #endif /* IPSEC */ 182 u_int32_t ipsecflowinfo = 0; 183 184 udpstat_inc(udps_ipackets); 185 186 IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); 187 if (!uh) { 188 udpstat_inc(udps_hdrops); 189 return IPPROTO_DONE; 190 } 191 192 /* Check for illegal destination port 0 */ 193 if (uh->uh_dport == 0) { 194 udpstat_inc(udps_noport); 195 goto bad; 196 } 197 198 /* 199 * Make mbuf data length reflect UDP length. 200 * If not enough data to reflect UDP length, drop. 201 */ 202 len = ntohs((u_int16_t)uh->uh_ulen); 203 switch (af) { 204 case AF_INET: 205 if (m->m_pkthdr.len - iphlen != len) { 206 if (len > (m->m_pkthdr.len - iphlen) || 207 len < sizeof(struct udphdr)) { 208 udpstat_inc(udps_badlen); 209 goto bad; 210 } 211 m_adj(m, len - (m->m_pkthdr.len - iphlen)); 212 } 213 ip = mtod(m, struct ip *); 214 /* 215 * Save a copy of the IP header in case we want restore it 216 * for sending an ICMP error message in response. 217 */ 218 save_ip = *ip; 219 break; 220 #ifdef INET6 221 case AF_INET6: 222 /* jumbograms */ 223 if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff) 224 len = m->m_pkthdr.len - iphlen; 225 if (len != m->m_pkthdr.len - iphlen) { 226 udpstat_inc(udps_badlen); 227 goto bad; 228 } 229 ip6 = mtod(m, struct ip6_hdr *); 230 break; 231 #endif /* INET6 */ 232 default: 233 unhandled_af(af); 234 } 235 236 /* 237 * Checksum extended UDP header and data. 238 * from W.R.Stevens: check incoming udp cksums even if 239 * udpcksum is not set. 240 */ 241 savesum = uh->uh_sum; 242 if (uh->uh_sum == 0) { 243 udpstat_inc(udps_nosum); 244 #ifdef INET6 245 /* 246 * In IPv6, the UDP checksum is ALWAYS used. 247 */ 248 if (ip6) 249 goto bad; 250 #endif /* INET6 */ 251 } else { 252 if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) { 253 if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) { 254 udpstat_inc(udps_badsum); 255 goto bad; 256 } 257 udpstat_inc(udps_inswcsum); 258 259 if (ip) 260 uh->uh_sum = in4_cksum(m, IPPROTO_UDP, 261 iphlen, len); 262 #ifdef INET6 263 else if (ip6) 264 uh->uh_sum = in6_cksum(m, IPPROTO_UDP, 265 iphlen, len); 266 #endif /* INET6 */ 267 if (uh->uh_sum != 0) { 268 udpstat_inc(udps_badsum); 269 goto bad; 270 } 271 } 272 } 273 274 #ifdef IPSEC 275 if (udpencap_enable && udpencap_port && esp_enable && 276 #if NPF > 0 277 !(m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) && 278 #endif 279 uh->uh_dport == htons(udpencap_port)) { 280 u_int32_t spi; 281 int skip = iphlen + sizeof(struct udphdr); 282 283 if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) { 284 /* packet too short */ 285 m_freem(m); 286 return IPPROTO_DONE; 287 } 288 m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); 289 /* 290 * decapsulate if the SPI is not zero, otherwise pass 291 * to userland 292 */ 293 if (spi != 0) { 294 if ((m = *mp = m_pullup(m, skip)) == NULL) { 295 udpstat_inc(udps_hdrops); 296 return IPPROTO_DONE; 297 } 298 299 /* remove the UDP header */ 300 bcopy(mtod(m, u_char *), 301 mtod(m, u_char *) + sizeof(struct udphdr), iphlen); 302 m_adj(m, sizeof(struct udphdr)); 303 skip -= sizeof(struct udphdr); 304 305 espstat_inc(esps_udpencin); 306 protoff = af == AF_INET ? offsetof(struct ip, ip_p) : 307 offsetof(struct ip6_hdr, ip6_nxt); 308 return ipsec_common_input(mp, skip, protoff, 309 af, IPPROTO_ESP, 1); 310 } 311 } 312 #endif 313 314 switch (af) { 315 case AF_INET: 316 bzero(&srcsa, sizeof(struct sockaddr_in)); 317 srcsa.sin.sin_len = sizeof(struct sockaddr_in); 318 srcsa.sin.sin_family = AF_INET; 319 srcsa.sin.sin_port = uh->uh_sport; 320 srcsa.sin.sin_addr = ip->ip_src; 321 322 bzero(&dstsa, sizeof(struct sockaddr_in)); 323 dstsa.sin.sin_len = sizeof(struct sockaddr_in); 324 dstsa.sin.sin_family = AF_INET; 325 dstsa.sin.sin_port = uh->uh_dport; 326 dstsa.sin.sin_addr = ip->ip_dst; 327 break; 328 #ifdef INET6 329 case AF_INET6: 330 bzero(&srcsa, sizeof(struct sockaddr_in6)); 331 srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6); 332 srcsa.sin6.sin6_family = AF_INET6; 333 srcsa.sin6.sin6_port = uh->uh_sport; 334 #if 0 /*XXX inbound flowinfo */ 335 srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow; 336 #endif 337 /* KAME hack: recover scopeid */ 338 in6_recoverscope(&srcsa.sin6, &ip6->ip6_src); 339 340 bzero(&dstsa, sizeof(struct sockaddr_in6)); 341 dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6); 342 dstsa.sin6.sin6_family = AF_INET6; 343 dstsa.sin6.sin6_port = uh->uh_dport; 344 #if 0 /*XXX inbound flowinfo */ 345 dstsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow; 346 #endif 347 /* KAME hack: recover scopeid */ 348 in6_recoverscope(&dstsa.sin6, &ip6->ip6_dst); 349 break; 350 #endif /* INET6 */ 351 } 352 353 #if NVXLAN > 0 354 if (vxlan_enable > 0 && 355 #if NPF > 0 356 !(m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) && 357 #endif 358 vxlan_lookup(m, uh, iphlen, &srcsa.sa, &dstsa.sa) != 0) 359 return IPPROTO_DONE; 360 #endif 361 362 if (m->m_flags & (M_BCAST|M_MCAST)) { 363 struct inpcb *last; 364 /* 365 * Deliver a multicast or broadcast datagram to *all* sockets 366 * for which the local and remote addresses and ports match 367 * those of the incoming datagram. This allows more than 368 * one process to receive multi/broadcasts on the same port. 369 * (This really ought to be done for unicast datagrams as 370 * well, but that would cause problems with existing 371 * applications that open both address-specific sockets and 372 * a wildcard socket listening to the same port -- they would 373 * end up receiving duplicates of every unicast datagram. 374 * Those applications open the multiple sockets to overcome an 375 * inadequacy of the UDP socket interface, but for backwards 376 * compatibility we avoid the problem here rather than 377 * fixing the interface. Maybe 4.5BSD will remedy this?) 378 */ 379 380 /* 381 * Locate pcb(s) for datagram. 382 * (Algorithm copied from raw_intr().) 383 */ 384 last = NULL; 385 NET_ASSERT_LOCKED(); 386 TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) { 387 if (inp->inp_socket->so_state & SS_CANTRCVMORE) 388 continue; 389 #ifdef INET6 390 /* don't accept it if AF does not match */ 391 if (ip6 && !(inp->inp_flags & INP_IPV6)) 392 continue; 393 if (!ip6 && (inp->inp_flags & INP_IPV6)) 394 continue; 395 #endif 396 if (rtable_l2(inp->inp_rtableid) != 397 rtable_l2(m->m_pkthdr.ph_rtableid)) 398 continue; 399 if (inp->inp_lport != uh->uh_dport) 400 continue; 401 #ifdef INET6 402 if (ip6) { 403 if (inp->inp_ip6_minhlim && 404 inp->inp_ip6_minhlim > ip6->ip6_hlim) 405 continue; 406 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) 407 if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, 408 &ip6->ip6_dst)) 409 continue; 410 } else 411 #endif /* INET6 */ 412 { 413 if (inp->inp_ip_minttl && 414 inp->inp_ip_minttl > ip->ip_ttl) 415 continue; 416 417 if (inp->inp_laddr.s_addr != INADDR_ANY) { 418 if (inp->inp_laddr.s_addr != 419 ip->ip_dst.s_addr) 420 continue; 421 } 422 } 423 #ifdef INET6 424 if (ip6) { 425 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) 426 if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, 427 &ip6->ip6_src) || 428 inp->inp_fport != uh->uh_sport) 429 continue; 430 } else 431 #endif /* INET6 */ 432 if (inp->inp_faddr.s_addr != INADDR_ANY) { 433 if (inp->inp_faddr.s_addr != 434 ip->ip_src.s_addr || 435 inp->inp_fport != uh->uh_sport) 436 continue; 437 } 438 439 if (last != NULL) { 440 struct mbuf *n; 441 442 n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 443 if (n != NULL) { 444 udp_sbappend(last, n, ip, ip6, iphlen, 445 uh, &srcsa.sa, 0); 446 } 447 } 448 last = inp; 449 /* 450 * Don't look for additional matches if this one does 451 * not have either the SO_REUSEPORT or SO_REUSEADDR 452 * socket options set. This heuristic avoids searching 453 * through all pcbs in the common case of a non-shared 454 * port. It assumes that an application will never 455 * clear these options after setting them. 456 */ 457 if ((last->inp_socket->so_options & (SO_REUSEPORT | 458 SO_REUSEADDR)) == 0) 459 break; 460 } 461 462 if (last == NULL) { 463 /* 464 * No matching pcb found; discard datagram. 465 * (No need to send an ICMP Port Unreachable 466 * for a broadcast or multicast datgram.) 467 */ 468 udpstat_inc(udps_noportbcast); 469 goto bad; 470 } 471 472 udp_sbappend(last, m, ip, ip6, iphlen, uh, &srcsa.sa, 0); 473 return IPPROTO_DONE; 474 } 475 /* 476 * Locate pcb for datagram. 477 */ 478 #if NPF > 0 479 inp = pf_inp_lookup(m); 480 #endif 481 if (inp == NULL) { 482 #ifdef INET6 483 if (ip6) 484 inp = in6_pcbhashlookup(&udbtable, &ip6->ip6_src, 485 uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 486 m->m_pkthdr.ph_rtableid); 487 else 488 #endif /* INET6 */ 489 inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport, 490 ip->ip_dst, uh->uh_dport, m->m_pkthdr.ph_rtableid); 491 } 492 if (inp == NULL) { 493 udpstat_inc(udps_pcbhashmiss); 494 #ifdef INET6 495 if (ip6) { 496 inp = in6_pcblookup_listen(&udbtable, &ip6->ip6_dst, 497 uh->uh_dport, m, m->m_pkthdr.ph_rtableid); 498 } else 499 #endif /* INET6 */ 500 inp = in_pcblookup_listen(&udbtable, ip->ip_dst, 501 uh->uh_dport, m, m->m_pkthdr.ph_rtableid); 502 } 503 504 #ifdef IPSEC 505 if (ipsec_in_use) { 506 mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 507 if (mtag != NULL) { 508 tdbi = (struct tdb_ident *)(mtag + 1); 509 tdb = gettdb(tdbi->rdomain, tdbi->spi, 510 &tdbi->dst, tdbi->proto); 511 } else 512 tdb = NULL; 513 ipsp_spd_lookup(m, af, iphlen, &error, 514 IPSP_DIRECTION_IN, tdb, inp, 0); 515 if (error) { 516 udpstat_inc(udps_nosec); 517 goto bad; 518 } 519 /* create ipsec options while we know that tdb cannot be modified */ 520 if (tdb && tdb->tdb_ids) 521 ipsecflowinfo = tdb->tdb_ids->id_flow; 522 } 523 #endif /*IPSEC */ 524 525 if (inp == NULL) { 526 udpstat_inc(udps_noport); 527 if (m->m_flags & (M_BCAST | M_MCAST)) { 528 udpstat_inc(udps_noportbcast); 529 goto bad; 530 } 531 #ifdef INET6 532 if (ip6) { 533 uh->uh_sum = savesum; 534 icmp6_error(m, ICMP6_DST_UNREACH, 535 ICMP6_DST_UNREACH_NOPORT,0); 536 } else 537 #endif /* INET6 */ 538 { 539 *ip = save_ip; 540 uh->uh_sum = savesum; 541 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 542 0, 0); 543 } 544 return IPPROTO_DONE; 545 } 546 547 KASSERT(sotoinpcb(inp->inp_socket) == inp); 548 soassertlocked(inp->inp_socket); 549 550 #ifdef INET6 551 if (ip6 && inp->inp_ip6_minhlim && 552 inp->inp_ip6_minhlim > ip6->ip6_hlim) { 553 goto bad; 554 } else 555 #endif 556 if (ip && inp->inp_ip_minttl && 557 inp->inp_ip_minttl > ip->ip_ttl) { 558 goto bad; 559 } 560 561 #if NPF > 0 562 if (inp->inp_socket->so_state & SS_ISCONNECTED) 563 pf_inp_link(m, inp); 564 #endif 565 566 #ifdef PIPEX 567 if (pipex_enable && inp->inp_pipex) { 568 struct pipex_session *session; 569 int off = iphlen + sizeof(struct udphdr); 570 if ((session = pipex_l2tp_lookup_session(m, off)) != NULL) { 571 if ((m = *mp = pipex_l2tp_input(m, off, session, 572 ipsecflowinfo)) == NULL) { 573 /* the packet is handled by PIPEX */ 574 return IPPROTO_DONE; 575 } 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 (void) in6_pcbnotify(&udbtable, &sa6, uh.uh_dport, 806 &sa6_src, uh.uh_sport, rdomain, cmd, cmdarg, notify); 807 } else { 808 (void) 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 if ((m = pipex_l2tp_userland_output( 1157 m, session)) == NULL) { 1158 error = ENOMEM; 1159 goto release; 1160 } 1161 } 1162 #endif 1163 1164 #ifdef INET6 1165 if (inp->inp_flags & INP_IPV6) 1166 error = udp6_output(inp, m, addr, control); 1167 else 1168 #endif 1169 error = udp_output(inp, m, addr, control); 1170 return (error); 1171 1172 case PRU_ABORT: 1173 soisdisconnected(so); 1174 in_pcbdetach(inp); 1175 break; 1176 1177 case PRU_SOCKADDR: 1178 #ifdef INET6 1179 if (inp->inp_flags & INP_IPV6) 1180 in6_setsockaddr(inp, addr); 1181 else 1182 #endif /* INET6 */ 1183 in_setsockaddr(inp, addr); 1184 break; 1185 1186 case PRU_PEERADDR: 1187 #ifdef INET6 1188 if (inp->inp_flags & INP_IPV6) 1189 in6_setpeeraddr(inp, addr); 1190 else 1191 #endif /* INET6 */ 1192 in_setpeeraddr(inp, addr); 1193 break; 1194 1195 case PRU_SENSE: 1196 /* 1197 * stat: don't bother with a blocksize. 1198 */ 1199 /* 1200 * Perhaps Path MTU might be returned for a connected 1201 * UDP socket in this case. 1202 */ 1203 break; 1204 1205 case PRU_SENDOOB: 1206 case PRU_FASTTIMO: 1207 case PRU_SLOWTIMO: 1208 case PRU_PROTORCV: 1209 case PRU_PROTOSEND: 1210 case PRU_RCVD: 1211 case PRU_RCVOOB: 1212 error = EOPNOTSUPP; 1213 break; 1214 1215 default: 1216 panic("udp_usrreq"); 1217 } 1218 release: 1219 if (req != PRU_RCVD && req != PRU_RCVOOB && req != PRU_SENSE) { 1220 m_freem(control); 1221 m_freem(m); 1222 } 1223 return (error); 1224 } 1225 1226 int 1227 udp_attach(struct socket *so, int proto) 1228 { 1229 int error; 1230 1231 if (so->so_pcb != NULL) 1232 return EINVAL; 1233 1234 if ((error = soreserve(so, udp_sendspace, udp_recvspace))) 1235 return error; 1236 1237 NET_ASSERT_LOCKED(); 1238 if ((error = in_pcballoc(so, &udbtable))) 1239 return error; 1240 #ifdef INET6 1241 if (sotoinpcb(so)->inp_flags & INP_IPV6) 1242 sotoinpcb(so)->inp_ipv6.ip6_hlim = ip6_defhlim; 1243 else 1244 #endif /* INET6 */ 1245 sotoinpcb(so)->inp_ip.ip_ttl = ip_defttl; 1246 return 0; 1247 } 1248 1249 int 1250 udp_detach(struct socket *so) 1251 { 1252 struct inpcb *inp; 1253 1254 soassertlocked(so); 1255 1256 inp = sotoinpcb(so); 1257 if (inp == NULL) 1258 return (EINVAL); 1259 1260 in_pcbdetach(inp); 1261 return (0); 1262 } 1263 1264 /* 1265 * Sysctl for udp variables. 1266 */ 1267 int 1268 udp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 1269 size_t newlen) 1270 { 1271 int error; 1272 1273 /* All sysctl names at this level are terminal. */ 1274 if (namelen != 1) 1275 return (ENOTDIR); 1276 1277 switch (name[0]) { 1278 case UDPCTL_BADDYNAMIC: 1279 NET_LOCK(); 1280 error = sysctl_struct(oldp, oldlenp, newp, newlen, 1281 baddynamicports.udp, sizeof(baddynamicports.udp)); 1282 NET_UNLOCK(); 1283 return (error); 1284 1285 case UDPCTL_ROOTONLY: 1286 if (newp && securelevel > 0) 1287 return (EPERM); 1288 NET_LOCK(); 1289 error = sysctl_struct(oldp, oldlenp, newp, newlen, 1290 rootonlyports.udp, sizeof(rootonlyports.udp)); 1291 NET_UNLOCK(); 1292 return (error); 1293 1294 case UDPCTL_STATS: 1295 if (newp != NULL) 1296 return (EPERM); 1297 1298 return (udp_sysctl_udpstat(oldp, oldlenp, newp)); 1299 1300 default: 1301 NET_LOCK(); 1302 error = sysctl_bounded_arr(udpctl_vars, nitems(udpctl_vars), 1303 name, namelen, oldp, oldlenp, newp, newlen); 1304 NET_UNLOCK(); 1305 return (error); 1306 } 1307 /* NOTREACHED */ 1308 } 1309 1310 int 1311 udp_sysctl_udpstat(void *oldp, size_t *oldlenp, void *newp) 1312 { 1313 uint64_t counters[udps_ncounters]; 1314 struct udpstat udpstat; 1315 u_long *words = (u_long *)&udpstat; 1316 int i; 1317 1318 CTASSERT(sizeof(udpstat) == (nitems(counters) * sizeof(u_long))); 1319 memset(&udpstat, 0, sizeof udpstat); 1320 counters_read(udpcounters, counters, nitems(counters)); 1321 1322 for (i = 0; i < nitems(counters); i++) 1323 words[i] = (u_long)counters[i]; 1324 1325 return (sysctl_rdstruct(oldp, oldlenp, newp, 1326 &udpstat, sizeof(udpstat))); 1327 } 1328