From 8bff422255e003d595b727bcf2832648dfad012a Mon Sep 17 00:00:00 2001 From: rrs Date: Tue, 6 Jan 2009 12:13:40 +0000 Subject: 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. --- sys/netinet/udp_usrreq.c | 93 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 8 deletions(-) (limited to 'sys/netinet/udp_usrreq.c') 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); } -- cgit v1.1