Module Name:    src
Committed By:   rmind
Date:           Thu May 22 22:56:53 UTC 2014

Modified Files:
        src/sys/netinet: udp_usrreq.c
        src/sys/netinet6: in6_proto.c udp6_usrreq.c udp6_var.h

Log Message:
Move udp6_input(), udp6_sendup(), udp6_realinput() and udp6_input_checksum()
from udp_usrreq.c to udp6_usrreq.c where they belong.  No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.197 -r1.198 src/sys/netinet/udp_usrreq.c
cvs rdiff -u -r1.101 -r1.102 src/sys/netinet6/in6_proto.c
cvs rdiff -u -r1.96 -r1.97 src/sys/netinet6/udp6_usrreq.c
cvs rdiff -u -r1.26 -r1.27 src/sys/netinet6/udp6_var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/udp_usrreq.c
diff -u src/sys/netinet/udp_usrreq.c:1.197 src/sys/netinet/udp_usrreq.c:1.198
--- src/sys/netinet/udp_usrreq.c:1.197	Tue May 20 19:04:00 2014
+++ src/sys/netinet/udp_usrreq.c	Thu May 22 22:56:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp_usrreq.c,v 1.197 2014/05/20 19:04:00 rmind Exp $	*/
+/*	$NetBSD: udp_usrreq.c,v 1.198 2014/05/22 22:56:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -60,8 +60,13 @@
  *	@(#)udp_usrreq.c	8.6 (Berkeley) 5/23/95
  */
 
+/*
+ * UDP protocol implementation.
+ * Per RFC 768, August, 1980.
+ */
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.197 2014/05/20 19:04:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.198 2014/05/22 22:56:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_compat_netbsd.h"
@@ -71,14 +76,11 @@ __KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c
 #include "opt_mbuftrace.h"
 
 #include <sys/param.h>
-#include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/once.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
 #include <sys/domain.h>
@@ -106,7 +108,6 @@ __KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c
 #include <netinet6/in6_pcb.h>
 #include <netinet6/udp6_var.h>
 #include <netinet6/udp6_private.h>
-#include <netinet6/scope6_var.h>
 #endif
 
 #ifndef INET6
@@ -114,11 +115,6 @@ __KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c
 #include <netinet/ip6.h>
 #endif
 
-#include "faith.h"
-#if defined(NFAITH) && NFAITH > 0
-#include <net/if_faith.h>
-#endif
-
 #ifdef IPSEC
 #include <netipsec/ipsec.h>
 #include <netipsec/ipsec_var.h>
@@ -137,10 +133,6 @@ __KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c
 #include <ipkdb/ipkdb.h>
 #endif
 
-/*
- * UDP protocol implementation.
- * Per RFC 768, August, 1980.
- */
 int	udpcksum = 1;
 int	udp_do_loopback_cksum = 0;
 
@@ -159,13 +151,6 @@ static int udp4_realinput (struct sockad
 	struct mbuf **, int);
 static int udp4_input_checksum(struct mbuf *, const struct udphdr *, int, int);
 #endif
-#ifdef INET6
-static void udp6_sendup (struct mbuf *, int, struct sockaddr *,
-	struct socket *);
-static int udp6_realinput (int, struct sockaddr_in6 *,
-	struct sockaddr_in6 *, struct mbuf *, int);
-static int udp6_input_checksum(struct mbuf *, const struct udphdr *, int, int);
-#endif
 #ifdef INET
 static	void udp_notify (struct inpcb *, int);
 #endif
@@ -206,28 +191,9 @@ EVCNT_ATTACH_STATIC(udp_hwcsum_data);
 EVCNT_ATTACH_STATIC(udp_swcsum);
 #endif /* defined(INET) */
 
