Index: sys/netinet/udp_var.h =================================================================== --- sys/netinet/udp_var.h (.../freebsd7/20090415) (revision 191260) +++ sys/netinet/udp_var.h (.../stable/7) (revision 191260) @@ -51,6 +51,16 @@ #define ui_ulen ui_u.uh_ulen #define ui_sum ui_u.uh_sum +/* + * Udp control block, one per udp. + */ +struct udpcb { + struct inpcb *u_inpcb; +}; + +#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 */ Index: sys/netinet/udp_usrreq.c =================================================================== --- sys/netinet/udp_usrreq.c (.../freebsd7/20090415) (revision 191260) +++ sys/netinet/udp_usrreq.c (.../stable/7) (revision 191260) @@ -151,11 +153,14 @@ static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *, struct mbuf *, struct thread *); +static uma_zone_t udpcb_zone; + static void udp_zone_change(void *tag) { uma_zone_set_max(udbinfo.ipi_zone, maxsockets); + uma_zone_set_max(udpcb_zone, maxsockets); } static int @@ -182,6 +187,9 @@ udbinfo.ipi_zone = uma_zcreate("udpcb", sizeof(struct inpcb), NULL, NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); uma_zone_set_max(udbinfo.ipi_zone, maxsockets); + udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); + uma_zone_set_max(udpcb_zone, maxsockets); EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL, EVENTHANDLER_PRI_ANY); TUNABLE_INT_FETCH("net.inet.udp.soreceive_dgram_enabled", @@ -194,7 +202,28 @@ } } +static struct udpcb * +udp_newudpcb(struct inpcb *inp) +{ + struct udpcb *up; + + up = uma_zalloc(udpcb_zone, M_NOWAIT | M_ZERO); + if (up == NULL) + return (NULL); + up->u_inpcb = inp; + inp->inp_ppcb = up; + return (up); +} + +static void +udp_discardcb(struct udpcb *up) +{ + + up->u_inpcb = NULL; + uma_zfree(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 * contains the source address. If the socket ends up being an IPv6 socket, @@ -205,12 +293,14 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, struct sockaddr_in *udp_in) { + struct udpcb *up; struct sockaddr *append_sa; struct socket *so; struct mbuf *opts = 0; #ifdef INET6 struct sockaddr_in6 udp_in6; #endif + int rval; INP_RLOCK_ASSERT(inp); @@ -1113,6 +1334,7 @@ static int udp_attach(struct socket *so, int proto, struct thread *td) { + struct udpcb *up; struct inpcb *inp; int error; @@ -1129,6 +1351,12 @@ } inp = (struct inpcb *)so->so_pcb; + up = udp_newudpcb(inp); + if (up == NULL) { + in_pcbdetach(inp); + in_pcbfree(inp); + return (ENOBUFS); + } INP_INFO_WUNLOCK(&udbinfo); inp->inp_vflag |= INP_IPV4; inp->inp_ip_ttl = ip_defttl; @@ -1204,17 +1432,22 @@ static void udp_detach(struct socket *so) { + struct udpcb *up; struct inpcb *inp; inp = sotoinpcb(so); + up = intoudpcb(inp); KASSERT(inp != NULL, ("udp_detach: inp == NULL")); + KASSERT(up != NULL, ("udp_detach: up == NULL")); KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, ("udp_detach: not disconnected")); INP_INFO_WLOCK(&udbinfo); INP_WLOCK(inp); + inp->inp_ppcb = NULL; in_pcbdetach(inp); in_pcbfree(inp); INP_INFO_WUNLOCK(&udbinfo); + udp_discardcb(up); } static int