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

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

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