Remove the "temporary connection" hack in udp_output(). In order

to send datagrams from an unconnected socket, we used to first block
input, then connect the socket to the sendmsg/sendto destination,
send the datagram, and finally disconnect the socket and unblock
input.

We now use in_pcbconnect_setup() to check if a connect() would have
succeeded, but we never record the connection in the PCB (local
anonymous port allocation is still recorded, though). The result
from in_pcbconnect_setup() authorises the sending of the datagram
and selects the local address and port to use, so we just construct
the header and call ip_output().

Discussed on:	-net
Approved by:	re
This commit is contained in:
Ian Dowse
2002-10-21 20:10:05 +00:00
parent c177d125bf
commit 90162a4e87
+26 -23
View File
@@ -688,9 +688,10 @@ udp_output(inp, m, addr, control, td)
{ {
register struct udpiphdr *ui; register struct udpiphdr *ui;
register int len = m->m_pkthdr.len; register int len = m->m_pkthdr.len;
struct in_addr laddr; struct in_addr faddr, laddr;
struct sockaddr_in *sin; struct sockaddr_in *sin;
int s = 0, error = 0; int error = 0;
u_short fport, lport;
#ifdef MAC #ifdef MAC
mac_create_mbuf_from_socket(inp->inp_socket, m); mac_create_mbuf_from_socket(inp->inp_socket, m);
@@ -704,26 +705,36 @@ udp_output(inp, m, addr, control, td)
goto release; goto release;
} }
laddr = inp->inp_laddr;
lport = inp->inp_lport;
if (addr) { if (addr) {
sin = (struct sockaddr_in *)addr; sin = (struct sockaddr_in *)addr;
if (td && jailed(td->td_ucred)) if (td && jailed(td->td_ucred))
prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr); prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
laddr = inp->inp_laddr;
if (inp->inp_faddr.s_addr != INADDR_ANY) { if (inp->inp_faddr.s_addr != INADDR_ANY) {
error = EISCONN; error = EISCONN;
goto release; goto release;
} }
/* error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, &lport,
* Must block input while temporarily connected. &faddr.s_addr, &fport, NULL, td);
*/ if (error)
s = splnet();
error = in_pcbconnect(inp, addr, td);
if (error) {
splx(s);
goto release; goto release;
/* Commit the local port if newly assigned. */
if (inp->inp_laddr.s_addr == INADDR_ANY &&
inp->inp_lport == 0) {
inp->inp_lport = lport;
if (in_pcbinshash(inp) != 0) {
inp->inp_lport = 0;
error = EAGAIN;
goto release;
}
inp->inp_flags |= INP_ANONPORT;
} }
} else { } else {
if (inp->inp_faddr.s_addr == INADDR_ANY) { faddr = inp->inp_faddr;
fport = inp->inp_fport;
if (faddr.s_addr == INADDR_ANY) {
error = ENOTCONN; error = ENOTCONN;
goto release; goto release;
} }
@@ -735,8 +746,6 @@ udp_output(inp, m, addr, control, td)
M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
if (m == 0) { if (m == 0) {
error = ENOBUFS; error = ENOBUFS;
if (addr)
splx(s);
goto release; goto release;
} }
@@ -747,10 +756,10 @@ udp_output(inp, m, addr, control, td)
ui = mtod(m, struct udpiphdr *); ui = mtod(m, struct udpiphdr *);
bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */ bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */
ui->ui_pr = IPPROTO_UDP; ui->ui_pr = IPPROTO_UDP;
ui->ui_src = inp->inp_laddr; ui->ui_src = laddr;
ui->ui_dst = inp->inp_faddr; ui->ui_dst = faddr;
ui->ui_sport = inp->inp_lport; ui->ui_sport = lport;
ui->ui_dport = inp->inp_fport; ui->ui_dport = fport;
ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr)); ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr));
/* /*
@@ -772,12 +781,6 @@ udp_output(inp, m, addr, control, td)
error = ip_output(m, inp->inp_options, &inp->inp_route, error = ip_output(m, inp->inp_options, &inp->inp_route,
(inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)),
inp->inp_moptions, inp); inp->inp_moptions, inp);
if (addr) {
in_pcbdisconnect(inp);
inp->inp_laddr = laddr; /* XXX rehash? */
splx(s);
}
return (error); return (error);
release: release: