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