Commit 9d899ea3 authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] sctp_sendmsg() updates for TCP-style sockets.

parent d1256358
...@@ -299,8 +299,7 @@ void sctp_association_free(struct sctp_association *asoc) ...@@ -299,8 +299,7 @@ void sctp_association_free(struct sctp_association *asoc)
list_del(&asoc->asocs); list_del(&asoc->asocs);
/* Decrement the backlog value for a TCP-style listening socket. */ /* Decrement the backlog value for a TCP-style listening socket. */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
(SCTP_SS_LISTENING == sk->state))
sk->ack_backlog--; sk->ack_backlog--;
/* Mark as dead, so other users can know this structure is /* Mark as dead, so other users can know this structure is
...@@ -834,7 +833,7 @@ void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk) ...@@ -834,7 +833,7 @@ void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk)
list_del(&assoc->asocs); list_del(&assoc->asocs);
/* Decrement the backlog value for a TCP-style socket. */ /* Decrement the backlog value for a TCP-style socket. */
if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type) if (sctp_style(oldsk, TCP))
oldsk->ack_backlog--; oldsk->ack_backlog--;
/* Release references to the old endpoint and the sock. */ /* Release references to the old endpoint and the sock. */
...@@ -877,7 +876,7 @@ void sctp_assoc_update(struct sctp_association *asoc, ...@@ -877,7 +876,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
* current next_tsn in case data sent to peer * current next_tsn in case data sent to peer
* has been discarded and needs retransmission. * has been discarded and needs retransmission.
*/ */
if (SCTP_STATE_ESTABLISHED == asoc->state) { if (sctp_state(asoc, ESTABLISHED)) {
asoc->next_tsn = new->next_tsn; asoc->next_tsn = new->next_tsn;
asoc->ctsn_ack_point = new->ctsn_ack_point; asoc->ctsn_ack_point = new->ctsn_ack_point;
......
...@@ -177,8 +177,7 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, ...@@ -177,8 +177,7 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
list_add_tail(&asoc->asocs, &ep->asocs); list_add_tail(&asoc->asocs, &ep->asocs);
/* Increment the backlog value for a TCP-style listening socket. */ /* Increment the backlog value for a TCP-style listening socket. */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
(SCTP_SS_LISTENING == sk->state))
sk->ack_backlog++; sk->ack_backlog++;
} }
......
...@@ -456,8 +456,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -456,8 +456,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
tp->last_time_used = jiffies; tp->last_time_used = jiffies;
/* Restart the AUTOCLOSE timer when sending data. */ /* Restart the AUTOCLOSE timer when sending data. */
if ((SCTP_STATE_ESTABLISHED == asoc->state) && if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) {
(asoc->autoclose)) {
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
...@@ -608,7 +607,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -608,7 +607,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* unacknowledged. * unacknowledged.
*/ */
if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) { q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
unsigned len = datasize + q->out_qlen; unsigned len = datasize + q->out_qlen;
/* Check whether this chunk and all the rest of pending /* Check whether this chunk and all the rest of pending
......
...@@ -610,30 +610,27 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, ...@@ -610,30 +610,27 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc,
sctp_state_t state) sctp_state_t state)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct sctp_opt *sp = sctp_sk(sk);
asoc->state = state; asoc->state = state;
asoc->state_timestamp = jiffies; asoc->state_timestamp = jiffies;
if (SCTP_SOCKET_TCP == sp->type) { if (sctp_style(sk, TCP)) {
/* Change the sk->state of a TCP-style socket that has /* Change the sk->state of a TCP-style socket that has
* sucessfully completed a connect() call. * sucessfully completed a connect() call.
*/ */
if ((SCTP_STATE_ESTABLISHED == asoc->state) && if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
(SCTP_SS_CLOSED == sk->state))
sk->state = SCTP_SS_ESTABLISHED; sk->state = SCTP_SS_ESTABLISHED;
/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */ /* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
if (SCTP_STATE_SHUTDOWN_RECEIVED == asoc->state) if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
sctp_sstate(sk, ESTABLISHED))
sk->shutdown |= RCV_SHUTDOWN; sk->shutdown |= RCV_SHUTDOWN;
} }
if ((SCTP_STATE_ESTABLISHED == asoc->state) || if (sctp_state(asoc, ESTABLISHED) ||
(SCTP_STATE_CLOSED == asoc->state) || sctp_state(asoc, CLOSED) ||
(SCTP_STATE_SHUTDOWN_RECEIVED == asoc->state)) { sctp_state(asoc, SHUTDOWN_RECEIVED)) {
/* Wake up any processes waiting in the asoc's wait queue in /* Wake up any processes waiting in the asoc's wait queue in
* sctp_wait_for_connect() or sctp_wait_for_sndbuf(). * sctp_wait_for_connect() or sctp_wait_for_sndbuf().
*/ */
...@@ -646,7 +643,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *as ...@@ -646,7 +643,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *as
* For a UDP-style socket, the waiters are woken up by the * For a UDP-style socket, the waiters are woken up by the
* notifications. * notifications.
*/ */
if (SCTP_SOCKET_UDP != sp->type) if (!sctp_style(sk, UDP))
sk->state_change(sk); sk->state_change(sk);
} }
} }
...@@ -661,8 +658,7 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds, ...@@ -661,8 +658,7 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
* listening socket, do not free it so that accept() can pick it * listening socket, do not free it so that accept() can pick it
* up later. * up later.
*/ */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && (!asoc->temp))
(SCTP_SS_LISTENING == sk->state) && (!asoc->temp))
return; return;
sctp_unhash_established(asoc); sctp_unhash_established(asoc);
......
...@@ -794,7 +794,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -794,7 +794,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name);
if (sctp_style(sk, TCP) && (SCTP_SS_ESTABLISHED != sk->state)) { /* We cannot send a message over a TCP-style listening socket. */
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) {
err = -EPIPE; err = -EPIPE;
goto out_nounlock; goto out_nounlock;
} }
...@@ -843,6 +844,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -843,6 +844,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n",
msg_len, sinfo_flags); msg_len, sinfo_flags);
/* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */
if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) {
err = -EINVAL;
goto out_nounlock;
}
/* If MSG_EOF is set, no data can be sent. Disallow sending zero /* If MSG_EOF is set, no data can be sent. Disallow sending zero
* length messages when MSG_EOF|MSG_ABORT is not set. * length messages when MSG_EOF|MSG_ABORT is not set.
* If MSG_ABORT is set, the message length could be non zero with * If MSG_ABORT is set, the message length could be non zero with
...@@ -874,10 +881,13 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -874,10 +881,13 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);
if (!asoc) { if (!asoc) {
/* If we could not find a matching association on the /* If we could not find a matching association on the
* endpoint, make sure that there is no peeled-off * endpoint, make sure that it is not a TCP-style
* association on another socket. * socket that already has an association or there is
* no peeled-off association on another socket.
*/ */
if (sctp_endpoint_is_peeled_off(ep, &to)) { if ((sctp_style(sk, TCP) &&
sctp_sstate(sk, ESTABLISHED)) ||
sctp_endpoint_is_peeled_off(ep, &to)) {
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
goto out_unlock; goto out_unlock;
} }
...@@ -885,7 +895,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -885,7 +895,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
} else { } else {
asoc = sctp_id2assoc(sk, associd); asoc = sctp_id2assoc(sk, associd);
if (!asoc) { if (!asoc) {
err = -EINVAL; err = -EPIPE;
goto out_unlock; goto out_unlock;
} }
} }
...@@ -1050,11 +1060,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1050,11 +1060,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_free; goto out_free;
} }
/* This flag, in the UDP model, requests the SCTP stack to /* If an address is passed with the sendto/sendmsg call, it is used
* override the primary destination address with the * to override the primary destination address in the TCP model, or
* address found with the sendto/sendmsg call. * when MSG_ADDR_OVER flag is set in the UDP model.
*/ */
if (sinfo_flags & MSG_ADDR_OVER) { if ((sctp_style(sk, TCP) && msg_name) ||
(sinfo_flags & MSG_ADDR_OVER)) {
chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);
if (!chunk_tp) { if (!chunk_tp) {
err = -EINVAL; err = -EINVAL;
...@@ -1064,7 +1075,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1064,7 +1075,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
chunk_tp = NULL; chunk_tp = NULL;
/* Auto-connect, if we aren't connected already. */ /* Auto-connect, if we aren't connected already. */
if (SCTP_STATE_CLOSED == asoc->state) { if (sctp_state(asoc, CLOSED)) {
err = sctp_primitive_ASSOCIATE(asoc, NULL); err = sctp_primitive_ASSOCIATE(asoc, NULL);
if (err < 0) if (err < 0)
goto out_free; goto out_free;
...@@ -1193,7 +1204,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1193,7 +1204,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
sctp_lock_sock(sk); sctp_lock_sock(sk);
if (sctp_style(sk, TCP) && (SCTP_SS_ESTABLISHED != sk->state)) { if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) {
err = -ENOTCONN; err = -ENOTCONN;
goto out; goto out;
} }
...@@ -2095,7 +2106,7 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in ...@@ -2095,7 +2106,7 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in
static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
{ {
/* Applicable to UDP-style socket only */ /* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) if (sctp_style(sk, TCP))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (len != sizeof(int)) if (len != sizeof(int))
return -EINVAL; return -EINVAL;
...@@ -2115,7 +2126,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, ...@@ -2115,7 +2126,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
/* An association cannot be branched off from an already peeled-off /* An association cannot be branched off from an already peeled-off
* socket, nor is this supported for tcp style sockets. * socket, nor is this supported for tcp style sockets.
*/ */
if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) if (!sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
/* Create a new socket. */ /* Create a new socket. */
...@@ -2861,10 +2872,10 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) ...@@ -2861,10 +2872,10 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
/* Only UDP style sockets that are not peeled off are allowed to /* Only UDP style sockets that are not peeled off are allowed to
* listen(). * listen().
*/ */
if (SCTP_SOCKET_UDP != sp->type) if (!sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (sk->state == SCTP_SS_LISTENING) if (sctp_sstate(sk, LISTENING))
return 0; return 0;
/* /*
...@@ -2897,7 +2908,7 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) ...@@ -2897,7 +2908,7 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
if (sk->state == SCTP_SS_LISTENING) if (sctp_sstate(sk, LISTENING))
return 0; return 0;
/* /*
...@@ -2994,7 +3005,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -2994,7 +3005,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
/* A TCP-style listening socket becomes readable when the accept queue /* A TCP-style listening socket becomes readable when the accept queue
* is not empty. * is not empty.
*/ */
if ((SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_LISTENING == sk->state)) if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
return (!list_empty(&sp->ep->asocs)) ? return (!list_empty(&sp->ep->asocs)) ?
(POLLIN | POLLRDNORM) : 0; (POLLIN | POLLRDNORM) : 0;
...@@ -3011,11 +3022,9 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -3011,11 +3022,9 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
(sk->shutdown & RCV_SHUTDOWN)) (sk->shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { /* The association is either gone or not ready. */
/* The association is either gone or not ready. */ if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED))
if (SCTP_SS_CLOSED == sk->state) return mask;
return mask;
}
/* Is it writable? */ /* Is it writable? */
if (sctp_writeable(sk)) { if (sctp_writeable(sk)) {
...@@ -3255,8 +3264,7 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) ...@@ -3255,8 +3264,7 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
error = -ENOTCONN; error = -ENOTCONN;
/* Is there a good reason to think that we may receive some data? */ /* Is there a good reason to think that we may receive some data? */
if ((list_empty(&sctp_sk(sk)->ep->asocs)) && if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING))
(sk->state != SCTP_SS_LISTENING))
goto out; goto out;
/* Handle signals. */ /* Handle signals. */
...@@ -3578,7 +3586,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) ...@@ -3578,7 +3586,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
if (signal_pending(current)) if (signal_pending(current))
goto do_interrupted; goto do_interrupted;
if (asoc->state == SCTP_STATE_ESTABLISHED) if (sctp_state(asoc, ESTABLISHED))
break; break;
/* Let another process have a go. Since we are going /* Let another process have a go. Since we are going
...@@ -3633,7 +3641,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) ...@@ -3633,7 +3641,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
} }
err = -EINVAL; err = -EINVAL;
if (sk->state != SCTP_SS_LISTENING) if (!sctp_sstate(sk, LISTENING))
break; break;
err = 0; err = 0;
...@@ -3738,6 +3746,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3738,6 +3746,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
/* Migrate the association to the new socket. */ /* Migrate the association to the new socket. */
sctp_assoc_migrate(assoc, newsk); sctp_assoc_migrate(assoc, newsk);
/* If the association on the newsk is already closed before accept()
* is called, set RCV_SHUTDOWN flag.
*/
if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP))
newsk->shutdown |= RCV_SHUTDOWN;
newsk->state = SCTP_SS_ESTABLISHED; newsk->state = SCTP_SS_ESTABLISHED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment