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.
This commit is contained in:
Randall Stewart 2009-01-06 12:13:40 +00:00
parent 600b915569
commit c7c7ea4b5a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186813
3 changed files with 133 additions and 10 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -287,8 +287,25 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
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, int proto)
}
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, int proto)
}
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);