Commit 18c195f8 authored by Sridhar Samudrala's avatar Sridhar Samudrala

sctp: User initiated ABORT support. (ardelle.fan)

parent ecf2c214
......@@ -44,6 +44,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -253,6 +254,9 @@ sctp_chunk_t *sctp_make_abort(const sctp_association_t *,
sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *,
const sctp_chunk_t *,
__u32 tsn);
sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *,
const sctp_chunk_t *,
const struct msghdr *);
sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *,
const sctp_transport_t *,
const void *payload,
......
......@@ -47,6 +47,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -838,6 +839,53 @@ sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc,
return retval;
}
/* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */
sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
const sctp_chunk_t *chunk,
const struct msghdr *msg)
{
sctp_chunk_t *retval;
void *payload = NULL, *payoff;
size_t paylen;
struct iovec *iov = msg->msg_iov;
int iovlen = msg->msg_iovlen;
paylen = get_user_iov_size(iov, iovlen);
retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen);
if (!retval)
goto err_chunk;
if (paylen) {
/* Put the msg_iov together into payload. */
payload = kmalloc(paylen, GFP_ATOMIC);
if (!payload)
goto err_payload;
payoff = payload;
for (; iovlen > 0; --iovlen) {
if (copy_from_user(payoff, iov->iov_base, iov->iov_len))
goto err_copy;
payoff += iov->iov_len;
iov++;
}
}
sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen);
if (paylen)
kfree(payload);
return retval;
err_copy:
kfree(payload);
err_payload:
sctp_free_chunk(retval);
retval = NULL;
err_chunk:
return retval;
}
/* Make a HEARTBEAT chunk. */
sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc,
const sctp_transport_t *transport,
......
......@@ -66,7 +66,8 @@ static void sctp_do_ecn_cwr_work(sctp_association_t *asoc,
static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
sctp_transport_t *transport);
static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc);
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc);
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc,
sctp_event_t event_type, sctp_chunk_t *chunk);
static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc,
sctp_chunk_t *chunk,
sctp_init_chunk_t *peer_init,
......@@ -251,7 +252,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
int force;
sctp_cmd_t *command;
sctp_chunk_t *new_obj;
sctp_chunk_t *chunk;
sctp_chunk_t *chunk = NULL;
sctp_packet_t *packet;
struct list_head *pos;
struct timer_list *timer;
......@@ -259,7 +260,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_transport_t *t;
sctp_sackhdr_t sackh;
chunk = (sctp_chunk_t *) event_arg;
if(SCTP_EVENT_T_TIMEOUT != event_type)
chunk = (sctp_chunk_t *) event_arg;
/* Note: This whole file is a huge candidate for rework.
* For example, each command could either have its own handler, so
......@@ -504,7 +506,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break;
case SCTP_CMD_ASSOC_FAILED:
sctp_cmd_assoc_failed(commands, asoc);
sctp_cmd_assoc_failed(commands, asoc, event_type,
chunk);
break;
case SCTP_CMD_COUNTER_INC:
......@@ -1038,14 +1041,26 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_association_t *asoc)
sctp_association_t *asoc,
sctp_event_t event_type,
sctp_chunk_t *chunk)
{
sctp_ulpevent_t *event;
__u16 error = 0;
if (event_type == SCTP_EVENT_T_PRIMITIVE)
error = SCTP_ERROR_USER_ABORT;
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;
}
event = sctp_ulpevent_make_assoc_change(asoc,
0,
SCTP_COMM_LOST,
0, 0, 0,
error, 0, 0,
GFP_ATOMIC);
if (event)
......
......@@ -43,6 +43,7 @@
* Hui Huang <hui.huang@nokia.com>
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -3401,13 +3402,14 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
* from its upper layer, but retransmits data to the far end
* if necessary to fill gaps.
*/
struct msghdr *msg = arg;
sctp_chunk_t *abort;
sctp_disposition_t retval;
retval = SCTP_DISPOSITION_CONSUME;
/* Generate ABORT chunk to send the peer. */
abort = sctp_make_abort(asoc, NULL, 0);
abort = sctp_make_abort_user(asoc, NULL, msg);
if (!abort)
retval = SCTP_DISPOSITION_NOMEM;
else
......@@ -3525,6 +3527,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
void *arg,
sctp_cmd_seq_t *commands)
{
struct msghdr *msg = arg;
sctp_chunk_t *abort;
sctp_disposition_t retval;
......@@ -3534,7 +3537,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
retval = SCTP_DISPOSITION_CONSUME;
/* Generate ABORT chunk to send the peer */
abort = sctp_make_abort(asoc, NULL, 0);
abort = sctp_make_abort_user(asoc, NULL, msg);
if (!abort)
retval = SCTP_DISPOSITION_NOMEM;
else
......
......@@ -804,10 +804,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n",
msg_len, sinfo_flags);
/* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow
* sending 0-length messages when MSG_EOF|MSG_ABORT is not set.
*/
if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) ||
/* If MSG_EOF is set, no data can be sent. Disallow sending zero
* length messages when MSG_EOF|MSG_ABORT is not set.
* If MSG_ABORT is set, the message length could be non zero with
* the msg_iov set to the user abort reason.
*/
if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) ||
(!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) {
err = -EINVAL;
goto out_nounlock;
......@@ -879,7 +881,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
if (sinfo_flags & MSG_ABORT) {
SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
sctp_primitive_ABORT(asoc, NULL);
sctp_primitive_ABORT(asoc, msg);
err = 0;
goto out_unlock;
}
......
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