|
|
|
@ -62,8 +62,12 @@ |
|
|
|
|
#include <net/sctp/sctp.h> |
|
|
|
|
#include <net/sctp/sm.h> |
|
|
|
|
|
|
|
|
|
static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, |
|
|
|
|
__u8 type, __u8 flags, int paylen); |
|
|
|
|
static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, |
|
|
|
|
__u8 type, __u8 flags, int paylen); |
|
|
|
|
static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, |
|
|
|
|
__u8 flags, int paylen); |
|
|
|
|
static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, |
|
|
|
|
__u8 type, __u8 flags, int paylen); |
|
|
|
|
static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, |
|
|
|
|
const struct sctp_association *asoc, |
|
|
|
|
const struct sctp_chunk *init_chunk, |
|
|
|
@ -76,6 +80,28 @@ static int sctp_process_param(struct sctp_association *asoc, |
|
|
|
|
static void *sctp_addto_param(struct sctp_chunk *chunk, int len, |
|
|
|
|
const void *data); |
|
|
|
|
|
|
|
|
|
/* Control chunk destructor */ |
|
|
|
|
static void sctp_control_release_owner(struct sk_buff *skb) |
|
|
|
|
{ |
|
|
|
|
/*TODO: do memory release */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void sctp_control_set_owner_w(struct sctp_chunk *chunk) |
|
|
|
|
{ |
|
|
|
|
struct sctp_association *asoc = chunk->asoc; |
|
|
|
|
struct sk_buff *skb = chunk->skb; |
|
|
|
|
|
|
|
|
|
/* TODO: properly account for control chunks.
|
|
|
|
|
* To do it right we'll need: |
|
|
|
|
* 1) endpoint if association isn't known. |
|
|
|
|
* 2) proper memory accounting. |
|
|
|
|
* |
|
|
|
|
* For now don't do anything for now. |
|
|
|
|
*/ |
|
|
|
|
skb->sk = asoc ? asoc->base.sk : NULL; |
|
|
|
|
skb->destructor = sctp_control_release_owner; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* What was the inbound interface for this chunk? */ |
|
|
|
|
int sctp_chunk_iif(const struct sctp_chunk *chunk) |
|
|
|
|
{ |
|
|
|
@ -290,7 +316,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, |
|
|
|
|
* PLEASE DO NOT FIXME [This version does not support Host Name.] |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
|
|
|
|
@ -437,7 +463,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, |
|
|
|
|
num_ext); |
|
|
|
|
|
|
|
|
|
/* Now allocate and fill out the chunk. */ |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nomem_chunk; |
|
|
|
|
|
|
|
|
@ -542,7 +568,7 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, |
|
|
|
|
cookie_len = asoc->peer.cookie_len; |
|
|
|
|
|
|
|
|
|
/* Build a cookie echo chunk. */ |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
retval->subh.cookie_hdr = |
|
|
|
@ -587,7 +613,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, |
|
|
|
|
{ |
|
|
|
|
struct sctp_chunk *retval; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0); |
|
|
|
|
|
|
|
|
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
|
|
|
|
* |
|
|
|
@ -635,8 +661,8 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, |
|
|
|
|
sctp_cwrhdr_t cwr; |
|
|
|
|
|
|
|
|
|
cwr.lowest_tsn = htonl(lowest_tsn); |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, |
|
|
|
|
sizeof(sctp_cwrhdr_t)); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0, |
|
|
|
|
sizeof(sctp_cwrhdr_t)); |
|
|
|
|
|
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
@ -669,8 +695,8 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, |
|
|
|
|
sctp_ecnehdr_t ecne; |
|
|
|
|
|
|
|
|
|
ecne.lowest_tsn = htonl(lowest_tsn); |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, |
|
|
|
|
sizeof(sctp_ecnehdr_t)); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0, |
|
|
|
|
sizeof(sctp_ecnehdr_t)); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
retval->subh.ecne_hdr = |
|
|
|
@ -706,7 +732,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, |
|
|
|
|
dp.ssn = htons(ssn); |
|
|
|
|
|
|
|
|
|
chunk_len = sizeof(dp) + data_len; |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); |
|
|
|
|
retval = sctp_make_data(asoc, flags, chunk_len); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
|
|
|
|
@ -753,7 +779,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) |
|
|
|
|
+ sizeof(__u32) * num_dup_tsns; |
|
|
|
|
|
|
|
|
|
/* Create the chunk. */ |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
|
|
|
|
@ -832,8 +858,8 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, |
|
|
|
|
ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); |
|
|
|
|
shut.cum_tsn_ack = htonl(ctsn); |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, |
|
|
|
|
sizeof(sctp_shutdownhdr_t)); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0, |
|
|
|
|
sizeof(sctp_shutdownhdr_t)); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
|
|
|
|
@ -851,7 +877,7 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, |
|
|
|
|
{ |
|
|
|
|
struct sctp_chunk *retval; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); |
|
|
|
|
|
|
|
|
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
|
|
|
|
* |
|
|
|
@ -880,7 +906,7 @@ struct sctp_chunk *sctp_make_shutdown_complete( |
|
|
|
|
*/ |
|
|
|
|
flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); |
|
|
|
|
|
|
|
|
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
|
|
|
|
* |
|
|
|
@ -919,7 +945,7 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, |
|
|
|
|
flags = SCTP_CHUNK_FLAG_T; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint); |
|
|
|
|
|
|
|
|
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
|
|
|
|
* |
|
|
|
@ -1111,7 +1137,7 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, |
|
|
|
|
struct sctp_chunk *retval; |
|
|
|
|
sctp_sender_hb_info_t hbinfo; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); |
|
|
|
|
|
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
@ -1139,7 +1165,7 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, |
|
|
|
|
{ |
|
|
|
|
struct sctp_chunk *retval; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
|
|
|
|
@ -1171,8 +1197,8 @@ static struct sctp_chunk *sctp_make_op_error_space( |
|
|
|
|
{ |
|
|
|
|
struct sctp_chunk *retval; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, |
|
|
|
|
sizeof(sctp_errhdr_t) + size); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0, |
|
|
|
|
sizeof(sctp_errhdr_t) + size); |
|
|
|
|
if (!retval) |
|
|
|
|
goto nodata; |
|
|
|
|
|
|
|
|
@ -1242,7 +1268,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc) |
|
|
|
|
if (unlikely(!hmac_desc)) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0, |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0, |
|
|
|
|
hmac_desc->hmac_len + sizeof(sctp_authhdr_t)); |
|
|
|
|
if (!retval) |
|
|
|
|
return NULL; |
|
|
|
@ -1345,8 +1371,8 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) |
|
|
|
|
/* Create a new chunk, setting the type and flags headers from the
|
|
|
|
|
* arguments, reserving enough space for a 'paylen' byte payload. |
|
|
|
|
*/ |
|
|
|
|
static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, |
|
|
|
|
__u8 type, __u8 flags, int paylen) |
|
|
|
|
static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, |
|
|
|
|
__u8 type, __u8 flags, int paylen) |
|
|
|
|
{ |
|
|
|
|
struct sctp_chunk *retval; |
|
|
|
|
sctp_chunkhdr_t *chunk_hdr; |
|
|
|
@ -1379,14 +1405,27 @@ static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, |
|
|
|
|
if (sctp_auth_send_cid(type, asoc)) |
|
|
|
|
retval->auth = 1; |
|
|
|
|
|
|
|
|
|
/* Set the skb to the belonging sock for accounting. */ |
|
|
|
|
skb->sk = sk; |
|
|
|
|
|
|
|
|
|
return retval; |
|
|
|
|
nodata: |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, |
|
|
|
|
__u8 flags, int paylen) |
|
|
|
|
{ |
|
|
|
|
return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, |
|
|
|
|
__u8 type, __u8 flags, int paylen) |
|
|
|
|
{ |
|
|
|
|
struct sctp_chunk *chunk = _sctp_make_chunk(asoc, type, flags, paylen); |
|
|
|
|
|
|
|
|
|
if (chunk) |
|
|
|
|
sctp_control_set_owner_w(chunk); |
|
|
|
|
|
|
|
|
|
return chunk; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Release the memory occupied by a chunk. */ |
|
|
|
|
static void sctp_chunk_destroy(struct sctp_chunk *chunk) |
|
|
|
@ -2727,7 +2766,7 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, |
|
|
|
|
length += addrlen; |
|
|
|
|
|
|
|
|
|
/* Create the chunk. */ |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF, 0, length); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length); |
|
|
|
|
if (!retval) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
@ -2911,7 +2950,7 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as |
|
|
|
|
int length = sizeof(asconf) + vparam_len; |
|
|
|
|
|
|
|
|
|
/* Create the chunk. */ |
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length); |
|
|
|
|
if (!retval) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
@ -3442,7 +3481,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, |
|
|
|
|
|
|
|
|
|
hint = (nstreams + 1) * sizeof(__u32); |
|
|
|
|
|
|
|
|
|
retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint); |
|
|
|
|
retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint); |
|
|
|
|
|
|
|
|
|
if (!retval) |
|
|
|
|
return NULL; |
|
|
|
|