Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 Jan 2009 12:13:41 +0000 (UTC)
From:      Randall Stewart <rrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r186813 - in head/sys: netinet netinet6
Message-ID:  <200901061213.n06CDfuv030333@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rrs
Date: Tue Jan  6 12:13:40 2009
New Revision: 186813
URL: http://svn.freebsd.org/changeset/base/186813

Log:
  Add the ability of an alternate transport protocol
  to easily tunnel over udp by providing a hook
  function that will be called instead of appending
  to the socket buffer.

Modified:
  head/sys/netinet/udp_usrreq.c
  head/sys/netinet/udp_var.h
  head/sys/netinet6/udp6_usrreq.c

Modified: head/sys/netinet/udp_usrreq.c
==============================================================================
--- head/sys/netinet/udp_usrreq.c	Tue Jan  6 12:12:39 2009	(r186812)
+++ head/sys/netinet/udp_usrreq.c	Tue Jan  6 12:13:40 2009	(r186813)
@@ -488,10 +488,33 @@ udp_input(struct mbuf *m, int off)
 				struct mbuf *n;
 
 				n = m_copy(m, 0, M_COPYALL);
-				if (n != NULL)
-					udp_append(last, ip, n, iphlen +
-					    sizeof(struct udphdr), &udp_in);
-				INP_RUNLOCK(last);
+				if (last->inp_ppcb == NULL) {
+					if (n != NULL)
+						udp_append(last, 
+						    ip, n, 
+						    iphlen +
+						    sizeof(struct udphdr),
+						    &udp_in);
+					INP_RUNLOCK(last);
+				} else {
+					/*
+					 * Engage the tunneling protocol we
+					 * will have to leave the info_lock
+					 * up, since we are hunting through
+					 * multiple UDP inp's hope we don't
+					 * break.
+					 * 
+					 * XXXML: Maybe add a flag to the
+					 * prototype so that the tunneling
+					 * can defer work that can't be done
+					 * under the info lock?
+					 */
+					udp_tun_func_t tunnel_func;
+
+					tunnel_func = (udp_tun_func_t)last->inp_ppcb;
+					tunnel_func(n, iphlen, last);
+					INP_RUNLOCK(last);
+				}
 			}
 			last = inp;
 			/*
@@ -516,10 +539,24 @@ udp_input(struct mbuf *m, int off)
 			V_udpstat.udps_noportbcast++;
 			goto badheadlocked;
 		}
-		udp_append(last, ip, m, iphlen + sizeof(struct udphdr),
-		    &udp_in);
-		INP_RUNLOCK(last);
-		INP_INFO_RUNLOCK(&V_udbinfo);
+		if (last->inp_ppcb == NULL) {
+			udp_append(last, ip, m, iphlen + sizeof(struct udphdr),
+			    &udp_in);
+			INP_RUNLOCK(last);
+			INP_INFO_RUNLOCK(&V_udbinfo);
+		} else {
+			/*
+			 * Engage the tunneling protocol we must make sure
+			 * all locks are released when we call the tunneling
+			 * protocol.
+			 */
+			udp_tun_func_t tunnel_func;
+
+			tunnel_func = (udp_tun_func_t)last->inp_ppcb;
+			tunnel_func(m, iphlen, last);
+			INP_RUNLOCK(last);
+			INP_INFO_RUNLOCK(&V_udbinfo);
+		}
 		return;
 	}
 
@@ -563,6 +600,18 @@ udp_input(struct mbuf *m, int off)
 		INP_RUNLOCK(inp);
 		goto badunlocked;
 	}
+	if (inp->inp_ppcb != NULL) {
+		/*
+		 * Engage the tunneling protocol we must make sure all locks
+		 * are released when we call the tunneling protocol.
+		 */
+		udp_tun_func_t tunnel_func;
+
+		tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
+		tunnel_func(m, iphlen, inp);
+		INP_RUNLOCK(inp);
+		return;
+	}
 	udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
 	INP_RUNLOCK(inp);
 	return;
