From b6157d8e03e1e780660a328f7183bcbfa4a93a19 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 24 Oct 2007 15:59:16 -0400 Subject: SCTP: Fix difference cases of retransmit. Commit d0ce92910bc04e107b2f3f2048f07e94f570035d broke several retransmit cases including fast retransmit. The reason is that we should only delay by rto while doing retranmists as a result of a timeout. Retransmit as a result of path mtu discover, fast retransmit, or other evernts that should trigger immidiate retransmissions got broken. Also, since rto is doubled prior to marking of packets elegable for retransmission, we never marked correct chunks anyway. The fix is provide a reason for a given retransmission so that we can mark chunks appropriately and to save the old rto value to do comparisons against. All regressions tests passed with this code. Spotted by Wei Yongjun Signed-off-by: Vlad Yasevich --- include/net/sctp/command.h | 1 + include/net/sctp/constants.h | 1 + include/net/sctp/sctp.h | 1 + include/net/sctp/structs.h | 5 +++-- 4 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index b8733364557f..c1f797673571 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -103,6 +103,7 @@ typedef enum { SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */ SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */ SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ + SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ SCTP_CMD_LAST } sctp_verb_t; diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index da8354e8e33c..73fbdf6a24f8 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -407,6 +407,7 @@ typedef enum { SCTP_RTXR_T3_RTX, SCTP_RTXR_FAST_RTX, SCTP_RTXR_PMTUD, + SCTP_RTXR_T1_RTX, } sctp_retransmit_reason_t; /* Reasons to lower cwnd. */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 93eb708609e7..70827305f501 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -267,6 +267,7 @@ enum SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS, SCTP_MIB_DELAY_SACK_EXPIREDS, SCTP_MIB_AUTOCLOSE_EXPIREDS, + SCTP_MIB_T1_RETRANSMITS, SCTP_MIB_T3_RETRANSMITS, SCTP_MIB_PMTUD_RETRANSMITS, SCTP_MIB_FAST_RETRANSMITS, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ef892e00c833..482c2aab3d67 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -873,10 +873,11 @@ struct sctp_transport { * address list derived from the INIT or INIT ACK chunk, a * number of data elements needs to be maintained including: */ - __u32 rtt; /* This is the most recent RTT. */ - /* RTO : The current retransmission timeout value. */ unsigned long rto; + unsigned long last_rto; + + __u32 rtt; /* This is the most recent RTT. */ /* RTTVAR : The current RTT variation. */ __u32 rttvar; -- cgit v1.2.3 From 0ed90fb0f668fd07f14ae2007a809e8b26cd27a6 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 24 Oct 2007 16:10:00 -0400 Subject: SCTP: Update RCU handling during the ADD-IP case After learning more about rcu, it looks like the ADD-IP hadling doesn't need to call call_rcu_bh. All the rcu critical sections use rcu_read_lock, so using call_rcu_bh is wrong here. Now, restore the local_bh_disable() code blocks and use normal call_rcu() calls. Also restore the missing return statement. Signed-off-by: Vlad Yasevich --- include/net/sctp/structs.h | 4 +--- net/sctp/bind_addr.c | 13 +++---------- net/sctp/sm_make_chunk.c | 6 +++++- net/sctp/socket.c | 2 +- 4 files changed, 10 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 482c2aab3d67..a17701740624 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1185,9 +1185,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, int flags); int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, __u8 use_as_src, gfp_t gfp); -int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *, - void fastcall (*rcu_call)(struct rcu_head *, - void (*func)(struct rcu_head *))); +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, struct sctp_sock *); union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index dfffa94fb9f6..cae95af9a8cc 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -180,9 +180,7 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, /* Delete an address from the bind address list in the SCTP_bind_addr * structure. */ -int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr, - void fastcall (*rcu_call)(struct rcu_head *head, - void (*func)(struct rcu_head *head))) +int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) { struct sctp_sockaddr_entry *addr, *temp; @@ -198,15 +196,10 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr, } } - /* Call the rcu callback provided in the args. This function is - * called by both BH packet processing and user side socket option - * processing, but it works on different lists in those 2 contexts. - * Each context provides it's own callback, whether call_rcu_bh() - * or call_rcu(), to make sure that we wait for an appropriate time. - */ if (addr && !addr->valid) { - rcu_call(&addr->rcu, sctp_local_addr_free); + call_rcu(&addr->rcu, sctp_local_addr_free); SCTP_DBG_OBJCNT_DEC(addr); + return 0; } return -EINVAL; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 5de4729fe993..c60564dd169d 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2953,13 +2953,17 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, /* This is always done in BH context with a socket lock * held, so the list can not change. */ + local_bh_disable(); list_for_each_entry(saddr, &bp->address_list, list) { if (sctp_cmp_addr_exact(&saddr->a, &addr)) saddr->use_as_src = 1; } + local_bh_enable(); break; case SCTP_PARAM_DEL_IP: - retval = sctp_del_bind_addr(bp, &addr, call_rcu_bh); + local_bh_disable(); + retval = sctp_del_bind_addr(bp, &addr); + local_bh_enable(); list_for_each(pos, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a7ecf3159e53..6ce9b490fad5 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -660,7 +660,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) * socket routing and failover schemes. Refer to comments in * sctp_do_bind(). -daisy */ - retval = sctp_del_bind_addr(bp, sa_addr, call_rcu); + retval = sctp_del_bind_addr(bp, sa_addr); addr_buf += af->sockaddr_len; err_bindx_rem: -- cgit v1.2.3 From 88799fe5ec65fad1d5cb1d4dc5d8f78edb949f1c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 24 Oct 2007 17:24:23 -0400 Subject: SCTP: Correctly disable ADD-IP when AUTH is not supported. Signed-off-by: Vlad Yasevich --- include/net/sctp/structs.h | 1 - net/sctp/associola.c | 2 +- net/sctp/sm_make_chunk.c | 5 +++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index a17701740624..41f1039186dd 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1540,7 +1540,6 @@ struct sctp_association { __u8 asconf_capable; /* Does peer support ADDIP? */ __u8 prsctp_capable; /* Can peer do PR-SCTP? */ __u8 auth_capable; /* Is peer doing SCTP-AUTH? */ - __u8 addip_capable; /* Can peer do ADD-IP */ __u32 adaptation_ind; /* Adaptation Code point. */ diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 03158e3665da..eaad5c5535a8 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -265,7 +265,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Assume that the peer recongizes ASCONF until reported otherwise * via an ERROR chunk. */ - asoc->peer.asconf_capable = 1; + asoc->peer.asconf_capable = 0; /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index c60564dd169d..2ff3a3df049d 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1847,7 +1847,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc, break; case SCTP_CID_ASCONF: case SCTP_CID_ASCONF_ACK: - asoc->peer.addip_capable = 1; + asoc->peer.asconf_capable = 1; break; default: break; @@ -2138,10 +2138,11 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, /* If the peer claims support for ADD-IP without support * for AUTH, disable support for ADD-IP. */ - if (asoc->peer.addip_capable && !asoc->peer.auth_capable) { + if (asoc->peer.asconf_capable && !asoc->peer.auth_capable) { asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP | SCTP_PARAM_DEL_IP | SCTP_PARAM_SET_PRIMARY); + asoc->peer.asconf_capable = 0; } /* Walk list of transports, removing transports in the UNKNOWN state. */ -- cgit v1.2.3 From 73d9c4fd1a6ec4950b2eac8135d35506bf400d6c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 24 Oct 2007 17:24:26 -0400 Subject: SCTP: Allow ADD_IP to work with AUTH for backward compatibility. This patch adds a tunable that will allow ADD_IP to work without AUTH for backward compatibility. The default value is off since the default value for ADD_IP is off as well. People who need to use ADD-IP with older implementations take risks of connection hijacking and should consider upgrading or turning this tunable on. Signed-off-by: Vlad Yasevich --- include/net/sctp/structs.h | 2 ++ net/sctp/associola.c | 8 ++++++-- net/sctp/protocol.c | 1 + net/sctp/sm_make_chunk.c | 4 +++- net/sctp/sysctl.c | 9 +++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 41f1039186dd..44f2672859e2 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -212,6 +212,7 @@ extern struct sctp_globals { /* Flag to indicate if addip is enabled. */ int addip_enable; + int addip_noauth_enable; /* Flag to indicate if PR-SCTP is enabled. */ int prsctp_enable; @@ -249,6 +250,7 @@ extern struct sctp_globals { #define sctp_local_addr_list (sctp_globals.local_addr_list) #define sctp_local_addr_lock (sctp_globals.addr_list_lock) #define sctp_addip_enable (sctp_globals.addip_enable) +#define sctp_addip_noauth (sctp_globals.addip_noauth_enable) #define sctp_prsctp_enable (sctp_globals.prsctp_enable) #define sctp_auth_enable (sctp_globals.auth_enable) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index eaad5c5535a8..013e3d3ab0f1 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -262,10 +262,14 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a */ asoc->peer.sack_needed = 1; - /* Assume that the peer recongizes ASCONF until reported otherwise - * via an ERROR chunk. + /* Assume that the peer will tell us if he recognizes ASCONF + * as part of INIT exchange. + * The sctp_addip_noauth option is there for backward compatibilty + * and will revert old behavior. */ asoc->peer.asconf_capable = 0; + if (sctp_addip_noauth) + asoc->peer.asconf_capable = 1; /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 40c1a47d1b8d..ecfab0344e73 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1179,6 +1179,7 @@ SCTP_STATIC __init int sctp_init(void) /* Disable ADDIP by default. */ sctp_addip_enable = 0; + sctp_addip_noauth = 0; /* Enable PR-SCTP by default. */ sctp_prsctp_enable = 1; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 2ff3a3df049d..43e8de1228f9 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2137,8 +2137,10 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, /* If the peer claims support for ADD-IP without support * for AUTH, disable support for ADD-IP. + * Do this only if backward compatible mode is turned off. */ - if (asoc->peer.asconf_capable && !asoc->peer.auth_capable) { + if (!sctp_addip_noauth && + (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) { asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP | SCTP_PARAM_DEL_IP | SCTP_PARAM_SET_PRIMARY); diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 0669778e4335..da4f15734fb1 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -263,6 +263,15 @@ static ctl_table sctp_table[] = { .proc_handler = &proc_dointvec, .strategy = &sysctl_intvec }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "addip_noauth_enable", + .data = &sctp_addip_noauth, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, { .ctl_name = 0 } }; -- cgit v1.2.3 From d970dbf8455eb1b8cebd3cde6e18f73dd1b3ce38 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 9 Nov 2007 11:43:40 -0500 Subject: SCTP: Convert custom hash lists to use hlist. Convert the custom hash list traversals to use hlist functions. Signed-off-by: Vlad Yasevich --- include/net/sctp/sctp.h | 3 +++ include/net/sctp/structs.h | 10 ++++------ net/sctp/endpointola.c | 3 ++- net/sctp/input.c | 43 +++++++++++-------------------------------- net/sctp/proc.c | 6 ++++-- net/sctp/protocol.c | 6 +++--- net/sctp/socket.c | 14 +++++--------- 7 files changed, 32 insertions(+), 53 deletions(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 70827305f501..67c997cecf58 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -665,6 +665,9 @@ static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) return (h & (sctp_assoc_hashsize-1)); } +#define sctp_for_each_hentry(epb, node, head) \ + hlist_for_each_entry(epb, node, head, node) + /* Is a socket of this style? */ #define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) static inline int __sctp_style(const struct sock *sk, sctp_socket_type_t style) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 44f2672859e2..eb3113c38a94 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -100,20 +100,19 @@ struct crypto_hash; struct sctp_bind_bucket { unsigned short port; unsigned short fastreuse; - struct sctp_bind_bucket *next; - struct sctp_bind_bucket **pprev; + struct hlist_node node; struct hlist_head owner; }; struct sctp_bind_hashbucket { spinlock_t lock; - struct sctp_bind_bucket *chain; + struct hlist_head chain; }; /* Used for hashing all associations. */ struct sctp_hashbucket { rwlock_t lock; - struct sctp_ep_common *chain; + struct hlist_head chain; } __attribute__((__aligned__(8))); @@ -1230,8 +1229,7 @@ typedef enum { struct sctp_ep_common { /* Fields to help us manage our entries in the hash tables. */ - struct sctp_ep_common *next; - struct sctp_ep_common **pprev; + struct hlist_node node; int hashent; /* Runtime type information. What kind of endpoint is this? */ diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 68f0556efcc6..de6f505d6ff8 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -332,6 +332,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( struct sctp_transport *t = NULL; struct sctp_hashbucket *head; struct sctp_ep_common *epb; + struct hlist_node *node; int hash; int rport; @@ -341,7 +342,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( hash = sctp_assoc_hashfn(ep->base.bind_addr.port, rport); head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); - for (epb = head->chain; epb; epb = epb->next) { + sctp_for_each_hentry(epb, node, &head->chain) { asoc = sctp_assoc(epb); if (asoc->ep != ep || rport != asoc->peer.port) goto next; diff --git a/net/sctp/input.c b/net/sctp/input.c index 86503e7fa21e..91ae463b079b 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -656,7 +656,6 @@ discard: /* Insert endpoint into the hash table. */ static void __sctp_hash_endpoint(struct sctp_endpoint *ep) { - struct sctp_ep_common **epp; struct sctp_ep_common *epb; struct sctp_hashbucket *head; @@ -666,12 +665,7 @@ static void __sctp_hash_endpoint(struct sctp_endpoint *ep) head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); - epp = &head->chain; - epb->next = *epp; - if (epb->next) - (*epp)->pprev = &epb->next; - *epp = epb; - epb->pprev = epp; + hlist_add_head(&epb->node, &head->chain); sctp_write_unlock(&head->lock); } @@ -691,19 +685,15 @@ static void __sctp_unhash_endpoint(struct sctp_endpoint *ep) epb = &ep->base; + if (hlist_unhashed(&epb->node)) + return; + epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); - - if (epb->pprev) { - if (epb->next) - epb->next->pprev = epb->pprev; - *epb->pprev = epb->next; - epb->pprev = NULL; - } - + __hlist_del(&epb->node); sctp_write_unlock(&head->lock); } @@ -721,12 +711,13 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l struct sctp_hashbucket *head; struct sctp_ep_common *epb; struct sctp_endpoint *ep; + struct hlist_node *node; int hash; hash = sctp_ep_hashfn(ntohs(laddr->v4.sin_port)); head = &sctp_ep_hashtable[hash]; read_lock(&head->lock); - for (epb = head->chain; epb; epb = epb->next) { + sctp_for_each_hentry(epb, node, &head->chain) { ep = sctp_ep(epb); if (sctp_endpoint_is_match(ep, laddr)) goto hit; @@ -744,7 +735,6 @@ hit: /* Insert association into the hash table. */ static void __sctp_hash_established(struct sctp_association *asoc) { - struct sctp_ep_common **epp; struct sctp_ep_common *epb; struct sctp_hashbucket *head; @@ -756,12 +746,7 @@ static void __sctp_hash_established(struct sctp_association *asoc) head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); - epp = &head->chain; - epb->next = *epp; - if (epb->next) - (*epp)->pprev = &epb->next; - *epp = epb; - epb->pprev = epp; + hlist_add_head(&epb->node, &head->chain); sctp_write_unlock(&head->lock); } @@ -790,14 +775,7 @@ static void __sctp_unhash_established(struct sctp_association *asoc) head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); - - if (epb->pprev) { - if (epb->next) - epb->next->pprev = epb->pprev; - *epb->pprev = epb->next; - epb->pprev = NULL; - } - + __hlist_del(&epb->node); sctp_write_unlock(&head->lock); } @@ -822,6 +800,7 @@ static struct sctp_association *__sctp_lookup_association( struct sctp_ep_common *epb; struct sctp_association *asoc; struct sctp_transport *transport; + struct hlist_node *node; int hash; /* Optimize here for direct hit, only listening connections can @@ -830,7 +809,7 @@ static struct sctp_association *__sctp_lookup_association( hash = sctp_assoc_hashfn(ntohs(local->v4.sin_port), ntohs(peer->v4.sin_port)); head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); - for (epb = head->chain; epb; epb = epb->next) { + sctp_for_each_hentry(epb, node, &head->chain) { asoc = sctp_assoc(epb); transport = sctp_assoc_is_match(asoc, local, peer); if (transport) diff --git a/net/sctp/proc.c b/net/sctp/proc.c index e4cd841a22e4..249973204070 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -225,6 +225,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) struct sctp_ep_common *epb; struct sctp_endpoint *ep; struct sock *sk; + struct hlist_node *node; int hash = *(loff_t *)v; if (hash >= sctp_ep_hashsize) @@ -233,7 +234,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) head = &sctp_ep_hashtable[hash]; sctp_local_bh_disable(); read_lock(&head->lock); - for (epb = head->chain; epb; epb = epb->next) { + sctp_for_each_hentry(epb, node, &head->chain) { ep = sctp_ep(epb); sk = epb->sk; seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk, @@ -328,6 +329,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) struct sctp_ep_common *epb; struct sctp_association *assoc; struct sock *sk; + struct hlist_node *node; int hash = *(loff_t *)v; if (hash >= sctp_assoc_hashsize) @@ -336,7 +338,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) head = &sctp_assoc_hashtable[hash]; sctp_local_bh_disable(); read_lock(&head->lock); - for (epb = head->chain; epb; epb = epb->next) { + sctp_for_each_hentry(epb, node, &head->chain) { assoc = sctp_assoc(epb); sk = epb->sk; seq_printf(seq, diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index ecfab0344e73..d50f610d1b02 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1137,7 +1137,7 @@ SCTP_STATIC __init int sctp_init(void) } for (i = 0; i < sctp_assoc_hashsize; i++) { rwlock_init(&sctp_assoc_hashtable[i].lock); - sctp_assoc_hashtable[i].chain = NULL; + INIT_HLIST_HEAD(&sctp_assoc_hashtable[i].chain); } /* Allocate and initialize the endpoint hash table. */ @@ -1151,7 +1151,7 @@ SCTP_STATIC __init int sctp_init(void) } for (i = 0; i < sctp_ep_hashsize; i++) { rwlock_init(&sctp_ep_hashtable[i].lock); - sctp_ep_hashtable[i].chain = NULL; + INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain); } /* Allocate and initialize the SCTP port hash table. */ @@ -1170,7 +1170,7 @@ SCTP_STATIC __init int sctp_init(void) } for (i = 0; i < sctp_port_hashsize; i++) { spin_lock_init(&sctp_port_hashtable[i].lock); - sctp_port_hashtable[i].chain = NULL; + INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); } printk(KERN_INFO "SCTP: Hash tables configured " diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6ce9b490fad5..ff8bc95670ed 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5307,6 +5307,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) { struct sctp_bind_hashbucket *head; /* hash list */ struct sctp_bind_bucket *pp; /* hash list port iterator */ + struct hlist_node *node; unsigned short snum; int ret; @@ -5331,7 +5332,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) index = sctp_phashfn(rover); head = &sctp_port_hashtable[index]; sctp_spin_lock(&head->lock); - for (pp = head->chain; pp; pp = pp->next) + sctp_for_each_hentry(pp, node, &head->chain) if (pp->port == rover) goto next; break; @@ -5358,7 +5359,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) */ head = &sctp_port_hashtable[sctp_phashfn(snum)]; sctp_spin_lock(&head->lock); - for (pp = head->chain; pp; pp = pp->next) { + sctp_for_each_hentry(pp, node, &head->chain) { if (pp->port == snum) goto pp_found; } @@ -5702,10 +5703,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( pp->port = snum; pp->fastreuse = 0; INIT_HLIST_HEAD(&pp->owner); - if ((pp->next = head->chain) != NULL) - pp->next->pprev = &pp->next; - head->chain = pp; - pp->pprev = &head->chain; + hlist_add_head(&pp->node, &head->chain); } return pp; } @@ -5714,9 +5712,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) { if (pp && hlist_empty(&pp->owner)) { - if (pp->next) - pp->next->pprev = pp->pprev; - *(pp->pprev) = pp->next; + __hlist_del(&pp->node); kmem_cache_free(sctp_bucket_cachep, pp); SCTP_DBG_OBJCNT_DEC(bind_bucket); } -- cgit v1.2.3 From 7ab9080467040054e27ae54d67cc185f24d881ae Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 9 Nov 2007 11:43:41 -0500 Subject: SCTP: Make sctp_verify_param return multiple indications. SCTP-AUTH and future ADD-IP updates have a requirement to do additional verification of parameters and an ability to ABORT the association if verification fails. So, introduce additional return code so that we can clear signal a required action. Signed-off-by: Vlad Yasevich --- include/net/sctp/constants.h | 2 + net/sctp/sm_make_chunk.c | 149 ++++++++++++++++++++++--------------------- 2 files changed, 77 insertions(+), 74 deletions(-) (limited to 'include') diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 73fbdf6a24f8..f30b537d6952 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -186,6 +186,8 @@ typedef enum { SCTP_IERROR_AUTH_BAD_HMAC, SCTP_IERROR_AUTH_BAD_KEYID, SCTP_IERROR_PROTO_VIOLATION, + SCTP_IERROR_ERROR, + SCTP_IERROR_ABORT, } sctp_ierror_t; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 43e8de1228f9..5a9783c38de1 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1788,9 +1788,14 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, sizeof(sctp_paramhdr_t); + /* This is a fatal error. Any accumulated non-fatal errors are + * not reported. + */ + if (*errp) + sctp_chunk_free(*errp); + /* Create an error chunk and fill it in with our payload. */ - if (!*errp) - *errp = sctp_make_op_error_space(asoc, chunk, payload_len); + *errp = sctp_make_op_error_space(asoc, chunk, payload_len); if (*errp) { sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, @@ -1813,9 +1818,15 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, { __u16 len = ntohs(param.p->length); - /* Make an ERROR chunk. */ - if (!*errp) - *errp = sctp_make_op_error_space(asoc, chunk, len); + /* Processing of the HOST_NAME parameter will generate an + * ABORT. If we've accumulated any non-fatal errors, they + * would be unrecognized parameters and we should not include + * them in the ABORT. + */ + if (*errp) + sctp_chunk_free(*errp); + + *errp = sctp_make_op_error_space(asoc, chunk, len); if (*errp) { sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); @@ -1862,56 +1873,40 @@ static void sctp_process_ext_param(struct sctp_association *asoc, * taken if the processing endpoint does not recognize the * Parameter Type. * - * 00 - Stop processing this SCTP chunk and discard it, - * do not process any further chunks within it. + * 00 - Stop processing this parameter; do not process any further + * parameters within this chunk * - * 01 - Stop processing this SCTP chunk and discard it, - * do not process any further chunks within it, and report - * the unrecognized parameter in an 'Unrecognized - * Parameter Type' (in either an ERROR or in the INIT ACK). + * 01 - Stop processing this parameter, do not process any further + * parameters within this chunk, and report the unrecognized + * parameter in an 'Unrecognized Parameter' ERROR chunk. * * 10 - Skip this parameter and continue processing. * * 11 - Skip this parameter and continue processing but * report the unrecognized parameter in an - * 'Unrecognized Parameter Type' (in either an ERROR or in - * the INIT ACK). + * 'Unrecognized Parameter' ERROR chunk. * * Return value: - * 0 - discard the chunk - * 1 - continue with the chunk + * SCTP_IERROR_NO_ERROR - continue with the chunk + * SCTP_IERROR_ERROR - stop and report an error. + * SCTP_IERROR_NOMEME - out of memory. */ -static int sctp_process_unk_param(const struct sctp_association *asoc, - union sctp_params param, - struct sctp_chunk *chunk, - struct sctp_chunk **errp) +static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc, + union sctp_params param, + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { - int retval = 1; + int retval = SCTP_IERROR_NO_ERROR; switch (param.p->type & SCTP_PARAM_ACTION_MASK) { case SCTP_PARAM_ACTION_DISCARD: - retval = 0; - break; - case SCTP_PARAM_ACTION_DISCARD_ERR: - retval = 0; - /* Make an ERROR chunk, preparing enough room for - * returning multiple unknown parameters. - */ - if (NULL == *errp) - *errp = sctp_make_op_error_space(asoc, chunk, - ntohs(chunk->chunk_hdr->length)); - - if (*errp) { - sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, - WORD_ROUND(ntohs(param.p->length))); - sctp_addto_chunk(*errp, - WORD_ROUND(ntohs(param.p->length)), - param.v); - } - + retval = SCTP_IERROR_ERROR; break; case SCTP_PARAM_ACTION_SKIP: break; + case SCTP_PARAM_ACTION_DISCARD_ERR: + retval = SCTP_IERROR_ERROR; + /* Fall through */ case SCTP_PARAM_ACTION_SKIP_ERR: /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. @@ -1932,9 +1927,8 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, * to the peer and the association won't be * established. */ - retval = 0; + retval = SCTP_IERROR_NOMEM; } - break; default: break; @@ -1943,18 +1937,20 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, return retval; } -/* Find unrecognized parameters in the chunk. +/* Verify variable length parameters * Return values: - * 0 - discard the chunk - * 1 - continue with the chunk + * SCTP_IERROR_ABORT - trigger an ABORT + * SCTP_IERROR_NOMEM - out of memory (abort) + * SCTP_IERROR_ERROR - stop processing, trigger an ERROR + * SCTP_IERROR_NO_ERROR - continue with the chunk */ -static int sctp_verify_param(const struct sctp_association *asoc, - union sctp_params param, - sctp_cid_t cid, - struct sctp_chunk *chunk, - struct sctp_chunk **err_chunk) +static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc, + union sctp_params param, + sctp_cid_t cid, + struct sctp_chunk *chunk, + struct sctp_chunk **err_chunk) { - int retval = 1; + int retval = SCTP_IERROR_NO_ERROR; /* FIXME - This routine is not looking at each parameter per the * chunk type, i.e., unrecognized parameters should be further @@ -1976,7 +1972,9 @@ static int sctp_verify_param(const struct sctp_association *asoc, 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); + sctp_process_hn_param(asoc, param, chunk, err_chunk); + retval = SCTP_IERROR_ABORT; + break; case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) @@ -1993,9 +1991,11 @@ static int sctp_verify_param(const struct sctp_association *asoc, * cause 'Protocol Violation'. */ if (SCTP_AUTH_RANDOM_LENGTH != - ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) - return sctp_process_inv_paramlength(asoc, param.p, + ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) { + sctp_process_inv_paramlength(asoc, param.p, chunk, err_chunk); + retval = SCTP_IERROR_ABORT; + } break; case SCTP_PARAM_CHUNKS: @@ -2007,9 +2007,11 @@ static int sctp_verify_param(const struct sctp_association *asoc, * INIT-ACK chunk if the sender wants to receive authenticated * chunks. Its maximum length is 260 bytes. */ - if (260 < ntohs(param.p->length)) - return sctp_process_inv_paramlength(asoc, param.p, - chunk, err_chunk); + if (260 < ntohs(param.p->length)) { + sctp_process_inv_paramlength(asoc, param.p, + chunk, err_chunk); + retval = SCTP_IERROR_ABORT; + } break; case SCTP_PARAM_HMAC_ALGO: @@ -2020,8 +2022,7 @@ fallthrough: 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); - + retval = sctp_process_unk_param(asoc, param, chunk, err_chunk); break; } return retval; @@ -2036,6 +2037,7 @@ int sctp_verify_init(const struct sctp_association *asoc, { union sctp_params param; int has_cookie = 0; + int result; /* Verify stream values are non-zero. */ if ((0 == peer_init->init_hdr.num_outbound_streams) || @@ -2043,8 +2045,7 @@ int sctp_verify_init(const struct sctp_association *asoc, (0 == peer_init->init_hdr.init_tag) || (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) { - sctp_process_inv_mandatory(asoc, chunk, errp); - return 0; + return sctp_process_inv_mandatory(asoc, chunk, errp); } /* Check for missing mandatory parameters. */ @@ -2062,29 +2063,29 @@ int sctp_verify_init(const struct sctp_association *asoc, * VIOLATION error. We build the ERROR chunk here and let the normal * error handling code build and send the packet. */ - if (param.v != (void*)chunk->chunk_end) { - sctp_process_inv_paramlength(asoc, param.p, chunk, errp); - return 0; - } + if (param.v != (void*)chunk->chunk_end) + return sctp_process_inv_paramlength(asoc, param.p, chunk, errp); /* The only missing mandatory param possible today is * the state cookie for an INIT-ACK chunk. */ - if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { - sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, - chunk, errp); - return 0; - } - - /* Find unrecognized parameters. */ + if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) + return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, + chunk, errp); + /* Verify all the variable length parameters */ sctp_walk_params(param, peer_init, init_hdr.params) { - if (!sctp_verify_param(asoc, param, cid, chunk, errp)) { - if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type) + result = sctp_verify_param(asoc, param, cid, chunk, errp); + switch (result) { + case SCTP_IERROR_ABORT: + case SCTP_IERROR_NOMEM: return 0; - else + case SCTP_IERROR_ERROR: return 1; + case SCTP_IERROR_NO_ERROR: + default: + break; } } /* for (loop through all parameters) */ -- cgit v1.2.3 From fa7ff654e14ccacd4e758c9878ff4884f816c877 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 9 Nov 2007 11:43:41 -0500 Subject: SCTP: Clean-up some defines for regressions tests. Signed-off-by: Vlad Yasevich --- include/net/sctp/sctp.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 67c997cecf58..34318a33a94c 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -65,7 +65,6 @@ #ifdef TEST_FRAME -#undef CONFIG_PROC_FS #undef CONFIG_SCTP_DBG_OBJCNT #undef CONFIG_SYSCTL #endif /* TEST_FRAME */ -- cgit v1.2.3