|
|
@@ -68,7 +68,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
|
|
|
|
|
|
static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
|
|
|
|
|
|
-static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp);
|
|
|
+static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp);
|
|
|
|
|
|
/* Add data to the front of the queue. */
|
|
|
static inline void sctp_outq_head_data(struct sctp_outq *q,
|
|
|
@@ -285,10 +285,9 @@ void sctp_outq_free(struct sctp_outq *q)
|
|
|
}
|
|
|
|
|
|
/* Put a new chunk in an sctp_outq. */
|
|
|
-int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp)
|
|
|
+void sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp)
|
|
|
{
|
|
|
struct net *net = sock_net(q->asoc->base.sk);
|
|
|
- int error = 0;
|
|
|
|
|
|
pr_debug("%s: outq:%p, chunk:%p[%s]\n", __func__, q, chunk,
|
|
|
chunk && chunk->chunk_hdr ?
|
|
|
@@ -299,54 +298,26 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp)
|
|
|
* immediately.
|
|
|
*/
|
|
|
if (sctp_chunk_is_data(chunk)) {
|
|
|
- /* Is it OK to queue data chunks? */
|
|
|
- /* From 9. Termination of Association
|
|
|
- *
|
|
|
- * When either endpoint performs a shutdown, the
|
|
|
- * association on each peer will stop accepting new
|
|
|
- * data from its user and only deliver data in queue
|
|
|
- * at the time of sending or receiving the SHUTDOWN
|
|
|
- * chunk.
|
|
|
- */
|
|
|
- switch (q->asoc->state) {
|
|
|
- case SCTP_STATE_CLOSED:
|
|
|
- case SCTP_STATE_SHUTDOWN_PENDING:
|
|
|
- case SCTP_STATE_SHUTDOWN_SENT:
|
|
|
- case SCTP_STATE_SHUTDOWN_RECEIVED:
|
|
|
- case SCTP_STATE_SHUTDOWN_ACK_SENT:
|
|
|
- /* Cannot send after transport endpoint shutdown */
|
|
|
- error = -ESHUTDOWN;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- pr_debug("%s: outqueueing: outq:%p, chunk:%p[%s])\n",
|
|
|
- __func__, q, chunk, chunk && chunk->chunk_hdr ?
|
|
|
- sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
|
|
|
- "illegal chunk");
|
|
|
-
|
|
|
- sctp_chunk_hold(chunk);
|
|
|
- sctp_outq_tail_data(q, chunk);
|
|
|
- if (chunk->asoc->prsctp_enable &&
|
|
|
- SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags))
|
|
|
- chunk->asoc->sent_cnt_removable++;
|
|
|
- if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
|
|
|
- SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
|
|
|
- else
|
|
|
- SCTP_INC_STATS(net, SCTP_MIB_OUTORDERCHUNKS);
|
|
|
- break;
|
|
|
- }
|
|
|
+ pr_debug("%s: outqueueing: outq:%p, chunk:%p[%s])\n",
|
|
|
+ __func__, q, chunk, chunk && chunk->chunk_hdr ?
|
|
|
+ sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
|
|
|
+ "illegal chunk");
|
|
|
+
|
|
|
+ sctp_outq_tail_data(q, chunk);
|
|
|
+ if (chunk->asoc->prsctp_enable &&
|
|
|
+ SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags))
|
|
|
+ chunk->asoc->sent_cnt_removable++;
|
|
|
+ if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
|
|
|
+ SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
|
|
|
+ else
|
|
|
+ SCTP_INC_STATS(net, SCTP_MIB_OUTORDERCHUNKS);
|
|
|
} else {
|
|
|
list_add_tail(&chunk->list, &q->control_chunk_list);
|
|
|
SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
|
|
|
}
|
|
|
|
|
|
- if (error < 0)
|
|
|
- return error;
|
|
|
-
|
|
|
if (!q->cork)
|
|
|
- error = sctp_outq_flush(q, 0, gfp);
|
|
|
-
|
|
|
- return error;
|
|
|
+ sctp_outq_flush(q, 0, gfp);
|
|
|
}
|
|
|
|
|
|
/* Insert a chunk into the sorted list based on the TSNs. The retransmit list
|
|
|
@@ -559,7 +530,6 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
|
|
|
sctp_retransmit_reason_t reason)
|
|
|
{
|
|
|
struct net *net = sock_net(q->asoc->base.sk);
|
|
|
- int error = 0;
|
|
|
|
|
|
switch (reason) {
|
|
|
case SCTP_RTXR_T3_RTX:
|
|
|
@@ -603,10 +573,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
|
|
|
* will be flushed at the end.
|
|
|
*/
|
|
|
if (reason != SCTP_RTXR_FAST_RTX)
|
|
|
- error = sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC);
|
|
|
-
|
|
|
- if (error)
|
|
|
- q->asoc->base.sk->sk_err = -error;
|
|
|
+ sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -778,12 +745,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
|
|
|
}
|
|
|
|
|
|
/* Cork the outqueue so queued chunks are really queued. */
|
|
|
-int sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
|
|
|
+void sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
|
|
|
{
|
|
|
if (q->cork)
|
|
|
q->cork = 0;
|
|
|
|
|
|
- return sctp_outq_flush(q, 0, gfp);
|
|
|
+ sctp_outq_flush(q, 0, gfp);
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -796,7 +763,7 @@ int sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
|
|
|
* locking concerns must be made. Today we use the sock lock to protect
|
|
|
* this function.
|
|
|
*/
|
|
|
-static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
|
|
|
+static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
|
|
|
{
|
|
|
struct sctp_packet *packet;
|
|
|
struct sctp_packet singleton;
|
|
|
@@ -919,8 +886,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
|
|
|
sctp_packet_config(&singleton, vtag, 0);
|
|
|
sctp_packet_append_chunk(&singleton, chunk);
|
|
|
error = sctp_packet_transmit(&singleton, gfp);
|
|
|
- if (error < 0)
|
|
|
- return error;
|
|
|
+ if (error < 0) {
|
|
|
+ asoc->base.sk->sk_err = -error;
|
|
|
+ return;
|
|
|
+ }
|
|
|
break;
|
|
|
|
|
|
case SCTP_CID_ABORT:
|
|
|
@@ -1018,6 +987,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
|
|
|
retran:
|
|
|
error = sctp_outq_flush_rtx(q, packet,
|
|
|
rtx_timeout, &start_timer);
|
|
|
+ if (error < 0)
|
|
|
+ asoc->base.sk->sk_err = -error;
|
|
|
|
|
|
if (start_timer) {
|
|
|
sctp_transport_reset_t3_rtx(transport);
|
|
|
@@ -1192,14 +1163,15 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
|
|
|
struct sctp_transport,
|
|
|
send_ready);
|
|
|
packet = &t->packet;
|
|
|
- if (!sctp_packet_empty(packet))
|
|
|
+ if (!sctp_packet_empty(packet)) {
|
|
|
error = sctp_packet_transmit(packet, gfp);
|
|
|
+ if (error < 0)
|
|
|
+ asoc->base.sk->sk_err = -error;
|
|
|
+ }
|
|
|
|
|
|
/* Clear the burst limited state, if any */
|
|
|
sctp_transport_burst_reset(t);
|
|
|
}
|
|
|
-
|
|
|
- return error;
|
|
|
}
|
|
|
|
|
|
/* Update unack_data based on the incoming SACK chunk */
|