summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2010-09-05 20:13:07 +0000
committertuexen <tuexen@FreeBSD.org>2010-09-05 20:13:07 +0000
commit908a61906a3959d7159393310a134e5e7ccaf193 (patch)
tree6da56548b04b564ea6db054076b52256e27ae83e /sys/netinet
parentdf58c57d8a012bf9e3ba7473400ccef5a5749b8a (diff)
downloadFreeBSD-src-908a61906a3959d7159393310a134e5e7ccaf193.zip
FreeBSD-src-908a61906a3959d7159393310a134e5e7ccaf193.tar.gz
Implement correct handling of address parameter and
sendinfo for SCTP send calls. MFC after: 4 weeks.
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/sctp_output.c182
-rw-r--r--sys/netinet/sctp_uio.h18
2 files changed, 78 insertions, 122 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 87b9143..38ad9d9 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -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,28 +12237,39 @@ sctp_lower_sosend(struct socket *so,
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n",
addr,
sndlen);
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
+ (inp->sctp_socket->so_qlimit)) {
+ /* The listener can NOT send */
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
+ error = ENOTCONN;
+ goto out_unlocked;
+ }
/**
* Pre-screen address, if one is given the sin-len
* must be set correctly!
*/
if (addr) {
- switch (addr->sa_family) {
+ union sctp_sockstore *raddr = (union sctp_sockstore *)addr;
+
+ switch (raddr->sa.sa_family) {
#if defined(INET)
case AF_INET:
- if (addr->sa_len != sizeof(struct sockaddr_in)) {
+ 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 (addr->sa_len != sizeof(struct sockaddr_in6)) {
+ 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:
@@ -12265,32 +12277,34 @@ sctp_lower_sosend(struct socket *so,
error = EAFNOSUPPORT;
goto out_unlocked;
}
- }
- hold_tcblock = 0;
+ } else
+ port = 0;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_socket->so_qlimit)) {
- /* The listener can NOT send */
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
- error = ENOTCONN;
- goto out_unlocked;
- }
- if ((use_rcvinfo) && srcv) {
- if (INVALID_SINFO_FLAG(srcv->sinfo_flags) ||
- PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) {
+ 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)) {
/*-
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index e3fbc3e..1cd5465 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -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
);
OpenPOWER on IntegriCloud