diff options
-rw-r--r-- | include/net/sctp/sctp.h | 10 | ||||
-rw-r--r-- | net/sctp/input.c | 2 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 2 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 6 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 103 | ||||
-rw-r--r-- | net/sctp/socket.c | 45 | ||||
-rw-r--r-- | net/sctp/tsnmap.c | 14 |
7 files changed, 123 insertions, 59 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 16baef4dab7..d529045c167 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -190,6 +190,16 @@ void sctp_assocs_proc_exit(void); /* + * Module global variables + */ + + /* + * sctp/protocol.c + */ +extern struct kmem_cache *sctp_chunk_cachep __read_mostly; +extern struct kmem_cache *sctp_bucket_cachep __read_mostly; + +/* * Section: Macros, externs, and inlines */ diff --git a/net/sctp/input.c b/net/sctp/input.c index d57ff7f3c57..47e56017f4c 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -590,7 +590,7 @@ out_unlock: * Return 0 - If further processing is needed. * Return 1 - If the packet can be discarded right away. */ -int sctp_rcv_ootb(struct sk_buff *skb) +static int sctp_rcv_ootb(struct sk_buff *skb) { sctp_chunkhdr_t *ch; __u8 *ch_end; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 2c29394fd92..f8aa23dda1c 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -641,6 +641,8 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, newsctp6sk = (struct sctp6_sock *)newsk; inet_sk(newsk)->pinet6 = &newsctp6sk->inet6; + sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped; + newinet = inet_sk(newsk); newnp = inet6_sk(newsk); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 8d18f570c2e..51c4d7fef1d 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -65,8 +65,6 @@ #include <net/sctp/sctp.h> #include <net/sctp/sm.h> -extern struct kmem_cache *sctp_chunk_cachep; - SCTP_STATIC struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, __u8 type, __u8 flags, int paylen); @@ -115,15 +113,12 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, const void *payload, size_t paylen) { sctp_errhdr_t err; - int padlen; __u16 len; /* Cause code constants are now defined in network order. */ err.cause = cause_code; len = sizeof(sctp_errhdr_t) + paylen; - padlen = len % 4; err.length = htons(len); - len += padlen; chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); sctp_addto_chunk(chunk, paylen, payload); } @@ -1454,7 +1449,6 @@ no_hmac: do_gettimeofday(&tv); if (!asoc && tv_lt(bear_cookie->expiration, tv)) { - __u16 len; /* * Section 3.3.10.3 Stale Cookie Error (3) * diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index fd2dfdd7d7f..71cad56dd73 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -97,6 +97,13 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, const struct sctp_association *asoc, struct sctp_transport *transport); +static sctp_disposition_t sctp_sf_abort_violation( + const struct sctp_association *asoc, + void *arg, + sctp_cmd_seq_t *commands, + const __u8 *payload, + const size_t paylen); + static sctp_disposition_t sctp_sf_violation_chunklen( const struct sctp_endpoint *ep, const struct sctp_association *asoc, @@ -104,6 +111,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen( void *arg, sctp_cmd_seq_t *commands); +static sctp_disposition_t sctp_sf_violation_ctsn( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands); + /* Small helper function that checks if the chunk length * is of the appropriate length. The 'required_length' argument * is set to be the size of a specific chunk we are testing. @@ -2880,6 +2894,13 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, return SCTP_DISPOSITION_DISCARD; } + /* If Cumulative TSN Ack beyond the max tsn currently + * send, terminating the association and respond to the + * sender with an ABORT. + */ + if (!TSN_lt(ctsn, asoc->next_tsn)) + return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands); + /* Return this SACK for further processing. */ sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh)); @@ -3691,40 +3712,21 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, return SCTP_DISPOSITION_VIOLATION; } - /* - * Handle a protocol violation when the chunk length is invalid. - * "Invalid" length is identified as smaller then the minimal length a - * given chunk can be. For example, a SACK chunk has invalid length - * if it's length is set to be smaller then the size of sctp_sack_chunk_t. - * - * We inform the other end by sending an ABORT with a Protocol Violation - * error code. - * - * Section: Not specified - * Verification Tag: Nothing to do - * Inputs - * (endpoint, asoc, chunk) - * - * Outputs - * (reply_msg, msg_up, counters) - * - * Generate an ABORT chunk and terminate the association. + * Common function to handle a protocol violation. */ -static sctp_disposition_t sctp_sf_violation_chunklen( - const struct sctp_endpoint *ep, +static sctp_disposition_t sctp_sf_abort_violation( const struct sctp_association *asoc, - const sctp_subtype_t type, void *arg, - sctp_cmd_seq_t *commands) + sctp_cmd_seq_t *commands, + const __u8 *payload, + const size_t paylen) { struct sctp_chunk *chunk = arg; struct sctp_chunk *abort = NULL; - char err_str[]="The following chunk had invalid length:"; /* Make the abort chunk. */ - abort = sctp_make_abort_violation(asoc, chunk, err_str, - sizeof(err_str)); + abort = sctp_make_abort_violation(asoc, chunk, payload, paylen); if (!abort) goto nomem; @@ -3756,6 +3758,57 @@ nomem: return SCTP_DISPOSITION_NOMEM; } +/* + * Handle a protocol violation when the chunk length is invalid. + * "Invalid" length is identified as smaller then the minimal length a + * given chunk can be. For example, a SACK chunk has invalid length + * if it's length is set to be smaller then the size of sctp_sack_chunk_t. + * + * We inform the other end by sending an ABORT with a Protocol Violation + * error code. + * + * Section: Not specified + * Verification Tag: Nothing to do + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (reply_msg, msg_up, counters) + * + * Generate an ABORT chunk and terminate the association. + */ +static sctp_disposition_t sctp_sf_violation_chunklen( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + char err_str[]="The following chunk had invalid length:"; + + return sctp_sf_abort_violation(asoc, arg, commands, err_str, + sizeof(err_str)); +} + +/* Handle a protocol violation when the peer trying to advance the + * cumulative tsn ack to a point beyond the max tsn currently sent. + * + * We inform the other end by sending an ABORT with a Protocol Violation + * error code. + */ +static sctp_disposition_t sctp_sf_violation_ctsn( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; + + return sctp_sf_abort_violation(asoc, arg, commands, err_str, + sizeof(err_str)); +} + /*************************************************************************** * These are the state functions for handling primitive (Section 10) events. ***************************************************************************/ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ee88f2ea510..01c6364245b 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -107,8 +107,6 @@ static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; -extern struct kmem_cache *sctp_bucket_cachep; - /* Get the sndbuf space available at the time on the association. */ static inline int sctp_wspace(struct sctp_association *asoc) { @@ -433,7 +431,7 @@ out: * * Only sctp_setsockopt_bindx() is supposed to call this function. */ -int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) +static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) { int cnt; int retval = 0; @@ -602,7 +600,7 @@ out: * * Only sctp_setsockopt_bindx() is supposed to call this function. */ -int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) +static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) { struct sctp_sock *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; @@ -977,7 +975,7 @@ static int __sctp_connect(struct sock* sk, int err = 0; int addrcnt = 0; int walk_size = 0; - union sctp_addr *sa_addr; + union sctp_addr *sa_addr = NULL; void *addr_buf; unsigned short port; unsigned int f_flags = 0; @@ -1011,7 +1009,10 @@ static int __sctp_connect(struct sock* sk, goto out_free; } - err = sctp_verify_addr(sk, sa_addr, af->sockaddr_len); + /* Save current address so we can work with it */ + memcpy(&to, sa_addr, af->sockaddr_len); + + err = sctp_verify_addr(sk, &to, af->sockaddr_len); if (err) goto out_free; @@ -1021,12 +1022,11 @@ static int __sctp_connect(struct sock* sk, if (asoc && asoc->peer.port && asoc->peer.port != port) goto out_free; - memcpy(&to, sa_addr, af->sockaddr_len); /* Check if there already is a matching association on the * endpoint (other than the one created here). */ - asoc2 = sctp_endpoint_lookup_assoc(ep, sa_addr, &transport); + asoc2 = sctp_endpoint_lookup_assoc(ep, &to, &transport); if (asoc2 && asoc2 != asoc) { if (asoc2->state >= SCTP_STATE_ESTABLISHED) err = -EISCONN; @@ -1039,7 +1039,7 @@ static int __sctp_connect(struct sock* sk, * make sure that there is no peeled-off association matching * the peer address even on another socket. */ - if (sctp_endpoint_is_peeled_off(ep, sa_addr)) { + if (sctp_endpoint_is_peeled_off(ep, &to)) { err = -EADDRNOTAVAIL; goto out_free; } @@ -1070,7 +1070,7 @@ static int __sctp_connect(struct sock* sk, } } - scope = sctp_scope(sa_addr); + scope = sctp_scope(&to); asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); if (!asoc) { err = -ENOMEM; @@ -1079,7 +1079,7 @@ static int __sctp_connect(struct sock* sk, } /* Prime the peer's transport structures. */ - transport = sctp_assoc_add_peer(asoc, sa_addr, GFP_KERNEL, + transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN); if (!transport) { err = -ENOMEM; @@ -1103,8 +1103,8 @@ static int __sctp_connect(struct sock* sk, /* Initialize sk's dport and daddr for getpeername() */ inet_sk(sk)->dport = htons(asoc->peer.port); - af = sctp_get_af_specific(to.sa.sa_family); - af->to_sk_daddr(&to, sk); + af = sctp_get_af_specific(sa_addr->sa.sa_family); + af->to_sk_daddr(sa_addr, sk); sk->sk_err = 0; /* in-kernel sockets don't generally have a file allocated to them @@ -1531,7 +1531,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_unlock; } if (sinfo_flags & SCTP_ABORT) { - struct sctp_chunk *chunk; chunk = sctp_make_abort_user(asoc, msg, msg_len); if (!chunk) { @@ -4353,7 +4352,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, space_left, &bytes_copied); if (cnt < 0) { err = cnt; - goto error; + goto error_lock; } goto copy_getaddrs; } @@ -4367,7 +4366,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; if (space_left < addrlen) { err = -ENOMEM; /*fixme: right error?*/ - goto error; + goto error_lock; } memcpy(buf, &temp, addrlen); buf += addrlen; @@ -4381,15 +4380,21 @@ copy_getaddrs: if (copy_to_user(to, addrs, bytes_copied)) { err = -EFAULT; - goto error; + goto out; } if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { err = -EFAULT; - goto error; + goto out; } if (put_user(bytes_copied, optlen)) err = -EFAULT; -error: + + goto out; + +error_lock: + sctp_read_unlock(addr_lock); + +out: kfree(addrs); return err; } @@ -5964,7 +5969,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) return err; } -void sctp_wait_for_close(struct sock *sk, long timeout) +static void sctp_wait_for_close(struct sock *sk, long timeout) { DEFINE_WAIT(wait); diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index d3192a1babc..1ff0daade30 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c @@ -161,7 +161,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, __u16 *start, __u16 *end) { int started, ended; - __u16 _start, _end, offset; + __u16 start_, end_, offset; /* We haven't found a gap yet. */ started = ended = 0; @@ -175,7 +175,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, offset = iter->start - map->base_tsn; sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0, - &started, &_start, &ended, &_end); + &started, &start_, &ended, &end_); } /* Do we need to check the overflow map? */ @@ -193,8 +193,8 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, offset, map->len, map->len, - &started, &_start, - &ended, &_end); + &started, &start_, + &ended, &end_); } /* The Gap Ack Block happens to end at the end of the @@ -202,7 +202,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, */ if (started && !ended) { ended++; - _end = map->len + map->len - 1; + end_ = map->len + map->len - 1; } /* If we found a Gap Ack Block, return the start and end and @@ -215,8 +215,8 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, int gap = map->cumulative_tsn_ack_point - map->base_tsn; - *start = _start - gap; - *end = _end - gap; + *start = start_ - gap; + *end = end_ - gap; /* Move the iterator forward. */ iter->start = map->cumulative_tsn_ack_point + *end + 1; |