Commit d5e3a331 authored by David S. Miller's avatar David S. Miller

Merge http://linux-lksctp.bkbits.net/lksctp-2.5

into nuts.ninka.net:/home/davem/src/BK/sctp-2.5
parents b3819ec5 ef010578
...@@ -155,15 +155,15 @@ typedef struct sctp_paramhdr { ...@@ -155,15 +155,15 @@ typedef struct sctp_paramhdr {
typedef enum { typedef enum {
/* RFC 2960 Section 3.3.5 */ /* RFC 2960 Section 3.3.5 */
SCTP_PARAM_HEATBEAT_INFO = __constant_htons(1), SCTP_PARAM_HEARTBEAT_INFO = __constant_htons(1),
/* RFC 2960 Section 3.3.2.1 */ /* RFC 2960 Section 3.3.2.1 */
SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5), SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5),
SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6), SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6),
SCTP_PARAM_STATE_COOKIE = __constant_htons(7), SCTP_PARAM_STATE_COOKIE = __constant_htons(7),
SCTP_PARAM_UNRECOGNIZED_PARAMETERS = __constant_htons(8), SCTP_PARAM_UNRECOGNIZED_PARAMETERS = __constant_htons(8),
SCTP_PARAM_COOKIE_PRESERVATIVE = __constant_htons(9), SCTP_PARAM_COOKIE_PRESERVATIVE = __constant_htons(9),
SCTP_PARAM_HOST_NAME_ADDRESS = __constant_htons(11), SCTP_PARAM_HOST_NAME_ADDRESS = __constant_htons(11),
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12),
SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000),
/* Add-IP Extension. Section 3.2 */ /* Add-IP Extension. Section 3.2 */
...@@ -190,6 +190,7 @@ typedef enum { ...@@ -190,6 +190,7 @@ typedef enum {
SCTP_PARAM_ACTION_SKIP_ERR = __constant_htons(0xc000), SCTP_PARAM_ACTION_SKIP_ERR = __constant_htons(0xc000),
} sctp_param_action_t; } sctp_param_action_t;
enum { SCTP_PARAM_ACTION_MASK = __constant_htons(0xc000), };
/* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ /* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */
......
...@@ -103,6 +103,14 @@ ...@@ -103,6 +103,14 @@
#define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT #define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT
#endif #endif
/* Certain internal static functions need to be exported when
* compiled into the test frame.
*/
#ifndef SCTP_STATIC
#define SCTP_STATIC static
#endif
/* /*
* Function declarations. * Function declarations.
*/ */
......
...@@ -215,7 +215,8 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *, ...@@ -215,7 +215,8 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *,
int priority); int priority);
sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *,
const sctp_chunk_t *, const sctp_chunk_t *,
const int priority); const int priority,
const int unkparam_len);
sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *,
const sctp_chunk_t *); const sctp_chunk_t *);
sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *,
...@@ -304,6 +305,14 @@ void sctp_generate_t3_rtx_event(unsigned long peer); ...@@ -304,6 +305,14 @@ void sctp_generate_t3_rtx_event(unsigned long peer);
void sctp_generate_heartbeat_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer);
sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *);
sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
sctp_chunk_t *chunk,
const void *payload,
size_t paylen);
sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
const sctp_chunk_t *chunk);
void sctp_ootb_pkt_free(sctp_packet_t *packet);
sctp_cookie_param_t * sctp_cookie_param_t *
sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *,
......
...@@ -1044,6 +1044,20 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, ...@@ -1044,6 +1044,20 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *,
const sockaddr_storage_t *); const sockaddr_storage_t *);
int sctp_verify_init(const sctp_association_t *asoc,
sctp_cid_t cid,
sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
int sctp_verify_param(const sctp_association_t *asoc,
sctpParam_t param,
sctp_cid_t cid,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
int sctp_process_unk_param(const sctp_association_t *asoc,
sctpParam_t param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr, const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init, int priority); sctp_init_chunk_t *peer_init, int priority);
......
...@@ -97,7 +97,7 @@ const char *sctp_cname(const sctp_subtype_t cid) ...@@ -97,7 +97,7 @@ const char *sctp_cname(const sctp_subtype_t cid)
/* These are printable form of variable-length parameters. */ /* These are printable form of variable-length parameters. */
const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = { const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = {
"", "",
"PARAM_HEATBEAT_INFO", "PARAM_HEARTBEAT_INFO",
"", "",
"", "",
"", "",
......
...@@ -104,7 +104,7 @@ void sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q) ...@@ -104,7 +104,7 @@ void sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q)
void sctp_outqueue_teardown(sctp_outqueue_t *q) void sctp_outqueue_teardown(sctp_outqueue_t *q)
{ {
sctp_transport_t *transport; sctp_transport_t *transport;
struct list_head *lchunk, *pos; struct list_head *lchunk, *pos, *temp;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
/* Throw away unacknowledged chunks. */ /* Throw away unacknowledged chunks. */
...@@ -117,6 +117,13 @@ void sctp_outqueue_teardown(sctp_outqueue_t *q) ...@@ -117,6 +117,13 @@ void sctp_outqueue_teardown(sctp_outqueue_t *q)
} }
} }
/* Throw away chunks that have been gap ACKed. */
list_for_each_safe(lchunk, temp, &q->sacked) {
list_del(lchunk);
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
sctp_free_chunk(chunk);
}
/* Throw away any leftover chunks. */ /* Throw away any leftover chunks. */
while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out))) while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out)))
sctp_free_chunk(chunk); sctp_free_chunk(chunk);
......
...@@ -223,7 +223,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -223,7 +223,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
const sctp_chunk_t *chunk, const sctp_chunk_t *chunk,
int priority) int priority, int unkparam_len)
{ {
sctp_inithdr_t initack; sctp_inithdr_t initack;
sctp_chunk_t *retval; sctp_chunk_t *retval;
...@@ -278,7 +278,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -278,7 +278,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
if (!cookie) if (!cookie)
goto nomem_cookie; goto nomem_cookie;
chunksize = sizeof(initack) + addrs_len + cookie_len; /* Calculate the total size of allocation, include the reserved
* space for reporting unknown parameters if it is specified.
*/
chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
/* Tell peer that we'll do ECN only if peer advertised such cap. */ /* Tell peer that we'll do ECN only if peer advertised such cap. */
if (asoc->peer.ecn_capable) if (asoc->peer.ecn_capable)
...@@ -883,25 +886,27 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, ...@@ -883,25 +886,27 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc,
return retval; return retval;
} }
/* Create an Operation Error chunk. */ /* Create an Operation Error chunk with the specified space reserved.
sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, * This routine can be used for containing multiple causes in the chunk.
const sctp_chunk_t *chunk, */
__u16 cause_code, const void *payload, sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc,
size_t paylen) const sctp_chunk_t *chunk,
size_t size)
{ {
sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, sctp_chunk_t *retval;
sizeof(sctp_errhdr_t) + paylen);
retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0,
sizeof(sctp_errhdr_t) + size);
if (!retval) if (!retval)
goto nodata; goto nodata;
sctp_init_cause(retval, cause_code, payload, paylen);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
* *
* An endpoint SHOULD transmit reply chunks (e.g., SACK, * An endpoint SHOULD transmit reply chunks (e.g., SACK,
* HEARTBEAT ACK, * etc.) to the same destination transport * HEARTBEAT ACK, etc.) to the same destination transport
* address from which it * received the DATA or control chunk * address from which it received the DATA or control chunk
* to which it is replying. * to which it is replying.
*
*/ */
if (chunk) if (chunk)
retval->transport = chunk->transport; retval->transport = chunk->transport;
...@@ -910,6 +915,23 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, ...@@ -910,6 +915,23 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc,
return retval; return retval;
} }
/* Create an Operation Error chunk. */
sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc,
const sctp_chunk_t *chunk,
__u16 cause_code, const void *payload,
size_t paylen)
{
sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen);
if (!retval)
goto nodata;
sctp_init_cause(retval, cause_code, payload, paylen);
nodata:
return retval;
}
/******************************************************************** /********************************************************************
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
...@@ -1405,6 +1427,162 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1405,6 +1427,162 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions * 3rd Level Abstractions
********************************************************************/ ********************************************************************/
/* Verify the INIT packet before we process it. */
int sctp_verify_init(const sctp_association_t *asoc,
sctp_cid_t cid,
sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
sctpParam_t param;
uint8_t *end;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify
* the mandatory parameters somewhere here and generate either the
* "Missing mandatory parameter" error or the "Invalid mandatory
* parameter" error. */
/* Find unrecognized parameters. */
end = ((uint8_t *)peer_init + ntohs(peer_init->chunk_hdr.length));
for (param.v = peer_init->init_hdr.params;
param.v < end;
param.v += WORD_ROUND(ntohs(param.p->length))) {
if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p))
return 0;
} /* for (loop through all parameters) */
return 1;
}
/* Find unrecognized parameters in the chunk.
* Return values:
* 0 - discard the chunk
* 1 - continue with the chunk
*/
int sctp_verify_param(const sctp_association_t *asoc,
sctpParam_t param,
sctp_cid_t cid,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
int retval = 1;
/* FIXME - This routine is not looking at each parameter per the
* chunk type, i.e., unrecognized parameters should be further
* identified based on the chunk id.
*/
switch (param.p->type) {
case SCTP_PARAM_IPV4_ADDRESS:
case SCTP_PARAM_IPV6_ADDRESS:
case SCTP_PARAM_COOKIE_PRESERVATIVE:
/* FIXME - If we don't support the host name parameter, we should
* generate an error for this - Unresolvable address.
*/
case SCTP_PARAM_HOST_NAME_ADDRESS:
case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
case SCTP_PARAM_STATE_COOKIE:
case SCTP_PARAM_HEARTBEAT_INFO:
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
case SCTP_PARAM_ECN_CAPABLE:
break;
default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
ntohs(param.p->type), cid);
return sctp_process_unk_param(asoc, param, chunk, err_chk_p);
break;
}
return retval;
}
/* RFC 3.2.1 & the Implementers Guide 2.2.
*
* The Parameter Types are encoded such that the
* highest-order two bits specify the action that must be
* taken if the processing endpoint does not recognize the
* Parameter Type.
*
* 00 - Stop processing this SCTP chunk and discard it,
* do not process any further chunks within it.
*
* 01 - Stop processing this SCTP chunk and discard it,
* do not process any further chunks within it, and report
* the unrecognized parameter in an 'Unrecognized
* Parameter Type' (in either an ERROR or in the INIT ACK).
*
* 10 - Skip this parameter and continue processing.
*
* 11 - Skip this parameter and continue processing but
* report the unrecognized parameter in an
* 'Unrecognized Parameter Type' (in either an ERROR or in
* the INIT ACK).
*
* Return value:
* 0 - discard the chunk
* 1 - continue with the chunk
*/
int sctp_process_unk_param(const sctp_association_t *asoc,
sctpParam_t param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
int retval = 1;
switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
case SCTP_PARAM_ACTION_DISCARD:
retval = 0;
break;
case SCTP_PARAM_ACTION_DISCARD_ERR:
retval = 0;
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if (NULL == *err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk,
ntohs(chunk->chunk_hdr->length));
if (*err_chk_p)
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
(const void *)param.p,
WORD_ROUND(ntohs(param.p->length)));
break;
case SCTP_PARAM_ACTION_SKIP:
break;
case SCTP_PARAM_ACTION_SKIP_ERR:
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if (NULL == *err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk,
ntohs(chunk->chunk_hdr->length));
if (*err_chk_p) {
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
(const void *)param.p,
WORD_ROUND(ntohs(param.p->length)));
} else {
/* If there is no memory for generating the ERROR
* report as specified, an ABORT will be triggered
* to the peer and the association won't be established.
*/
retval = 0;
}
break;
default:
break;
}
return retval;
}
/* Unpack the parameters in an INIT packet. /* Unpack the parameters in an INIT packet.
* FIXME: There is no return status to allow callers to do * FIXME: There is no return status to allow callers to do
* error handling. * error handling.
...@@ -1609,9 +1787,9 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1609,9 +1787,9 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
asoc->peer.cookie = param.cookie->body; asoc->peer.cookie = param.cookie->body;
break; break;
case SCTP_PARAM_HEATBEAT_INFO: case SCTP_PARAM_HEARTBEAT_INFO:
SCTP_DEBUG_PRINTK("unimplemented " SCTP_DEBUG_PRINTK("unimplemented "
"SCTP_PARAM_HEATBEAT_INFO\n"); "SCTP_PARAM_HEARTBEAT_INFO\n");
break; break;
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
...@@ -1624,14 +1802,13 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1624,14 +1802,13 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
break; break;
default: default:
/* Any unrecognized parameters should have been caught
* and handled by sctp_verify_param() which should be
* called prior to this routine. Simply log the error
* here.
*/
SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n", SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n",
ntohs(param.p->type), asoc); ntohs(param.p->type), asoc);
/* FIXME: The entire parameter processing really needs
* redesigned. For now, always return success as doing
* otherwise craters the system.
*/
retval = 1;
break; break;
}; };
......
...@@ -327,7 +327,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -327,7 +327,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_GEN_INIT_ACK: case SCTP_CMD_GEN_INIT_ACK:
/* Generate an INIT ACK chunk. */ /* Generate an INIT ACK chunk. */
new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC); new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC,
0);
if (!new_obj) if (!new_obj)
goto nomem; goto nomem;
...@@ -344,10 +345,20 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -344,10 +345,20 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_GEN_COOKIE_ECHO: case SCTP_CMD_GEN_COOKIE_ECHO:
/* Generate a COOKIE ECHO chunk. */ /* Generate a COOKIE ECHO chunk. */
new_obj = sctp_make_cookie_echo(asoc, chunk); new_obj = sctp_make_cookie_echo(asoc, chunk);
if (!new_obj) if (!new_obj) {
if (command->obj.ptr)
sctp_free_chunk(command->obj.ptr);
goto nomem; goto nomem;
}
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(new_obj)); SCTP_CHUNK(new_obj));
/* If there is an ERROR chunk to be sent along with
* the COOKIE_ECHO, send it, too.
*/
if (command->obj.ptr)
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(command->obj.ptr));
break; break;
case SCTP_CMD_GEN_SHUTDOWN: case SCTP_CMD_GEN_SHUTDOWN:
...@@ -397,8 +408,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -397,8 +408,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
/* Send a full packet to our peer. */ /* Send a full packet to our peer. */
packet = command->obj.ptr; packet = command->obj.ptr;
sctp_packet_transmit(packet); sctp_packet_transmit(packet);
sctp_transport_free(packet->transport); sctp_ootb_pkt_free(packet);
sctp_packet_free(packet);
break; break;
case SCTP_CMD_RETRAN: case SCTP_CMD_RETRAN:
......
This diff is collapsed.
This diff is collapsed.
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