aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/udp_usrreq.c102
-rw-r--r--sys/netinet/udp_var.h18
-rw-r--r--sys/netinet/vinet.h2
-rw-r--r--sys/netinet6/udp6_usrreq.c55
-rw-r--r--sys/sys/param.h2
5 files changed, 114 insertions, 65 deletions
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 9aa83dd1f9fc..a49240c14b0c 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -137,6 +137,7 @@ SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
#ifdef VIMAGE_GLOBALS
struct inpcbhead udb; /* from udp_var.h */
struct inpcbinfo udbinfo;
+static uma_zone_t udpcb_zone;
struct udpstat udpstat; /* from udp_var.h */
#endif
@@ -158,6 +159,7 @@ udp_zone_change(void *tag)
INIT_VNET_INET(curvnet);
uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
+ uma_zone_set_max(V_udpcb_zone, maxsockets);
}
static int
@@ -187,13 +189,39 @@ udp_init(void)
&V_udbinfo.ipi_hashmask);
V_udbinfo.ipi_porthashbase = hashinit(UDBHASHSIZE, M_PCB,
&V_udbinfo.ipi_porthashmask);
- V_udbinfo.ipi_zone = uma_zcreate("udpcb", sizeof(struct inpcb), NULL,
- NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ V_udbinfo.ipi_zone = uma_zcreate("udp_inpcb", sizeof(struct inpcb),
+ NULL, NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
+
+ V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ uma_zone_set_max(V_udpcb_zone, maxsockets);
+
EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL,
EVENTHANDLER_PRI_ANY);
}
+int
+udp_newudpcb(struct inpcb *inp)
+{
+ INIT_VNET_INET(curvnet);
+ struct udpcb *up;
+
+ up = uma_zalloc(V_udpcb_zone, M_NOWAIT | M_ZERO);
+ if (up == NULL)
+ return (ENOBUFS);
+ inp->inp_ppcb = up;
+ return (0);
+}
+
+void
+udp_discardcb(struct udpcb *up)
+{
+ INIT_VNET_INET(curvnet);
+
+ uma_zfree(V_udpcb_zone, up);
+}
+
/*
* Subroutine of udp_input(), which appends the provided mbuf chain to the
* passed pcb/socket. The caller must provide a sockaddr_in via udp_in that
@@ -272,6 +300,7 @@ udp_input(struct mbuf *m, int off)
struct udphdr *uh;
struct ifnet *ifp;
struct inpcb *inp;
+ struct udpcb *up;
int len;
struct ip save_ip;
struct sockaddr_in udp_in;
@@ -455,28 +484,25 @@ udp_input(struct mbuf *m, int off)
struct mbuf *n;
n = m_copy(m, 0, M_COPYALL);
- if (last->inp_ppcb == NULL) {
+ up = intoudpcb(last);
+ if (up->u_tun_func == 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's.
- *
*/
- udp_tun_func_t tunnel_func;
- tunnel_func = (udp_tun_func_t)last->inp_ppcb;
- tunnel_func(n, iphlen, last);
- INP_RUNLOCK(last);
+ (*up->u_tun_func)(n, iphlen, last);
}
+ INP_RUNLOCK(last);
}
last = inp;
/*
@@ -501,22 +527,18 @@ udp_input(struct mbuf *m, int off)
UDPSTAT_INC(udps_noportbcast);
goto badheadlocked;
}
- if (last->inp_ppcb == NULL) {
+ up = intoudpcb(last);
+ if (up->u_tun_func == 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.
*/
- 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);
+ (*up->u_tun_func)(m, iphlen, last);
}
+ INP_RUNLOCK(last);
+ INP_INFO_RUNLOCK(&V_udbinfo);
return;
}
@@ -560,18 +582,16 @@ udp_input(struct mbuf *m, int off)
INP_RUNLOCK(inp);
goto badunlocked;
}
- if (inp->inp_ppcb != NULL) {
+ up = intoudpcb(inp);
+ if (up->u_tun_func == NULL) {
+ udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
+ } else {
/*
* Engage 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;
+ (*up->u_tun_func)(m, iphlen, inp);
}
- udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
INP_RUNLOCK(inp);
return;
@@ -1142,18 +1162,19 @@ udp_attach(struct socket *so, int proto, struct thread *td)
}
inp = (struct inpcb *)so->so_pcb;
- 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;
+
+ error = udp_newudpcb(inp);
+ if (error) {
+ in_pcbdetach(inp);
+ in_pcbfree(inp);
+ INP_INFO_WUNLOCK(&V_udbinfo);
+ return (error);
+ }
+
INP_WUNLOCK(inp);
+ INP_INFO_WUNLOCK(&V_udbinfo);
return (0);
}
@@ -1161,24 +1182,26 @@ int
udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f)
{
struct inpcb *inp;
+ struct udpcb *up;
- inp = (struct inpcb *)so->so_pcb;
KASSERT(so->so_type == SOCK_DGRAM, ("udp_set_kernel_tunneling: !dgram"));
KASSERT(so->so_pcb != NULL, ("udp_set_kernel_tunneling: NULL inp"));
if (so->so_type != SOCK_DGRAM) {
/* Not UDP socket... sorry! */
return (ENOTSUP);
}
+ inp = (struct inpcb *)so->so_pcb;
if (inp == NULL) {
/* NULL INP? */
return (EINVAL);
}
INP_WLOCK(inp);
- if (inp->inp_ppcb != NULL) {
+ up = intoudpcb(inp);
+ if (up->u_tun_func != NULL) {
INP_WUNLOCK(inp);
return (EBUSY);
}
- inp->inp_ppcb = f;
+ up->u_tun_func = f;
INP_WUNLOCK(inp);
return (0);
}
@@ -1256,6 +1279,7 @@ udp_detach(struct socket *so)
{
INIT_VNET_INET(so->so_vnet);
struct inpcb *inp;
+ struct udpcb *up;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
@@ -1263,9 +1287,13 @@ udp_detach(struct socket *so)
("udp_detach: not disconnected"));
INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
+ up = intoudpcb(inp);
+ KASSERT(up != NULL, ("%s: up == NULL", __func__));
+ inp->inp_ppcb = NULL;
in_pcbdetach(inp);
in_pcbfree(inp);
INP_INFO_WUNLOCK(&V_udbinfo);
+ udp_discardcb(up);
}
static int
diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h
index d83f705f58a6..e4298191e090 100644
--- a/sys/netinet/udp_var.h
+++ b/sys/netinet/udp_var.h
@@ -51,6 +51,19 @@ struct udpiphdr {
#define ui_ulen ui_u.uh_ulen
#define ui_sum ui_u.uh_sum
+typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
+
+/*
+ * UDP control block; one per udp.
+ */
+struct udpcb {
+ udp_tun_func_t u_tun_func; /* UDP kernel tunneling callback. */
+ u_int u_flags; /* Generic UDP flags. */
+};
+
+#define intoudpcb(ip) ((struct udpcb *)(ip)->inp_ppcb)
+#define sotoudpcb(so) (intoudpcb(sotoinpcb(so)))
+
struct udpstat {
/* input statistics: */
u_long udps_ipackets; /* total input packets */
@@ -110,14 +123,15 @@ extern u_long udp_sendspace;
extern u_long udp_recvspace;
extern int udp_log_in_vain;
+int udp_newudpcb(struct inpcb *);
+void udp_discardcb(struct udpcb *);
+
void udp_ctlinput(int, struct sockaddr *, void *);
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
diff --git a/sys/netinet/vinet.h b/sys/netinet/vinet.h
index 6dcb685b98eb..026869326e28 100644
--- a/sys/netinet/vinet.h
+++ b/sys/netinet/vinet.h
@@ -149,6 +149,7 @@ struct vnet_inet {
struct inpcbhead _udb;
struct inpcbinfo _udbinfo;
+ uma_zone_t _udpcb_zone;
struct udpstat _udpstat;
int _udp_blackhole;
@@ -373,6 +374,7 @@ extern struct vnet_inet vnet_inet_0;
#define V_twq_2msl VNET_INET(twq_2msl)
#define V_udb VNET_INET(udb)
#define V_udbinfo VNET_INET(udbinfo)
+#define V_udpcb_zone VNET_INET(udpcb_zone)
#define V_udp_blackhole VNET_INET(udp_blackhole)
#define V_udpstat VNET_INET(udpstat)
#define V_useloopback VNET_INET(useloopback)
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 19cca2c11810..11dcf249db50 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -181,6 +181,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
struct ip6_hdr *ip6;
struct udphdr *uh;
struct inpcb *inp;
+ struct udpcb *up;
int off = *offp;
int plen, ulen;
struct sockaddr_in6 fromsa;
@@ -315,7 +316,10 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
INP_RLOCK(last);
- if (last->inp_ppcb != NULL) {
+ up = intoudpcb(last);
+ if (up->u_tun_func == NULL) {
+ udp6_append(last, n, off, &fromsa);
+ } else {
/*
* Engage the tunneling
* protocol we will have to
@@ -324,15 +328,9 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
* through multiple UDP's.
*
*/
- 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);
+ (*up->u_tun_func)(n, off, last);
}
+ INP_RUNLOCK(last);
}
}
last = inp;
@@ -361,18 +359,15 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
}
INP_RLOCK(last);
INP_INFO_RUNLOCK(&V_udbinfo);
- if (last->inp_ppcb != NULL) {
+ up = intoudpcb(last);
+ if (up->u_tun_func == NULL) {
+ udp6_append(last, m, off, &fromsa);
+ } else {
/*
* Engage 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);
+ (*up->u_tun_func)(m, off, last);
}
- udp6_append(last, m, off, &fromsa);
INP_RUNLOCK(last);
return (IPPROTO_DONE);
}
@@ -409,18 +404,16 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
}
INP_RLOCK(inp);
INP_INFO_RUNLOCK(&V_udbinfo);
- if (inp->inp_ppcb != NULL) {
+ up = intoudpcb(inp);
+ if (up->u_tun_func == NULL) {
+ udp6_append(inp, m, off, &fromsa);
+ } else {
/*
* Engage 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);
+ (*up->u_tun_func)(m, off, inp);
}
- udp6_append(inp, m, off, &fromsa);
INP_RUNLOCK(inp);
return (IPPROTO_DONE);
@@ -820,7 +813,6 @@ udp6_attach(struct socket *so, int proto, struct thread *td)
return (error);
}
inp = (struct inpcb *)so->so_pcb;
- INP_INFO_WUNLOCK(&V_udbinfo);
inp->inp_vflag |= INP_IPV6;
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
inp->inp_vflag |= INP_IPV4;
@@ -833,7 +825,16 @@ udp6_attach(struct socket *so, int proto, struct thread *td)
* which may match an IPv4-mapped IPv6 address.
*/
inp->inp_ip_ttl = V_ip_defttl;
+
+ error = udp_newudpcb(inp);
+ if (error) {
+ in_pcbdetach(inp);
+ in_pcbfree(inp);
+ INP_INFO_WUNLOCK(&V_udbinfo);
+ return (error);
+ }
INP_WUNLOCK(inp);
+ INP_INFO_WUNLOCK(&V_udbinfo);
return (0);
}
@@ -968,15 +969,19 @@ udp6_detach(struct socket *so)
{
INIT_VNET_INET(so->so_vnet);
struct inpcb *inp;
+ struct udpcb *up;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
+ up = intoudpcb(inp);
+ KASSERT(up != NULL, ("%s: up == NULL", __func__));
in_pcbdetach(inp);
in_pcbfree(inp);
INP_INFO_WUNLOCK(&V_udbinfo);
+ udp_discardcb(up);
}
static int
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 4b02e6ad98a4..19dc83eedcda 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -57,7 +57,7 @@
* is created, otherwise 1.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 800088 /* Master, propagated to newvers */
+#define __FreeBSD_version 800089 /* Master, propagated to newvers */
#ifndef LOCORE
#include <sys/types.h>