-#if defined(INET6)
-struct evcnt udp6_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
-    NULL, "udp6", "hwcsum bad");
-struct evcnt udp6_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
-    NULL, "udp6", "hwcsum ok");
-struct evcnt udp6_hwcsum_data = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
-    NULL, "udp6", "hwcsum data");
-struct evcnt udp6_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
-    NULL, "udp6", "swcsum");
-
-EVCNT_ATTACH_STATIC(udp6_hwcsum_bad);
-EVCNT_ATTACH_STATIC(udp6_hwcsum_ok);
-EVCNT_ATTACH_STATIC(udp6_hwcsum_data);
-EVCNT_ATTACH_STATIC(udp6_swcsum);
-#endif /* defined(INET6) */
-
 #define	UDP_CSUM_COUNTER_INCR(ev)	(ev)->ev_count++
-
 #else
-
 #define	UDP_CSUM_COUNTER_INCR(ev)	/* nothing */
-
 #endif /* UDP_CSUM_COUNTERS */
 
 static void sysctl_net_inet_udp_setup(struct sysctllog **);
@@ -484,151 +450,6 @@ badcsum:
 }
 #endif
 
-#ifdef INET6
-static int
-udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len)
-{
-
-	/*
-	 * XXX it's better to record and check if this mbuf is
-	 * already checked.
-	 */
-
-	if (__predict_false((m->m_flags & M_LOOP) && !udp_do_loopback_cksum)) {
-		goto good;
-	}
-	if (uh->uh_sum == 0) {
-		UDP6_STATINC(UDP6_STAT_NOSUM);
-		goto bad;
-	}
-
-	switch (m->m_pkthdr.csum_flags &
-	    ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv6) |
-	    M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
-	case M_CSUM_UDPv6|M_CSUM_TCP_UDP_BAD:
-		UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_bad);
-		UDP6_STATINC(UDP6_STAT_BADSUM);
-		goto bad;
-
-#if 0 /* notyet */
-	case M_CSUM_UDPv6|M_CSUM_DATA:
-#endif
-
-	case M_CSUM_UDPv6:
-		/* Checksum was okay. */
-		UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_ok);
-		break;
-
-	default:
-		/*
-		 * Need to compute it ourselves.  Maybe skip checksum
-		 * on loopback interfaces.
-		 */
-		UDP_CSUM_COUNTER_INCR(&udp6_swcsum);
-		if (in6_cksum(m, IPPROTO_UDP, off, len) != 0) {
-			UDP6_STATINC(UDP6_STAT_BADSUM);
-			goto bad;
-		}
-	}
-
-good:
-	return 0;
-bad:
-	return -1;
-}
-
-int
-udp6_input(struct mbuf **mp, int *offp, int proto)
-{
-	struct mbuf *m = *mp;
-	int off = *offp;
-	struct sockaddr_in6 src, dst;
-	struct ip6_hdr *ip6;
-	struct udphdr *uh;
-	u_int32_t plen, ulen;
-
-	ip6 = mtod(m, struct ip6_hdr *);
-
-#if defined(NFAITH) && 0 < NFAITH
-	if (faithprefix(&ip6->ip6_dst)) {
-		/* send icmp6 host unreach? */
-		m_freem(m);
-		return IPPROTO_DONE;
-	}
-#endif
-
-	UDP6_STATINC(UDP6_STAT_IPACKETS);
-
-	/* check for jumbogram is done in ip6_input.  we can trust pkthdr.len */
-	plen = m->m_pkthdr.len - off;
-	IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
-	if (uh == NULL) {
-		IP6_STATINC(IP6_STAT_TOOSHORT);
-		return IPPROTO_DONE;
-	}
-	KASSERT(UDP_HDR_ALIGNED_P(uh));
-	ulen = ntohs((u_short)uh->uh_ulen);
-	/*
-	 * RFC2675 section 4: jumbograms will have 0 in the UDP header field,
-	 * iff payload length > 0xffff.
-	 */
-	if (ulen == 0 && plen > 0xffff)
-		ulen = plen;
-
-	if (plen != ulen) {
-		UDP6_STATINC(UDP6_STAT_BADLEN);
-		goto bad;
-	}
-
-	/* destination port of 0 is illegal, based on RFC768. */
-	if (uh->uh_dport == 0)
-		goto bad;
-
-	/* Be proactive about malicious use of IPv4 mapped address */
-	if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
-	    IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
-		/* XXX stat */
-		goto bad;
-	}
-
-	/*
-	 * Checksum extended UDP header and data.  Maybe skip checksum
-	 * on loopback interfaces.
-	 */
-	if (udp6_input_checksum(m, uh, off, ulen))
-		goto bad;
-
-	/*
-	 * Construct source and dst sockaddrs.
-	 */
-	memset(&src, 0, sizeof(src));
-	src.sin6_family = AF_INET6;
-	src.sin6_len = sizeof(struct sockaddr_in6);
-	src.sin6_addr = ip6->ip6_src;
-	src.sin6_port = uh->uh_sport;
-	memset(&dst, 0, sizeof(dst));
-	dst.sin6_family = AF_INET6;
-	dst.sin6_len = sizeof(struct sockaddr_in6);
-	dst.sin6_addr = ip6->ip6_dst;
-	dst.sin6_port = uh->uh_dport;
-
-	if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) {
-		if (m->m_flags & M_MCAST) {
-			UDP6_STATINC(UDP6_STAT_NOPORTMCAST);
-			goto bad;
-		}
-		UDP6_STATINC(UDP6_STAT_NOPORT);
-		icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
-		m = NULL;
-	}
-
-bad:
-	if (m)
-		m_freem(m);
-	return IPPROTO_DONE;
-}
-#endif
-
 #ifdef INET
 static void
 udp4_sendup(struct mbuf *m, int off /* offset of data portion */,
@@ -687,55 +508,6 @@ udp4_sendup(struct mbuf *m, int off /* o
 }
 #endif
 
-#ifdef INET6
-static void
-udp6_sendup(struct mbuf *m, int off /* offset of data portion */,
-	struct sockaddr *src, struct socket *so)
-{
-	struct mbuf *opts = NULL;
-	struct mbuf *n;
-	struct in6pcb *in6p = NULL;
-
-	if (!so)
-		return;
-	if (so->so_proto->pr_domain->dom_family != AF_INET6)
-		return;
-	in6p = sotoin6pcb(so);
-
-#if defined(IPSEC)
-	/* check AH/ESP integrity. */
-	if (so != NULL && ipsec6_in_reject_so(m, so)) {
-		IPSEC6_STATINC(IPSEC_STAT_IN_POLVIO);
-		if ((n = m_copypacket(m, M_DONTWAIT)) != NULL)
-			icmp6_error(n, ICMP6_DST_UNREACH,
-			    ICMP6_DST_UNREACH_ADMIN, 0);
-		return;
-	}
-#endif /*IPSEC*/
-
-	if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) {
-		if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS
-#ifdef SO_OTIMESTAMP
-		    || in6p->in6p_socket->so_options & SO_OTIMESTAMP
-#endif
-		    || in6p->in6p_socket->so_options & SO_TIMESTAMP)) {
-			struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *);
-			ip6_savecontrol(in6p, &opts, ip6, n);
-		}
-
-		m_adj(n, off);
-		if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) {
-			m_freem(n);
-			if (opts)
-				m_freem(opts);
-			so->so_rcv.sb_overflowed++;
-			UDP6_STATINC(UDP6_STAT_FULLSOCK);
-		} else
-			sorwakeup(so);
-	}
-}
-#endif
-
 #ifdef INET
 static int
 udp4_realinput(struct sockaddr_in *src, struct sockaddr_in *dst,
@@ -873,126 +645,6 @@ bad:
 }
 #endif
 
