summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Grimm <jgrimm@touki.austin.ibm.com>2003-03-25 04:11:45 -0600
committerJon Grimm <jgrimm@touki.austin.ibm.com>2003-03-25 04:11:45 -0600
commit1bafb09e6ebf31151b7c9b62e67f1f3bcb419337 (patch)
tree176470c1bb0d781b9c30bbae52c809575088819d
parent9850a96f26ed8491c4524158c0febd6224532f53 (diff)
[SCTP] Add SEND_FAILED support. (Ardelle Fan)
-rw-r--r--include/net/sctp/structs.h3
-rw-r--r--net/sctp/outqueue.c23
-rw-r--r--net/sctp/sm_sideeffect.c53
-rw-r--r--net/sctp/sm_statefuns.c53
4 files changed, 79 insertions, 53 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e22b333a94b2..44c81f5c3020 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -872,6 +872,9 @@ struct sctp_outq {
unsigned out_qlen; /* Total length of queued data chunks. */
+ /* Error of send failed, may used in SCTP_SEND_FAILED event. */
+ unsigned error;
+
/* These are control chunks we want to send. */
struct sk_buff_head control;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 87bad9667e66..ae964d48c1db 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -138,13 +138,13 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
}
/* Free the outqueue structure and any related pending chunks.
- * FIXME: Add SEND_FAILED support.
*/
void sctp_outq_teardown(struct sctp_outq *q)
{
struct sctp_transport *transport;
struct list_head *lchunk, *pos, *temp;
sctp_chunk_t *chunk;
+ struct sctp_ulpevent *ev;
/* Throw away unacknowledged chunks. */
list_for_each(pos, &q->asoc->peer.transport_addr_list) {
@@ -152,6 +152,14 @@ void sctp_outq_teardown(struct sctp_outq *q)
while ((lchunk = sctp_list_dequeue(&transport->transmitted))) {
chunk = list_entry(lchunk, sctp_chunk_t,
transmitted_list);
+
+ /* Generate a SEND FAILED event. */
+ ev = sctp_ulpevent_make_send_failed(q->asoc,
+ chunk, SCTP_DATA_SENT,
+ q->error, GFP_ATOMIC);
+ if (ev)
+ sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
+
sctp_free_chunk(chunk);
}
}
@@ -171,8 +179,19 @@ void sctp_outq_teardown(struct sctp_outq *q)
}
/* Throw away any leftover data chunks. */
- while ((chunk = sctp_outq_dequeue_data(q)))
+ while ((chunk = sctp_outq_dequeue_data(q))) {
+
+ /* Generate a SEND FAILED event. */
+ ev = sctp_ulpevent_make_send_failed(q->asoc,
+ chunk, SCTP_DATA_UNSENT,
+ q->error, GFP_ATOMIC);
+ if (ev)
+ sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
+
sctp_free_chunk(chunk);
+ }
+
+ q->error = 0;
/* Throw away any leftover control chunks. */
while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control)))
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 63cad2d13e07..2a794ada7247 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -133,7 +133,7 @@ static void sctp_do_ecn_cwr_work(sctp_association_t *asoc,
}
/* Generate SACK if necessary. We call this at the end of a packet. */
-int sctp_gen_sack(struct sctp_association *asoc, int force,
+int sctp_gen_sack(struct sctp_association *asoc, int force,
sctp_cmd_seq_t *commands)
{
__u32 ctsn, max_tsn_seen;
@@ -410,7 +410,8 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
/* Worker routine to handle INIT command failure. */
static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
- sctp_association_t *asoc)
+ sctp_association_t *asoc,
+ unsigned error)
{
struct sctp_ulpevent *event;
@@ -421,46 +422,27 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(event));
- /* FIXME: We need to handle data possibly either
- * sent via COOKIE-ECHO bundling or just waiting in
- * the transmit queue, if the user has enabled
- * SEND_FAILED notifications.
- */
+ /* SEND_FAILED sent later when cleaning up the association. */
+ asoc->outqueue.error = error;
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
}
/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
- sctp_association_t *asoc,
+ struct sctp_association *asoc,
sctp_event_t event_type,
sctp_subtype_t subtype,
- sctp_chunk_t *chunk)
+ struct sctp_chunk *chunk,
+ unsigned error)
{
struct sctp_ulpevent *event;
- __u16 error = 0;
-
- switch(event_type) {
- case SCTP_EVENT_T_PRIMITIVE:
- if (SCTP_PRIMITIVE_ABORT == subtype.primitive)
- error = SCTP_ERROR_USER_ABORT;
- break;
- case SCTP_EVENT_T_CHUNK:
- if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) &&
- (ntohs(chunk->chunk_hdr->length) >=
- (sizeof(struct sctp_chunkhdr) +
- sizeof(struct sctp_errhdr)))) {
- error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
- }
- break;
- default:
- break;
- }
/* Cancel any partial delivery in progress. */
sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
- error, 0, 0, GFP_ATOMIC);
+ (__u16)error, 0, 0,
+ GFP_ATOMIC);
if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(event));
@@ -468,9 +450,8 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
- /* FIXME: We need to handle data that could not be sent or was not
- * acked, if the user has enabled SEND_FAILED notifications.
- */
+ /* SEND_FAILED sent later when cleaning up the association. */
+ asoc->outqueue.error = error;
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
}
@@ -640,9 +621,9 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
asoc->state_timestamp = jiffies;
if ((SCTP_STATE_ESTABLISHED == asoc->state) ||
- (SCTP_STATE_CLOSED == asoc->state)) {
+ (SCTP_STATE_CLOSED == asoc->state)) {
/* 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().
*/
if (waitqueue_active(&asoc->wait))
wake_up_interruptible(&asoc->wait);
@@ -1077,12 +1058,12 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break;
case SCTP_CMD_INIT_FAILED:
- sctp_cmd_init_failed(commands, asoc);
+ sctp_cmd_init_failed(commands, asoc, cmd->obj.u32);
break;
case SCTP_CMD_ASSOC_FAILED:
sctp_cmd_assoc_failed(commands, asoc, event_type,
- subtype, chunk);
+ subtype, chunk, cmd->obj.u32);
break;
case SCTP_CMD_COUNTER_INC:
@@ -1094,7 +1075,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break;
case SCTP_CMD_REPORT_DUP:
- sctp_tsnmap_mark_dup(&asoc->peer.tsn_map,
+ sctp_tsnmap_mark_dup(&asoc->peer.tsn_map,
cmd->obj.u32);
break;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 9e2862892013..cec75eb93946 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -729,7 +729,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_DELETE_TCB;
@@ -1772,14 +1773,16 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
sctp_chunk_t *chunk = arg;
sctp_errhdr_t *err;
+ err = (sctp_errhdr_t *)(chunk->skb->data);
+
/* If we have gotten too many failures, give up. */
if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] >
asoc->max_init_attempts) {
/* INIT_FAILED will issue an ulpevent. */
- sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+ SCTP_U32(err->cause));
return SCTP_DISPOSITION_DELETE_TCB;
}
- err = (sctp_errhdr_t *)(chunk->skb->data);
/* Process the error here */
switch (err->cause) {
@@ -1834,7 +1837,8 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1;
if (attempts >= asoc->max_init_attempts) {
- sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+ SCTP_U32(SCTP_ERROR_STALE_COOKIE));
return SCTP_DISPOSITION_DELETE_TCB;
}
@@ -1936,12 +1940,18 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
+ __u16 error = SCTP_ERROR_NO_ERROR;
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+ if (chunk && (ntohs(chunk->chunk_hdr->length) >=
+ (sizeof(struct sctp_chunkhdr) +
+ sizeof(struct sctp_errhdr))))
+ error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+
/* ASSOC_FAILED will DELETE_TCB. */
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
@@ -1961,6 +1971,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
+ __u16 error = SCTP_ERROR_NO_ERROR;
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -1971,10 +1982,14 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+ if (chunk && (ntohs(chunk->chunk_hdr->length) >=
+ (sizeof(struct sctp_chunkhdr) +
+ sizeof(struct sctp_errhdr))))
+ error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+
/* CMD_INIT_FAILED will DELETE_TCB. */
- sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
- /* BUG? This does not look complete... */
return SCTP_DISPOSITION_ABORT;
}
@@ -2381,7 +2396,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_DATA));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_CONSUME;
@@ -2596,7 +2612,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_DATA));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_CONSUME;
@@ -3547,7 +3564,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
*/
/* Delete the established association. */
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_USER_ABORT));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
@@ -3686,7 +3704,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
*/
/* Delete the established association. */
- sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+ SCTP_U32(SCTP_ERROR_USER_ABORT));
return retval;
}
@@ -4012,7 +4031,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_DELETE_TCB;
@@ -4147,7 +4167,8 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
SCTP_TO(timer));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
} else {
- sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_ERROR));
return SCTP_DISPOSITION_DELETE_TCB;
}
@@ -4181,7 +4202,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_DELETE_TCB;
@@ -4244,7 +4266,8 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_U32(SCTP_ERROR_NO_ERROR));
return SCTP_DISPOSITION_DELETE_TCB;
nomem: