Commit d979fc87 authored by Jon Grimm's avatar Jon Grimm

[SCTP] More param handling, mostly handling hostname parm (jgrimm)

Per RFC, ABORT the peer if you don't want to support hostname parm.
Found/fixed potential div by zero.
Changed process_init to return error code, so its clients can do error handling.
parent e9499fc9
......@@ -3,41 +3,41 @@
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
*
* The base lksctp header.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
*
* The base lksctp header.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org>
* Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
......@@ -52,10 +52,10 @@
* structs
* prototypes
* macros, externs, and inlines
*
* Move test_frame specific items out of the kernel headers
*
* Move test_frame specific items out of the kernel headers
* and into the test frame headers. This is not perfect in any sense
* and will continue to evolve.
* and will continue to evolve.
*/
......@@ -78,7 +78,7 @@
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/ipv6.h>
#include <net/ip6_route.h>
#endif
#endif
#include <asm/uaccess.h>
#include <asm/page.h>
......@@ -105,19 +105,19 @@
#endif
/* Certain internal static functions need to be exported when
/* 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.
*/
/*
* sctp_protocol.c
* sctp_protocol.c
*/
extern sctp_protocol_t sctp_proto;
extern struct sock *sctp_get_ctl_sock(void);
......@@ -421,14 +421,15 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
* there is room for a param header too.
* there is room for a param header too.
*/
#define sctp_walk_params(pos, chunk, member)\
_sctp_walk_params(((union sctp_params)(pos)), (chunk), member)
_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)
#define _sctp_walk_params(pos, chunk, member)\
for (pos.v = (void *)&chunk->member;\
pos.v <= (void *)chunk + ntohs(chunk->chunk_hdr.length) - sizeof(sctp_paramhdr_t);\
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += WORD_ROUND(ntohs(pos.p->length)))
/* Round an int up to the next multiple of 4. */
......
......@@ -3,34 +3,34 @@
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 International Business Machines Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email addresses:
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Written or modified by:
* Randall Stewart <randall@sctp.chicago.il.us>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
......@@ -41,8 +41,8 @@
* Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Dajiang Zhang <dajiang.zhang@nokia.com>
*
* Dajiang Zhang <dajiang.zhang@nokia.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
......@@ -250,7 +250,7 @@ typedef struct sctp_func {
sockaddr_storage_t *saddr);
int (*cmp_saddr) (struct dst_entry *dst,
sockaddr_storage_t *saddr);
__u16 net_header_len;
__u16 net_header_len;
int sockaddr_len;
sa_family_t sa_family;
struct list_head list;
......@@ -374,7 +374,7 @@ typedef union {
*/
union sctp_params {
void *v;
sctp_paramhdr_t *p;
sctp_paramhdr_t *p;
sctp_cookie_preserve_param_t *life;
sctp_hostname_param_t *dns;
sctp_cookie_param_t *cookie;
......@@ -475,7 +475,7 @@ struct SCTP_chunk {
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */
/* What is the origin IP address for this chunk? */
......@@ -914,7 +914,7 @@ int sctp_addr_is_valid(const sockaddr_storage_t *addr);
typedef enum {
SCTP_EP_TYPE_SOCKET,
SCTP_EP_TYPE_ASSOCIATION,
} sctp_endpoint_type_t;
} sctp_endpoint_type_t;
/*
* A common base class to bridge the implmentation view of a
......@@ -1062,22 +1062,11 @@ int sctp_verify_init(const sctp_association_t *asoc,
sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
int sctp_verify_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_cid_t cid,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
int sctp_process_unk_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init, int priority);
int sctp_process_param(sctp_association_t *asoc,
union sctp_params param,
const sockaddr_storage_t *peer_addr,
sctp_cid_t cid, int priority);
int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init, int priority);
int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
const sockaddr_storage_t *peer_addr, int priority);
__u32 sctp_generate_tag(const sctp_endpoint_t *ep);
__u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
......@@ -1164,10 +1153,10 @@ struct SCTP_association {
sctp_transport_t *primary_path;
/* Cache the primary path address here, when we
* need a an address for msg_name.
* need a an address for msg_name.
*/
sockaddr_storage_t primary_addr;
/* active_path
* The path that we are currently using to
* transmit new data and most control chunks.
......@@ -1268,7 +1257,7 @@ struct SCTP_association {
/* Overall : The threshold for this association that if
* Error : the Overall Error Count reaches will cause
* Threshold : this association to be torn down.
* Threshold : this association to be torn down.
*/
int overall_error_threshold;
......@@ -1314,13 +1303,13 @@ struct SCTP_association {
*/
__u32 next_tsn;
/*
/*
* Last Rcvd : This is the last TSN received in sequence. This value
* TSN : is set initially by taking the peer's Initial TSN,
* : received in the INIT or INIT ACK chunk, and
* : subtracting one from it.
*
* Most of RFC 2960 refers to this as the Cumulative TSN Ack Point.
* Most of RFC 2960 refers to this as the Cumulative TSN Ack Point.
*/
__u32 ctsn_ack_point;
......
......@@ -568,7 +568,7 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr,
sctp_local_bh_disable();
asoc = __sctp_lookup_association(laddr, paddr, transportp);
sctp_local_bh_enable();
return asoc;
}
......@@ -614,13 +614,11 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
sockaddr_storage_t *paddr = &addr;
struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
sctp_chunkhdr_t *ch;
__u8 *ch_end, *data;
sctp_paramhdr_t *parm;
union sctp_params params;
sctp_init_chunk_t *init;
ch = (sctp_chunkhdr_t *) skb->data;
ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
/* If this is INIT/INIT-ACK look inside the chunk too. */
switch (ch->type) {
case SCTP_CID_INIT:
......@@ -646,24 +644,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Find the start of the TLVs and the end of the chunk. This is
* the region we search for address parameters.
*/
data = skb->data + sizeof(sctp_init_chunk_t);
/* See sctp_process_init() for how to go thru TLVs. */
while (data < ch_end) {
parm = (sctp_paramhdr_t *)data;
if (!parm->length)
break;
init = (sctp_init_chunk_t *)skb->data;
data += WORD_ROUND(ntohs(parm->length));
/* Walk the parameters looking for embedded addresses. */
sctp_walk_params(params, init, init_hdr.params) {
/* Note: Ignoring hostname addresses. */
if ((SCTP_PARAM_IPV4_ADDRESS != parm->type) &&
(SCTP_PARAM_IPV6_ADDRESS != parm->type))
if ((SCTP_PARAM_IPV4_ADDRESS != params.p->type) &&
(SCTP_PARAM_IPV6_ADDRESS != params.p->type))
continue;
sctp_param2sockaddr(paddr, (sctp_addr_param_t *)parm,
ntohs(sh->source));
sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source));
asoc = __sctp_lookup_association(laddr, paddr, transportp);
if (asoc)
return asoc;
......
......@@ -1482,74 +1482,28 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 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)
{
union sctp_params param;
/* 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. */
sctp_walk_params(param, peer_init, init_hdr.params) {
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
/* Do not attempt to handle the HOST_NAME parm. However, do
* send back an indicator to the peer.
*/
int sctp_verify_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_cid_t cid,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
static int sctp_process_hn_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
int retval = 1;
__u16 len = ntohs(param.p->length);
/* 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.
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if (!*err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
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);
if (*err_chk_p)
sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED,
param.v, len);
break;
}
return retval;
/* Stop processing this chunk. */
return 0;
}
/* RFC 3.2.1 & the Implementers Guide 2.2.
......@@ -1578,10 +1532,10 @@ int sctp_verify_param(const sctp_association_t *asoc,
* 0 - discard the chunk
* 1 - continue with the chunk
*/
int sctp_process_unk_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
static int sctp_process_unk_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
int retval = 1;
......@@ -1600,7 +1554,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
if (*err_chk_p)
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
(const void *)param.p,
param.v,
WORD_ROUND(ntohs(param.p->length)));
break;
......@@ -1616,7 +1570,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
if (*err_chk_p) {
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
(const void *)param.p,
param.v,
WORD_ROUND(ntohs(param.p->length)));
} else {
/* If there is no memory for generating the ERROR
......@@ -1634,14 +1588,82 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
return retval;
}
/* Unpack the parameters in an INIT packet.
* FIXME: There is no return status to allow callers to do
* error handling.
/* Find unrecognized parameters in the chunk.
* Return values:
* 0 - discard the chunk
* 1 - continue with the chunk
*/
void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init,
int priority)
static int sctp_verify_param(const sctp_association_t *asoc,
union sctp_params param,
sctp_cid_t cid,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk)
{
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:
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;
case SCTP_PARAM_HOST_NAME_ADDRESS:
/* Tell the peer, we won't support this param. */
return sctp_process_hn_param(asoc, param, chunk, err_chunk);
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_chunk);
break;
}
return retval;
}
/* 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)
{
union sctp_params param;
/* 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. */
sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p))
return 0;
} /* for (loop through all parameters) */
return 1;
}
/* Unpack the parameters in an INIT packet into an association.
* Returns 0 on failure, else success.
*/
int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init,
int priority)
{
union sctp_params param;
sctp_transport_t *transport;
......@@ -1659,14 +1681,14 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* be a a better choice than any of the embedded addresses.
*/
if (peer_addr)
sctp_assoc_add_peer(asoc, peer_addr, priority);
if(!sctp_assoc_add_peer(asoc, peer_addr, priority))
goto nomem;
/* Process the initialization parameters. */
sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_process_param(asoc, param, peer_addr, cid,
priority))
if (!sctp_process_param(asoc, param, peer_addr, priority))
goto clean_up;
}
......@@ -1732,7 +1754,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* association to the same value as the Initial TSN.
*/
asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;
return;
return 1;
clean_up:
/* Release the transport structures. */
......@@ -1741,8 +1763,11 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
list_del(pos);
sctp_transport_free(transport);
}
nomem:
return 0;
}
/* Update asoc with the option described in param.
*
* RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT
......@@ -1755,13 +1780,11 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* structures for the addresses.
*/
int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
const sockaddr_storage_t *peer_addr,
sctp_cid_t cid, int priority)
const sockaddr_storage_t *peer_addr, int priority)
{
sockaddr_storage_t addr;
sctp_addr_param_t *addrparm;
int j;
int i;
__u16 sat;
int retval = 1;
sctp_scope_t scope;
......@@ -1770,25 +1793,16 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
* came from a fresh INIT, and INIT ACK, or were stored in a cookie.
*/
switch (param.p->type) {
case SCTP_PARAM_IPV6_ADDRESS:
if( PF_INET6 != asoc->base.sk->family)
break;
/* Fall through. */
case SCTP_PARAM_IPV4_ADDRESS:
addrparm = (sctp_addr_param_t *)param.v;
sctp_param2sockaddr(&addr, addrparm, asoc->peer.port);
sctp_param2sockaddr(&addr, param.addr, asoc->peer.port);
scope = sctp_scope(peer_addr);
if (sctp_in_scope(&addr, scope))
sctp_assoc_add_peer(asoc, &addr, priority);
break;
case SCTP_PARAM_IPV6_ADDRESS:
/* Rethink this as we may need to keep for
* restart considerations.
*/
if (PF_INET6 == asoc->base.sk->family) {
addrparm = (sctp_addr_param_t *)param.v;
sctp_param2sockaddr(&addr, addrparm, asoc->peer.port);
scope = sctp_scope(peer_addr);
if (sctp_in_scope(&addr, scope))
sctp_assoc_add_peer(asoc, &addr, priority);
}
if (!sctp_assoc_add_peer(asoc, &addr, priority))
return 0;
break;
case SCTP_PARAM_COOKIE_PRESERVATIVE:
......@@ -1807,10 +1821,12 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
asoc->peer.ipv4_address = 0;
asoc->peer.ipv6_address = 0;
j = (ntohs(param.p->length) -
sizeof(sctp_paramhdr_t)) /
sizeof(__u16);
for (i = 0; i < j; ++i) {
/* Cycle through address types; avoid divide by 0. */
sat = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
if (sat)
sat /= sizeof(__u16);
for (i = 0; i < sat; ++i) {
switch (param.sat->types[i]) {
case SCTP_PARAM_IPV4_ADDRESS:
asoc->peer.ipv4_address = 1;
......@@ -1837,13 +1853,11 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
break;
case SCTP_PARAM_HEARTBEAT_INFO:
SCTP_DEBUG_PRINTK("unimplemented "
"SCTP_PARAM_HEARTBEAT_INFO\n");
/* Would be odd to receive, but it causes no problems. */
break;
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
SCTP_DEBUG_PRINTK("unimplemented "
"SCTP_PARAM_UNRECOGNIZED_PARAMETERS\n");
/* Rejected during verify stage. */
break;
case SCTP_PARAM_ECN_CAPABLE:
......
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