-#ifdef INET6
-static int
-udp6_realinput(int af, struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
-	struct mbuf *m, int off)
-{
-	u_int16_t sport, dport;
-	int rcvcnt;
-	struct in6_addr src6, *dst6;
-	const struct in_addr *dst4;
-	struct inpcb_hdr *inph;
-	struct in6pcb *in6p;
-
-	rcvcnt = 0;
-	off += sizeof(struct udphdr);	/* now, offset of payload */
-
-	if (af != AF_INET && af != AF_INET6)
-		goto bad;
-	if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6)
-		goto bad;
-
-	src6 = src->sin6_addr;
-	if (sa6_recoverscope(src) != 0) {
-		/* XXX: should be impossible. */
-		goto bad;
-	}
-	sport = src->sin6_port;
-
-	dport = dst->sin6_port;
-	dst4 = (struct in_addr *)&dst->sin6_addr.s6_addr[12];
-	dst6 = &dst->sin6_addr;
-
-	if (IN6_IS_ADDR_MULTICAST(dst6) ||
-	    (af == AF_INET && IN_MULTICAST(dst4->s_addr))) {
-		/*
-		 * Deliver a multicast or broadcast datagram to *all* sockets
-		 * for which the local and remote addresses and ports match
-		 * those of the incoming datagram.  This allows more than
-		 * one process to receive multi/broadcasts on the same port.
-		 * (This really ought to be done for unicast datagrams as
-		 * well, but that would cause problems with existing
-		 * applications that open both address-specific sockets and
-		 * a wildcard socket listening to the same port -- they would
-		 * end up receiving duplicates of every unicast datagram.
-		 * Those applications open the multiple sockets to overcome an
-		 * inadequacy of the UDP socket interface, but for backwards
-		 * compatibility we avoid the problem here rather than
-		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
-		 */
-
-		/*
-		 * KAME note: traditionally we dropped udpiphdr from mbuf here.
-		 * we need udpiphdr for IPsec processing so we do that later.
-		 */
-		/*
-		 * Locate pcb(s) for datagram.
-		 */
-		TAILQ_FOREACH(inph, &udbtable.inpt_queue, inph_queue) {
-			in6p = (struct in6pcb *)inph;
-			if (in6p->in6p_af != AF_INET6)
-				continue;
-
-			if (in6p->in6p_lport != dport)
-				continue;
-			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
-				if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
-				    dst6))
-					continue;
-			} else {
-				if (IN6_IS_ADDR_V4MAPPED(dst6) &&
-				    (in6p->in6p_flags & IN6P_IPV6_V6ONLY))
-					continue;
-			}
-			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
-				if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
-				    &src6) || in6p->in6p_fport != sport)
-					continue;
-			} else {
-				if (IN6_IS_ADDR_V4MAPPED(&src6) &&
-				    (in6p->in6p_flags & IN6P_IPV6_V6ONLY))
-					continue;
-			}
-
-			udp6_sendup(m, off, (struct sockaddr *)src,
-				in6p->in6p_socket);
-			rcvcnt++;
-
-			/*
-			 * Don't look for additional matches if this one does
-			 * not have either the SO_REUSEPORT or SO_REUSEADDR
-			 * socket options set.  This heuristic avoids searching
-			 * through all pcbs in the common case of a non-shared
-			 * port.  It assumes that an application will never
-			 * clear these options after setting them.
-			 */
-			if ((in6p->in6p_socket->so_options &
-			    (SO_REUSEPORT|SO_REUSEADDR)) == 0)
-				break;
-		}
-	} else {
-		/*
-		 * Locate pcb for datagram.
-		 */
-		in6p = in6_pcblookup_connect(&udbtable, &src6, sport, dst6,
-					     dport, 0, 0);
-		if (in6p == 0) {
-			UDP_STATINC(UDP_STAT_PCBHASHMISS);
-			in6p = in6_pcblookup_bind(&udbtable, dst6, dport, 0);
-			if (in6p == 0)
-				return rcvcnt;
-		}
-
-		udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket);
-		rcvcnt++;
-	}
-
-bad:
-	return rcvcnt;
-}
-#endif
-
 #ifdef INET
 /*
  * Notify a udp user of an asynchronous error;

Index: src/sys/netinet6/in6_proto.c
diff -u src/sys/netinet6/in6_proto.c:1.101 src/sys/netinet6/in6_proto.c:1.102
--- src/sys/netinet6/in6_proto.c:1.101	Sun May 18 14:46:16 2014
+++ src/sys/netinet6/in6_proto.c	Thu May 22 22:56:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_proto.c,v 1.101 2014/05/18 14:46:16 rmind Exp $	*/
+/*	$NetBSD: in6_proto.c,v 1.102 2014/05/22 22:56:53 rmind Exp $	*/
 /*	$KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.101 2014/05/18 14:46:16 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.102 2014/05/22 22:56:53 rmind Exp $");
 
 #include "opt_gateway.h"
 #include "opt_inet.h"
@@ -468,8 +468,3 @@ int	icmp6_rediraccept = 1;		/* accept an
 int	icmp6_redirtimeout = 10 * 60;	/* 10 minutes */
 int	icmp6errppslim = 100;		/* 100pps */
 int	icmp6_nodeinfo = 1;		/* enable/disable NI response */
