diff options
author | rrs <rrs@FreeBSD.org> | 2009-01-06 12:13:40 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2009-01-06 12:13:40 +0000 |
commit | 8bff422255e003d595b727bcf2832648dfad012a (patch) | |
tree | cad2ca9862c1a23be9a4b0173dc9c2fc8924165a /sys/netinet | |
parent | df83de35ebaea44832c83fe1de66ab651752d270 (diff) | |
download | FreeBSD-src-8bff422255e003d595b727bcf2832648dfad012a.zip FreeBSD-src-8bff422255e003d595b727bcf2832648dfad012a.tar.gz |
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.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/udp_usrreq.c | 93 | ||||
-rw-r--r-- | sys/netinet/udp_var.h | 4 |
2 files changed, 89 insertions, 8 deletions
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index e402297..cdca664 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -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, struct thread *td) 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); } diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index 39805ed..76a31b8 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -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 |