diff options
| author | Sridhar Samudrala <sridhar@dyn9-47-18-140.beaverton.ibm.com> | 2002-11-10 23:37:00 -0800 |
|---|---|---|
| committer | Sridhar Samudrala <sridhar@dyn9-47-18-140.beaverton.ibm.com> | 2002-11-10 23:37:00 -0800 |
| commit | af18c09381cf2bd0ab8263d086aa2f48cf174b28 (patch) | |
| tree | 75a2e3f93b672b19b580a49121d9893954314b50 | |
| parent | 5be2bc3c89f6813ab0ab21cdd27d6d0f2ee94d91 (diff) | |
| parent | 7851956a217f9c2a5a674f3ccd9b29b60cbeeeaf (diff) | |
Merge dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/linux-2.5.47
into dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/lksctp-2.5.47
| -rw-r--r-- | include/net/sctp/command.h | 3 | ||||
| -rw-r--r-- | include/net/sctp/sctp.h | 81 | ||||
| -rw-r--r-- | include/net/sctp/sm.h | 10 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 209 | ||||
| -rw-r--r-- | net/sctp/associola.c | 45 | ||||
| -rw-r--r-- | net/sctp/bind_addr.c | 147 | ||||
| -rw-r--r-- | net/sctp/endpointola.c | 51 | ||||
| -rw-r--r-- | net/sctp/input.c | 136 | ||||
| -rw-r--r-- | net/sctp/ipv6.c | 151 | ||||
| -rw-r--r-- | net/sctp/output.c | 18 | ||||
| -rw-r--r-- | net/sctp/outqueue.c | 6 | ||||
| -rw-r--r-- | net/sctp/primitive.c | 23 | ||||
| -rw-r--r-- | net/sctp/protocol.c | 217 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 335 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 111 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 165 | ||||
| -rw-r--r-- | net/sctp/sm_statetable.c | 24 | ||||
| -rw-r--r-- | net/sctp/socket.c | 456 | ||||
| -rw-r--r-- | net/sctp/transport.c | 16 |
19 files changed, 1312 insertions, 892 deletions
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index d299eee377c1..b1fba0151675 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -27,6 +27,7 @@ * * La Monte H.P. Yarroll <piggy@acm.org> * Karl Knutson <karl@athena.chicago.il.us> + * Ardelle Fan <ardelle.fan@intel.com> * * 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. */ @@ -83,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/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 9997455f9a74..73c948813e72 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -1,43 +1,43 @@ /* 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 - * - * The base lksctp header. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * + * The base lksctp header. + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers <lksctp-developers@lists.sourceforge.net> - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * La Monte H.P. Yarroll <piggy@acm.org> * Xingang Guo <xingang.guo@intel.com> * Jon Grimm <jgrimm@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com> - * + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ @@ -52,10 +52,10 @@ * structs * prototypes * macros, externs, and inlines - * - * Move test_frame specific items out of the kernel headers + * + * Move test_frame specific items out of the kernel headers * and into the test frame headers. This is not perfect in any sense - * and will continue to evolve. + * and will continue to evolve. */ @@ -78,7 +78,7 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include <net/ipv6.h> #include <net/ip6_route.h> -#endif +#endif #include <asm/uaccess.h> #include <asm/page.h> @@ -105,19 +105,19 @@ #endif -/* Certain internal static functions need to be exported when +/* Certain internal static functions need to be exported when * compiled into the test frame. */ #ifndef SCTP_STATIC #define SCTP_STATIC static #endif -/* - * Function declarations. +/* + * Function declarations. */ /* - * sctp_protocol.c + * sctp_protocol.c */ extern sctp_protocol_t sctp_proto; extern struct sock *sctp_get_ctl_sock(void); @@ -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 @@ -418,6 +418,19 @@ 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((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) + +#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. */ #define WORD_ROUND(s) (((s)+3)&~3) @@ -460,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 80cc12e4ac5c..5082a4a11cb9 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; @@ -206,9 +207,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. */ @@ -334,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 sctpParam_t, 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 9c3979f31d1f..a6f1651ad0f1 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -2,35 +2,35 @@ * 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 - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email addresses: * lksctp developers <lksctp-developers@lists.sourceforge.net> - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * Randall Stewart <randall@sctp.chicago.il.us> * Ken Morneau <kmorneau@cisco.com> * Qiaobing Xie <qxie1@email.mot.com> @@ -41,8 +41,8 @@ * Hui Huang <hui.huang@nokia.com> * Sridhar Samudrala <sri@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com> - * Dajiang Zhang <dajiang.zhang@nokia.com> - * + * Dajiang Zhang <dajiang.zhang@nokia.com> + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ @@ -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,29 +246,41 @@ 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); - __u16 net_header_len; + 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); + 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; 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 { 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. */ 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. */ @@ -339,7 +351,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. @@ -359,20 +371,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 @@ -383,6 +381,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 @@ -392,7 +405,7 @@ typedef union { */ 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)); @@ -433,7 +446,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; @@ -474,13 +487,13 @@ 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? */ - 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 @@ -497,8 +510,8 @@ 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); -const sockaddr_storage_t *sctp_source(const 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. */ /* sin_family -- AF_INET or AF_INET6 @@ -507,7 +520,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 *); @@ -573,7 +586,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 * @@ -601,7 +614,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; @@ -684,13 +697,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. */ @@ -739,11 +754,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 *); @@ -890,30 +905,30 @@ 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 *); -sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, - int *addrs_len, - int priority); +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); int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, int addrs_len, 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? */ 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 @@ -1048,35 +1063,25 @@ 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 **); +int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); 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, sctp_init_chunk_t *peer_init, sctp_chunk_t *chunk, sctp_chunk_t **err_chunk); -int sctp_verify_param(const sctp_association_t *asoc, - sctpParam_t param, - sctp_cid_t cid, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chunk); -int sctp_process_unk_param(const sctp_association_t *asoc, - sctpParam_t param, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chunk); -void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, - 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, - 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 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 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); @@ -1163,10 +1168,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; - + union sctp_addr primary_addr; + /* active_path * The path that we are currently using to * transmit new data and most control chunks. @@ -1267,7 +1272,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; @@ -1313,13 +1318,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; @@ -1543,16 +1548,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); @@ -1560,10 +1565,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 d6d8f9f9c873..b0b061e5ba32 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.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 La Monte H.P. Yarroll * @@ -363,7 +363,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; @@ -423,7 +423,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, @@ -460,6 +460,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. */ @@ -474,7 +477,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; } @@ -487,7 +490,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; @@ -522,12 +525,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; @@ -557,7 +560,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; @@ -577,7 +580,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; @@ -650,7 +653,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; @@ -706,8 +709,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; @@ -842,8 +845,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; @@ -902,17 +905,13 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) * the incoming chunk. If so, get out of the while loop. */ if (!sctp_id2assoc(sk, associd)) - goto out; + break; - if (error != 0) - goto err_out; + /* If there is an error on chunk, discard this packet. */ + if (error && chunk) + chunk->pdiscard = 1; } -err_out: - /* Is this the right way to pass errors up to the ULP? */ - if (error) - sk->err = -error; -out: } /* This routine moves an association from its old sk to a new sk. */ @@ -1017,7 +1016,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/bind_addr.c b/net/sctp/bind_addr.c index 1c70d05e2c33..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. @@ -52,7 +52,7 @@ #include <net/sctp/sm.h> /* 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; @@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) * * The second argument is the return value for the length. */ -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) { - sctpParam_t addrparms; - sctpParam_t retval; + union sctp_params addrparms; + union sctp_params retval; int addrparms_len; sctp_addr_param_t rawaddr; int len; struct sockaddr_storage_list *addr; struct list_head *pos; - - retval.v = NULL; addrparms_len = 0; len = 0; @@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, len += sizeof(sctp_addr_param_t); } - addrparms.v = kmalloc(len, priority); - if (!addrparms.v) + retval.v = kmalloc(len, priority); + if (!retval.v) goto end_raw; - retval = addrparms; + addrparms = retval; list_for_each(pos, &bp->address_list) { addr = list_entry(pos, struct sockaddr_storage_list, list); @@ -244,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; @@ -254,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); @@ -285,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; @@ -300,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(); @@ -326,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; @@ -352,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); @@ -422,112 +420,13 @@ 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 retval = SCTP_SCOPE_GLOBAL; - - 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 <draft-stewart-tsvwg-sctp-ipv4-00.txt>. - * 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 <net/if_inet6.h>. - * 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 sockaddr_storage_t *addr) +sctp_scope_t sctp_scope(const union sctp_addr *addr) { - unsigned short sa_family = addr->sa.sa_family; + struct sctp_func *af; - 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/endpointola.c b/net/sctp/endpointola.c index d3f16f85acb5..c095caf7badd 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.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 @@ -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; @@ -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. */ @@ -316,13 +340,13 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) int error = 0; if (ep->base.dead) - goto out; + return; asoc = NULL; inqueue = &ep->base.inqueue; sk = ep->base.sk; - while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { subtype.chunk = chunk->chunk_hdr->type; /* We might have grown an association since last we @@ -350,25 +374,16 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) if (chunk->transport) chunk->transport->last_time_heard = jiffies; - /* FIX ME We really would rather NOT have to use - * GFP_ATOMIC. - */ error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state, ep, asoc, chunk, GFP_ATOMIC); - if (error != 0) - goto err_out; + if (error && chunk) + chunk->pdiscard = 1; /* Check to see if the endpoint is freed in response to * the incoming chunk. If so, get out of the while loop. */ if (!sctp_sk(sk)->ep) - goto out; + break; } - -err_out: - /* Is this the right way to pass errors up to the ULP? */ - if (error) - ep->base.sk->err = -error; -out: } diff --git a/net/sctp/input.c b/net/sctp/input.c index ede0def64d93..cf9e54b99283 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. @@ -179,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); @@ -219,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; @@ -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; @@ -568,13 +521,13 @@ 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; } /* 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,21 +559,19 @@ 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; - __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 +597,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; @@ -674,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..d81ea9f589ec 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, @@ -181,7 +181,7 @@ struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *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; @@ -206,12 +206,124 @@ 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) +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); +} + +/* 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. + * + * 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 <net/if_inet6.h>. 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. */ @@ -227,12 +339,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; @@ -288,6 +401,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, @@ -327,7 +457,12 @@ 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, + .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, @@ -336,6 +471,8 @@ 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, + .af = &sctp_ipv6_specific, }; /* Initialize IPv6 support and register with inet6 stack. */ diff --git a/net/sctp/output.c b/net/sctp/output.c index 5962d3e72e52..9726bbe04246 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 @@ -434,6 +429,8 @@ int sctp_packet_transmit(sctp_packet_t *packet) } nskb->dst = dst_clone(transport->dst); + if (!nskb->dst) + goto no_route; SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", nskb->len); @@ -441,6 +438,11 @@ int sctp_packet_transmit(sctp_packet_t *packet) out: packet->size = SCTP_IP_OVERHEAD; return err; +no_route: + kfree_skb(nskb); + IP_INC_STATS_BH(IpOutNoRoutes); + err = -EHOSTUNREACH; + goto out; } /******************************************************************** 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 <piggy@acm.org> * Narasimha Budihal <narasimha@refcode.org> * Karl Knutson <karl@athena.chicago.il.us> + * Ardelle Fan <ardelle.fan@intel.com> * * 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/protocol.c b/net/sctp/protocol.c index 5724996717d7..7891dfdff134 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1,46 +1,46 @@ /* 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 - * + * * 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 <lksctp-developers@lists.sourceforge.net> - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * La Monte H.P. Yarroll <piggy@acm.org> * Karl Knutson <karl@athena.chicago.il.us> * Jon Grimm <jgrimm@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com> - * + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ @@ -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,13 +223,16 @@ 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 = - daddr->v4.sin_addr.s_addr, - } } }; + struct flowi fl = { + .nl_u = { + .ip4_u = { .daddr = + daddr->v4.sin_addr.s_addr, }}, + .proto = IPPROTO_SCTP, + }; if (saddr) fl.fl4_src = saddr->v4.sin_addr.s_addr; @@ -285,12 +252,88 @@ 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; - return (rt->rt_src == saddr->v4.sin_addr.s_addr); + 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. + * + * 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 <draft-stewart-tsvwg-sctp-ipv4-00.txt>. + */ +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. @@ -336,11 +379,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 +392,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; } @@ -362,13 +405,13 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) 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) { @@ -381,26 +424,37 @@ 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); +} + +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, + .skb_msgname = sctp_inet_skb_msgname, + .af_supported = sctp_inet_af_supported, + .af = &sctp_ipv4_specific, }; @@ -448,12 +502,17 @@ 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, + .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), .sa_family = AF_INET, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fc0404a5880c..288f4ec6edb4 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1,8 +1,8 @@ /* SCTP kernel reference Implementation * 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 Intel Corp. + * Copyright (c) 2001-2002 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -166,7 +166,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, int priority) { sctp_inithdr_t init; - sctpParam_t addrs; + union sctp_params addrs; size_t chunksize; sctp_chunk_t *retval = NULL; int addrs_len = 0; @@ -228,7 +228,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, { sctp_inithdr_t initack; sctp_chunk_t *retval; - sctpParam_t addrs; + union sctp_params addrs; int addrs_len; sctp_cookie_param_t *cookie; int cookie_len; @@ -1031,51 +1031,15 @@ 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) { - sockaddr_storage_t *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. */ -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) { @@ -1482,78 +1446,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) -{ - sctpParam_t param; - uint8_t *end; - - /* FIXME - Verify the fixed fields of the INIT chunk. Also, verify - * the mandatory parameters somewhere here and generate either the - * "Missing mandatory parameter" error or the "Invalid mandatory - * parameter" error. */ - - /* Find unrecognized parameters. */ - - end = ((uint8_t *)peer_init + ntohs(peer_init->chunk_hdr.length)); - - for (param.v = peer_init->init_hdr.params; - param.v < end; - param.v += WORD_ROUND(ntohs(param.p->length))) { - - if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p)) - return 0; - - } /* for (loop through all parameters) */ - - return 1; -} - - -/* Find unrecognized parameters in the chunk. - * Return values: - * 0 - discard the chunk - * 1 - continue with the chunk +/* 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, - sctpParam_t 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. @@ -1582,10 +1496,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, - sctpParam_t 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; @@ -1604,7 +1518,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; @@ -1620,7 +1534,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 @@ -1638,17 +1552,84 @@ 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) { - sctpParam_t param; - __u8 *end; + 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 union sctp_addr *peer_addr, + sctp_init_chunk_t *peer_init, + int priority) +{ + union sctp_params param; sctp_transport_t *transport; struct list_head *pos, *temp; char *cookie; @@ -1664,15 +1645,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. */ - end = ((__u8 *)peer_init + ntohs(peer_init->chunk_hdr.length)); - for (param.v = peer_init->init_hdr.params; - param.v < end; - param.v += WORD_ROUND(ntohs(param.p->length))) { - if (!sctp_process_param(asoc, param, peer_addr, cid, - priority)) + + sctp_walk_params(param, peer_init, init_hdr.params) { + + if (!sctp_process_param(asoc, param, peer_addr, priority)) goto clean_up; } @@ -1738,7 +1718,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. */ @@ -1747,8 +1727,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 @@ -1760,14 +1743,12 @@ clean_up: * work we do. In particular, we should not build transport * structures for the addresses. */ -int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, - const sockaddr_storage_t *peer_addr, - sctp_cid_t cid, int priority) +int sctp_process_param(sctp_association_t *asoc, union sctp_params param, + const union sctp_addr *peer_addr, int priority) { - sockaddr_storage_t addr; - sctp_addr_param_t *addrparm; - int j; + union sctp_addr addr; int i; + __u16 sat; int retval = 1; sctp_scope_t scope; @@ -1776,30 +1757,21 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t 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: asoc->cookie_preserve = - ntohl(param.bht->lifespan_increment); + ntohl(param.life->lifespan_increment); break; case SCTP_PARAM_HOST_NAME_ADDRESS: @@ -1813,10 +1785,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t 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; @@ -1843,13 +1817,11 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t 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: @@ -1898,8 +1870,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) { @@ -1926,11 +1898,8 @@ 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(sctpParam_t p, sockaddr_storage_t *sa) +int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa) { - if (!p.v) - return 0; - switch (p.p->type) { case SCTP_PARAM_IPV4_ADDRESS: sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); @@ -1950,30 +1919,10 @@ int sctp_addr2sockaddr(sctpParam_t 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. + * 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_sideeffect.c b/net/sctp/sm_sideeffect.c index 81e11238fd1e..69ca9dccc364 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -41,6 +41,7 @@ * Dajiang Zhang <dajiang.zhang@nokia.com> * Daisy Chang <daisyc@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com> + * Ardelle Fan <ardelle.fan@intel.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -68,11 +69,13 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc, sctp_event_t event_type, sctp_chunk_t *chunk); -static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_init_chunk_t *peer_init, - int priority); +static int sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, + sctp_chunk_t *chunk, + 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 *, @@ -83,6 +86,8 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *, sctp_sackhdr_t *); static void sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, sctp_chunk_t *); +static void sctp_cmd_new_state(sctp_cmd_seq_t *, sctp_association_t *, + sctp_state_t); /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real @@ -193,6 +198,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: @@ -301,8 +307,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_NEW_STATE: /* Enter a new state. */ - asoc->state = command->obj.state; - asoc->state_timestamp = jiffies; + sctp_cmd_new_state(commands, asoc, command->obj.state); break; case SCTP_CMD_REPORT_TSN: @@ -339,9 +344,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, break; case SCTP_CMD_PEER_INIT: - /* Process a unified INIT from the peer. */ - sctp_cmd_process_init(commands, asoc, chunk, - command->obj.ptr, priority); + /* Process a unified INIT from the peer. + * Note: Only used during INIT-ACK processing. If + * there is an error just return to the outter + * layer which will bail. + */ + error = sctp_cmd_process_init(commands, asoc, chunk, + command->obj.ptr, + priority); break; case SCTP_CMD_GEN_COOKIE_ECHO: @@ -561,6 +571,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, 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; break; @@ -581,11 +596,18 @@ 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); break; }; + if (error) + return error; } return error; @@ -648,7 +670,7 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, } /* Always try to quiet the other end. In case of lost CWR, - * resend last_cwr_tsn. + * resend last_cwr_tsn. */ repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); @@ -978,7 +1000,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", @@ -1058,22 +1080,32 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, } /* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT - * inside the cookie. + * inside the cookie. In reality, this is only used for INIT-ACK processing + * since all other cases use "temporary" associations and can do all + * their work in statefuns directly. */ -static void sctp_cmd_process_init(sctp_cmd_seq_t *commands, - sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_init_chunk_t *peer_init, - int priority) +static int sctp_cmd_process_init(sctp_cmd_seq_t *commands, + sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_init_chunk_t *peer_init, + int priority) { - /* The command sequence holds commands assuming that the - * processing will happen successfully. If this is not the - * case, rewind the sequence and add appropriate error handling - * to the sequence. + int error; + + /* We only process the init as a sideeffect in a single + * case. This is when we process the INIT-ACK. If we + * fail during INIT processing (due to malloc problems), + * just return the error and stop processing the stack. */ - sctp_process_init(asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, - priority); + + if (!sctp_process_init(asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, + priority)) + error = -ENOMEM; + else + error = 0; + + return error; } /* Helper function to break out starting up of heartbeat timers. */ @@ -1096,6 +1128,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 +1173,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 +1196,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. */ @@ -1196,3 +1234,18 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; chunk->transport = t; } + +/* Helper function to change the state of an association. */ +static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_state_t state) +{ + asoc->state = state; + asoc->state_timestamp = jiffies; + + /* Wake up any process waiting for the association to + * get established. + */ + if ((SCTP_STATE_ESTABLISHED == asoc->state) && + (waitqueue_active(&asoc->wait))) + wake_up_interruptible(&asoc->wait); +} diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e0e39d0d9d1f..4ddd1146bf5a 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -236,20 +236,18 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; /* Tag the variable length parameters. */ - chunk->param_hdr.v = - skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); if (!new_asoc) goto nomem; - /* FIXME: sctp_process_init can fail, but there is no - * status nor handling. - */ - sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), - (sctp_init_chunk_t *)chunk->chunk_hdr, - GFP_ATOMIC); + /* The call, sctp_process_init(), can fail on memory allocation. */ + if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, + GFP_ATOMIC)) + goto nomem_init; sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); @@ -302,10 +300,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, return SCTP_DISPOSITION_DELETE_TCB; nomem_ack: - sctp_association_free(new_asoc); if (err_chunk) sctp_free_chunk(err_chunk); - +nomem_init: + sctp_association_free(new_asoc); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -563,9 +561,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, * effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - sctp_process_init(new_asoc, chunk->chunk_hdr->type, - &chunk->subh.cookie_hdr->c.peer_addr, peer_init, - GFP_ATOMIC); + + if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + &chunk->subh.cookie_hdr->c.peer_addr, + peer_init, GFP_ATOMIC)) + goto nomem_init; repl = sctp_make_cookie_ack(new_asoc, chunk); if (!repl) @@ -592,10 +592,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, nomem_ev: sctp_free_chunk(repl); - nomem_repl: +nomem_init: sctp_association_free(new_asoc); - nomem: return SCTP_DISPOSITION_NOMEM; } @@ -664,6 +663,39 @@ 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; + + /* 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; +} + /* 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; } /* @@ -817,7 +833,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; @@ -866,7 +882,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) { @@ -1125,8 +1141,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( * Verification Tag and Peers Verification tag into a reserved * place (local tie-tag and per tie-tag) within the state cookie. */ - sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_source(chunk), - (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC); + if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, + GFP_ATOMIC)) { + retval = SCTP_DISPOSITION_NOMEM; + goto nomem_init; + } /* Make sure no new addresses are being added during the * restart. Do not do this check for COOKIE-WAIT state, @@ -1197,6 +1218,7 @@ cleanup: nomem: retval = SCTP_DISPOSITION_NOMEM; goto cleanup; +nomem_init: cleanup_asoc: sctp_association_free(new_asoc); goto cleanup; @@ -1326,15 +1348,16 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, GFP_ATOMIC); + + if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, GFP_ATOMIC)) + goto nomem; /* Make sure no new addresses are being added during the * restart. Though this is a pretty complicated attack * since you'd have to get inside the cookie. */ if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { - printk("cookie echo check\n"); return SCTP_DISPOSITION_CONSUME; } @@ -1391,8 +1414,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, GFP_ATOMIC); + if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, GFP_ATOMIC)) + goto nomem; /* Update the content of current association. */ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); @@ -3657,6 +3681,39 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( } /* + * 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 * * The return value is the disposition of the primitive. @@ -4257,7 +4314,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/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 <jgrimm@us.ibm.com> * Hui Huang <hui.huang@nokia.com> * Daisy Chang <daisyc@us.ibm.com> + * Ardelle Fan <ardelle.fan@intel.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * 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..a9bfe566754e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -86,15 +86,16 @@ static void sctp_wfree(struct sk_buff *skb); 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 int sctp_wait_for_connect(sctp_association_t *asoc, 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 *); -static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); + const union sctp_addr *); +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 *, sockaddr_storage_t *, int); +static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_autobind(struct sock *sk); @@ -122,7 +123,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 +136,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 +404,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 +482,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 +501,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 +512,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 +742,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; @@ -777,7 +778,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 +828,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 @@ -1252,6 +1240,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; + union sctp_addr *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 = (union sctp_addr *) &(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 +1391,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; @@ -1354,11 +1408,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; + long timeo; + 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); + goto out_unlock; + } + + timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); + err = sctp_wait_for_connect(asoc, &timeo); + +out_unlock: + sctp_release_sock(sk); + + return err; } /* FIXME: Write comments. */ @@ -1503,28 +1653,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); @@ -1542,8 +1690,8 @@ 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)); - status.sstat_primary.spinfo_state = transport->state.active; + &(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; status.sstat_primary.spinfo_rto = transport->rto; @@ -1551,7 +1699,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 +1708,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 +1829,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 +1856,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; + union sctp_addr *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 = (union sctp_addr *) &(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 +1934,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 +1958,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; } @@ -1880,7 +2074,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 " @@ -2183,34 +2377,17 @@ void sctp_put_port(struct sock *sk) */ static int sctp_autobind(struct sock *sk) { - sockaddr_storage_t autoaddr; - int addr_len = 0; - - memset(&autoaddr, 0, sizeof(sockaddr_storage_t)); - - 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; + union sctp_addr autoaddr; + struct sctp_func *af; + unsigned short port; - 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; + /* Initialize a local sockaddr structure to INADDR_ANY. */ + af = sctp_sk(sk)->pf->af; - 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. @@ -2327,8 +2504,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); @@ -2355,7 +2532,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); @@ -2498,38 +2675,33 @@ no_packet: return NULL; } -static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) +/* Verify that this is a valid address. */ +static int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int len) { - sockaddr_storage_t *sa; + struct sctp_func *af; - if (msg->msg_namelen < sizeof (struct sockaddr)) + /* Check minimum size. */ + if (len < sizeof (struct sockaddr)) return -EINVAL; - sa = (sockaddr_storage_t *) msg->msg_name; - switch (sa->sa.sa_family) { - case AF_INET: - if (msg->msg_namelen < sizeof(struct sockaddr_in)) - return -EINVAL; - break; - - case AF_INET6: - if (PF_INET == sk->family) - return -EINVAL; - SCTP_V6( - if (msg->msg_namelen < 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. */ @@ -2710,6 +2882,70 @@ static int sctp_writeable(struct sock *sk) return amt; } +/* Wait for an association to go into ESTABLISHED state. If timeout is 0, + * returns immediately with EINPROGRESS. + */ +static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p) +{ + struct sock *sk = asoc->base.sk; + int err = 0; + long current_timeo = *timeo_p; + DECLARE_WAITQUEUE(wait, current); + + SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, + (long)(*timeo_p)); + + add_wait_queue_exclusive(&asoc->wait, &wait); + + /* Increment the association's refcnt. */ + sctp_association_hold(asoc); + + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if (!*timeo_p) + goto do_nonblock; + if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + asoc->base.dead) + goto do_error; + if (signal_pending(current)) + goto do_interrupted; + + if (asoc->state == SCTP_STATE_ESTABLISHED) + break; + + /* Let another process have a go. Since we are going + * to sleep anyway. + */ + sctp_release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + sctp_lock_sock(sk); + + *timeo_p = current_timeo; + } + +out: + remove_wait_queue(&asoc->wait, &wait); + + /* Release the association's refcnt. */ + sctp_association_put(asoc); + + __set_current_state(TASK_RUNNING); + + return err; + +do_error: + err = -ECONNABORTED; + goto out; + +do_interrupted: + err = sock_intr_errno(*timeo_p); + goto out; + +do_nonblock: + err = -EINPROGRESS; + goto out; +} + /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", diff --git a/net/sctp/transport.c b/net/sctp/transport.c index eed219643e9d..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: @@ -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; @@ -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; |