-
-/* UDP on IP6 parameters */
-int	udp6_sendspace = 9216;		/* really max datagram size */
-int	udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6));
-					/* 40 1K datagrams */

Index: src/sys/netinet6/udp6_usrreq.c
diff -u src/sys/netinet6/udp6_usrreq.c:1.96 src/sys/netinet6/udp6_usrreq.c:1.97
--- src/sys/netinet6/udp6_usrreq.c:1.96	Tue May 20 19:04:00 2014
+++ src/sys/netinet6/udp6_usrreq.c	Thu May 22 22:56:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp6_usrreq.c,v 1.96 2014/05/20 19:04:00 rmind Exp $	*/
+/*	$NetBSD: udp6_usrreq.c,v 1.97 2014/05/22 22:56:53 rmind Exp $	*/
 /*	$KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $	*/
 
 /*
@@ -62,18 +62,16 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.96 2014/05/20 19:04:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.97 2014/05/22 22:56:53 rmind Exp $");
 
 #include "opt_inet.h"
+#include "opt_inet_csum.h"
 
 #include <sys/param.h>
-#include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
 #include <sys/syslog.h>
@@ -87,19 +85,23 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/in_systm.h>
+#include <netinet/in_offload.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
 #include <netinet/in_pcb.h>
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
+#include <netinet/udp_private.h>
+
 #include <netinet/ip6.h>
+#include <netinet/icmp6.h>
 #include <netinet6/ip6_var.h>
+#include <netinet6/ip6_private.h>
 #include <netinet6/in6_pcb.h>
-#include <netinet/icmp6.h>
 #include <netinet6/udp6_var.h>
 #include <netinet6/udp6_private.h>
 #include <netinet6/ip6protosw.h>
-#include <netinet/in_offload.h>
+#include <netinet6/scope6_var.h>
 
 #include "faith.h"
 #if defined(NFAITH) && NFAITH > 0
@@ -115,13 +117,38 @@ extern struct inpcbtable udbtable;
 
 percpu_t *udp6stat_percpu;
 
+/* UDP on IP6 parameters */
+static int	udp6_sendspace = 9216;	/* really max datagram size */
+static int	udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6));
+					/* 40 1K datagrams */
+
 static	void udp6_notify(struct in6pcb *, int);
 static	void sysctl_net_inet6_udp6_setup(struct sysctllog **);
 
