Implement correct handling of address parameter and
sendinfo for SCTP send calls. MFC after: 4 weeks.
This commit is contained in:
parent
d57429e2c2
commit
049640c1f0
@ -2381,7 +2381,6 @@ sctp_generic_sendmsg (td, uap)
|
||||
struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL;
|
||||
struct socket *so;
|
||||
struct file *fp = NULL;
|
||||
int use_rcvinfo = 1;
|
||||
int error = 0, len;
|
||||
struct sockaddr *to = NULL;
|
||||
#ifdef KTRACE
|
||||
@ -2434,7 +2433,7 @@ sctp_generic_sendmsg (td, uap)
|
||||
CURVNET_SET(so->so_vnet);
|
||||
error = sctp_lower_sosend(so, to, &auio,
|
||||
(struct mbuf *)NULL, (struct mbuf *)NULL,
|
||||
uap->flags, use_rcvinfo, u_sinfo, td);
|
||||
uap->flags, u_sinfo, td);
|
||||
CURVNET_RESTORE();
|
||||
if (error) {
|
||||
if (auio.uio_resid != len && (error == ERESTART ||
|
||||
@ -2485,7 +2484,6 @@ sctp_generic_sendmsg_iov(td, uap)
|
||||
struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL;
|
||||
struct socket *so;
|
||||
struct file *fp = NULL;
|
||||
int use_rcvinfo = 1;
|
||||
int error=0, len, i;
|
||||
struct sockaddr *to = NULL;
|
||||
#ifdef KTRACE
|
||||
@ -2552,7 +2550,7 @@ sctp_generic_sendmsg_iov(td, uap)
|
||||
CURVNET_SET(so->so_vnet);
|
||||
error = sctp_lower_sosend(so, to, &auio,
|
||||
(struct mbuf *)NULL, (struct mbuf *)NULL,
|
||||
uap->flags, use_rcvinfo, u_sinfo, td);
|
||||
uap->flags, u_sinfo, td);
|
||||
CURVNET_RESTORE();
|
||||
if (error) {
|
||||
if (auio.uio_resid != len && (error == ERESTART ||
|
||||
|
@ -12158,7 +12158,7 @@ sctp_sosend(struct socket *so,
|
||||
error = sctp_lower_sosend(so, addr_to_use, uio, top,
|
||||
control,
|
||||
flags,
|
||||
use_rcvinfo, &srcv
|
||||
use_rcvinfo ? &srcv : NULL
|
||||
,p
|
||||
);
|
||||
return (error);
|
||||
@ -12172,7 +12172,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
struct mbuf *i_pak,
|
||||
struct mbuf *control,
|
||||
int flags,
|
||||
int use_rcvinfo,
|
||||
struct sctp_sndrcvinfo *srcv
|
||||
,
|
||||
struct thread *p
|
||||
@ -12200,8 +12199,10 @@ sctp_lower_sosend(struct socket *so,
|
||||
int got_all_of_the_send = 0;
|
||||
int hold_tcblock = 0;
|
||||
int non_blocking = 0;
|
||||
int temp_flags = 0;
|
||||
uint32_t local_add_more, local_soresv = 0;
|
||||
uint16_t port;
|
||||
uint16_t sinfo_flags;
|
||||
sctp_assoc_t sinfo_assoc_id;
|
||||
|
||||
error = 0;
|
||||
net = NULL;
|
||||
@ -12236,38 +12237,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n",
|
||||
addr,
|
||||
sndlen);
|
||||
/**
|
||||
* Pre-screen address, if one is given the sin-len
|
||||
* must be set correctly!
|
||||
*/
|
||||
if (addr) {
|
||||
switch (addr->sa_family) {
|
||||
#if defined(INET)
|
||||
case AF_INET:
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if defined(INET6)
|
||||
case AF_INET6:
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAFNOSUPPORT);
|
||||
error = EAFNOSUPPORT;
|
||||
goto out_unlocked;
|
||||
}
|
||||
}
|
||||
hold_tcblock = 0;
|
||||
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
|
||||
(inp->sctp_socket->so_qlimit)) {
|
||||
/* The listener can NOT send */
|
||||
@ -12275,22 +12244,67 @@ sctp_lower_sosend(struct socket *so,
|
||||
error = ENOTCONN;
|
||||
goto out_unlocked;
|
||||
}
|
||||
if ((use_rcvinfo) && srcv) {
|
||||
if (INVALID_SINFO_FLAG(srcv->sinfo_flags) ||
|
||||
PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) {
|
||||
/**
|
||||
* Pre-screen address, if one is given the sin-len
|
||||
* must be set correctly!
|
||||
*/
|
||||
if (addr) {
|
||||
union sctp_sockstore *raddr = (union sctp_sockstore *)addr;
|
||||
|
||||
switch (raddr->sa.sa_family) {
|
||||
#if defined(INET)
|
||||
case AF_INET:
|
||||
if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
port = raddr->sin.sin_port;
|
||||
break;
|
||||
#endif
|
||||
#if defined(INET6)
|
||||
case AF_INET6:
|
||||
if (raddr->sin6.sin6_len != sizeof(struct sockaddr_in6)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
port = raddr->sin6.sin6_port;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAFNOSUPPORT);
|
||||
error = EAFNOSUPPORT;
|
||||
goto out_unlocked;
|
||||
}
|
||||
} else
|
||||
port = 0;
|
||||
|
||||
if (srcv) {
|
||||
sinfo_flags = srcv->sinfo_flags;
|
||||
sinfo_assoc_id = srcv->sinfo_assoc_id;
|
||||
if (INVALID_SINFO_FLAG(sinfo_flags) ||
|
||||
PR_SCTP_INVALID_POLICY(sinfo_flags)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
if (srcv->sinfo_flags)
|
||||
SCTP_STAT_INCR(sctps_sends_with_flags);
|
||||
|
||||
if (srcv->sinfo_flags & SCTP_SENDALL) {
|
||||
/* its a sendall */
|
||||
error = sctp_sendall(inp, uio, top, srcv);
|
||||
top = NULL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
} else {
|
||||
sinfo_flags = inp->def_send.sinfo_flags;
|
||||
sinfo_assoc_id = inp->def_send.sinfo_assoc_id;
|
||||
}
|
||||
if (sinfo_flags & SCTP_SENDALL) {
|
||||
/* its a sendall */
|
||||
error = sctp_sendall(inp, uio, top, srcv);
|
||||
top = NULL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
/* now we must find the assoc */
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
|
||||
@ -12306,80 +12320,8 @@ sctp_lower_sosend(struct socket *so,
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
hold_tcblock = 1;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
if (addr) {
|
||||
/* Must locate the net structure if addr given */
|
||||
net = sctp_findnet(stcb, addr);
|
||||
if (net) {
|
||||
/* validate port was 0 or correct */
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
if ((sin->sin_port != 0) &&
|
||||
(sin->sin_port != stcb->rport)) {
|
||||
net = NULL;
|
||||
}
|
||||
}
|
||||
temp_flags |= SCTP_ADDR_OVER;
|
||||
} else
|
||||
net = stcb->asoc.primary_destination;
|
||||
if (addr && (net == NULL)) {
|
||||
/* Could not find address, was it legal */
|
||||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
if (sin->sin_addr.s_addr == 0) {
|
||||
if ((sin->sin_port == 0) ||
|
||||
(sin->sin_port == stcb->rport)) {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)addr;
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
|
||||
if ((sin6->sin6_port == 0) ||
|
||||
(sin6->sin6_port == stcb->rport)) {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (net == NULL) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
} else if (use_rcvinfo && srcv && srcv->sinfo_assoc_id) {
|
||||
stcb = sctp_findassociation_ep_asocid(inp, srcv->sinfo_assoc_id, 0);
|
||||
if (stcb) {
|
||||
if (addr)
|
||||
/*
|
||||
* Must locate the net structure if addr
|
||||
* given
|
||||
*/
|
||||
net = sctp_findnet(stcb, addr);
|
||||
else
|
||||
net = stcb->asoc.primary_destination;
|
||||
if ((srcv->sinfo_flags & SCTP_ADDR_OVER) &&
|
||||
((net == NULL) || (addr == NULL))) {
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
if (addr == NULL) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
/* Validate port is 0 or correct */
|
||||
if ((sin->sin_port != 0) &&
|
||||
(sin->sin_port != stcb->rport)) {
|
||||
net = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
hold_tcblock = 0;
|
||||
} else if (sinfo_assoc_id) {
|
||||
stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0);
|
||||
} else if (addr) {
|
||||
/*-
|
||||
* Since we did not use findep we must
|
||||
@ -12452,10 +12394,8 @@ sctp_lower_sosend(struct socket *so,
|
||||
*/
|
||||
uint32_t vrf_id;
|
||||
|
||||
if ((use_rcvinfo) && (srcv) &&
|
||||
((srcv->sinfo_flags & SCTP_ABORT) ||
|
||||
((srcv->sinfo_flags & SCTP_EOF) &&
|
||||
(sndlen == 0)))) {
|
||||
if ((sinfo_flags & SCTP_ABORT) ||
|
||||
((sinfo_flags & SCTP_EOF) && (sndlen == 0))) {
|
||||
/*-
|
||||
* User asks to abort a non-existant assoc,
|
||||
* or EOF a non-existant assoc with no data
|
||||
@ -12584,10 +12524,25 @@ sctp_lower_sosend(struct socket *so,
|
||||
* structure may now have an update and thus we may need to
|
||||
* change it BEFORE we append the message.
|
||||
*/
|
||||
net = stcb->asoc.primary_destination;
|
||||
asoc = &stcb->asoc;
|
||||
}
|
||||
}
|
||||
if (srcv == NULL)
|
||||
srcv = (struct sctp_sndrcvinfo *)&stcb->asoc.def_send;
|
||||
if (srcv->sinfo_flags & SCTP_ADDR_OVER) {
|
||||
if (addr)
|
||||
net = sctp_findnet(stcb, addr);
|
||||
else
|
||||
net = NULL;
|
||||
if ((net == NULL) ||
|
||||
((port != 0) && (port != stcb->rport))) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
|
||||
if ((SCTP_SO_IS_NBIO(so)
|
||||
|| (flags & MSG_NBIO)
|
||||
)) {
|
||||
@ -12658,10 +12613,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
|
||||
queue_only = 1;
|
||||
}
|
||||
if ((use_rcvinfo == 0) || (srcv == NULL)) {
|
||||
/* Grab the default stuff from the asoc */
|
||||
srcv = (struct sctp_sndrcvinfo *)&stcb->asoc.def_send;
|
||||
}
|
||||
/* we are now done with all control */
|
||||
if (control) {
|
||||
sctp_m_freem(control);
|
||||
@ -12671,8 +12622,7 @@ sctp_lower_sosend(struct socket *so,
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
|
||||
(asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) {
|
||||
if ((use_rcvinfo) &&
|
||||
(srcv->sinfo_flags & SCTP_ABORT)) {
|
||||
if (srcv->sinfo_flags & SCTP_ABORT) {
|
||||
;
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
|
||||
@ -12684,16 +12634,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
if (p) {
|
||||
p->td_ru.ru_msgsnd++;
|
||||
}
|
||||
if (stcb) {
|
||||
if (((srcv->sinfo_flags | temp_flags) & SCTP_ADDR_OVER) == 0) {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
}
|
||||
if (net == NULL) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
if ((net->flight_size > net->cwnd) &&
|
||||
(asoc->sctp_cmt_on_off == 0)) {
|
||||
/*-
|
||||
|
@ -982,6 +982,23 @@ union sctp_sockstore {
|
||||
struct sockaddr sa;
|
||||
};
|
||||
|
||||
|
||||
/***********************************/
|
||||
/* And something for us old timers */
|
||||
/***********************************/
|
||||
|
||||
#ifndef ntohll
|
||||
#include <sys/endian.h>
|
||||
#define ntohll(x) be64toh(x)
|
||||
#endif
|
||||
|
||||
#ifndef htonll
|
||||
#include <sys/endian.h>
|
||||
#define htonll(x) htobe64(x)
|
||||
#endif
|
||||
/***********************************/
|
||||
|
||||
|
||||
struct xsctp_inpcb {
|
||||
uint32_t last;
|
||||
uint32_t flags;
|
||||
@ -1079,7 +1096,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
struct mbuf *i_pak,
|
||||
struct mbuf *control,
|
||||
int flags,
|
||||
int use_rcvinfo,
|
||||
struct sctp_sndrcvinfo *srcv
|
||||
,struct thread *p
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user