Page MenuHomeFreeBSD

D60967.1793476304.diff
No OneTemporary

Authored By
Unknown
Size
4 KB
Referenced Files
None
Subscribers
None

D60967.1793476304.diff

diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -578,23 +578,27 @@
bzero(&uh, sizeof(uh));
m_copydata(m, off, sizeof(*uhp), &uh);
- /* Check to see if its tunneled */
- inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_dst, uh.uh_dport,
- &ip6->ip6_src, uh.uh_sport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB,
- m->m_pkthdr.rcvif, m);
+ inp = in6_pcblookup(pcbinfo, &ip6->ip6_dst, uh.uh_dport, &ip6->ip6_src,
+ uh.uh_sport, INPLOOKUP_WLOCKPCB, NULL);
if (inp != NULL) {
- struct udpcb *up;
- udp_tun_icmp_t *func;
-
- up = intoudpcb(inp);
- func = up->u_icmp_func;
- INP_RUNLOCK(inp);
- if (func != NULL)
- func(ip6cp);
+ INP_WLOCK_ASSERT(inp);
+ udp_notify(inp, errno);
+ INP_WUNLOCK(inp);
+ } else {
+ inp = in6_pcblookup(pcbinfo, &ip6->ip6_dst, uh.uh_dport,
+ &ip6->ip6_src, uh.uh_sport,
+ INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
+ if (inp != NULL) {
+ struct udpcb *up;
+ udp_tun_icmp_t *func;
+
+ up = intoudpcb(inp);
+ func = up->u_icmp_func;
+ INP_RUNLOCK(inp);
+ if (func != NULL)
+ func(ip6cp);
+ }
}
- in6_pcbnotify(pcbinfo, ip6cp->ip6c_finaldst, uh.uh_dport,
- ip6cp->ip6c_src, uh.uh_sport, errno, ip6cp->ip6c_cmdarg,
- udp_notify);
}
static void
diff --git a/tests/sys/netinet6/Makefile b/tests/sys/netinet6/Makefile
--- a/tests/sys/netinet6/Makefile
+++ b/tests/sys/netinet6/Makefile
@@ -4,6 +4,7 @@
BINDIR= ${TESTSDIR}
FILESDIR= ${TESTSDIR}
+ATF_TESTS_C= udp6
ATF_TESTS_PYTEST= test_ip6_output.py
ATF_TESTS_SH= exthdr \
mld \
diff --git a/tests/sys/netinet6/udp6.c b/tests/sys/netinet6/udp6.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/netinet6/udp6.c
@@ -0,0 +1,97 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Gleb Smirnoff <glebius@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <atf-c.h>
+
+static int
+connectedsock(void)
+{
+ struct sockaddr_in6 sa = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(sa),
+ .sin6_port = htons(1638),
+ .sin6_addr = IN6ADDR_LOOPBACK_INIT,
+ };
+ int s;
+
+ ATF_REQUIRE((s = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0);
+ ATF_REQUIRE(connect(s, (struct sockaddr *)&sa, sizeof(sa)) == 0);
+ return (s);
+}
+
+static void
+REQUIRE_SO_ERROR(int s, int expected)
+{
+ socklen_t len = sizeof(int);
+ int error;
+
+ ATF_REQUIRE(getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == 0);
+ ATF_REQUIRE_MSG(error == expected,
+ "SO_ERROR: got %d (%s), expected %d (%s)",
+ error, strerror(error), expected, strerror(expected));
+}
+
+/*
+ * Two connected sockets to the same remote address and port. Kernel will
+ * assign different local ports to them. Trigger ICMPv6 Port Unreachable for
+ * each (kernel generates it). Assert that only one of them is notified.
+ * XXX: the remote is actually ::1 and the test relies on port being
+ * unreachable.
+ */
+ATF_TC_WITHOUT_HEAD(icmp_port_unreach_notify);
+ATF_TC_BODY(icmp_port_unreach_notify, tc)
+{
+ const char buf[] = "probe";
+ int s1, s2;
+
+ s1 = connectedsock();
+ s2 = connectedsock();
+ ATF_REQUIRE(send(s1, buf, sizeof(buf), 0) == sizeof(buf));
+ usleep(100000);
+ REQUIRE_SO_ERROR(s1, ECONNREFUSED);
+ REQUIRE_SO_ERROR(s2, 0);
+ ATF_REQUIRE(send(s2, buf, sizeof(buf), 0) == sizeof(buf));
+ usleep(100000);
+ REQUIRE_SO_ERROR(s2, ECONNREFUSED);
+ REQUIRE_SO_ERROR(s1, 0);
+
+ close(s1);
+ close(s2);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, icmp_port_unreach_notify);
+
+ return (atf_no_error());
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 31, 7:51 PM (10 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41268926
Default Alt Text
D60967.1793476304.diff (4 KB)

Event Timeline