From 63e15a363ef770ba85841736af847559bb9bdf2d Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Wed, 30 Oct 2002 22:24:22 -0600 Subject: [SCTP] sctp_params cleanup (jgrimm) naming, purge typdef add macro for walking parameters, stronger validity checks --- include/net/sctp/sctp.h | 12 ++++++++++++ include/net/sctp/sm.h | 5 +---- include/net/sctp/structs.h | 43 ++++++++++++++++++++++--------------------- 3 files changed, 35 insertions(+), 25 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 9997455f9a74..5672a603700c 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -418,6 +418,18 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) return retval; } +/* 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. + */ +#define sctp_walk_params(pos, chunk, member)\ +_sctp_walk_params(((union sctp_params)(pos)), (chunk), 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);\ + pos.v += WORD_ROUND(ntohs(pos.p->length))) /* Round an int up to the next multiple of 4. */ #define WORD_ROUND(s) (((s)+3)&~3) diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 80cc12e4ac5c..755b09375932 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -206,9 +206,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *, sctp_chunk_t *, const int priority); __u32 sctp_generate_verification_tag(void); -sctpParam_t sctp_get_my_addrs_raw(const sctp_association_t *, - const int priority, int *addrs_len); - void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); /* Prototypes for chunk-building functions. */ @@ -336,7 +333,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *); /* 4th level prototypes */ void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *, __u16 port); -int sctp_addr2sockaddr(const sctpParam_t, sockaddr_storage_t *); +int sctp_addr2sockaddr(const union sctp_params, sockaddr_storage_t *); int sockaddr2sctp_addr(const sockaddr_storage_t *, sctp_addr_param_t *); /* Extern declarations for major data structures. */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 5a8b75d2da26..8974a653930a 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -356,20 +356,6 @@ typedef struct sctp_signed_cookie { } sctp_signed_cookie_t; -/* This convenience type allows us to avoid casting when walking - * through a parameter list. - */ -typedef union { - __u8 *v; - sctp_paramhdr_t *p; - - sctp_cookie_preserve_param_t *bht; - sctp_hostname_param_t *dns; - sctp_cookie_param_t *cookie; - sctp_supported_addrs_param_t *sat; - sctp_ipv4addr_param_t *v4; - sctp_ipv6addr_param_t *v6; -} sctpParam_t; /* This is another convenience type to allocate memory for address * params for the maximum size and pass such structures around @@ -380,6 +366,21 @@ typedef union { sctp_ipv6addr_param_t v6; } sctp_addr_param_t; +/* A convenience type to allow walking through the various + * parameters and avoid casting all over the place. + */ +union sctp_params { + void *v; + sctp_paramhdr_t *p; + sctp_cookie_preserve_param_t *life; + sctp_hostname_param_t *dns; + sctp_cookie_param_t *cookie; + sctp_supported_addrs_param_t *sat; + sctp_ipv4addr_param_t *v4; + sctp_ipv6addr_param_t *v6; + sctp_addr_param_t *addr; +}; + /* RFC 2960. Section 3.3.5 Heartbeat. * Heartbeat Information: variable length * The Sender-specific Heartbeat Info field should normally include @@ -430,7 +431,7 @@ struct SCTP_chunk { */ /* We point this at the FIRST TLV parameter to chunk_hdr. */ - sctpParam_t param_hdr; + union sctp_params param_hdr; union { __u8 *v; sctp_datahdr_t *data_hdr; @@ -885,9 +886,9 @@ int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, int priority); int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); -sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, - int *addrs_len, - int priority); +union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, + int *addrs_len, + int priority); int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, int addrs_len, @@ -1053,19 +1054,19 @@ int sctp_verify_init(const sctp_association_t *asoc, sctp_chunk_t *chunk, sctp_chunk_t **err_chunk); int sctp_verify_param(const sctp_association_t *asoc, - sctpParam_t param, + 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, - sctpParam_t param, + 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, - sctpParam_t param, + union sctp_params param, const sockaddr_storage_t *peer_addr, sctp_cid_t cid, int priority); __u32 sctp_generate_tag(const sctp_endpoint_t *ep); -- cgit v1.2.3 From d979fc874be7dadb48c0829aa631e444dd4c87e3 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Fri, 1 Nov 2002 05:35:12 -0600 Subject: [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. --- include/net/sctp/sctp.h | 55 +++++------ include/net/sctp/structs.h | 65 ++++++------- net/sctp/input.c | 27 ++---- net/sctp/sm_make_chunk.c | 228 ++++++++++++++++++++++++--------------------- 4 files changed, 185 insertions(+), 190 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 5672a603700c..43511bc4775f 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -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 - * + * * 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 * Xingang Guo * Jon Grimm * Daisy Chang - * + * * 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 #include -#endif +#endif #include #include @@ -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. */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7fdc35407211..8d3987f47037 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -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 - * + * * 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 * Ken Morneau * Qiaobing Xie @@ -41,8 +41,8 @@ * Hui Huang * Sridhar Samudrala * Daisy Chang - * Dajiang Zhang - * + * Dajiang Zhang + * * 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; diff --git a/net/sctp/input.c b/net/sctp/input.c index c2182d2d1b29..c54f983d040d 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -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; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index c5f527ba8630..fb4c5b6f561b 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1482,74 +1482,28 @@ malformed: * 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 @@ clean_up: 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 @@ clean_up: * 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: -- cgit v1.2.3 From 63c6e5b3eb1fab2c4ddd853959791e3537232c50 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Sun, 3 Nov 2002 18:15:03 -0800 Subject: [SCTP] Support for Peer address parameters socket option. --- include/net/sctp/command.h | 2 + include/net/sctp/sctp.h | 2 +- include/net/sctp/sm.h | 1 + include/net/sctp/structs.h | 14 +++-- net/sctp/associola.c | 13 ++-- net/sctp/outqueue.c | 6 +- net/sctp/primitive.c | 23 +++++++ net/sctp/sm_sideeffect.c | 27 ++++++-- net/sctp/sm_statefuns.c | 107 +++++++++++++++++++++++--------- net/sctp/sm_statetable.c | 24 +++++--- net/sctp/socket.c | 150 +++++++++++++++++++++++++++++++++++++++------ net/sctp/transport.c | 4 +- 12 files changed, 293 insertions(+), 80 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index d299eee377c1..67524f0b1a03 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -27,6 +27,7 @@ * * La Monte H.P. Yarroll * Karl Knutson + * Ardelle Fan * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -72,6 +73,7 @@ typedef enum { SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ + SCTP_CMD_HB_TIMERS_UPDATE, /* Update the heartbeat timers. */ SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */ SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */ SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 9997455f9a74..aa09fb75b21d 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -142,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); extern int sctp_primitive_SEND(sctp_association_t *, void *arg); - +extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg); /* * sctp_crc32c.c diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 80cc12e4ac5c..22816b3ded1b 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -157,6 +157,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort; sctp_state_fn_t sctp_sf_error_closed; sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_ignore_primitive; +sctp_state_fn_t sctp_sf_do_prm_requestheartbeat; /* Prototypes for other event state functions. */ sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 9c3979f31d1f..00dc25e6040d 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -684,13 +684,15 @@ struct SCTP_transport { */ unsigned long last_time_ecne_reduced; - /* state : The current state of this destination, - * : i.e. DOWN, UP, ALLOW-HB, NO-HEARTBEAT, etc. + /* active : The current active state of this destination, + * : i.e. DOWN, UP, etc. */ - struct { - int active; - int hb_allowed; - } state; + int active; + + /* hb_allowed : The current heartbeat state of this destination, + * : i.e. ALLOW-HB, NO-HEARTBEAT, etc. + */ + int hb_allowed; /* These are the error stats for this destination. */ diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 958ee7caa1cc..49a0b0e9fe2f 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -461,6 +461,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, min(asoc->overall_error_threshold + peer->error_threshold, asoc->max_retrans); + /* By default, enable heartbeat for peer address. */ + peer->hb_allowed = 1; + /* Initialize the peer's heartbeat interval based on the * sock configured value. */ @@ -523,12 +526,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, /* Record the transition on the transport. */ switch (command) { case SCTP_TRANSPORT_UP: - transport->state.active = 1; + transport->active = 1; spc_state = ADDRESS_AVAILABLE; break; case SCTP_TRANSPORT_DOWN: - transport->state.active = 0; + transport->active = 0; spc_state = ADDRESS_UNREACHABLE; break; @@ -558,7 +561,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, list_for_each(pos, &asoc->peer.transport_addr_list) { t = list_entry(pos, sctp_transport_t, transports); - if (!t->state.active) + if (!t->active) continue; if (!first || t->last_time_heard > first->last_time_heard) { second = first; @@ -578,7 +581,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, * [If the primary is active but not most recent, bump the most * recently used transport.] */ - if (asoc->peer.primary_path->state.active && + if (asoc->peer.primary_path->active && first != asoc->peer.primary_path) { second = first; first = asoc->peer.primary_path; @@ -1018,7 +1021,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) /* Try to find an active transport. */ - if (t->state.active) { + if (t->active) { break; } else { /* Keep track of the next transport in case diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 45708249450a..5c313a6bb804 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -678,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) if (!new_transport) { new_transport = asoc->peer.active_path; - } else if (!new_transport->state.active) { + } else if (!new_transport->active) { /* If the chunk is Heartbeat, send it to * chunk->transport, even it's inactive. */ @@ -835,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) */ new_transport = chunk->transport; if (new_transport == NULL || - !new_transport->state.active) + !new_transport->active) new_transport = asoc->peer.active_path; /* Change packets if necessary. */ @@ -1404,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, /* Mark the destination transport address as * active if it is not so marked. */ - if (!transport->state.active) { + if (!transport->active) { sctp_assoc_control_transport( transport->asoc, transport, diff --git a/net/sctp/primitive.c b/net/sctp/primitive.c index 5e72c910a390..76db4b56a807 100644 --- a/net/sctp/primitive.c +++ b/net/sctp/primitive.c @@ -38,6 +38,7 @@ * La Monte H.P. Yarroll * Narasimha Budihal * Karl Knutson + * Ardelle Fan * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT); DECLARE_PRIMITIVE(SEND); +/* 10.1 ULP-to-SCTP + * J) Request Heartbeat + * + * Format: REQUESTHEARTBEAT(association id, destination transport address) + * + * -> result + * + * Instructs the local endpoint to perform a HeartBeat on the specified + * destination transport address of the given association. The returned + * result should indicate whether the transmission of the HEARTBEAT + * chunk to the destination address is successful. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * o destination transport address - the transport address of the + * asociation on which a heartbeat should be issued. + */ + +DECLARE_PRIMITIVE(REQUESTHEARTBEAT); + /* COMMENT BUG. Find out where this is mentioned in the spec. */ int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) { diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 81e11238fd1e..ed2a5dbb23ce 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -41,6 +41,7 @@ * Dajiang Zhang * Daisy Chang * Sridhar Samudrala + * Ardelle Fan * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -73,6 +74,8 @@ static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, sctp_init_chunk_t *peer_init, int priority); static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); +static void sctp_cmd_hb_timers_update(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *); static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, sctp_bind_addr_t *); static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, @@ -193,6 +196,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, /* BUG--we should now recover some memory, probably by * reneging... */ + error = -ENOMEM; break; case SCTP_DISPOSITION_DELETE_TCB: @@ -560,6 +564,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_HB_TIMERS_START: sctp_cmd_hb_timers_start(commands, asoc); break; + + case SCTP_CMD_HB_TIMERS_UPDATE: + t = command->obj.transport; + sctp_cmd_hb_timers_update(commands, asoc, t); + break; case SCTP_CMD_REPORT_ERROR: error = command->obj.error; @@ -978,7 +987,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, */ asoc->overall_error_count++; - if (transport->state.active && + if (transport->active && (transport->error_count++ >= transport->error_threshold)) { SCTP_DEBUG_PRINTK("transport_strike: transport " "IP:%d.%d.%d.%d failed.\n", @@ -1096,6 +1105,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, } } +/* Helper function to update the heartbeat timer. */ +static void sctp_cmd_hb_timers_update(sctp_cmd_seq_t *cmds, + sctp_association_t *asoc, + sctp_transport_t *t) +{ + /* Update the heartbeat timer. */ + if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) + sctp_transport_hold(t); +} + /* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, sctp_bind_addr_t *bp) @@ -1131,7 +1150,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, /* Mark the destination transport address as active if it is not so * marked. */ - if (!t->state.active) + if (!t->active) sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, SCTP_HEARTBEAT_SUCCESS); @@ -1154,10 +1173,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, /* Mark one strike against a transport. */ sctp_do_8_2_transport_strike(asoc, t); - - /* Update the heartbeat timer. */ - if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) - sctp_transport_hold(t); } /* Helper function to process the process SACK command. */ diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e0e39d0d9d1f..f8f3bc6540db 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -664,6 +664,38 @@ nomem: return SCTP_DISPOSITION_NOMEM; } +/* Generate and sendout a heartbeat packet. */ +sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_transport_t *transport = (sctp_transport_t *) arg; + sctp_chunk_t *reply; + sctp_sender_hb_info_t hbinfo; + size_t paylen = 0; + + hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; + hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); + hbinfo.daddr = transport->ipaddr; + hbinfo.sent_at = jiffies; + + /* Set rto_pending indicating that an RTT measurement + * is started with this heartbeat chunk. + */ + transport->rto_pending = 1; + + /* Send a heartbeat to our peer. */ + paylen = sizeof(sctp_sender_hb_info_t); + reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); + if (!reply) + return SCTP_DISPOSITION_NOMEM; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + return SCTP_DISPOSITION_CONSUME; +} + /* Generate a HEARTBEAT packet on the given transport. */ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, const sctp_association_t *asoc, @@ -672,9 +704,6 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, sctp_cmd_seq_t *commands) { sctp_transport_t *transport = (sctp_transport_t *) arg; - sctp_chunk_t *reply; - sctp_sender_hb_info_t hbinfo; - size_t paylen = 0; if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ @@ -689,34 +718,21 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, * HEARTBEAT is sent (see Section 8.3). */ - hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; - hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); - hbinfo.daddr = transport->ipaddr; - hbinfo.sent_at = jiffies; - - /* Set rto_pending indicating that an RTT measurement is started - * with this heartbeat chunk. - */ - transport->rto_pending = 1; - - /* Send a heartbeat to our peer. */ - paylen = sizeof(sctp_sender_hb_info_t); - reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); - if (!reply) - goto nomem; - - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - - /* Set transport error counter and association error counter - * when sending heartbeat. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET, + if (transport->hb_allowed) { + if (SCTP_DISPOSITION_NOMEM == + sctp_sf_heartbeat(ep, asoc, type, arg, + commands)) + return SCTP_DISPOSITION_NOMEM; + /* Set transport error counter and association error counter + * when sending heartbeat. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET, + SCTP_TRANSPORT(transport)); + } + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_UPDATE, SCTP_TRANSPORT(transport)); - + return SCTP_DISPOSITION_CONSUME; - -nomem: - return SCTP_DISPOSITION_NOMEM; } /* @@ -3656,6 +3672,39 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( return sctp_sf_shutdown_sent_prm_abort(ep, asoc, type, arg, commands); } +/* + * Process the REQUESTHEARTBEAT primitive + * + * 10.1 ULP-to-SCTP + * J) Request Heartbeat + * + * Format: REQUESTHEARTBEAT(association id, destination transport address) + * + * -> result + * + * Instructs the local endpoint to perform a HeartBeat on the specified + * destination transport address of the given association. The returned + * result should indicate whether the transmission of the HEARTBEAT + * chunk to the destination address is successful. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * o destination transport address - the transport address of the + * asociation on which a heartbeat should be issued. + */ +sctp_disposition_t sctp_sf_do_prm_requestheartbeat( + const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return sctp_sf_heartbeat(ep, asoc, type, (sctp_transport_t *)arg, + commands); +} + /* * Ignore the primitive event * diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 8d61ad763f83..e0744f1f463a 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -39,6 +39,7 @@ * Jon Grimm * Hui Huang * Daisy Chang + * Ardelle Fan * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ /* SCTP_STATE_CLOSED */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ /* SCTP_STATE_COOKIE_ECHOED */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ /* SCTP_STATE_ESTABLISHED */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_do_prm_requestheartbeat, \ + .name = "sctp_sf_do_prm_requestheartbeat"}, \ } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ #define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ab4bf2a9c3f0..6533707fb521 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1252,6 +1252,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, return 0; } +static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk, + char *optval, + int optlen) +{ + struct sctp_paddrparams params; + sctp_association_t *asoc; + sockaddr_storage_t *addr; + sctp_transport_t *trans; + int error; + + if (optlen != sizeof(struct sctp_paddrparams)) + return -EINVAL; + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, params.spp_assoc_id); + if (!asoc) + return -EINVAL; + + addr = (sockaddr_storage_t *) &(params.spp_address); + + trans = sctp_assoc_lookup_paddr(asoc, addr); + if (!trans) + return -ENOENT; + + /* Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. + * + * The value of the heartbeat interval, in milliseconds. A value of + * UINT32_MAX (4294967295), when modifying the parameter, specifies + * that a heartbeat should be sent immediately to the peer address, + * and the current interval should remain unchanged. + */ + if (0xffffffff == params.spp_hbinterval) { + error = sctp_primitive_REQUESTHEARTBEAT (asoc, trans); + if (error) + return error; + } + else { + /* The value of the heartbeat interval, in milliseconds. A value of 0, + * when modifying the parameter, specifies that the heartbeat on this + * address should be disabled. + */ + if (params.spp_hbinterval) { + trans->hb_allowed = 1; + trans->hb_interval = params.spp_hbinterval * HZ / 1000; + } else + trans->hb_allowed = 0; + } + + /* spp_pathmaxrxt contains the maximum number of retransmissions + * before this address shall be considered unreachable. + */ + trans->error_threshold = params.spp_pathmaxrxt; + + return 0; +} + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -1342,6 +1403,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_autoclose(sk, optval, optlen); break; + case SCTP_SET_PEER_ADDR_PARAMS: + retval = sctp_setsockopt_set_peer_addr_params(sk, optval, + optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -1503,28 +1569,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, if (len != sizeof(status)) { retval = -EINVAL; - goto out_nounlock; + goto out; } if (copy_from_user(&status, optval, sizeof(status))) { retval = -EFAULT; - goto out_nounlock; + goto out; } - sctp_lock_sock(sk); - associd = status.sstat_assoc_id; if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) { assoc = sctp_id2assoc(sk, associd); if (!assoc) { retval = -EINVAL; - goto out_unlock; + goto out; } } else { ep = sctp_sk(sk)->ep; if (list_empty(&ep->asocs)) { retval = -EINVAL; - goto out_unlock; + goto out; } assoc = list_entry(ep->asocs.next, sctp_association_t, asocs); @@ -1543,7 +1607,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, &(transport->ipaddr), sizeof(sockaddr_storage_t)); - status.sstat_primary.spinfo_state = transport->state.active; + status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; status.sstat_primary.spinfo_rto = transport->rto; @@ -1551,7 +1615,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, if (put_user(len, optlen)) { retval = -EFAULT; - goto out_unlock; + goto out; } SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", @@ -1560,13 +1624,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, if (copy_to_user(optval, &status, len)) { retval = -EFAULT; - goto out_unlock; + goto out; } -out_unlock: - sctp_release_sock(sk); - -out_nounlock: +out: return (retval); } @@ -1684,25 +1745,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - sctp_lock_sock(sk); - assoc = sctp_id2assoc(sk, peeloff.associd); if (NULL == assoc) { retval = -EINVAL; - goto out_unlock; + goto out; } SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); retval = sctp_do_peeloff(assoc, &newsock); if (retval < 0) - goto out_unlock; + goto out; /* Map the socket to an unused fd that can be returned to the user. */ retval = sock_map_fd(newsock); if (retval < 0) { sock_release(newsock); - goto out_unlock; + goto out; } SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", @@ -1713,11 +1772,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval if (copy_to_user(optval, &peeloff, len)) retval = -EFAULT; -out_unlock: - sctp_release_sock(sk); +out: return retval; } +static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk, + int len, char *optval, int *optlen) +{ + struct sctp_paddrparams params; + sctp_association_t *asoc; + sockaddr_storage_t *addr; + sctp_transport_t *trans; + + if (len != sizeof(struct sctp_paddrparams)) + return -EINVAL; + if (copy_from_user(¶ms, optval, *optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, params.spp_assoc_id); + if (!asoc) + return -EINVAL; + + addr = (sockaddr_storage_t *) &(params.spp_address); + + trans = sctp_assoc_lookup_paddr(asoc, addr); + if (!trans) + return -ENOENT; + + /* The value of the heartbeat interval, in milliseconds. A value of 0, + * when modifying the parameter, specifies that the heartbeat on this + * address should be disabled. + */ + if (!trans->hb_allowed) + params.spp_hbinterval = 0; + else + params.spp_hbinterval = trans->hb_interval * 1000 / HZ; + + /* spp_pathmaxrxt contains the maximum number of retransmissions + * before this address shall be considered unreachable. + */ + params.spp_pathmaxrxt = trans->error_threshold; + + if (copy_to_user(optval, ¶ms, len)) + return -EFAULT; + *optlen = len; + + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { @@ -1748,6 +1850,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, if (get_user(len, optlen)) return -EFAULT; + sctp_lock_sock(sk); + switch (optname) { case SCTP_STATUS: retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); @@ -1770,11 +1874,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); break; + case SCTP_GET_PEER_ADDR_PARAMS: + retval = sctp_getsockopt_get_peer_addr_params(sk, len, optval, + optlen); + break; + default: retval = -ENOPROTOOPT; break; }; + sctp_release_sock(sk); return retval; } diff --git a/net/sctp/transport.c b/net/sctp/transport.c index eed219643e9d..e5cc78b8726e 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -104,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, peer->last_time_used = jiffies; peer->last_time_ecne_reduced = jiffies; - peer->state.active = 1; - peer->state.hb_allowed = 0; + peer->active = 1; + peer->hb_allowed = 0; /* Initialize the default path max_retrans. */ peer->max_retrans = proto->max_retrans_path; -- cgit v1.2.3 From 3e780f7bb3fb27d604ce835228f89cb875d9e917 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Tue, 5 Nov 2002 23:09:53 -0600 Subject: [SCTP] sctp_addr code cleanup. Replace sockaddr_storage_t with 'union sctp_addr'. Split up more ipv4/ipv6 code into af specific functions. More later, but this gives me a base to do the rest. --- include/net/sctp/sctp.h | 22 +++++++++- include/net/sctp/sm.h | 6 +-- include/net/sctp/structs.h | 85 +++++++++++++++++++----------------- net/sctp/associola.c | 18 ++++---- net/sctp/bind_addr.c | 20 ++++----- net/sctp/endpointola.c | 6 +-- net/sctp/input.c | 105 +++++++++++++-------------------------------- net/sctp/ipv6.c | 68 ++++++++++++++++++++++++++--- net/sctp/output.c | 11 ++--- net/sctp/protocol.c | 95 ++++++++++++++++++---------------------- net/sctp/sm_make_chunk.c | 38 ++++------------ net/sctp/sm_statefuns.c | 6 +-- net/sctp/socket.c | 50 ++++++++++----------- net/sctp/transport.c | 12 +++--- 14 files changed, 272 insertions(+), 270 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 7b261af05ad4..73c948813e72 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001-2002 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * * This file is part of the SCTP kernel reference Implementation @@ -473,6 +473,26 @@ static inline sctp_protocol_t *sctp_get_protocol(void) return &sctp_proto; } +/* Convert from an IP version number to an Address Family symbol. */ +static inline int ipver2af(__u8 ipver) +{ + int family; + + switch (ipver) { + case 4: + family = AF_INET; + break; + case 6: + family = AF_INET6; + break; + default: + family = 0; + break; + }; + + return family; +} + /* Warning: The following hash functions assume a power of two 'size'. */ /* This is the hash function for the SCTP port hash table. */ static inline int sctp_phashfn(__u16 lport) diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 9c5d678b2b14..5082a4a11cb9 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -332,10 +332,10 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *); __u32 sctp_generate_tsn(const sctp_endpoint_t *); /* 4th level prototypes */ -void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *, +void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *, __u16 port); -int sctp_addr2sockaddr(const union sctp_params, sockaddr_storage_t *); -int sockaddr2sctp_addr(const sockaddr_storage_t *, sctp_addr_param_t *); +int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *); +int sockaddr2sctp_addr(const union sctp_addr *, sctp_addr_param_t *); /* Extern declarations for major data structures. */ sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 505e9a54bb39..62c2cb28ccb4 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -95,11 +95,11 @@ struct sockaddr_storage { /* A convenience structure for handling sockaddr structures. * We should wean ourselves off this. */ -typedef union { +union sctp_addr { struct sockaddr_in v4; struct sockaddr_in6 v6; struct sockaddr sa; -} sockaddr_storage_t; +}; /* Forward declarations for data structures. */ @@ -246,17 +246,24 @@ typedef struct sctp_func { int optname, char *optval, int *optlen); - struct dst_entry *(*get_dst) (sockaddr_storage_t *daddr, - sockaddr_storage_t *saddr); + struct dst_entry *(*get_dst) (union sctp_addr *daddr, + union sctp_addr *saddr); + void (*copy_addrlist) (struct list_head *, + struct net_device *); int (*cmp_saddr) (struct dst_entry *dst, - sockaddr_storage_t *saddr); + union sctp_addr *saddr); + void (*addr_copy) (union sctp_addr *dst, + union sctp_addr *src); + void (*from_skb) (union sctp_addr *, + struct sk_buff *skb, + int saddr); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; struct list_head list; } sctp_func_t; -sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); +sctp_func_t *sctp_get_af_specific(sa_family_t); /* Protocol family functions. */ typedef struct sctp_pf { @@ -339,7 +346,7 @@ typedef struct sctp_cookie { __u32 initial_tsn; /* This holds the originating address of the INIT packet. */ - sockaddr_storage_t peer_addr; + union sctp_addr peer_addr; /* This is a shim for my peer's INIT packet, followed by * a copy of the raw address list of the association. @@ -393,7 +400,7 @@ union sctp_params { */ typedef struct sctp_sender_hb_info { sctp_paramhdr_t param_hdr; - sockaddr_storage_t daddr; + union sctp_addr daddr; unsigned long sent_at; } sctp_sender_hb_info_t __attribute__((packed)); @@ -479,9 +486,9 @@ struct SCTP_chunk { __u8 tsn_missing_report; /* Data chunk missing counter. */ /* What is the origin IP address for this chunk? */ - sockaddr_storage_t source; + union sctp_addr source; /* Destination address for this chunk. */ - sockaddr_storage_t dest; + union sctp_addr dest; /* For an inbound chunk, this tells us where it came from. * For an outbound chunk, it tells us where we'd like it to @@ -499,7 +506,7 @@ int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data); sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *, struct sock *); void sctp_init_addrs(sctp_chunk_t *chunk); -const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); +const union sctp_addr *sctp_source(const sctp_chunk_t *chunk); /* This is a structure for holding either an IPv6 or an IPv4 address. */ /* sin_family -- AF_INET or AF_INET6 @@ -508,7 +515,7 @@ const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); */ struct sockaddr_storage_list { struct list_head list; - sockaddr_storage_t a; + union sctp_addr a; }; typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); @@ -574,7 +581,7 @@ void sctp_packet_free(sctp_packet_t *); /* This represents a remote transport address. - * For local transport addresses, we just use sockaddr_storage_t. + * For local transport addresses, we just use union sctp_addr. * * RFC2960 Section 1.4 Key Terms * @@ -602,7 +609,7 @@ struct SCTP_transport { int dead; /* This is the peer's IP address and port. */ - sockaddr_storage_t ipaddr; + union sctp_addr ipaddr; /* These are the functions we call to handle LLP stuff. */ sctp_func_t *af_specific; @@ -742,11 +749,11 @@ struct SCTP_transport { int malloced; /* Is this structure kfree()able? */ }; -extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int); +extern sctp_transport_t *sctp_transport_new(const union sctp_addr *, int); extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, - const sockaddr_storage_t *, int); + const union sctp_addr *, int); extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); -extern void sctp_transport_route(sctp_transport_t *, sockaddr_storage_t *); +extern void sctp_transport_route(sctp_transport_t *, union sctp_addr *); extern void sctp_transport_free(sctp_transport_t *); extern void sctp_transport_destroy(sctp_transport_t *); extern void sctp_transport_reset_timers(sctp_transport_t *); @@ -893,10 +900,10 @@ void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); void sctp_bind_addr_free(sctp_bind_addr_t *); int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, sctp_scope_t scope, int priority,int flags); -int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, +int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *, int priority); -int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); -int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); +int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *); +int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const union sctp_addr *); union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, int priority); @@ -906,10 +913,10 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, unsigned short port, int priority); -sctp_scope_t sctp_scope(const sockaddr_storage_t *); -int sctp_in_scope(const sockaddr_storage_t *addr, const sctp_scope_t scope); -int sctp_is_any(const sockaddr_storage_t *addr); -int sctp_addr_is_valid(const sockaddr_storage_t *addr); +sctp_scope_t sctp_scope(const union sctp_addr *); +int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope); +int sctp_is_any(const union sctp_addr *addr); +int sctp_addr_is_valid(const union sctp_addr *addr); /* What type of sctp_endpoint_common? */ @@ -1051,13 +1058,13 @@ void sctp_endpoint_put(sctp_endpoint_t *); void sctp_endpoint_hold(sctp_endpoint_t *); void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc); sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, - const sockaddr_storage_t *paddr, + const union sctp_addr *paddr, sctp_transport_t **); sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, - const sockaddr_storage_t *); + const union sctp_addr *); -int sctp_has_association(const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr); +int sctp_has_association(const union sctp_addr *laddr, + const union sctp_addr *paddr); int sctp_verify_init(const sctp_association_t *asoc, sctp_cid_t cid, @@ -1065,10 +1072,10 @@ int sctp_verify_init(const sctp_association_t *asoc, sctp_chunk_t *chunk, sctp_chunk_t **err_chunk); int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, - const sockaddr_storage_t *peer_addr, + const union sctp_addr *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); + const union sctp_addr *peer_addr, int priority); __u32 sctp_generate_tag(const sctp_endpoint_t *ep); __u32 sctp_generate_tsn(const sctp_endpoint_t *ep); @@ -1157,7 +1164,7 @@ struct SCTP_association { /* Cache the primary path address here, when we * need a an address for msg_name. */ - sockaddr_storage_t primary_addr; + union sctp_addr primary_addr; /* active_path * The path that we are currently using to @@ -1535,16 +1542,16 @@ void sctp_association_hold(sctp_association_t *); sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *); sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *, - const sockaddr_storage_t *); + const union sctp_addr *); sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *, - const sockaddr_storage_t *address, + const union sctp_addr *address, const int priority); void sctp_assoc_control_transport(sctp_association_t *, sctp_transport_t *, sctp_transport_cmd_t, sctp_sn_error_t); sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, __u32); sctp_transport_t *sctp_assoc_is_match(sctp_association_t *, - const sockaddr_storage_t *, - const sockaddr_storage_t *); + const union sctp_addr *, + const union sctp_addr *); void sctp_assoc_migrate(sctp_association_t *, struct sock *); void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src); @@ -1552,10 +1559,10 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *); __u32 __sctp_association_get_tsn_block(sctp_association_t *, int); __u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid); -int sctp_cmp_addr(const sockaddr_storage_t *ss1, - const sockaddr_storage_t *ss2); -int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, - const sockaddr_storage_t *ss2); +int sctp_cmp_addr(const union sctp_addr *ss1, + const union sctp_addr *ss2); +int sctp_cmp_addr_exact(const union sctp_addr *ss1, + const union sctp_addr *ss2); sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc); sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc); diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 096c02e8ea67..1ba2060789ce 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -364,7 +364,7 @@ static void sctp_association_destroy(sctp_association_t *asoc) /* Add a transport address to an association. */ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, - const sockaddr_storage_t *addr, + const union sctp_addr *addr, int priority) { sctp_transport_t *peer; @@ -424,7 +424,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, asoc->frag_point = asoc->pmtu - (SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t)); - /* The asoc->peer.port might not be meaningful as of now, but + /* The asoc->peer.port might not be meaningful yet, but * initialize the packet structure anyway. */ (asoc->outqueue.init_output)(&peer->packet, @@ -478,7 +478,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, asoc->peer.primary_path = peer; /* Set a default msg_name for events. */ memcpy(&asoc->peer.primary_addr, &peer->ipaddr, - sizeof(sockaddr_storage_t)); + sizeof(union sctp_addr)); asoc->peer.active_path = peer; asoc->peer.retran_path = peer; } @@ -491,7 +491,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, /* Lookup a transport by address. */ sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, - const sockaddr_storage_t *address) + const union sctp_addr *address) { sctp_transport_t *t; struct list_head *pos; @@ -654,7 +654,7 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) * * FIXME: We do not match address scopes correctly. */ -int sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2) +int sctp_cmp_addr(const union sctp_addr *ss1, const union sctp_addr *ss2) { int len; const void *base1; @@ -710,8 +710,8 @@ match: * * FIXME: We do not match address scopes correctly. */ -int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, - const sockaddr_storage_t *ss2) +int sctp_cmp_addr_exact(const union sctp_addr *ss1, + const union sctp_addr *ss2) { int len; const void *base1; @@ -846,8 +846,8 @@ out: /* Is this the association we are looking for? */ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, - const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr) + const union sctp_addr *laddr, + const union sctp_addr *paddr) { sctp_transport_t *transport; diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index bc2ea6cb2120..69b61643f861 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -52,7 +52,7 @@ #include /* Forward declarations for internal helpers. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *, sockaddr_storage_t *, +static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *, sctp_scope_t scope, int priority, int flags); static void sctp_bind_addr_clean(sctp_bind_addr_t *); @@ -143,7 +143,7 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp) } /* Add an address to the bind address list in the SCTP_bind_addr structure. */ -int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, +int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new, int priority) { struct sockaddr_storage_list *addr; @@ -171,7 +171,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, /* Delete an address from the bind address list in the SCTP_bind_addr * structure. */ -int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) +int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr) { struct list_head *pos, *temp; struct sockaddr_storage_list *addr; @@ -242,7 +242,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, { sctp_addr_param_t *rawaddr; sctp_paramhdr_t *param; - sockaddr_storage_t addr; + union sctp_addr addr; int retval = 0; int len; @@ -283,7 +283,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, ********************************************************************/ /* Does this contain a specified address? */ -int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr) +int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const union sctp_addr *addr) { struct sockaddr_storage_list *laddr; struct list_head *pos; @@ -298,7 +298,7 @@ int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr } /* Copy out addresses from the global local address list. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, +static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, sctp_scope_t scope, int priority, int flags) { sctp_protocol_t *proto = sctp_get_protocol(); @@ -324,7 +324,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, } /* Is addr one of the wildcards? */ -int sctp_is_any(const sockaddr_storage_t *addr) +int sctp_is_any(const union sctp_addr *addr) { int retval = 0; @@ -350,7 +350,7 @@ int sctp_is_any(const sockaddr_storage_t *addr) } /* Is 'addr' valid for 'scope'? */ -int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) +int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) { sctp_scope_t addr_scope = sctp_scope(addr); @@ -420,7 +420,7 @@ int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) ********************************************************************/ /* What is the scope of 'addr'? */ -sctp_scope_t sctp_scope(const sockaddr_storage_t *addr) +sctp_scope_t sctp_scope(const union sctp_addr *addr) { sctp_scope_t retval = SCTP_SCOPE_GLOBAL; @@ -501,7 +501,7 @@ sctp_scope_t sctp_scope(const sockaddr_storage_t *addr) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -int sctp_addr_is_valid(const sockaddr_storage_t *addr) +int sctp_addr_is_valid(const union sctp_addr *addr) { unsigned short sa_family = addr->sa.sa_family; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 5abbd964d262..36b39aa20eba 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -237,7 +237,7 @@ void sctp_endpoint_put(sctp_endpoint_t *ep) /* Is this the endpoint we are looking for? */ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, - const sockaddr_storage_t *laddr) + const union sctp_addr *laddr) { sctp_endpoint_t *retval; @@ -262,7 +262,7 @@ out: */ sctp_association_t *__sctp_endpoint_lookup_assoc( const sctp_endpoint_t *endpoint, - const sockaddr_storage_t *paddr, + const union sctp_addr *paddr, sctp_transport_t **transport) { int rport; @@ -289,7 +289,7 @@ sctp_association_t *__sctp_endpoint_lookup_assoc( /* Lookup association on an endpoint based on a peer address. BH-safe. */ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, - const sockaddr_storage_t *paddr, + const union sctp_addr *paddr, sctp_transport_t **transport) { sctp_association_t *asoc; diff --git a/net/sctp/input.c b/net/sctp/input.c index c54f983d040d..fc699388cf3e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -60,64 +60,11 @@ /* Forward declarations for internal helpers. */ static int sctp_rcv_ootb(struct sk_buff *); sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, - const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr, + const union sctp_addr *laddr, + const union sctp_addr *paddr, sctp_transport_t **transportp); -sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr); +sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); -/* Initialize a sockaddr_storage from in incoming skb. - * FIXME: This belongs with AF specific sctp_func_t. --jgrimm - */ -static sockaddr_storage_t *sctp_sockaddr_storage_init(sockaddr_storage_t *addr, - const struct sk_buff *skb, - int is_saddr) -{ - sockaddr_storage_t *ret = NULL; - void *to, *saddr, *daddr; - __u16 *port; - size_t len; - struct sctphdr *sh; - - switch (skb->nh.iph->version) { - case 4: - to = &addr->v4.sin_addr.s_addr; - port = &addr->v4.sin_port; - saddr = &skb->nh.iph->saddr; - daddr = &skb->nh.iph->daddr; - len = sizeof(struct in_addr); - addr->v4.sin_family = AF_INET; - break; - - case 6: - SCTP_V6( - to = &addr->v6.sin6_addr; - port = &addr->v6.sin6_port; - saddr = &skb->nh.ipv6h->saddr; - daddr = &skb->nh.ipv6h->daddr; - len = sizeof(struct in6_addr); - addr->v6.sin6_family = AF_INET6; - addr->v6.sin6_flowinfo = 0; /* FIXME */ - addr->v6.sin6_scope_id = 0; /* FIXME */ - break; - ) - - default: - goto out; - }; - - sh = (struct sctphdr *) skb->h.raw; - if (is_saddr) { - *port = ntohs(sh->source); - memcpy(to, saddr, len); - } else { - *port = ntohs(sh->dest); - memcpy(to, daddr, len); - } - - ret = addr; -out: - return ret; -} /* Calculate the SCTP checksum of an SCTP packet. */ static inline int sctp_rcv_checksum(struct sk_buff *skb) @@ -147,8 +94,9 @@ int sctp_rcv(struct sk_buff *skb) sctp_transport_t *transport = NULL; sctp_chunk_t *chunk; struct sctphdr *sh; - sockaddr_storage_t src; - sockaddr_storage_t dest; + union sctp_addr src; + union sctp_addr dest; + struct sctp_func *af; int ret = 0; if (skb->pkt_type!=PACKET_HOST) @@ -163,10 +111,15 @@ int sctp_rcv(struct sk_buff *skb) if (sctp_rcv_checksum(skb) < 0) goto bad_packet; - skb_pull(skb, sizeof(struct sctphdr)); + skb_pull(skb, sizeof(struct sctphdr)); + + af = sctp_get_af_specific(ipver2af(skb->nh.iph->version)); + if (unlikely(!af)) + goto bad_packet; - sctp_sockaddr_storage_init(&src, skb, 1); - sctp_sockaddr_storage_init(&dest, skb, 0); + /* Initialize local addresses for lookups. */ + af->from_skb(&src, skb, 1); + af->from_skb(&dest, skb, 0); /* If the packet is to or from a non-unicast address, * silently discard the packet. @@ -431,7 +384,7 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep) } /* Look up an endpoint. */ -sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) +sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) { sctp_hashbucket_t *head; sctp_endpoint_common_t *epb; @@ -523,8 +476,8 @@ void __sctp_unhash_established(sctp_association_t *asoc) } /* Look up an association. */ -sctp_association_t *__sctp_lookup_association(const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr, +sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr, + const union sctp_addr *paddr, sctp_transport_t **transportp) { sctp_hashbucket_t *head; @@ -559,8 +512,8 @@ hit: } /* Look up an association. BH-safe. */ -sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr, +sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr, + const union sctp_addr *paddr, sctp_transport_t **transportp) { sctp_association_t *asoc; @@ -573,8 +526,8 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr, } /* Is there an association matching the given local and peer addresses? */ -int sctp_has_association(const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr) +int sctp_has_association(const union sctp_addr *laddr, + const union sctp_addr *paddr) { sctp_association_t *asoc; sctp_transport_t *transport; @@ -606,12 +559,12 @@ int sctp_has_association(const sockaddr_storage_t *laddr, * in certain circumstances. * */ -static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, - const sockaddr_storage_t *laddr, sctp_transport_t **transportp) +static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb, + const union sctp_addr *laddr, sctp_transport_t **transportp) { sctp_association_t *asoc; - sockaddr_storage_t addr; - sockaddr_storage_t *paddr = &addr; + union sctp_addr addr; + union sctp_addr *paddr = &addr; struct sctphdr *sh = (struct sctphdr *) skb->h.raw; sctp_chunkhdr_t *ch; union sctp_params params; @@ -665,20 +618,20 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, /* Lookup an association for an inbound skb. */ sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, - const sockaddr_storage_t *paddr, - const sockaddr_storage_t *laddr, + const union sctp_addr *paddr, + const union sctp_addr *laddr, sctp_transport_t **transportp) { sctp_association_t *asoc; asoc = __sctp_lookup_association(laddr, paddr, transportp); - /* Further lookup for INIT-ACK packet. + /* Further lookup for INIT/INIT-ACK packets. * SCTP Implementors Guide, 2.18 Handling of address * parameters within the INIT or INIT-ACK. */ if (!asoc) - asoc = __sctp_rcv_initack_lookup(skb, laddr, transportp); + asoc = __sctp_rcv_init_lookup(skb, laddr, transportp); return asoc; } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index eb31e378985c..b24470424218 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -172,8 +172,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) /* Returns the dst cache entry for the given source and destination ip * addresses. */ -struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr, - sockaddr_storage_t *saddr) +struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, + union sctp_addr *saddr) { struct dst_entry *dst; struct flowi fl = { .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, @@ -206,8 +206,63 @@ struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr, return dst; } +/* Make a copy of all potential local addresses. */ +static void sctp_v6_copy_addrlist(struct list_head *addrlist, + struct net_device *dev) +{ + struct inet6_dev *in6_dev; + struct inet6_ifaddr *ifp; + struct sockaddr_storage_list *addr; + + read_lock(&addrconf_lock); + if ((in6_dev = __in6_dev_get(dev)) == NULL) { + read_unlock(&addrconf_lock); + return; + } + + read_lock(&in6_dev->lock); + for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) { + /* Add the address to the local list. */ + addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); + if (addr) { + addr->a.v6.sin6_family = AF_INET6; + addr->a.v6.sin6_port = 0; + addr->a.v6.sin6_addr = ifp->addr; + INIT_LIST_HEAD(&addr->list); + list_add_tail(&addr->list, addrlist); + } + } + + read_unlock(&in6_dev->lock); + read_unlock(&addrconf_lock); +} + +/* Initialize a sockaddr_storage from in incoming skb. */ +static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, + int is_saddr) +{ + void *from; + __u16 *port; + struct sctphdr *sh; + + port = &addr->v6.sin6_port; + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; /* FIXME */ + addr->v6.sin6_scope_id = 0; /* FIXME */ + + sh = (struct sctphdr *) skb->h.raw; + if (is_saddr) { + *port = ntohs(sh->source); + from = &skb->nh.ipv6h->saddr; + } else { + *port = ntohs(sh->dest); + from = &skb->nh.ipv6h->daddr; + } + ipv6_addr_copy(&addr->v6.sin6_addr, from); +} + /* Check if the dst entry's source addr matches the given source addr. */ -int sctp_v6_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr) +int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) { struct rt6_info *rt = (struct rt6_info *)dst; @@ -227,12 +282,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len) } /* Initialize a PF_INET msgname from a ulpevent. */ -static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addrlen) +static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, + int *addrlen) { struct sockaddr_in6 *sin6, *sin6from; if (msgname) { - sockaddr_storage_t *addr; + union sctp_addr *addr; sctp_inet6_msgname(msgname, addrlen); sin6 = (struct sockaddr_in6 *)msgname; @@ -327,6 +383,8 @@ static sctp_func_t sctp_ipv6_specific = { .setsockopt = ipv6_setsockopt, .getsockopt = ipv6_getsockopt, .get_dst = sctp_v6_get_dst, + .copy_addrlist = sctp_v6_copy_addrlist, + .from_skb = sctp_v6_from_skb, .cmp_saddr = sctp_v6_cmp_saddr, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), diff --git a/net/sctp/output.c b/net/sctp/output.c index 5962d3e72e52..7620a118c1f8 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -366,18 +366,13 @@ int sctp_packet_transmit(sctp_packet_t *packet) */ sh->checksum = htonl(crc32); + /* FIXME: Delete the rest of this switch statement once phase 2 + * of address selection (ipv6 support) drops in. + */ switch (transport->ipaddr.sa.sa_family) { - case AF_INET: - inet_sk(sk)->daddr = transport->ipaddr.v4.sin_addr.s_addr; - break; - case AF_INET6: SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;) break; - - default: - /* This is bogus address type, just bail. */ - break; }; /* IP layer ECN support diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5724996717d7..22c709b4974c 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001-2002 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll @@ -103,8 +103,8 @@ void sctp_proc_exit(void) /* Private helper to extract ipv4 address and stash them in * the protocol structure. */ -static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, - struct net_device *dev) +static void sctp_v4_copy_addrlist(struct list_head *addrlist, + struct net_device *dev) { struct in_device *in_dev; struct in_ifaddr *ifa; @@ -117,7 +117,6 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, } read_lock(&in_dev->lock); - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { /* Add the address to the local list. */ addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); @@ -126,7 +125,7 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_port = 0; addr->a.v4.sin_addr.s_addr = ifa->ifa_local; - list_add_tail(&addr->list, &proto->local_addr_list); + list_add_tail(&addr->list, addrlist); } } @@ -134,56 +133,21 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, read_unlock(&inetdev_lock); } -/* Private helper to extract ipv6 address and stash them in - * the protocol structure. - * FIXME: Make this an address family function. - */ -static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto, - struct net_device *dev) -{ -#ifdef SCTP_V6_SUPPORT - /* FIXME: The testframe doesn't support this function. */ -#ifndef TEST_FRAME - struct inet6_dev *in6_dev; - struct inet6_ifaddr *ifp; - struct sockaddr_storage_list *addr; - - read_lock(&addrconf_lock); - if ((in6_dev = __in6_dev_get(dev)) == NULL) { - read_unlock(&addrconf_lock); - return; - } - - read_lock_bh(&in6_dev->lock); - for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) { - /* Add the address to the local list. */ - addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); - if (addr) { - addr->a.v6.sin6_family = AF_INET6; - addr->a.v6.sin6_port = 0; - addr->a.v6.sin6_addr = ifp->addr; - INIT_LIST_HEAD(&addr->list); - list_add_tail(&addr->list, &proto->local_addr_list); - } - } - - read_unlock_bh(&in6_dev->lock); - read_unlock(&addrconf_lock); -#endif /* TEST_FRAME */ -#endif /* SCTP_V6_SUPPORT */ -} - /* Extract our IP addresses from the system and stash them in the * protocol structure. */ static void __sctp_get_local_addr_list(sctp_protocol_t *proto) { struct net_device *dev; + struct list_head *pos; + struct sctp_func *af; read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { - sctp_v4_get_local_addr_list(proto, dev); - sctp_v6_get_local_addr_list(proto, dev); + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + af->copy_addrlist(&proto->local_addr_list, dev); + } } read_unlock(&dev_base_lock); } @@ -259,8 +223,8 @@ end_copy: /* Returns the dst cache entry for the given source and destination ip * addresses. */ -struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr, - sockaddr_storage_t *saddr) +struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr, + union sctp_addr *saddr) { struct rtable *rt; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = @@ -285,8 +249,31 @@ struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr, return &rt->u.dst; } + +/* Initialize a sctp_addr from in incoming skb. */ +static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, + int is_saddr) +{ + void *from; + __u16 *port; + struct sctphdr *sh; + + port = &addr->v4.sin_port; + addr->v4.sin_family = AF_INET; + + sh = (struct sctphdr *) skb->h.raw; + if (is_saddr) { + *port = ntohs(sh->source); + from = &skb->nh.iph->saddr; + } else { + *port = ntohs(sh->dest); + from = &skb->nh.iph->daddr; + } + memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr)); +} + /* Check if the dst entry's source addr matches the given source addr. */ -int sctp_v4_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr) +int sctp_v4_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) { struct rtable *rt = (struct rtable *)dst; @@ -336,11 +323,11 @@ int sctp_ctl_sock_init(void) /* Get the table of functions for manipulating a particular address * family. */ -sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) +sctp_func_t *sctp_get_af_specific(sa_family_t family) { struct list_head *pos; sctp_protocol_t *proto = sctp_get_protocol(); - sctp_func_t *retval, *af; + struct sctp_func *retval, *af; retval = NULL; @@ -349,7 +336,7 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) */ list_for_each(pos, &proto->address_families) { af = list_entry(pos, sctp_func_t, list); - if (address->sa.sa_family == af->sa_family) { + if (family == af->sa_family) { retval = af; break; } @@ -448,11 +435,13 @@ static struct inet_protocol sctp_protocol = { }; /* IPv4 address related functions. */ -sctp_func_t sctp_ipv4_specific = { +struct sctp_func sctp_ipv4_specific = { .queue_xmit = ip_queue_xmit, .setsockopt = ip_setsockopt, .getsockopt = ip_getsockopt, .get_dst = sctp_v4_get_dst, + .copy_addrlist = sctp_v4_copy_addrlist, + .from_skb = sctp_v4_from_skb, .cmp_saddr = sctp_v4_cmp_saddr, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fb4c5b6f561b..1b0e16b99e87 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1033,7 +1033,7 @@ nodata: /* Set chunk->source and dest based on the IP header in chunk->skb. */ void sctp_init_addrs(sctp_chunk_t *chunk) { - sockaddr_storage_t *source, *dest; + union sctp_addr *source, *dest; struct sk_buff *skb; struct sctphdr *sh; struct iphdr *ih4; @@ -1075,7 +1075,7 @@ void sctp_init_addrs(sctp_chunk_t *chunk) } /* Extract the source address from a chunk. */ -const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk) +const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) { /* If we have a known transport, use that. */ if (chunk->transport) { @@ -1661,7 +1661,7 @@ int sctp_verify_init(const sctp_association_t *asoc, * Returns 0 on failure, else success. */ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, - const sockaddr_storage_t *peer_addr, + const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, int priority) { @@ -1780,9 +1780,9 @@ nomem: * structures for the addresses. */ int sctp_process_param(sctp_association_t *asoc, union sctp_params param, - const sockaddr_storage_t *peer_addr, int priority) + const union sctp_addr *peer_addr, int priority) { - sockaddr_storage_t addr; + union sctp_addr addr; int i; __u16 sat; int retval = 1; @@ -1906,8 +1906,8 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep) * 4th Level Abstractions ********************************************************************/ -/* Convert from an SCTP IP parameter to a sockaddr_storage_t. */ -void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param, +/* Convert from an SCTP IP parameter to a union sctp_addr. */ +void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param, __u16 port) { switch(param->v4.param_hdr.type) { @@ -1934,7 +1934,7 @@ void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param, /* Convert an IP address in an SCTP param into a sockaddr_in. */ /* Returns true if a valid conversion was possible. */ -int sctp_addr2sockaddr(union sctp_params p, sockaddr_storage_t *sa) +int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa) { switch (p.p->type) { case SCTP_PARAM_IPV4_ADDRESS: @@ -1955,30 +1955,10 @@ int sctp_addr2sockaddr(union sctp_params p, sockaddr_storage_t *sa) return 1; } -/* Convert from an IP version number to an Address Family symbol. */ -int ipver2af(__u8 ipver) -{ - int family; - - switch (ipver) { - case 4: - family = AF_INET; - break; - case 6: - family = AF_INET6; - break; - default: - family = 0; - break; - }; - - return family; -} - /* Convert a sockaddr_in to an IP address in an SCTP param. * Returns len if a valid conversion was possible. */ -int sockaddr2sctp_addr(const sockaddr_storage_t *sa, sctp_addr_param_t *p) +int sockaddr2sctp_addr(const union sctp_addr *sa, sctp_addr_param_t *p) { int len = 0; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 9c0212a049da..f8830fc33079 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -832,7 +832,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, sctp_cmd_seq_t *commands) { sctp_chunk_t *chunk = arg; - sockaddr_storage_t from_addr; + union sctp_addr from_addr; sctp_transport_t *link; sctp_sender_hb_info_t *hbinfo; unsigned long max_interval; @@ -881,7 +881,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, /* Helper function to send out an abort for the restart * condition. */ -static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa, +static int sctp_sf_send_restart_abort(union sctp_addr *ssa, sctp_chunk_t *init, sctp_cmd_seq_t *commands) { @@ -4313,7 +4313,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, /* Cache a route for the transport with the chunk's destination as * the source address. */ - sctp_transport_route(transport, (sockaddr_storage_t *)&chunk->dest); + sctp_transport_route(transport, (union sctp_addr *)&chunk->dest); packet = sctp_packet_init(packet, transport, sport, dport); packet = sctp_packet_config(packet, vtag, 0, NULL); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6533707fb521..31e765f49306 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -87,14 +87,14 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static inline void sctp_sk_addr_set(struct sock *, - const sockaddr_storage_t *newaddr, - sockaddr_storage_t *saveaddr); + const union sctp_addr *newaddr, + union sctp_addr *saveaddr); static inline void sctp_sk_addr_restore(struct sock *, - const sockaddr_storage_t *); + const union sctp_addr *); static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); -static int sctp_do_bind(struct sock *, sockaddr_storage_t *, int); +static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_autobind(struct sock *sk); @@ -122,7 +122,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) /* Disallow binding twice. */ if (!sctp_sk(sk)->ep->base.bind_addr.port) - retval = sctp_do_bind(sk, (sockaddr_storage_t *)uaddr, + retval = sctp_do_bind(sk, (union sctp_addr *)uaddr, addr_len); else retval = -EINVAL; @@ -135,14 +135,14 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) static long sctp_get_port_local(struct sock *, unsigned short); /* Bind a local address either to an endpoint or to an association. */ -SCTP_STATIC int sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, +SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr, int addr_len) { sctp_opt_t *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; sctp_bind_addr_t *bp = &ep->base.bind_addr; unsigned short sa_family = newaddr->sa.sa_family; - sockaddr_storage_t tmpaddr, saveaddr; + union sctp_addr tmpaddr, saveaddr; unsigned short *snum; int ret = 0; @@ -403,7 +403,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) goto err_bindx_add; }; - retval = sctp_do_bind(sk, (sockaddr_storage_t *)&addrs[cnt], + retval = sctp_do_bind(sk, (union sctp_addr *)&addrs[cnt], addr_len); err_bindx_add: @@ -481,7 +481,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) int cnt; sctp_bind_addr_t *bp = &ep->base.bind_addr; int retval = 0; - sockaddr_storage_t saveaddr; + union sctp_addr saveaddr; SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n", sk, addrs, addrcnt); @@ -500,7 +500,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) */ switch (((struct sockaddr *)&addrs[cnt])->sa_family) { case AF_INET: - saveaddr = *((sockaddr_storage_t *) + saveaddr = *((union sctp_addr *) &addrs[cnt]); saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port); /* Verify the port. */ @@ -511,7 +511,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) break; case AF_INET6: - saveaddr = *((sockaddr_storage_t *) + saveaddr = *((union sctp_addr *) &addrs[cnt]); saveaddr.v6.sin6_port = ntohs(saveaddr.v6.sin6_port); @@ -741,7 +741,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, sctp_association_t *new_asoc=NULL, *asoc=NULL; sctp_transport_t *transport; sctp_chunk_t *chunk = NULL; - sockaddr_storage_t to; + union sctp_addr to; struct sockaddr *msg_name = NULL; struct sctp_sndrcvinfo default_sinfo = { 0 }; struct sctp_sndrcvinfo *sinfo; @@ -1258,7 +1258,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk, { struct sctp_paddrparams params; sctp_association_t *asoc; - sockaddr_storage_t *addr; + union sctp_addr *addr; sctp_transport_t *trans; int error; @@ -1271,7 +1271,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk, if (!asoc) return -EINVAL; - addr = (sockaddr_storage_t *) &(params.spp_address); + addr = (union sctp_addr *) &(params.spp_address); trans = sctp_assoc_lookup_paddr(asoc, addr); if (!trans) @@ -1606,7 +1606,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, status.sstat_fragmentation_point = assoc->frag_point; status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, - &(transport->ipaddr), sizeof(sockaddr_storage_t)); + &(transport->ipaddr), sizeof(union sctp_addr)); status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; @@ -1781,7 +1781,7 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk, { struct sctp_paddrparams params; sctp_association_t *asoc; - sockaddr_storage_t *addr; + union sctp_addr *addr; sctp_transport_t *trans; if (len != sizeof(struct sctp_paddrparams)) @@ -1793,7 +1793,7 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk, if (!asoc) return -EINVAL; - addr = (sockaddr_storage_t *) &(params.spp_address); + addr = (union sctp_addr *) &(params.spp_address); trans = sctp_assoc_lookup_paddr(asoc, addr); if (!trans) @@ -1990,7 +1990,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) * socket is going to be sk2. */ int sk_reuse = sk->reuse; - sockaddr_storage_t tmpaddr; + union sctp_addr tmpaddr; struct sock *sk2 = pp->sk; SCTP_DEBUG_PRINTK("sctp_get_port() found a " @@ -2293,10 +2293,10 @@ void sctp_put_port(struct sock *sk) */ static int sctp_autobind(struct sock *sk) { - sockaddr_storage_t autoaddr; + union sctp_addr autoaddr; int addr_len = 0; - memset(&autoaddr, 0, sizeof(sockaddr_storage_t)); + memset(&autoaddr, 0, sizeof(union sctp_addr)); switch (sk->family) { case PF_INET: @@ -2437,8 +2437,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, /* Setup sk->rcv_saddr before calling get_port(). */ static inline void sctp_sk_addr_set(struct sock *sk, - const sockaddr_storage_t *newaddr, - sockaddr_storage_t *saveaddr) + const union sctp_addr *newaddr, + union sctp_addr *saveaddr) { struct inet_opt *inet = inet_sk(sk); @@ -2465,7 +2465,7 @@ static inline void sctp_sk_addr_set(struct sock *sk, } /* Restore sk->rcv_saddr after failing get_port(). */ -static inline void sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) +static inline void sctp_sk_addr_restore(struct sock *sk, const union sctp_addr *addr) { struct inet_opt *inet = inet_sk(sk); @@ -2610,12 +2610,12 @@ no_packet: static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) { - sockaddr_storage_t *sa; + union sctp_addr *sa; if (msg->msg_namelen < sizeof (struct sockaddr)) return -EINVAL; - sa = (sockaddr_storage_t *) msg->msg_name; + sa = (union sctp_addr *) msg->msg_name; switch (sa->sa.sa_family) { case AF_INET: if (msg->msg_namelen < sizeof(struct sockaddr_in)) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index e5cc78b8726e..482b1a34effc 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -9,7 +9,7 @@ * * This module provides the abstraction for an SCTP tranport representing * a remote transport address. For local transport addresses, we just use - * sockaddr_storage_t. + * union sctp_addr. * * The SCTP reference implementation is free software; * you can redistribute it and/or modify it under the terms of @@ -53,7 +53,7 @@ /* 1st Level Abstractions. */ /* Allocate and initialize a new transport. */ -sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priority) +sctp_transport_t *sctp_transport_new(const union sctp_addr *addr, int priority) { sctp_transport_t *transport; @@ -78,14 +78,14 @@ fail: /* Intialize a new transport from provided memory. */ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, - const sockaddr_storage_t *addr, + const union sctp_addr *addr, int priority) { sctp_protocol_t *proto = sctp_get_protocol(); /* Copy in the address. */ peer->ipaddr = *addr; - peer->af_specific = sctp_get_af_specific(addr); + peer->af_specific = sctp_get_af_specific(addr->sa.sa_family); peer->asoc = NULL; /* From 6.3.1 RTO Calculation: @@ -204,11 +204,11 @@ void sctp_transport_set_owner(sctp_transport_t *transport, * souce address. */ void sctp_transport_route(sctp_transport_t *transport, - sockaddr_storage_t *saddr) + union sctp_addr *saddr) { sctp_association_t *asoc = transport->asoc; sctp_func_t *af = transport->af_specific; - sockaddr_storage_t *daddr = &transport->ipaddr; + union sctp_addr *daddr = &transport->ipaddr; sctp_bind_addr_t *bp; rwlock_t *addr_lock; struct sockaddr_storage_list *laddr; -- cgit v1.2.3 From d9a91e707629deb07074c7ca8a9b79dbddbd2e72 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 7 Nov 2002 01:21:14 -0800 Subject: [SCTP] udp-style connect support(non-blocking). --- include/net/sctp/structs.h | 1 + net/sctp/endpointola.c | 24 ++++++++ net/sctp/socket.c | 143 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 138 insertions(+), 30 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 62c2cb28ccb4..379c42f0666f 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1060,6 +1060,7 @@ void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc); sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, const union sctp_addr *paddr, sctp_transport_t **); +int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, const union sctp_addr *); diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 36b39aa20eba..c095caf7badd 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -301,6 +301,30 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, return asoc; } +/* Look for any peeled off association from the endpoint that matches the + * given peer address. + */ +int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, + const union sctp_addr *paddr) +{ + struct list_head *pos; + struct sockaddr_storage_list *addr; + sctp_bind_addr_t *bp; + + sctp_read_lock(&ep->base.addr_lock); + bp = &ep->base.bind_addr; + list_for_each(pos, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_has_association(&addr->a, paddr)) { + sctp_read_unlock(&ep->base.addr_lock); + return 1; + } + } + sctp_read_unlock(&ep->base.addr_lock); + + return 0; +} + /* Do delayed input processing. This is scheduled by sctp_rcv(). * This may be called on BH or task time. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 31e765f49306..691909b90aec 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -91,7 +91,7 @@ static inline void sctp_sk_addr_set(struct sock *, union sctp_addr *saveaddr); static inline void sctp_sk_addr_restore(struct sock *, const union sctp_addr *); -static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); +static inline int sctp_verify_addr(struct sock *, struct sockaddr *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); static int sctp_do_bind(struct sock *, union sctp_addr *, int); @@ -777,7 +777,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, * For a peeled-off socket, msg_name is ignored. */ if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { - err = sctp_sendmsg_verify_name(sk, msg); + err = sctp_verify_addr(sk, (struct sockaddr *)msg->msg_name, + msg->msg_namelen); if (err) return err; @@ -826,28 +827,14 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* Look for a matching association on the endpoint. */ asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); if (!asoc) { - struct list_head *pos; - struct sockaddr_storage_list *addr; - sctp_bind_addr_t *bp = &ep->base.bind_addr; - - sctp_read_lock(&ep->base.addr_lock); - - /* If we could not find a matching association on - * the endpoint, make sure that there is no peeled- - * off association. - */ - list_for_each(pos, &bp->address_list) { - addr = list_entry(pos, - struct sockaddr_storage_list, - list); - if (sctp_has_association(&addr->a, &to)) { - err = -EINVAL; - sctp_read_unlock(&ep->base.addr_lock); - goto out_unlock; - } + /* If we could not find a matching association on the + * endpoint, make sure that there is no peeled-off + * association on another socket. + */ + if (sctp_endpoint_is_peeled_off(ep, &to)) { + err = -EADDRNOTAVAIL; + goto out_unlock; } - - sctp_read_unlock(&ep->base.addr_lock); } } else { /* For a peeled-off socket, ignore any associd specified by @@ -1420,11 +1407,107 @@ out_nounlock: return retval; } -/* FIXME: Write comments. */ +/* API 3.1.6 connect() - UDP Style Syntax + * + * An application may use the connect() call in the UDP model to initiate an + * association without sending data. + * + * The syntax is: + * + * ret = connect(int sd, const struct sockaddr *nam, socklen_t len); + * + * sd: the socket descriptor to have a new association added to. + * + * nam: the address structure (either struct sockaddr_in or struct + * sockaddr_in6 defined in RFC2553 [7]). + * + * len: the size of the address. + */ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - return -EOPNOTSUPP; /* STUB */ + sctp_opt_t *sp; + sctp_endpoint_t *ep; + sctp_association_t *asoc; + sctp_transport_t *transport; + union sctp_addr to; + sctp_scope_t scope; + int err = 0; + + sctp_lock_sock(sk); + + SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d)\n", + __FUNCTION__, sk, uaddr, addr_len); + + sp = sctp_sk(sk); + ep = sp->ep; + + /* connect() cannot be done on a peeled-off socket. */ + if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) { + err = -EISCONN; + goto out_unlock; + } + + err = sctp_verify_addr(sk, uaddr, addr_len); + if (err) + goto out_unlock; + + memcpy(&to, uaddr, addr_len); + to.v4.sin_port = ntohs(to.v4.sin_port); + + asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); + if (asoc) { + if (asoc->state >= SCTP_STATE_ESTABLISHED) + err = -EISCONN; + else + err = -EALREADY; + goto out_unlock; + } + + /* If we could not find a matching association on the endpoint, + * make sure that there is no peeled-off association matching the + * peer address even on another socket. + */ + if (sctp_endpoint_is_peeled_off(ep, &to)) { + err = -EADDRNOTAVAIL; + goto out_unlock; + } + + /* If a bind() or sctp_bindx() is not called prior to a connect() + * call, the system picks an ephemeral port and will choose an address + * set equivalent to binding with a wildcard address. + */ + if (!ep->base.bind_addr.port) { + if (sctp_autobind(sk)) { + err = -EAGAIN; + goto out_unlock; + } + } + + scope = sctp_scope(&to); + asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); + if (!asoc) { + err = -ENOMEM; + goto out_unlock; + } + + /* Prime the peer's transport structures. */ + transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL); + + err = sctp_primitive_ASSOCIATE(asoc, NULL); + if (err < 0) + sctp_association_free(asoc); + + /* FIXME: Currently we support only non-blocking connect(). + * To support blocking connect(), we need to wait for the association + * to be ESTABLISHED before returning. + */ + err = -EINPROGRESS; + +out_unlock: + sctp_release_sock(sk); + + return err; } /* FIXME: Write comments. */ @@ -2608,17 +2691,17 @@ no_packet: return NULL; } -static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) +static inline int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int addrlen) { union sctp_addr *sa; - if (msg->msg_namelen < sizeof (struct sockaddr)) + if (addrlen < sizeof (struct sockaddr)) return -EINVAL; - sa = (union sctp_addr *) msg->msg_name; + sa = (union sctp_addr *)addr; switch (sa->sa.sa_family) { case AF_INET: - if (msg->msg_namelen < sizeof(struct sockaddr_in)) + if (addrlen < sizeof(struct sockaddr_in)) return -EINVAL; break; @@ -2626,7 +2709,7 @@ static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) if (PF_INET == sk->family) return -EINVAL; SCTP_V6( - if (msg->msg_namelen < sizeof(struct sockaddr_in6)) + if (addrlen < sizeof(struct sockaddr_in6)) return -EINVAL; break; ); -- cgit v1.2.3 From 664bf802f561e924e69c146ec8411fbb90e4ea6e Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 7 Nov 2002 19:48:38 -0800 Subject: [SCTP] Fix for sideeffect violation in sctp_sf_heartbeat(). --- include/net/sctp/command.h | 1 + net/sctp/sm_sideeffect.c | 5 +++++ net/sctp/sm_statefuns.c | 11 ++++++----- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 67524f0b1a03..b1fba0151675 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -85,6 +85,7 @@ typedef enum { SCTP_CMD_UPDATE_ASSOC, /* Update association information. */ SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ + SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */ SCTP_CMD_LAST } sctp_verb_t; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 5cf467eaab8b..1b8eb76f689e 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -595,6 +595,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, chunk->pdiscard = 1; break; + case SCTP_CMD_RTO_PENDING: + t = command->obj.transport; + t->rto_pending = 1; + break; + default: printk(KERN_WARNING "Impossible command: %u, %p\n", command->verb, command->obj.ptr); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index f8830fc33079..4ddd1146bf5a 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -680,17 +680,18 @@ sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep, hbinfo.daddr = transport->ipaddr; hbinfo.sent_at = jiffies; - /* Set rto_pending indicating that an RTT measurement - * is started with this heartbeat chunk. - */ - transport->rto_pending = 1; - /* Send a heartbeat to our peer. */ paylen = sizeof(sctp_sender_hb_info_t); reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); if (!reply) return SCTP_DISPOSITION_NOMEM; + /* Set rto_pending indicating that an RTT measurement + * is started with this heartbeat chunk. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_RTO_PENDING, + SCTP_TRANSPORT(transport)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); return SCTP_DISPOSITION_CONSUME; } -- cgit v1.2.3 From f8dfb3b05b4342ae594839a5e12984619e3e20e6 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Fri, 8 Nov 2002 02:27:25 -0600 Subject: [SCTP] Addr family cleanup part 2. (jgrimm) Splitting out yet more code. New af and pf specific functions. --- include/net/sctp/structs.h | 11 +++-- net/sctp/bind_addr.c | 115 ++++----------------------------------------- net/sctp/input.c | 4 +- net/sctp/ipv6.c | 79 +++++++++++++++++++++++++++++-- net/sctp/protocol.c | 109 +++++++++++++++++++++++++++++++----------- net/sctp/sm_make_chunk.c | 44 ++--------------- net/sctp/socket.c | 41 +++++++--------- 7 files changed, 195 insertions(+), 208 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 379c42f0666f..b4f6a1021c6e 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -2,7 +2,7 @@ * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001 International Business Machines Corp. + * Copyright (c) 2001-2002 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -257,6 +257,8 @@ typedef struct sctp_func { void (*from_skb) (union sctp_addr *, struct sk_buff *skb, int saddr); + int (*addr_valid) (union sctp_addr *); + sctp_scope_t (*scope) (union sctp_addr *); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; @@ -269,13 +271,14 @@ sctp_func_t *sctp_get_af_specific(sa_family_t); typedef struct sctp_pf { void (*event_msgname)(sctp_ulpevent_t *, char *, int *); void (*skb_msgname)(struct sk_buff *, char *, int *); + int (*af_supported)(sa_family_t); } sctp_pf_t; /* SCTP Socket type: UDP or TCP style. */ typedef enum { SCTP_SOCKET_UDP = 0, - SCTP_SOCKET_UDP_HIGH_BANDWIDTH, - SCTP_SOCKET_TCP + SCTP_SOCKET_UDP_HIGH_BANDWIDTH, + SCTP_SOCKET_TCP } sctp_socket_type_t; /* Per socket SCTP information. */ @@ -505,7 +508,7 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data); sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *, struct sock *); -void sctp_init_addrs(sctp_chunk_t *chunk); +void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *); const union sctp_addr *sctp_source(const sctp_chunk_t *chunk); /* This is a structure for holding either an IPv6 or an IPv4 address. */ diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 69b61643f861..31b627e84327 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation * Copyright (c) Cisco 1999,2000 * Copyright (c) Motorola 1999,2000,2001 - * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) International Business Machines Corp., 2001,2002 * Copyright (c) La Monte H.P. Yarroll 2001 * * This file is part of the SCTP kernel reference implementation. @@ -196,7 +196,7 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr) * * The second argument is the return value for the length. */ -union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, +union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, int priority) { union sctp_params addrparms; @@ -252,7 +252,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, rawaddr = (sctp_addr_param_t *)raw_addr_list; switch (param->type) { - case SCTP_PARAM_IPV4_ADDRESS: + case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV6_ADDRESS: sctp_param2sockaddr(&addr, rawaddr, port); retval = sctp_add_bind_addr(bp, &addr, priority); @@ -422,110 +422,11 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) /* What is the scope of 'addr'? */ sctp_scope_t sctp_scope(const union sctp_addr *addr) { - sctp_scope_t retval = SCTP_SCOPE_GLOBAL; + struct sctp_func *af; - switch (addr->sa.sa_family) { - case AF_INET: - /* We are checking the loopback, private and other address - * scopes as defined in RFC 1918. - * The IPv4 scoping is based on the draft for SCTP IPv4 - * scoping . - * The set of SCTP address scope hopefully can cover both - * types of addresses. - */ - - /* Should IPv4 scoping be a sysctl configurable option - * so users can turn it off (default on) for certain - * unconventional networking environments? - */ - - /* Check for unusable SCTP addresses. */ - if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { - retval = SCTP_SCOPE_UNUSABLE; - } else if (LOOPBACK(addr->v4.sin_addr.s_addr)) { - retval = SCTP_SCOPE_LOOPBACK; - } else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) { - retval = SCTP_SCOPE_LINK; - } else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) { - retval = SCTP_SCOPE_PRIVATE; - } else { - retval = SCTP_SCOPE_GLOBAL; - } - break; - - case AF_INET6: - { - SCTP_V6( - int v6scope; - v6scope = ipv6_addr_scope((struct in6_addr *) - &addr->v6.sin6_addr); - /* The IPv6 scope is really a set of bit - * fields. See IFA_* in . - * Mapping them to the generic SCTP scope - * set is an attempt to have code - * consistencies with the IPv4 scoping. - */ - switch (v6scope) { - case IFA_HOST: - retval = SCTP_SCOPE_LOOPBACK; - break; - - case IFA_LINK: - retval = SCTP_SCOPE_LINK; - break; - - case IFA_SITE: - retval = SCTP_SCOPE_PRIVATE; - break; - - default: - retval = SCTP_SCOPE_GLOBAL; - break; - }; - ); - break; - } - - default: - retval = SCTP_SCOPE_GLOBAL; - break; - }; - - return retval; -} - -/* This function checks if the address is a valid address to be used for - * SCTP. - * - * Output: - * Return 0 - If the address is a non-unicast or an illegal address. - * Return 1 - If the address is a unicast. - */ -int sctp_addr_is_valid(const union sctp_addr *addr) -{ - unsigned short sa_family = addr->sa.sa_family; - - switch (sa_family) { - case AF_INET: - /* Is this a non-unicast address or a unusable SCTP address? */ - if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) - return 0; - break; - - case AF_INET6: - SCTP_V6( - { - int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); - - /* Is this a non-unicast address */ - if (!(ret & IPV6_ADDR_UNICAST)) - return 0; - break; - }); - - default: - return 0; - }; + af = sctp_get_af_specific(addr->sa.sa_family); + if (!af) + return SCTP_SCOPE_UNUSABLE; - return 1; + return af->scope((union sctp_addr *)addr); } diff --git a/net/sctp/input.c b/net/sctp/input.c index fc699388cf3e..2a97b096ff70 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -132,7 +132,7 @@ int sctp_rcv(struct sk_buff *skb) * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest)) + if (!af->addr_valid(&src) || !af->addr_valid(&dest)) goto discard_it; asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); @@ -172,7 +172,7 @@ int sctp_rcv(struct sk_buff *skb) chunk->sctp_hdr = sh; /* Set the source and destination addresses of the incoming chunk. */ - sctp_init_addrs(chunk); + sctp_init_addrs(chunk, &src, &dest); /* Remember where we came from. */ chunk->transport = transport; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index b24470424218..a3be104983aa 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -181,7 +181,7 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", - __FUNCTION__, NIP6(fl.fl6_dst)); + __FUNCTION__, NIP6(fl.fl6_dst)); if (saddr) { fl.fl6_src = &saddr->v6.sin6_addr; @@ -249,7 +249,7 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, addr->v6.sin6_family = AF_INET6; addr->v6.sin6_flowinfo = 0; /* FIXME */ addr->v6.sin6_scope_id = 0; /* FIXME */ - + sh = (struct sctphdr *) skb->h.raw; if (is_saddr) { *port = ntohs(sh->source); @@ -262,11 +262,60 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, } /* Check if the dst entry's source addr matches the given source addr. */ -int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) +static int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) { struct rt6_info *rt = (struct rt6_info *)dst; - return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr); + return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr); +} + +/* This function checks if the address is a valid address to be used for + * SCTP. + * + * Output: + * Return 0 - If the address is a non-unicast or an illegal address. + * Return 1 - If the address is a unicast. + */ +static int sctp_v6_addr_valid(union sctp_addr *addr) +{ + int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); + + /* FIXME: v4-mapped-v6 address support. */ + + /* Is this a non-unicast address */ + if (!(ret & IPV6_ADDR_UNICAST)) + return 0; + + return 1; +} + +/* What is the scope of 'addr'? */ +static sctp_scope_t sctp_v6_scope(union sctp_addr *addr) +{ + int v6scope; + sctp_scope_t retval; + + /* The IPv6 scope is really a set of bit fields. + * See IFA_* in . Map to a generic SCTP scope. + */ + + v6scope = ipv6_addr_scope(&addr->v6.sin6_addr); + switch (v6scope) { + case IFA_HOST: + retval = SCTP_SCOPE_LOOPBACK; + break; + case IFA_LINK: + retval = SCTP_SCOPE_LINK; + break; + case IFA_SITE: + retval = SCTP_SCOPE_PRIVATE; + break; + default: + retval = SCTP_SCOPE_GLOBAL; + break; + }; + + return retval; } /* Initialize a PF_INET6 socket msg_name. */ @@ -282,7 +331,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len) } /* Initialize a PF_INET msgname from a ulpevent. */ -static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, +static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addrlen) { struct sockaddr_in6 *sin6, *sin6from; @@ -344,6 +393,23 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, } } +/* Do we support this AF? */ +static int sctp_inet6_af_supported(sa_family_t family) +{ + /* FIXME: v4-mapped-v6 addresses. The I-D is still waffling + * on what to do with sockaddr formats for PF_INET6 sockets. + * For now assume we'll support both. + */ + switch (family) { + case AF_INET6: + case AF_INET: + return 1; + default: + return 0; + } +} + + static struct proto_ops inet6_seqpacket_ops = { .family = PF_INET6, .release = inet6_release, @@ -386,6 +452,8 @@ static sctp_func_t sctp_ipv6_specific = { .copy_addrlist = sctp_v6_copy_addrlist, .from_skb = sctp_v6_from_skb, .cmp_saddr = sctp_v6_cmp_saddr, + .scope = sctp_v6_scope, + .addr_valid = sctp_v6_addr_valid, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, @@ -394,6 +462,7 @@ static sctp_func_t sctp_ipv6_specific = { static sctp_pf_t sctp_pf_inet6_specific = { .event_msgname = sctp_inet6_event_msgname, .skb_msgname = sctp_inet6_skb_msgname, + .af_supported = sctp_inet6_af_supported, }; /* Initialize IPv6 support and register with inet6 stack. */ diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 0d967c98befd..65321f6310a3 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -5,42 +5,42 @@ * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll - * + * * This file is part of the SCTP kernel reference Implementation - * - * Initialization/cleanup for SCTP protocol support. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * + * Initialization/cleanup for SCTP protocol support. + * + * 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 - * + * * 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 * Karl Knutson * Jon Grimm * Sridhar Samudrala * Daisy Chang - * + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ @@ -103,7 +103,7 @@ void sctp_proc_exit(void) /* Private helper to extract ipv4 address and stash them in * the protocol structure. */ -static void sctp_v4_copy_addrlist(struct list_head *addrlist, +static void sctp_v4_copy_addrlist(struct list_head *addrlist, struct net_device *dev) { struct in_device *in_dev; @@ -227,10 +227,10 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr, union sctp_addr *saddr) { struct rtable *rt; - struct flowi fl = { - .nl_u = { + struct flowi fl = { + .nl_u = { .ip4_u = { .daddr = - daddr->v4.sin_addr.s_addr, }}, + daddr->v4.sin_addr.s_addr, }}, .proto = IPPROTO_SCTP, }; @@ -280,7 +280,52 @@ int sctp_v4_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) { struct rtable *rt = (struct rtable *)dst; - return (rt->rt_src == saddr->v4.sin_addr.s_addr); + return (rt->rt_src == saddr->v4.sin_addr.s_addr); +} + +/* This function checks if the address is a valid address to be used for + * SCTP. + * + * Output: + * Return 0 - If the address is a non-unicast or an illegal address. + * Return 1 - If the address is a unicast. + */ +static int sctp_v4_addr_valid(union sctp_addr *addr) +{ + /* Is this a non-unicast address or a unusable SCTP address? */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) + return 0; + + return 1; +} + +/* Checking the loopback, private and other address scopes as defined in + * RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4 + * scoping . + */ +static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) +{ + sctp_scope_t retval; + + /* Should IPv4 scoping be a sysctl configurable option + * so users can turn it off (default on) for certain + * unconventional networking environments? + */ + + /* Check for unusable SCTP addresses. */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_UNUSABLE; + } else if (LOOPBACK(addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_LOOPBACK; + } else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_LINK; + } else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_PRIVATE; + } else { + retval = SCTP_SCOPE_GLOBAL; + } + + return retval; } /* Event handler for inet device events. @@ -352,13 +397,13 @@ sctp_func_t *sctp_get_af_specific(sa_family_t family) static void sctp_inet_msgname(char *msgname, int *addr_len) { struct sockaddr_in *sin; - + sin = (struct sockaddr_in *)msgname; *addr_len = sizeof(struct sockaddr_in); sin->sin_family = AF_INET; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); } - + /* Copy the primary address of the peer primary address as the msg_name. */ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addr_len) { @@ -371,26 +416,34 @@ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int * sin->sin_port = htons(event->asoc->peer.port); sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr; } -} +} /* Initialize and copy out a msgname from an inbound skb. */ -static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len) +static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len) { - struct sctphdr *sh; + struct sctphdr *sh; struct sockaddr_in *sin; if (msgname) { - sctp_inet_msgname(msgname, addr_len); + sctp_inet_msgname(msgname, len); sin = (struct sockaddr_in *)msgname; sh = (struct sctphdr *)skb->h.raw; sin->sin_port = sh->source; sin->sin_addr.s_addr = skb->nh.iph->saddr; } -} +} + +/* Do we support this AF? */ +static int sctp_inet_af_supported(sa_family_t family) +{ + /* PF_INET only supports AF_INET addresses. */ + return (AF_INET == family); +} static sctp_pf_t sctp_pf_inet = { .event_msgname = sctp_inet_event_msgname, - .skb_msgname = sctp_inet_skb_msgname, + .skb_msgname = sctp_inet_skb_msgname, + .af_supported = sctp_inet_af_supported, }; @@ -446,6 +499,8 @@ struct sctp_func sctp_ipv4_specific = { .copy_addrlist = sctp_v4_copy_addrlist, .from_skb = sctp_v4_from_skb, .cmp_saddr = sctp_v4_cmp_saddr, + .addr_valid = sctp_v4_addr_valid, + .scope = sctp_v4_scope, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), .sa_family = AF_INET, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 1b0e16b99e87..288f4ec6edb4 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1031,47 +1031,11 @@ nodata: } /* Set chunk->source and dest based on the IP header in chunk->skb. */ -void sctp_init_addrs(sctp_chunk_t *chunk) +void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src, + union sctp_addr *dest) { - union sctp_addr *source, *dest; - struct sk_buff *skb; - struct sctphdr *sh; - struct iphdr *ih4; - struct ipv6hdr *ih6; - - source = &chunk->source; - dest = &chunk->dest; - skb = chunk->skb; - ih4 = skb->nh.iph; - ih6 = skb->nh.ipv6h; - sh = chunk->sctp_hdr; - - switch (ih4->version) { - case 4: - source->v4.sin_family = AF_INET; - source->v4.sin_port = ntohs(sh->source); - source->v4.sin_addr.s_addr = ih4->saddr; - dest->v4.sin_family = AF_INET; - dest->v4.sin_port = ntohs(sh->dest); - dest->v4.sin_addr.s_addr = ih4->daddr; - break; - - case 6: - SCTP_V6( - source->v6.sin6_family = AF_INET6; - source->v6.sin6_port = ntohs(sh->source); - source->v6.sin6_addr = ih6->saddr; - dest->v6.sin6_family = AF_INET6; - dest->v6.sin6_port = ntohs(sh->dest); - dest->v6.sin6_addr = ih6->daddr; - /* FIXME: What do we do with scope, etc. ? */ - break; - ) - - default: - /* This is a bogus address type, just bail. */ - break; - }; + memcpy(&chunk->source, src, sizeof(union sctp_addr)); + memcpy(&chunk->dest, dest, sizeof(union sctp_addr)); } /* Extract the source address from a chunk. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 691909b90aec..52387d93fa32 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2691,38 +2691,33 @@ no_packet: return NULL; } -static inline int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int addrlen) +/* Verify that this is a valid address. */ +static int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int len) { - union sctp_addr *sa; + struct sctp_func *af; - if (addrlen < sizeof (struct sockaddr)) + /* Check minimum size. */ + if (len < sizeof (struct sockaddr)) return -EINVAL; - sa = (union sctp_addr *)addr; - switch (sa->sa.sa_family) { - case AF_INET: - if (addrlen < sizeof(struct sockaddr_in)) - return -EINVAL; - break; - - case AF_INET6: - if (PF_INET == sk->family) - return -EINVAL; - SCTP_V6( - if (addrlen < sizeof(struct sockaddr_in6)) - return -EINVAL; - break; - ); + /* Do we support this address family in general? */ + af = sctp_get_af_specific(addr->sa_family); + if (!af) + return -EINVAL; - default: + /* Does this PF support this AF? */ + if (!sctp_sk(sk)->pf->af_supported(addr->sa_family)) + return -EINVAL; + + /* Verify the minimum for this AF sockaddr. */ + if (len < af->sockaddr_len) return -EINVAL; - }; - /* Disallow any illegal addresses to be used as destinations. */ - if (!sctp_addr_is_valid(sa)) + /* Is this a valid SCTP address? */ + if (!af->addr_valid((union sctp_addr *)addr)) return -EINVAL; - return 0; + return 0; } /* Get the sndbuf space available at the time on the association. */ -- cgit v1.2.3 From 01e85b9f4af02041ac645532fb83e7da0071576e Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Sun, 10 Nov 2002 23:00:06 -0600 Subject: [SCTP]: enable v6 autobinding. This is just more address cleanup really, but the sideeffect is that this enables the autobinding on PF_INET6 sockets. --- include/net/sctp/structs.h | 2 ++ net/sctp/ipv6.c | 10 ++++++++++ net/sctp/protocol.c | 12 ++++++++++++ net/sctp/socket.c | 31 +++++++------------------------ 4 files changed, 31 insertions(+), 24 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index b4f6a1021c6e..a6f1651ad0f1 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -259,6 +259,7 @@ typedef struct sctp_func { int saddr); int (*addr_valid) (union sctp_addr *); sctp_scope_t (*scope) (union sctp_addr *); + void (*inaddr_any) (union sctp_addr *, unsigned short); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; @@ -272,6 +273,7 @@ typedef struct sctp_pf { void (*event_msgname)(sctp_ulpevent_t *, char *, int *); void (*skb_msgname)(struct sk_buff *, char *, int *); int (*af_supported)(sa_family_t); + struct sctp_func *af; } sctp_pf_t; /* SCTP Socket type: UDP or TCP style. */ diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a3be104983aa..d81ea9f589ec 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -269,6 +269,14 @@ static int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr); } +/* Initialize addr struct to INADDR_ANY. */ +void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port) +{ + memset(addr, 0x00, sizeof(union sctp_addr)); + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = port; +} + /* This function checks if the address is a valid address to be used for * SCTP. * @@ -454,6 +462,7 @@ static sctp_func_t sctp_ipv6_specific = { .cmp_saddr = sctp_v6_cmp_saddr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, + .inaddr_any = sctp_v6_inaddr_any, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, @@ -463,6 +472,7 @@ static sctp_pf_t sctp_pf_inet6_specific = { .event_msgname = sctp_inet6_event_msgname, .skb_msgname = sctp_inet6_skb_msgname, .af_supported = sctp_inet6_af_supported, + .af = &sctp_ipv6_specific, }; /* Initialize IPv6 support and register with inet6 stack. */ diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 65321f6310a3..7891dfdff134 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -283,6 +283,14 @@ int sctp_v4_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) return (rt->rt_src == saddr->v4.sin_addr.s_addr); } +/* Initialize addr struct to INADDR_ANY. */ +void sctp_v4_inaddr_any(union sctp_addr *addr, unsigned short port) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_addr.s_addr = INADDR_ANY; + addr->v4.sin_port = port; +} + /* This function checks if the address is a valid address to be used for * SCTP. * @@ -440,10 +448,13 @@ static int sctp_inet_af_supported(sa_family_t family) return (AF_INET == family); } +struct sctp_func sctp_ipv4_specific; + static sctp_pf_t sctp_pf_inet = { .event_msgname = sctp_inet_event_msgname, .skb_msgname = sctp_inet_skb_msgname, .af_supported = sctp_inet_af_supported, + .af = &sctp_ipv4_specific, }; @@ -500,6 +511,7 @@ struct sctp_func sctp_ipv4_specific = { .from_skb = sctp_v4_from_skb, .cmp_saddr = sctp_v4_cmp_saddr, .addr_valid = sctp_v4_addr_valid, + .inaddr_any = sctp_v4_inaddr_any, .scope = sctp_v4_scope, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 52387d93fa32..c3a281403765 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2377,33 +2377,16 @@ void sctp_put_port(struct sock *sk) static int sctp_autobind(struct sock *sk) { union sctp_addr autoaddr; - int addr_len = 0; - - memset(&autoaddr, 0, sizeof(union sctp_addr)); + struct sctp_func *af; + unsigned short port; - switch (sk->family) { - case PF_INET: - autoaddr.v4.sin_family = AF_INET; - autoaddr.v4.sin_addr.s_addr = INADDR_ANY; - autoaddr.v4.sin_port = htons(inet_sk(sk)->num); - addr_len = sizeof(struct sockaddr_in); - break; + /* Initialize a local sockaddr structure to INADDR_ANY. */ + af = sctp_sk(sk)->pf->af; - case PF_INET6: - SCTP_V6( - /* FIXME: Write me for v6! */ - BUG(); - autoaddr.v6.sin6_family = AF_INET6; - autoaddr.v6.sin6_port = htons(inet_sk(sk)->num); - addr_len = sizeof(struct sockaddr_in6); - ); - break; - - default: /* This should not happen. */ - break; - }; + port = htons(inet_sk(sk)->num); + af->inaddr_any(&autoaddr, port); - return sctp_do_bind(sk, &autoaddr, addr_len); + return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); } /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. -- cgit v1.2.3