Commit 3a97aeb5 authored by David S. Miller's avatar David S. Miller

Merge davem@master.kernel.org:/pub/scm/linux/kernel/git/vxy/lksctp-dev

parents d788d805 5f8f1c3c
...@@ -189,6 +189,16 @@ int sctp_assocs_proc_init(void); ...@@ -189,6 +189,16 @@ int sctp_assocs_proc_init(void);
void sctp_assocs_proc_exit(void); 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 * Section: Macros, externs, and inlines
*/ */
......
...@@ -590,7 +590,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -590,7 +590,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
* Return 0 - If further processing is needed. * Return 0 - If further processing is needed.
* Return 1 - If the packet can be discarded right away. * 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; sctp_chunkhdr_t *ch;
__u8 *ch_end; __u8 *ch_end;
......
...@@ -641,6 +641,8 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, ...@@ -641,6 +641,8 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
newsctp6sk = (struct sctp6_sock *)newsk; newsctp6sk = (struct sctp6_sock *)newsk;
inet_sk(newsk)->pinet6 = &newsctp6sk->inet6; inet_sk(newsk)->pinet6 = &newsctp6sk->inet6;
sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped;
newinet = inet_sk(newsk); newinet = inet_sk(newsk);
newnp = inet6_sk(newsk); newnp = inet6_sk(newsk);
......
...@@ -65,8 +65,6 @@ ...@@ -65,8 +65,6 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
extern struct kmem_cache *sctp_chunk_cachep;
SCTP_STATIC SCTP_STATIC
struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen); __u8 type, __u8 flags, int paylen);
...@@ -115,15 +113,12 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, ...@@ -115,15 +113,12 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
const void *payload, size_t paylen) const void *payload, size_t paylen)
{ {
sctp_errhdr_t err; sctp_errhdr_t err;
int padlen;
__u16 len; __u16 len;
/* Cause code constants are now defined in network order. */ /* Cause code constants are now defined in network order. */
err.cause = cause_code; err.cause = cause_code;
len = sizeof(sctp_errhdr_t) + paylen; len = sizeof(sctp_errhdr_t) + paylen;
padlen = len % 4;
err.length = htons(len); err.length = htons(len);
len += padlen;
chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
sctp_addto_chunk(chunk, paylen, payload); sctp_addto_chunk(chunk, paylen, payload);
} }
...@@ -1454,7 +1449,6 @@ struct sctp_association *sctp_unpack_cookie( ...@@ -1454,7 +1449,6 @@ struct sctp_association *sctp_unpack_cookie(
do_gettimeofday(&tv); do_gettimeofday(&tv);
if (!asoc && tv_lt(bear_cookie->expiration, tv)) { if (!asoc && tv_lt(bear_cookie->expiration, tv)) {
__u16 len;
/* /*
* Section 3.3.10.3 Stale Cookie Error (3) * Section 3.3.10.3 Stale Cookie Error (3)
* *
......
...@@ -97,6 +97,13 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, ...@@ -97,6 +97,13 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
const struct sctp_association *asoc, const struct sctp_association *asoc,
struct sctp_transport *transport); 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( static sctp_disposition_t sctp_sf_violation_chunklen(
const struct sctp_endpoint *ep, const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
...@@ -104,6 +111,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen( ...@@ -104,6 +111,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
void *arg, void *arg,
sctp_cmd_seq_t *commands); 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 /* Small helper function that checks if the chunk length
* is of the appropriate length. The 'required_length' argument * is of the appropriate length. The 'required_length' argument
* is set to be the size of a specific chunk we are testing. * 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, ...@@ -2880,6 +2894,13 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
return SCTP_DISPOSITION_DISCARD; 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. */ /* Return this SACK for further processing. */
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh)); 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, ...@@ -3691,40 +3712,21 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
return SCTP_DISPOSITION_VIOLATION; return SCTP_DISPOSITION_VIOLATION;
} }
/* /*
* Handle a protocol violation when the chunk length is invalid. * Common function to handle a protocol violation.
* "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( static sctp_disposition_t sctp_sf_abort_violation(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg, 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 *chunk = arg;
struct sctp_chunk *abort = NULL; struct sctp_chunk *abort = NULL;
char err_str[]="The following chunk had invalid length:";
/* Make the abort chunk. */ /* Make the abort chunk. */
abort = sctp_make_abort_violation(asoc, chunk, err_str, abort = sctp_make_abort_violation(asoc, chunk, payload, paylen);
sizeof(err_str));
if (!abort) if (!abort)
goto nomem; goto nomem;
...@@ -3756,6 +3758,57 @@ static sctp_disposition_t sctp_sf_violation_chunklen( ...@@ -3756,6 +3758,57 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
return SCTP_DISPOSITION_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. * These are the state functions for handling primitive (Section 10) events.
***************************************************************************/ ***************************************************************************/
......
...@@ -107,8 +107,6 @@ static void sctp_sock_migrate(struct sock *, struct sock *, ...@@ -107,8 +107,6 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
struct sctp_association *, sctp_socket_type_t); struct sctp_association *, sctp_socket_type_t);
static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; 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. */ /* Get the sndbuf space available at the time on the association. */
static inline int sctp_wspace(struct sctp_association *asoc) static inline int sctp_wspace(struct sctp_association *asoc)
{ {
...@@ -433,7 +431,7 @@ static int sctp_send_asconf(struct sctp_association *asoc, ...@@ -433,7 +431,7 @@ static int sctp_send_asconf(struct sctp_association *asoc,
* *
* Only sctp_setsockopt_bindx() is supposed to call this function. * 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 cnt;
int retval = 0; int retval = 0;
...@@ -602,7 +600,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ...@@ -602,7 +600,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
* *
* Only sctp_setsockopt_bindx() is supposed to call this function. * 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_sock *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
...@@ -977,7 +975,7 @@ static int __sctp_connect(struct sock* sk, ...@@ -977,7 +975,7 @@ static int __sctp_connect(struct sock* sk,
int err = 0; int err = 0;
int addrcnt = 0; int addrcnt = 0;
int walk_size = 0; int walk_size = 0;
union sctp_addr *sa_addr; union sctp_addr *sa_addr = NULL;
void *addr_buf; void *addr_buf;
unsigned short port; unsigned short port;
unsigned int f_flags = 0; unsigned int f_flags = 0;
...@@ -1011,7 +1009,10 @@ static int __sctp_connect(struct sock* sk, ...@@ -1011,7 +1009,10 @@ static int __sctp_connect(struct sock* sk,
goto out_free; 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) if (err)
goto out_free; goto out_free;
...@@ -1021,12 +1022,11 @@ static int __sctp_connect(struct sock* sk, ...@@ -1021,12 +1022,11 @@ static int __sctp_connect(struct sock* sk,
if (asoc && asoc->peer.port && asoc->peer.port != port) if (asoc && asoc->peer.port && asoc->peer.port != port)
goto out_free; goto out_free;
memcpy(&to, sa_addr, af->sockaddr_len);
/* Check if there already is a matching association on the /* Check if there already is a matching association on the
* endpoint (other than the one created here). * 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 && asoc2 != asoc) {
if (asoc2->state >= SCTP_STATE_ESTABLISHED) if (asoc2->state >= SCTP_STATE_ESTABLISHED)
err = -EISCONN; err = -EISCONN;
...@@ -1039,7 +1039,7 @@ static int __sctp_connect(struct sock* sk, ...@@ -1039,7 +1039,7 @@ static int __sctp_connect(struct sock* sk,
* make sure that there is no peeled-off association matching * make sure that there is no peeled-off association matching
* the peer address even on another socket. * 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; err = -EADDRNOTAVAIL;
goto out_free; goto out_free;
} }
...@@ -1070,7 +1070,7 @@ static int __sctp_connect(struct sock* sk, ...@@ -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); asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
if (!asoc) { if (!asoc) {
err = -ENOMEM; err = -ENOMEM;
...@@ -1079,7 +1079,7 @@ static int __sctp_connect(struct sock* sk, ...@@ -1079,7 +1079,7 @@ static int __sctp_connect(struct sock* sk,
} }
/* Prime the peer's transport structures. */ /* 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); SCTP_UNKNOWN);
if (!transport) { if (!transport) {
err = -ENOMEM; err = -ENOMEM;
...@@ -1103,8 +1103,8 @@ static int __sctp_connect(struct sock* sk, ...@@ -1103,8 +1103,8 @@ static int __sctp_connect(struct sock* sk,
/* Initialize sk's dport and daddr for getpeername() */ /* Initialize sk's dport and daddr for getpeername() */
inet_sk(sk)->dport = htons(asoc->peer.port); inet_sk(sk)->dport = htons(asoc->peer.port);
af = sctp_get_af_specific(to.sa.sa_family); af = sctp_get_af_specific(sa_addr->sa.sa_family);
af->to_sk_daddr(&to, sk); af->to_sk_daddr(sa_addr, sk);
sk->sk_err = 0; sk->sk_err = 0;
/* in-kernel sockets don't generally have a file allocated to them /* 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, ...@@ -1531,7 +1531,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_unlock; goto out_unlock;
} }
if (sinfo_flags & SCTP_ABORT) { if (sinfo_flags & SCTP_ABORT) {
struct sctp_chunk *chunk;
chunk = sctp_make_abort_user(asoc, msg, msg_len); chunk = sctp_make_abort_user(asoc, msg, msg_len);
if (!chunk) { if (!chunk) {
...@@ -4353,7 +4352,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -4353,7 +4352,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
space_left, &bytes_copied); space_left, &bytes_copied);
if (cnt < 0) { if (cnt < 0) {
err = cnt; err = cnt;
goto error; goto error_lock;
} }
goto copy_getaddrs; goto copy_getaddrs;
} }
...@@ -4367,7 +4366,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -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; addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if (space_left < addrlen) { if (space_left < addrlen) {
err = -ENOMEM; /*fixme: right error?*/ err = -ENOMEM; /*fixme: right error?*/
goto error; goto error_lock;
} }
memcpy(buf, &temp, addrlen); memcpy(buf, &temp, addrlen);
buf += addrlen; buf += addrlen;
...@@ -4381,15 +4380,21 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -4381,15 +4380,21 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
if (copy_to_user(to, addrs, bytes_copied)) { if (copy_to_user(to, addrs, bytes_copied)) {
err = -EFAULT; err = -EFAULT;
goto error; goto out;
} }
if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) {
err = -EFAULT; err = -EFAULT;
goto error; goto out;
} }
if (put_user(bytes_copied, optlen)) if (put_user(bytes_copied, optlen))
err = -EFAULT; err = -EFAULT;
error:
goto out;
error_lock:
sctp_read_unlock(addr_lock);
out:
kfree(addrs); kfree(addrs);
return err; return err;
} }
...@@ -5964,7 +5969,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) ...@@ -5964,7 +5969,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
return err; 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); DEFINE_WAIT(wait);
......
...@@ -161,7 +161,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, ...@@ -161,7 +161,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
__u16 *start, __u16 *end) __u16 *start, __u16 *end)
{ {
int started, ended; int started, ended;
__u16 _start, _end, offset; __u16 start_, end_, offset;
/* We haven't found a gap yet. */ /* We haven't found a gap yet. */
started = ended = 0; started = ended = 0;
...@@ -175,7 +175,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, ...@@ -175,7 +175,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
offset = iter->start - map->base_tsn; offset = iter->start - map->base_tsn;
sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0, 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? */ /* 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, ...@@ -193,8 +193,8 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
offset, offset,
map->len, map->len,
map->len, map->len,
&started, &_start, &started, &start_,
&ended, &_end); &ended, &end_);
} }
/* The Gap Ack Block happens to end at the end of the /* 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, ...@@ -202,7 +202,7 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
*/ */
if (started && !ended) { if (started && !ended) {
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 /* 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, ...@@ -215,8 +215,8 @@ SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
int gap = map->cumulative_tsn_ack_point - int gap = map->cumulative_tsn_ack_point -
map->base_tsn; map->base_tsn;
*start = _start - gap; *start = start_ - gap;
*end = _end - gap; *end = end_ - gap;
/* Move the iterator forward. */ /* Move the iterator forward. */
iter->start = map->cumulative_tsn_ack_point + *end + 1; iter->start = map->cumulative_tsn_ack_point + *end + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment