summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/udp_usrreq.c93
-rw-r--r--sys/netinet/udp_var.h4
-rw-r--r--sys/netinet6/udp6_usrreq.c46
3 files changed, 133 insertions, 10 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
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index f1634cb..ed75759 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -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);
OpenPOWER on IntegriCloud