diff options
author | Christopher Zimmermann <chrisz@cvs.openbsd.org> | 2014-04-06 17:40:37 +0000 |
---|---|---|
committer | Christopher Zimmermann <chrisz@cvs.openbsd.org> | 2014-04-06 17:40:37 +0000 |
commit | bbf770b2a23f6893e063d73e8d15c5e68a672d2a (patch) | |
tree | f255b21a54381628ae092a62896697b156f585b0 /sys/netinet | |
parent | 4b7bae6707955efee137067149c86fabbd22aad6 (diff) |
get rid of expensive temporary connect in udp_output().
Also fixes a possible memory leak where m doesn't get freed in bail case.
"lets do it like this" claudio@
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/udp_usrreq.c | 48 |
1 files changed, 23 insertions, 25 deletions
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 17f69795b40..0426ae0cf4c 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp_usrreq.c,v 1.176 2014/03/28 08:33:51 sthen Exp $ */ +/* $OpenBSD: udp_usrreq.c,v 1.177 2014/04/06 17:40:36 chrisz Exp $ */ /* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */ /* @@ -967,11 +967,12 @@ udp_output(struct mbuf *m, ...) { struct inpcb *inp; struct mbuf *addr, *control; + struct sockaddr_in *sin = NULL; struct udpiphdr *ui; u_int32_t ipsecflowinfo = 0; int len = m->m_pkthdr.len; - struct in_addr laddr; - int s = 0, error = 0; + struct in_addr laddr = { INADDR_ANY }; + int error = 0; va_list ap; va_start(ap, m); @@ -995,19 +996,23 @@ udp_output(struct mbuf *m, ...) } if (addr) { - laddr = inp->inp_laddr; + sin = mtod(addr, struct sockaddr_in *); + if (addr->m_len != sizeof(*sin)) { + error = EINVAL; + goto release; + } if (inp->inp_faddr.s_addr != INADDR_ANY) { error = EISCONN; goto release; } - /* - * Must block input while temporarily connected. - */ - s = splsoftnet(); - error = in_pcbconnect(inp, addr); - if (error) { - splx(s); + if ((error = in_fixaddr(inp, sin, &laddr))) goto release; + + if (inp->inp_lport == 0) { + int s = splsoftnet(); + error = in_pcbbind(inp, NULL, curproc); + splx(s); + if (error) goto release; } } else { if (inp->inp_faddr.s_addr == INADDR_ANY) { @@ -1028,7 +1033,7 @@ udp_output(struct mbuf *m, ...) */ if (control->m_next) { error = EINVAL; - goto bail; + goto release; } clen = control->m_len; @@ -1036,13 +1041,13 @@ udp_output(struct mbuf *m, ...) do { if (clen < CMSG_LEN(0)) { error = EINVAL; - goto bail; + goto release; } cm = (struct cmsghdr *)cmsgs; if (cm->cmsg_len < CMSG_LEN(0) || CMSG_ALIGN(cm->cmsg_len) > clen) { error = EINVAL; - goto bail; + goto release; } if (cm->cmsg_len == CMSG_LEN(sizeof(ipsecflowinfo)) && cm->cmsg_level == IPPROTO_IP && @@ -1073,10 +1078,10 @@ udp_output(struct mbuf *m, ...) bzero(ui->ui_x1, sizeof ui->ui_x1); ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); - ui->ui_src = inp->inp_laddr; - ui->ui_dst = inp->inp_faddr; + ui->ui_src = laddr; + ui->ui_dst = sin ? sin->sin_addr : inp->inp_faddr; ui->ui_sport = inp->inp_lport; - ui->ui_dport = inp->inp_fport; + ui->ui_dport = sin ? sin->sin_port : inp->inp_fport; ui->ui_ulen = ui->ui_len; ((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len); ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; @@ -1096,20 +1101,13 @@ udp_output(struct mbuf *m, ...) error = EHOSTUNREACH; bail: - if (addr) { - inp->inp_laddr = laddr; - in_pcbdisconnect(inp); - splx(s); - } if (control) m_freem(control); return (error); release: m_freem(m); - if (control) - m_freem(control); - return (error); + goto bail; } /*ARGSUSED*/ |