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
udp_init(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
udp_input(struct mbuf ** mp,int * offp,int proto,int af)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
udp_sbappend(struct inpcb * inp,struct mbuf * m,struct ip * ip,struct ip6_hdr * ip6,int hlen,struct udphdr * uh,struct sockaddr * srcaddr,u_int32_t ipsecflowinfo)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
udp_notify(struct inpcb * inp,int errno)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
udp6_ctlinput(int cmd,struct sockaddr * sa,u_int rdomain,void * d)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
udp_ctlinput(int cmd,struct sockaddr * sa,u_int rdomain,void * v)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
udp_output(struct inpcb * inp,struct mbuf * m,struct mbuf * addr,struct mbuf * control)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
udp_attach(struct socket * so,int proto,int wait)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
udp_detach(struct socket * so)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
udp_bind(struct socket * so,struct mbuf * addr,struct proc * p)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
udp_connect(struct socket * so,struct mbuf * addr)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
udp_disconnect(struct socket * so)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
udp_shutdown(struct socket * so)1203 udp_shutdown(struct socket *so)
1204 {
1205 soassertlocked(so);
1206 socantsendmore(so);
1207 return (0);
1208 }
1209
1210 int
udp_send(struct socket * so,struct mbuf * m,struct mbuf * addr,struct mbuf * control)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
udp_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)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
udp_sysctl_locked(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)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
udp_sysctl_udpstat(void * oldp,size_t * oldlenp,void * newp)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