summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/command.h3
-rw-r--r--include/net/sctp/structs.h1
-rw-r--r--net/sctp/chunk.c13
-rw-r--r--net/sctp/sm_sideeffect.c29
-rw-r--r--net/sctp/sm_statefuns.c4
-rw-r--r--net/sctp/socket.c26
6 files changed, 61 insertions, 15 deletions
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 3b966802e05d..8be5135ff7aa 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -106,6 +106,7 @@ typedef enum {
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
+ SCTP_CMD_SEND_MSG, /* Send the whole use message */
SCTP_CMD_LAST
} sctp_verb_t;
@@ -139,6 +140,7 @@ typedef union {
struct sctp_ulpevent *ulpevent;
struct sctp_packet *packet;
sctp_sackhdr_t *sackh;
+ struct sctp_datamsg *msg;
} sctp_arg_t;
/* We are simulating ML type constructors here.
@@ -188,6 +190,7 @@ SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent)
SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet)
SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh)
+SCTP_ARG_CONSTRUCTOR(DATAMSG, struct sctp_datamsg *, msg)
typedef struct {
sctp_arg_t obj;
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index edfcacf3250e..97024faaa08f 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -643,6 +643,7 @@ struct sctp_datamsg {
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
struct sctp_sndrcvinfo *,
struct msghdr *, int len);
+void sctp_datamsg_free(struct sctp_datamsg *);
void sctp_datamsg_put(struct sctp_datamsg *);
void sctp_chunk_fail(struct sctp_chunk *, int error);
int sctp_chunk_abandoned(struct sctp_chunk *);
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 7acaf15679b6..645577ddc33e 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -73,6 +73,19 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
return msg;
}
+void sctp_datamsg_free(struct sctp_datamsg *msg)
+{
+ struct sctp_chunk *chunk;
+
+ /* This doesn't have to be a _safe vairant because
+ * sctp_chunk_free() only drops the refs.
+ */
+ list_for_each_entry(chunk, &msg->chunks, frag_list)
+ sctp_chunk_free(chunk);
+
+ sctp_datamsg_put(msg);
+}
+
/* Final destructruction of datamsg memory. */
static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
{
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 86426aac1600..238adf7978e9 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -931,6 +931,27 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
}
+/* Send the whole message, chunk by chunk, to the outqueue.
+ * This way the whole message is queued up and bundling if
+ * encouraged for small fragments.
+ */
+static int sctp_cmd_send_msg(struct sctp_association *asoc,
+ struct sctp_datamsg *msg)
+{
+ struct sctp_chunk *chunk;
+ int error = 0;
+
+ list_for_each_entry(chunk, &msg->chunks, frag_list) {
+ error = sctp_outq_tail(&asoc->outqueue, chunk);
+ if (error)
+ break;
+ }
+
+ return error;
+}
+
+
+
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* functionality there.
@@ -1575,7 +1596,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_UPDATE_INITTAG:
asoc->peer.i.init_tag = cmd->obj.u32;
break;
-
+ case SCTP_CMD_SEND_MSG:
+ if (!asoc->outqueue.cork) {
+ sctp_outq_cork(&asoc->outqueue);
+ local_cork = 1;
+ }
+ error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
+ break;
default:
printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 50225dd2e6dc..910926906a3a 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -4555,9 +4555,9 @@ sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
void *arg,
sctp_cmd_seq_t *commands)
{
- struct sctp_chunk *chunk = arg;
+ struct sctp_datamsg *msg = arg;
- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk));
+ sctp_add_cmd_sf(commands, SCTP_CMD_SEND_MSG, SCTP_DATAMSG(msg));
return SCTP_DISPOSITION_CONSUME;
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a7e544e3f28a..95a5623d79a0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1814,20 +1814,22 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_set_owner_w(chunk);
chunk->transport = chunk_tp;
-
- /* Send it to the lower layers. Note: all chunks
- * must either fail or succeed. The lower layer
- * works that way today. Keep it that way or this
- * breaks.
- */
- err = sctp_primitive_SEND(asoc, chunk);
- /* Did the lower layer accept the chunk? */
- if (err)
- sctp_chunk_free(chunk);
- SCTP_DEBUG_PRINTK("We sent primitively.\n");
}
- sctp_datamsg_put(datamsg);
+ /* Send it to the lower layers. Note: all chunks
+ * must either fail or succeed. The lower layer
+ * works that way today. Keep it that way or this
+ * breaks.
+ */
+ err = sctp_primitive_SEND(asoc, datamsg);
+ /* Did the lower layer accept the chunk? */
+ if (err)
+ sctp_datamsg_free(datamsg);
+ else
+ sctp_datamsg_put(datamsg);
+
+ SCTP_DEBUG_PRINTK("We sent primitively.\n");
+
if (err)
goto out_free;
else