+#ifdef UDP_CSUM_COUNTERS
+#include <sys/device.h>
+struct evcnt udp6_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "udp6", "hwcsum bad");
+struct evcnt udp6_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "udp6", "hwcsum ok");
+struct evcnt udp6_hwcsum_data = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "udp6", "hwcsum data");
+struct evcnt udp6_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "udp6", "swcsum");
+
+EVCNT_ATTACH_STATIC(udp6_hwcsum_bad);
+EVCNT_ATTACH_STATIC(udp6_hwcsum_ok);
+EVCNT_ATTACH_STATIC(udp6_hwcsum_data);
+EVCNT_ATTACH_STATIC(udp6_swcsum);
+
+#define	UDP_CSUM_COUNTER_INCR(ev)	(ev)->ev_count++
+#else
+#define	UDP_CSUM_COUNTER_INCR(ev)	/* nothing */
+#endif
+
 void
 udp6_init(void)
 {
-
 	sysctl_net_inet6_udp6_setup(NULL);
 	udp6stat_percpu = percpu_alloc(sizeof(uint64_t) * UDP6_NSTATS);
 
@@ -298,9 +325,313 @@ end:
 	return error;
 }
 
+static void
+udp6_sendup(struct mbuf *m, int off /* offset of data portion */,
+	struct sockaddr *src, struct socket *so)
+{
+	struct mbuf *opts = NULL;
+	struct mbuf *n;
+	struct in6pcb *in6p = NULL;
+
+	if (!so)
+		return;
+	if (so->so_proto->pr_domain->dom_family != AF_INET6)
+		return;
+	in6p = sotoin6pcb(so);
+
+#if defined(IPSEC)
+	/* check AH/ESP integrity. */
+	if (so != NULL && ipsec6_in_reject_so(m, so)) {
+		IPSEC6_STATINC(IPSEC_STAT_IN_POLVIO);
+		if ((n = m_copypacket(m, M_DONTWAIT)) != NULL)
+			icmp6_error(n, ICMP6_DST_UNREACH,
+			    ICMP6_DST_UNREACH_ADMIN, 0);
+		return;
+	}
+#endif /*IPSEC*/
+
+	if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) {
+		if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS
+#ifdef SO_OTIMESTAMP
+		    || in6p->in6p_socket->so_options & SO_OTIMESTAMP
+#endif
+		    || in6p->in6p_socket->so_options & SO_TIMESTAMP)) {
+			struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *);
+			ip6_savecontrol(in6p, &opts, ip6, n);
+		}
+
+		m_adj(n, off);
+		if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) {
+			m_freem(n);
+			if (opts)
+				m_freem(opts);
+			so->so_rcv.sb_overflowed++;
+			UDP6_STATINC(UDP6_STAT_FULLSOCK);
+		} else
+			sorwakeup(so);
+	}
+}
+
+int
+udp6_realinput(int af, struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
+	struct mbuf *m, int off)
+{
+	u_int16_t sport, dport;
+	int rcvcnt;
+	struct in6_addr src6, *dst6;
+	const struct in_addr *dst4;
+	struct inpcb_hdr *inph;
+	struct in6pcb *in6p;
+
+	rcvcnt = 0;
+	off += sizeof(struct udphdr);	/* now, offset of payload */
+
+	if (af != AF_INET && af != AF_INET6)
+		goto bad;
+	if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6)
+		goto bad;
+
+	src6 = src->sin6_addr;
+	if (sa6_recoverscope(src) != 0) {
+		/* XXX: should be impossible. */
+		goto bad;
+	}
+	sport = src->sin6_port;
+
+	dport = dst->sin6_port;
+	dst4 = (struct in_addr *)&dst->sin6_addr.s6_addr[12];
+	dst6 = &dst->sin6_addr;
+
+	if (IN6_IS_ADDR_MULTICAST(dst6) ||
+	    (af == AF_INET && IN_MULTICAST(dst4->s_addr))) {
+		/*
+		 * Deliver a multicast or broadcast datagram to *all* sockets
+		 * for which the local and remote addresses and ports match
+		 * those of the incoming datagram.  This allows more than
+		 * one process to receive multi/broadcasts on the same port.
+		 * (This really ought to be done for unicast datagrams as
+		 * well, but that would cause problems with existing
+		 * applications that open both address-specific sockets and
+		 * a wildcard socket listening to the same port -- they would
+		 * end up receiving duplicates of every unicast datagram.
+		 * Those applications open the multiple sockets to overcome an
+		 * inadequacy of the UDP socket interface, but for backwards
+		 * compatibility we avoid the problem here rather than
+		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
+		 */
+
+		/*
+		 * KAME note: traditionally we dropped udpiphdr from mbuf here.
+		 * we need udpiphdr for IPsec processing so we do that later.
+		 */
+		/*
+		 * Locate pcb(s) for datagram.
+		 */
+		TAILQ_FOREACH(inph, &udbtable.inpt_queue, inph_queue) {
+			in6p = (struct in6pcb *)inph;
+			if (in6p->in6p_af != AF_INET6)
+				continue;
+
+			if (in6p->in6p_lport != dport)
+				continue;
+			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
+				if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
+				    dst6))
+					continue;
+			} else {
+				if (IN6_IS_ADDR_V4MAPPED(dst6) &&
+				    (in6p->in6p_flags & IN6P_IPV6_V6ONLY))
+					continue;
+			}
+			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+				if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
+				    &src6) || in6p->in6p_fport != sport)
+					continue;
+			} else {
+				if (IN6_IS_ADDR_V4MAPPED(&src6) &&
+				    (in6p->in6p_flags & IN6P_IPV6_V6ONLY))
+					continue;
+			}
+
+			udp6_sendup(m, off, (struct sockaddr *)src,
+				in6p->in6p_socket);
+			rcvcnt++;
+
+			/*
+			 * Don't look for additional matches if this one does
+			 * not have either the SO_REUSEPORT or SO_REUSEADDR
+			 * socket options set.  This heuristic avoids searching
+			 * through all pcbs in the common case of a non-shared
+			 * port.  It assumes that an application will never
+			 * clear these options after setting them.
+			 */
+			if ((in6p->in6p_socket->so_options &
+			    (SO_REUSEPORT|SO_REUSEADDR)) == 0)
+				break;
+		}
+	} else {
+		/*
+		 * Locate pcb for datagram.
+		 */
+		in6p = in6_pcblookup_connect(&udbtable, &src6, sport, dst6,
+					     dport, 0, 0);
+		if (in6p == 0) {
+			UDP_STATINC(UDP_STAT_PCBHASHMISS);
+			in6p = in6_pcblookup_bind(&udbtable, dst6, dport, 0);
+			if (in6p == 0)
+				return rcvcnt;
+		}
+
+		udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket);
+		rcvcnt++;
+	}
+
+bad:
+	return rcvcnt;
+}
+
+int
+udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len)
+{
+
+	/*
+	 * XXX it's better to record and check if this mbuf is
+	 * already checked.
+	 */
+
+	if (__predict_false((m->m_flags & M_LOOP) && !udp_do_loopback_cksum)) {
+		goto good;
+	}
+	if (uh->uh_sum == 0) {
+		UDP6_STATINC(UDP6_STAT_NOSUM);
+		goto bad;
+	}
+
+	switch (m->m_pkthdr.csum_flags &
+	    ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv6) |
+	    M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
+	case M_CSUM_UDPv6|M_CSUM_TCP_UDP_BAD:
+		UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_bad);
+		UDP6_STATINC(UDP6_STAT_BADSUM);
+		goto bad;
+
+#if 0 /* notyet */
+	case M_CSUM_UDPv6|M_CSUM_DATA:
+#endif
+
+	case M_CSUM_UDPv6:
+		/* Checksum was okay. */
+		UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_ok);
+		break;
+
+	default:
+		/*
+		 * Need to compute it ourselves.  Maybe skip checksum
+		 * on loopback interfaces.
+		 */
+		UDP_CSUM_COUNTER_INCR(&udp6_swcsum);
+		if (in6_cksum(m, IPPROTO_UDP, off, len) != 0) {
+			UDP6_STATINC(UDP6_STAT_BADSUM);
+			goto bad;
+		}
+	}
+
+good:
+	return 0;
+bad:
+	return -1;
+}
+
+int
+udp6_input(struct mbuf **mp, int *offp, int proto)
+{
+	struct mbuf *m = *mp;
+	int off = *offp;
+	struct sockaddr_in6 src, dst;
+	struct ip6_hdr *ip6;
+	struct udphdr *uh;
+	u_int32_t plen, ulen;
+
+	ip6 = mtod(m, struct ip6_hdr *);
 
-extern	int udp6_sendspace;
-extern	int udp6_recvspace;
+#if defined(NFAITH) && 0 < NFAITH
+	if (faithprefix(&ip6->ip6_dst)) {
+		/* send icmp6 host unreach? */
+		m_freem(m);
+		return IPPROTO_DONE;
+	}
+#endif
+
+	UDP6_STATINC(UDP6_STAT_IPACKETS);
+
+	/* check for jumbogram is done in ip6_input.  we can trust pkthdr.len */
+	plen = m->m_pkthdr.len - off;
+	IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
+	if (uh == NULL) {
+		IP6_STATINC(IP6_STAT_TOOSHORT);
+		return IPPROTO_DONE;
+	}
+	KASSERT(UDP_HDR_ALIGNED_P(uh));
+	ulen = ntohs((u_short)uh->uh_ulen);
+	/*
+	 * RFC2675 section 4: jumbograms will have 0 in the UDP header field,
+	 * iff payload length > 0xffff.
+	 */
+	if (ulen == 0 && plen > 0xffff)
+		ulen = plen;
+
+	if (plen != ulen) {
+		UDP6_STATINC(UDP6_STAT_BADLEN);
+		goto bad;
+	}
+
+	/* destination port of 0 is illegal, based on RFC768. */
+	if (uh->uh_dport == 0)
+		goto bad;
+
+	/* Be proactive about malicious use of IPv4 mapped address */
+	if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
+	    IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
+		/* XXX stat */
+		goto bad;
+	}
+
+	/*
+	 * Checksum extended UDP header and data.  Maybe skip checksum
+	 * on loopback interfaces.
+	 */
+	if (udp6_input_checksum(m, uh, off, ulen))
+		goto bad;
+
+	/*
+	 * Construct source and dst sockaddrs.
+	 */
+	memset(&src, 0, sizeof(src));
+	src.sin6_family = AF_INET6;
+	src.sin6_len = sizeof(struct sockaddr_in6);
+	src.sin6_addr = ip6->ip6_src;
+	src.sin6_port = uh->uh_sport;
+	memset(&dst, 0, sizeof(dst));
+	dst.sin6_family = AF_INET6;
+	dst.sin6_len = sizeof(struct sockaddr_in6);
+	dst.sin6_addr = ip6->ip6_dst;
+	dst.sin6_port = uh->uh_dport;
+
+	if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) {
+		if (m->m_flags & M_MCAST) {
+			UDP6_STATINC(UDP6_STAT_NOPORTMCAST);
+			goto bad;
+		}
+		UDP6_STATINC(UDP6_STAT_NOPORT);
+		icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
+		m = NULL;
+	}
+
+bad:
+	if (m)
+		m_freem(m);
+	return IPPROTO_DONE;
+}
 
 static int
 udp6_attach(struct socket *so, int proto)

Index: src/sys/netinet6/udp6_var.h
diff -u src/sys/netinet6/udp6_var.h:1.26 src/sys/netinet6/udp6_var.h:1.27
--- src/sys/netinet6/udp6_var.h:1.26	Sun May 18 14:46:16 2014
+++ src/sys/netinet6/udp6_var.h	Thu May 22 22:56:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp6_var.h,v 1.26 2014/05/18 14:46:16 rmind Exp $	*/
+/*	$NetBSD: udp6_var.h,v 1.27 2014/05/22 22:56:53 rmind Exp $	*/
 /*	$KAME: udp6_var.h,v 1.11 2000/06/05 00:14:31 itojun Exp $	*/
 
 /*
@@ -111,6 +111,9 @@ int	udp6_output(struct in6pcb *, struct 
 int	udp6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 int	udp6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
     struct mbuf *, struct lwp *);
+int	udp6_realinput(int, struct sockaddr_in6 *, struct sockaddr_in6 *,
+    struct mbuf *, int);
+int	udp6_input_checksum(struct mbuf *, const struct udphdr *, int, int);
 
 void	udp6_statinc(u_int);
 #endif /* _KERNEL */

Reply via email to