summaryrefslogtreecommitdiff
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/input.c76
-rw-r--r--net/sctp/inqueue.c4
-rw-r--r--net/sctp/ipv6.c26
-rw-r--r--net/sctp/proc.c32
-rw-r--r--net/sctp/sm_make_chunk.c18
-rw-r--r--net/sctp/sm_sideeffect.c7
-rw-r--r--net/sctp/sm_statefuns.c6
-rw-r--r--net/sctp/socket.c11
-rw-r--r--net/sctp/sysctl.c7
-rw-r--r--net/sctp/transport.c2
10 files changed, 120 insertions, 69 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 238f1bffa684..cb78b50868ee 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -225,6 +225,7 @@ int sctp_rcv(struct sk_buff *skb)
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
goto discard_release;
+ nf_reset(skb);
ret = sk_filter(sk, skb, 1);
if (ret)
@@ -256,20 +257,26 @@ int sctp_rcv(struct sk_buff *skb)
*/
sctp_bh_lock_sock(sk);
+ /* It is possible that the association could have moved to a different
+ * socket if it is peeled off. If so, update the sk.
+ */
+ if (sk != rcvr->sk) {
+ sctp_bh_lock_sock(rcvr->sk);
+ sctp_bh_unlock_sock(sk);
+ sk = rcvr->sk;
+ }
+
if (sock_owned_by_user(sk))
sk_add_backlog(sk, skb);
else
sctp_backlog_rcv(sk, skb);
- /* Release the sock and any reference counts we took in the
- * lookup calls.
+ /* Release the sock and the sock ref we took in the lookup calls.
+ * The asoc/ep ref will be released in sctp_backlog_rcv.
*/
sctp_bh_unlock_sock(sk);
- if (asoc)
- sctp_association_put(asoc);
- else
- sctp_endpoint_put(ep);
sock_put(sk);
+
return ret;
discard_it:
@@ -295,12 +302,50 @@ discard_release:
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
- struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
-
- sctp_inq_push(inqueue, chunk);
+ struct sctp_inq *inqueue = NULL;
+ struct sctp_ep_common *rcvr = NULL;
+
+ rcvr = chunk->rcvr;
+
+ BUG_TRAP(rcvr->sk == sk);
+
+ if (rcvr->dead) {
+ sctp_chunk_free(chunk);
+ } else {
+ inqueue = &chunk->rcvr->inqueue;
+ sctp_inq_push(inqueue, chunk);
+ }
+
+ /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */
+ if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
+ sctp_association_put(sctp_assoc(rcvr));
+ else
+ sctp_endpoint_put(sctp_ep(rcvr));
+
return 0;
}
+void sctp_backlog_migrate(struct sctp_association *assoc,
+ struct sock *oldsk, struct sock *newsk)
+{
+ struct sk_buff *skb;
+ struct sctp_chunk *chunk;
+
+ skb = oldsk->sk_backlog.head;
+ oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL;
+ while (skb != NULL) {
+ struct sk_buff *next = skb->next;
+
+ chunk = SCTP_INPUT_CB(skb)->chunk;
+ skb->next = NULL;
+ if (&assoc->base == chunk->rcvr)
+ sk_add_backlog(newsk, skb);
+ else
+ sk_add_backlog(oldsk, skb);
+ skb = next;
+ }
+}
+
/* Handle icmp frag needed error. */
void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
struct sctp_transport *t, __u32 pmtu)
@@ -543,10 +588,16 @@ int sctp_rcv_ootb(struct sk_buff *skb)
sctp_errhdr_t *err;
ch = (sctp_chunkhdr_t *) skb->data;
- ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
/* Scan through all the chunks in the packet. */
- while (ch_end > (__u8 *)ch && ch_end < skb->tail) {
+ do {
+ /* Break out if chunk length is less then minimal. */
+ if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
+ break;
+
+ ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+ if (ch_end > skb->tail)
+ break;
/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
* receiver MUST silently discard the OOTB packet and take no
@@ -577,8 +628,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
}
ch = (sctp_chunkhdr_t *) ch_end;
- ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
- }
+ } while (ch_end < skb->tail);
return 0;
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 2d33922c044b..297b8951463e 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue)
/* If there is a packet which is currently being worked on,
* free it as well.
*/
- if (queue->in_progress)
+ if (queue->in_progress) {
sctp_chunk_free(queue->in_progress);
+ queue->in_progress = NULL;
+ }
if (queue->malloced) {
/* Dump the master memory segment. */
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 15c05165c905..2e266129a764 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -180,8 +180,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
}
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
- "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
- "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
__FUNCTION__, skb, skb->len,
NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
@@ -206,13 +205,13 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
fl.oif = daddr->v6.sin6_scope_id;
- SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+ SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
__FUNCTION__, NIP6(fl.fl6_dst));
if (saddr) {
ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK(
- "SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
+ "SRC=" NIP6_FMT " - ",
NIP6(fl.fl6_src));
}
@@ -221,8 +220,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
SCTP_DEBUG_PRINTK(
- "rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
- "rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
} else {
SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -271,13 +269,12 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
__u8 bmatchlen;
SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
- "daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+ "daddr:" NIP6_FMT " ",
__FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
if (!asoc) {
ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
- "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
NIP6(saddr->v6.sin6_addr));
return;
}
@@ -305,13 +302,11 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
if (baddr) {
memcpy(saddr, baddr, sizeof(union sctp_addr));
- SCTP_DEBUG_PRINTK("saddr: "
- "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
NIP6(saddr->v6.sin6_addr));
} else {
printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
- "address for the "
- "dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ "address for the dest:" NIP6_FMT "\n",
__FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
}
@@ -675,8 +670,7 @@ static int sctp_v6_is_ce(const struct sk_buff *skb)
/* Dump the v6 addr to the seq file. */
static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
{
- seq_printf(seq, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
- NIP6(addr->v6.sin6_addr));
+ seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
}
/* Initialize a PF_INET6 socket msg_name. */
@@ -905,7 +899,7 @@ static struct inet_protosw sctpv6_stream_protosw = {
.flags = SCTP_PROTOSW_FLAG,
};
-static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int sctp6_rcv(struct sk_buff **pskb)
{
return sctp_rcv(*pskb) ? -1 : 0;
}
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 6e4dc28874d7..d47a52c303a8 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -176,7 +176,7 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
{
- if (*pos > sctp_ep_hashsize)
+ if (*pos >= sctp_ep_hashsize)
return NULL;
if (*pos < 0)
@@ -185,8 +185,6 @@ static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n");
- ++*pos;
-
return (void *)pos;
}
@@ -198,11 +196,9 @@ static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- if (*pos > sctp_ep_hashsize)
+ if (++*pos >= sctp_ep_hashsize)
return NULL;
- ++*pos;
-
return pos;
}
@@ -214,19 +210,19 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
struct sctp_ep_common *epb;
struct sctp_endpoint *ep;
struct sock *sk;
- int hash = *(int *)v;
+ int hash = *(loff_t *)v;
- if (hash > sctp_ep_hashsize)
+ if (hash >= sctp_ep_hashsize)
return -ENOMEM;
- head = &sctp_ep_hashtable[hash-1];
+ head = &sctp_ep_hashtable[hash];
sctp_local_bh_disable();
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
ep = sctp_ep(epb);
sk = epb->sk;
seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
- sctp_sk(sk)->type, sk->sk_state, hash-1,
+ sctp_sk(sk)->type, sk->sk_state, hash,
epb->bind_addr.port,
sock_i_uid(sk), sock_i_ino(sk));
@@ -283,7 +279,7 @@ void sctp_eps_proc_exit(void)
static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
{
- if (*pos > sctp_assoc_hashsize)
+ if (*pos >= sctp_assoc_hashsize)
return NULL;
if (*pos < 0)
@@ -293,8 +289,6 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
"RPORT LADDRS <-> RADDRS\n");
- ++*pos;
-
return (void *)pos;
}
@@ -306,11 +300,9 @@ static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- if (*pos > sctp_assoc_hashsize)
+ if (++*pos >= sctp_assoc_hashsize)
return NULL;
- ++*pos;
-
return pos;
}
@@ -321,12 +313,12 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
struct sctp_ep_common *epb;
struct sctp_association *assoc;
struct sock *sk;
- int hash = *(int *)v;
+ int hash = *(loff_t *)v;
- if (hash > sctp_assoc_hashsize)
+ if (hash >= sctp_assoc_hashsize)
return -ENOMEM;
- head = &sctp_assoc_hashtable[hash-1];
+ head = &sctp_assoc_hashtable[hash];
sctp_local_bh_disable();
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
@@ -335,7 +327,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
- assoc->state, hash-1, assoc->assoc_id,
+ assoc->state, hash, assoc->assoc_id,
(sk->sk_rcvbuf - assoc->rwnd),
assoc->sndbuf_used,
sock_i_uid(sk), sock_i_ino(sk),
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index f9573eba5c7a..5e0de3c0eead 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1275,7 +1275,12 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
unsigned int keylen;
char *key;
- headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE;
+ /* Header size is static data prior to the actual cookie, including
+ * any padding.
+ */
+ headersize = sizeof(sctp_paramhdr_t) +
+ (sizeof(struct sctp_signed_cookie) -
+ sizeof(struct sctp_cookie));
bodysize = sizeof(struct sctp_cookie)
+ ntohs(init_chunk->chunk_hdr->length) + addrs_len;
@@ -1287,7 +1292,7 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
- (bodysize % SCTP_COOKIE_MULTIPLE);
*cookie_len = headersize + bodysize;
- retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC);
+ retval = kmalloc(*cookie_len, GFP_ATOMIC);
if (!retval) {
*cookie_len = 0;
@@ -1354,7 +1359,7 @@ struct sctp_association *sctp_unpack_cookie(
struct sctp_signed_cookie *cookie;
struct sctp_cookie *bear_cookie;
int headersize, bodysize, fixed_size;
- __u8 digest[SCTP_SIGNATURE_SIZE];
+ __u8 *digest = ep->digest;
struct scatterlist sg;
unsigned int keylen, len;
char *key;
@@ -1362,7 +1367,12 @@ struct sctp_association *sctp_unpack_cookie(
struct sk_buff *skb = chunk->skb;
struct timeval tv;
- headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE;
+ /* Header size is static data prior to the actual cookie, including
+ * any padding.
+ */
+ headersize = sizeof(sctp_chunkhdr_t) +
+ (sizeof(struct sctp_signed_cookie) -
+ sizeof(struct sctp_cookie));
bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
fixed_size = headersize + sizeof(struct sctp_cookie);
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 2d7d8a5db2ac..8d1dc24bab4c 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1250,8 +1250,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_TIMER_START:
timer = &asoc->timers[cmd->obj.to];
timeout = asoc->timeouts[cmd->obj.to];
- if (!timeout)
- BUG();
+ BUG_ON(!timeout);
timer->expires = jiffies + timeout;
sctp_association_hold(asoc);
@@ -1301,7 +1300,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
"T1 INIT Timeout adjustment"
" init_err_counter: %d"
" cycle: %d"
- " timeout: %d\n",
+ " timeout: %ld\n",
asoc->init_err_counter,
asoc->init_cycle,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]);
@@ -1329,7 +1328,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
SCTP_DEBUG_PRINTK(
"T1 COOKIE Timeout adjustment"
" init_err_counter: %d"
- " timeout: %d\n",
+ " timeout: %ld\n",
asoc->init_err_counter,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 557a7d90b92a..71c9a961c321 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1036,14 +1036,14 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
if (from_addr.sa.sa_family == AF_INET6) {
printk(KERN_WARNING
"%s association %p could not find address "
- "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ NIP6_FMT "\n",
__FUNCTION__,
asoc,
NIP6(from_addr.v6.sin6_addr));
} else {
printk(KERN_WARNING
"%s association %p could not find address "
- "%u.%u.%u.%u\n",
+ NIPQUAD_FMT "\n",
__FUNCTION__,
asoc,
NIPQUAD(from_addr.v4.sin_addr.s_addr));
@@ -3090,6 +3090,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
break;
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+ if (ch_end > skb->tail)
+ break;
if (SCTP_CID_SHUTDOWN_ACK == ch->type)
ootb_shut_ack = 1;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fc04d185fa33..fb1821d9f338 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -63,6 +63,7 @@
#include <linux/wait.h>
#include <linux/time.h>
#include <linux/ip.h>
+#include <linux/capability.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/init.h>
@@ -860,7 +861,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
return -EFAULT;
/* Alloc space for the address array in kernel memory. */
- kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL);
+ kaddrs = kmalloc(addrs_size, GFP_KERNEL);
if (unlikely(!kaddrs))
return -ENOMEM;
@@ -1150,7 +1151,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
return -EFAULT;
/* Alloc space for the address array in kernel memory. */
- kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL);
+ kaddrs = kmalloc(addrs_size, GFP_KERNEL);
if (unlikely(!kaddrs))
return -ENOMEM;
@@ -2994,7 +2995,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->hbinterval = jiffies_to_msecs(sctp_hb_interval);
sp->pathmaxrxt = sctp_max_retrans_path;
sp->pathmtu = 0; // allow default discovery
- sp->sackdelay = sctp_sack_timeout;
+ sp->sackdelay = jiffies_to_msecs(sctp_sack_timeout);
sp->param_flags = SPP_HB_ENABLE |
SPP_PMTUD_ENABLE |
SPP_SACKDELAY_ENABLE;
@@ -5601,8 +5602,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
*/
newsp->type = type;
+ spin_lock_bh(&oldsk->sk_lock.slock);
+ /* Migrate the backlog from oldsk to newsk. */
+ sctp_backlog_migrate(assoc, oldsk, newsk);
/* Migrate the association to the new socket. */
sctp_assoc_migrate(assoc, newsk);
+ spin_unlock_bh(&oldsk->sk_lock.slock);
/* If the association on the newsk is already closed before accept()
* is called, set RCV_SHUTDOWN flag.
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index fcd7096c953d..dc6f3ff32358 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -159,12 +159,9 @@ static ctl_table sctp_table[] = {
.ctl_name = NET_SCTP_PRESERVE_ENABLE,
.procname = "cookie_preserve_enable",
.data = &sctp_cookie_preserve_enable,
- .maxlen = sizeof(long),
+ .maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
- .strategy = &sctp_sysctl_jiffies_ms,
- .extra1 = &rto_timer_min,
- .extra2 = &rto_timer_max
+ .proc_handler = &proc_dointvec
},
{
.ctl_name = NET_SCTP_RTO_ALPHA,
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 68d73e2dd155..160f62ad1cc5 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -350,7 +350,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
tp->rto_pending = 0;
SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d "
- "rttvar: %d, rto: %d\n", __FUNCTION__,
+ "rttvar: %d, rto: %ld\n", __FUNCTION__,
tp, rtt, tp->srtt, tp->rttvar, tp->rto);
}