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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to