@@ -1138,6 +1187,34 @@ udp_attach(struct socket *so, int proto,
 	INP_INFO_WUNLOCK(&V_udbinfo);
 	inp->inp_vflag |= INP_IPV4;
 	inp->inp_ip_ttl = V_ip_defttl;
+	/*
+	 * UDP does not have a per-protocol pcb (inp->inp_ppcb). 
+	 * We use this pointer for kernel tunneling pointer.
+	 * If we ever need to have a protocol block we will 
+	 * need to move this function pointer there. Null
+	 * in this pointer means "do the normal thing".
+	 */
+	inp->inp_ppcb = NULL;
+	INP_WUNLOCK(inp);
+	return (0);
+}
+
+int
+udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f)
+{
+	struct inpcb *inp;
+
+	inp = (struct inpcb *)so->so_pcb;
+	if (so->so_type != SOCK_DGRAM) {
+		/* Not UDP socket... sorry! */
+		return (ENOTSUP);
+	}
+	if (inp == NULL) {
+		/* NULL INP? */
+		return (EINVAL);
+	}
+	INP_WLOCK(inp);
+	inp->inp_ppcb = f;
 	INP_WUNLOCK(inp);
 	return (0);
 }

Modified: head/sys/netinet/udp_var.h
==============================================================================
--- head/sys/netinet/udp_var.h	Tue Jan  6 12:12:39 2009	(r186812)
+++ head/sys/netinet/udp_var.h	Tue Jan  6 12:13:40 2009	(r186813)
@@ -110,6 +110,10 @@ void		 udp_init(void);
 void		 udp_input(struct mbuf *, int);
 struct inpcb	*udp_notify(struct inpcb *inp, int errno);
 int		 udp_shutdown(struct socket *so);
+
+
+typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
+int udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f);
 #endif
 
 #endif

Modified: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c	Tue Jan  6 12:12:39 2009	(r186812)
+++ head/sys/netinet6/udp6_usrreq.c	Tue Jan  6 12:13:40 2009	(r186813)
@@ -287,8 +287,25 @@ udp6_input(struct mbuf **mp, int *offp, 
 
 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
 					INP_RLOCK(last);
-					udp6_append(last, n, off, &fromsa);
-					INP_RUNLOCK(last);
+					if (last->inp_ppcb != NULL) {
+						/*
+						 * Engage the tunneling
+						 * protocol we will have to
+						 * leave the info_lock up,
+						 * since we are hunting
+						 * through multiple UDP
+						 * inp's hope we don't break.
+						 * 
+						 */
+						udp_tun_func_t tunnel_func;
+
+						tunnel_func = (udp_tun_func_t)last->inp_ppcb;
+						tunnel_func(n, off, last);
+						INP_RUNLOCK(last);
+					} else {
+						udp6_append(last, n, off, &fromsa);
+						INP_RUNLOCK(last);
+					}
 				}
 			}
 			last = inp;
@@ -317,6 +334,19 @@ udp6_input(struct mbuf **mp, int *offp, 
 		}
 		INP_RLOCK(last);
 		INP_INFO_RUNLOCK(&V_udbinfo);
+		if (last->inp_ppcb != NULL) {
+			/*
+			 * Engage the tunneling protocol we must make sure
+			 * all locks are released when we call the tunneling
+			 * protocol.
+			 */
+			udp_tun_func_t tunnel_func;
+
+			tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
+			tunnel_func(m, off, last);
+			INP_RUNLOCK(last);
+			return (IPPROTO_DONE);
+		}
 		udp6_append(last, m, off, &fromsa);
 		INP_RUNLOCK(last);
 		return (IPPROTO_DONE);
@@ -354,6 +384,18 @@ udp6_input(struct mbuf **mp, int *offp, 
 	}
 	INP_RLOCK(inp);
 	INP_INFO_RUNLOCK(&V_udbinfo);
+	if (inp->inp_ppcb != NULL) {
+		/*
+		 * Engage the tunneling protocol we must make sure all locks
+		 * are released when we call the tunneling protocol.
+		 */
+		udp_tun_func_t tunnel_func;
+
+		tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
+		tunnel_func(m, off, inp);
+		INP_RUNLOCK(inp);
+		return (IPPROTO_DONE);
+	}
 	udp6_append(inp, m, off, &fromsa);
 	INP_RUNLOCK(inp);
 	return (IPPROTO_DONE);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901061213.n06CDfuv030333>