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