diff options
| author | Jon Grimm <jgrimm@touki.austin.ibm.com> | 2003-03-25 04:11:45 -0600 |
|---|---|---|
| committer | Jon Grimm <jgrimm@touki.austin.ibm.com> | 2003-03-25 04:11:45 -0600 |
| commit | 1bafb09e6ebf31151b7c9b62e67f1f3bcb419337 (patch) | |
| tree | 176470c1bb0d781b9c30bbae52c809575088819d | |
| parent | 9850a96f26ed8491c4524158c0febd6224532f53 (diff) | |
[SCTP] Add SEND_FAILED support. (Ardelle Fan)
| -rw-r--r-- | include/net/sctp/structs.h | 3 | ||||
| -rw-r--r-- | net/sctp/outqueue.c | 23 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 53 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 53 |
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: |
