mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge branch 'master' into for-next
Conflicts: drivers/devfreq/exynos4_bus.c Sync with Linus' tree to be able to apply patches that are against newer code (mvneta).
This commit is contained in:
commit
617677295b
11382 changed files with 530741 additions and 302619 deletions
|
|
@ -9,7 +9,6 @@ menuconfig IP_SCTP
|
|||
select CRYPTO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_MD5 if SCTP_HMAC_MD5
|
||||
select LIBCRC32C
|
||||
---help---
|
||||
Stream Control Transmission Protocol
|
||||
|
|
@ -67,34 +66,45 @@ config SCTP_DBG_OBJCNT
|
|||
'cat /proc/net/sctp/sctp_dbg_objcnt'
|
||||
|
||||
If unsure, say N
|
||||
|
||||
choice
|
||||
prompt "SCTP: Cookie HMAC Algorithm"
|
||||
default SCTP_HMAC_MD5
|
||||
prompt "Default SCTP cookie HMAC encoding"
|
||||
default SCTP_DEFAULT_COOKIE_HMAC_MD5
|
||||
help
|
||||
HMAC algorithm to be used during association initialization. It
|
||||
is strongly recommended to use HMAC-SHA1 or HMAC-MD5. See
|
||||
configuration for Cryptographic API and enable those algorithms
|
||||
to make usable by SCTP.
|
||||
This option sets the default sctp cookie hmac algorithm
|
||||
when in doubt select 'md5'
|
||||
|
||||
config SCTP_HMAC_NONE
|
||||
bool "None"
|
||||
help
|
||||
Choosing this disables the use of an HMAC during association
|
||||
establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1.
|
||||
|
||||
config SCTP_HMAC_SHA1
|
||||
bool "HMAC-SHA1"
|
||||
help
|
||||
Enable the use of HMAC-SHA1 during association establishment. It
|
||||
is advised to use either HMAC-MD5 or HMAC-SHA1.
|
||||
|
||||
config SCTP_HMAC_MD5
|
||||
bool "HMAC-MD5"
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_MD5
|
||||
bool "Enable optional MD5 hmac cookie generation"
|
||||
help
|
||||
Enable the use of HMAC-MD5 during association establishment. It is
|
||||
advised to use either HMAC-MD5 or HMAC-SHA1.
|
||||
Enable optional MD5 hmac based SCTP cookie generation
|
||||
select SCTP_COOKIE_HMAC_MD5
|
||||
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_SHA1
|
||||
bool "Enable optional SHA1 hmac cookie generation"
|
||||
help
|
||||
Enable optional SHA1 hmac based SCTP cookie generation
|
||||
select SCTP_COOKIE_HMAC_SHA1
|
||||
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_NONE
|
||||
bool "Use no hmac alg in SCTP cookie generation"
|
||||
help
|
||||
Use no hmac algorithm in SCTP cookie generation
|
||||
|
||||
endchoice
|
||||
|
||||
config SCTP_COOKIE_HMAC_MD5
|
||||
bool "Enable optional MD5 hmac cookie generation"
|
||||
help
|
||||
Enable optional MD5 hmac based SCTP cookie generation
|
||||
select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5
|
||||
select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5
|
||||
|
||||
config SCTP_COOKIE_HMAC_SHA1
|
||||
bool "Enable optional SHA1 hmac cookie generation"
|
||||
help
|
||||
Enable optional SHA1 hmac based SCTP cookie generation
|
||||
select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1
|
||||
select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1
|
||||
|
||||
|
||||
endif # IP_SCTP
|
||||
|
|
|
|||
|
|
@ -321,6 +321,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
|
|||
asoc->default_timetolive = sp->default_timetolive;
|
||||
asoc->default_rcv_context = sp->default_rcv_context;
|
||||
|
||||
/* SCTP_GET_ASSOC_STATS COUNTERS */
|
||||
memset(&asoc->stats, 0, sizeof(struct sctp_priv_assoc_stats));
|
||||
|
||||
/* AUTH related initializations */
|
||||
INIT_LIST_HEAD(&asoc->endpoint_shared_keys);
|
||||
err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp);
|
||||
|
|
@ -445,7 +448,7 @@ void sctp_association_free(struct sctp_association *asoc)
|
|||
/* Release the transport structures. */
|
||||
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
|
||||
transport = list_entry(pos, struct sctp_transport, transports);
|
||||
list_del(pos);
|
||||
list_del_rcu(pos);
|
||||
sctp_transport_free(transport);
|
||||
}
|
||||
|
||||
|
|
@ -565,7 +568,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
|
|||
sctp_assoc_update_retran_path(asoc);
|
||||
|
||||
/* Remove this peer from the list. */
|
||||
list_del(&peer->transports);
|
||||
list_del_rcu(&peer->transports);
|
||||
|
||||
/* Get the first transport of asoc. */
|
||||
pos = asoc->peer.transport_addr_list.next;
|
||||
|
|
@ -760,12 +763,13 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
|
|||
|
||||
/* Set the transport's RTO.initial value */
|
||||
peer->rto = asoc->rto_initial;
|
||||
sctp_max_rto(asoc, peer);
|
||||
|
||||
/* Set the peer's active state. */
|
||||
peer->state = peer_state;
|
||||
|
||||
/* Attach the remote transport to our asoc. */
|
||||
list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);
|
||||
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
|
||||
asoc->peer.transport_count++;
|
||||
|
||||
/* If we do not yet have a primary path, set one. */
|
||||
|
|
@ -1152,8 +1156,12 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
|
|||
*/
|
||||
if (sctp_chunk_is_data(chunk))
|
||||
asoc->peer.last_data_from = chunk->transport;
|
||||
else
|
||||
else {
|
||||
SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS);
|
||||
asoc->stats.ictrlchunks++;
|
||||
if (chunk->chunk_hdr->type == SCTP_CID_SACK)
|
||||
asoc->stats.isacks++;
|
||||
}
|
||||
|
||||
if (chunk->transport)
|
||||
chunk->transport->last_time_heard = jiffies;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||
|
||||
msg = sctp_datamsg_new(GFP_KERNEL);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* Note: Calculate this outside of the loop, so that all fragments
|
||||
* have the same expiration.
|
||||
|
|
@ -280,11 +280,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||
|
||||
chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
|
||||
|
||||
if (!chunk)
|
||||
if (!chunk) {
|
||||
err = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
goto errout_chunk_free;
|
||||
|
||||
offset += len;
|
||||
|
||||
|
|
@ -315,8 +318,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||
|
||||
chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
|
||||
|
||||
if (!chunk)
|
||||
if (!chunk) {
|
||||
err = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov);
|
||||
|
||||
|
|
@ -324,7 +329,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
|
||||
- (__u8 *)chunk->skb->data);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
goto errout_chunk_free;
|
||||
|
||||
sctp_datamsg_assign(msg, chunk);
|
||||
list_add_tail(&chunk->frag_list, &msg->chunks);
|
||||
|
|
@ -332,6 +337,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||
|
||||
return msg;
|
||||
|
||||
errout_chunk_free:
|
||||
sctp_chunk_free(chunk);
|
||||
|
||||
errout:
|
||||
list_for_each_safe(pos, temp, &msg->chunks) {
|
||||
list_del_init(pos);
|
||||
|
|
@ -339,7 +347,7 @@ errout:
|
|||
sctp_chunk_free(chunk);
|
||||
}
|
||||
sctp_datamsg_put(msg);
|
||||
return NULL;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/* Check whether this message has expired. */
|
||||
|
|
|
|||
|
|
@ -480,8 +480,11 @@ normal:
|
|||
*/
|
||||
if (asoc && sctp_chunk_is_data(chunk))
|
||||
asoc->peer.last_data_from = chunk->transport;
|
||||
else
|
||||
else {
|
||||
SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS);
|
||||
if (asoc)
|
||||
asoc->stats.ictrlchunks++;
|
||||
}
|
||||
|
||||
if (chunk->transport)
|
||||
chunk->transport->last_time_heard = jiffies;
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk)
|
|||
* on the BH related data structures.
|
||||
*/
|
||||
list_add_tail(&chunk->list, &q->in_chunk_list);
|
||||
if (chunk->asoc)
|
||||
chunk->asoc->stats.ipackets++;
|
||||
q->immediate.func(&q->immediate);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
|||
}
|
||||
|
||||
out:
|
||||
if (!IS_ERR(dst)) {
|
||||
if (!IS_ERR_OR_NULL(dst)) {
|
||||
struct rt6_info *rt;
|
||||
rt = (struct rt6_info *)dst;
|
||||
t->dst = dst;
|
||||
|
|
|
|||
|
|
@ -311,6 +311,8 @@ static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet,
|
|||
|
||||
case SCTP_CID_SACK:
|
||||
packet->has_sack = 1;
|
||||
if (chunk->asoc)
|
||||
chunk->asoc->stats.osacks++;
|
||||
break;
|
||||
|
||||
case SCTP_CID_AUTH:
|
||||
|
|
@ -584,11 +586,13 @@ int sctp_packet_transmit(struct sctp_packet *packet)
|
|||
*/
|
||||
|
||||
/* Dump that on IP! */
|
||||
if (asoc && asoc->peer.last_sent_to != tp) {
|
||||
/* Considering the multiple CPU scenario, this is a
|
||||
* "correcter" place for last_sent_to. --xguo
|
||||
*/
|
||||
asoc->peer.last_sent_to = tp;
|
||||
if (asoc) {
|
||||
asoc->stats.opackets++;
|
||||
if (asoc->peer.last_sent_to != tp)
|
||||
/* Considering the multiple CPU scenario, this is a
|
||||
* "correcter" place for last_sent_to. --xguo
|
||||
*/
|
||||
asoc->peer.last_sent_to = tp;
|
||||
}
|
||||
|
||||
if (has_data) {
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
|
|||
|
||||
/* Free the outqueue structure and any related pending chunks.
|
||||
*/
|
||||
void sctp_outq_teardown(struct sctp_outq *q)
|
||||
static void __sctp_outq_teardown(struct sctp_outq *q)
|
||||
{
|
||||
struct sctp_transport *transport;
|
||||
struct list_head *lchunk, *temp;
|
||||
|
|
@ -277,8 +277,6 @@ void sctp_outq_teardown(struct sctp_outq *q)
|
|||
sctp_chunk_free(chunk);
|
||||
}
|
||||
|
||||
q->error = 0;
|
||||
|
||||
/* Throw away any leftover control chunks. */
|
||||
list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
|
||||
list_del_init(&chunk->list);
|
||||
|
|
@ -286,11 +284,17 @@ void sctp_outq_teardown(struct sctp_outq *q)
|
|||
}
|
||||
}
|
||||
|
||||
void sctp_outq_teardown(struct sctp_outq *q)
|
||||
{
|
||||
__sctp_outq_teardown(q);
|
||||
sctp_outq_init(q->asoc, q);
|
||||
}
|
||||
|
||||
/* Free the outqueue structure and any related pending chunks. */
|
||||
void sctp_outq_free(struct sctp_outq *q)
|
||||
{
|
||||
/* Throw away leftover chunks. */
|
||||
sctp_outq_teardown(q);
|
||||
__sctp_outq_teardown(q);
|
||||
|
||||
/* If we were kmalloc()'d, free the memory. */
|
||||
if (q->malloced)
|
||||
|
|
@ -667,6 +671,7 @@ redo:
|
|||
chunk->fast_retransmit = SCTP_DONT_FRTX;
|
||||
|
||||
q->empty = 0;
|
||||
q->asoc->stats.rtxchunks++;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -876,12 +881,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
|
|||
if (status != SCTP_XMIT_OK) {
|
||||
/* put the chunk back */
|
||||
list_add(&chunk->list, &q->control_chunk_list);
|
||||
} else if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) {
|
||||
} else {
|
||||
asoc->stats.octrlchunks++;
|
||||
/* PR-SCTP C5) If a FORWARD TSN is sent, the
|
||||
* sender MUST assure that at least one T3-rtx
|
||||
* timer is running.
|
||||
*/
|
||||
sctp_transport_reset_timers(transport);
|
||||
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN)
|
||||
sctp_transport_reset_timers(transport);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -1055,6 +1062,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
|
|||
*/
|
||||
if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
|
||||
chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
|
||||
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
|
||||
asoc->stats.ouodchunks++;
|
||||
else
|
||||
asoc->stats.oodchunks++;
|
||||
|
||||
break;
|
||||
|
||||
|
|
@ -1162,6 +1173,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
|
|||
|
||||
sack_ctsn = ntohl(sack->cum_tsn_ack);
|
||||
gap_ack_blocks = ntohs(sack->num_gap_ack_blocks);
|
||||
asoc->stats.gapcnt += gap_ack_blocks;
|
||||
/*
|
||||
* SFR-CACC algorithm:
|
||||
* On receipt of a SACK the sender SHOULD execute the
|
||||
|
|
|
|||
|
|
@ -122,7 +122,8 @@ static const struct file_operations sctpprobe_fops = {
|
|||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
sctp_disposition_t jsctp_sf_eat_sack(const struct sctp_endpoint *ep,
|
||||
sctp_disposition_t jsctp_sf_eat_sack(struct net *net,
|
||||
const struct sctp_endpoint *ep,
|
||||
const struct sctp_association *asoc,
|
||||
const sctp_subtype_t type,
|
||||
void *arg,
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ static const struct file_operations sctp_snmp_seq_fops = {
|
|||
.open = sctp_snmp_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = single_release_net,
|
||||
};
|
||||
|
||||
/* Set up the proc fs entry for 'snmp' object. */
|
||||
|
|
@ -139,7 +139,11 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo
|
|||
primary = &peer->saddr;
|
||||
}
|
||||
|
||||
list_for_each_entry(laddr, &epb->bind_addr.address_list, list) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(laddr, &epb->bind_addr.address_list, list) {
|
||||
if (!laddr->valid)
|
||||
continue;
|
||||
|
||||
addr = &laddr->a;
|
||||
af = sctp_get_af_specific(addr->sa.sa_family);
|
||||
if (primary && af->cmp_addr(addr, primary)) {
|
||||
|
|
@ -147,6 +151,7 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo
|
|||
}
|
||||
af->seq_dump_addr(seq, addr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* Dump remote addresses of an association. */
|
||||
|
|
@ -157,15 +162,20 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
|
|||
struct sctp_af *af;
|
||||
|
||||
primary = &assoc->peer.primary_addr;
|
||||
list_for_each_entry(transport, &assoc->peer.transport_addr_list,
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(transport, &assoc->peer.transport_addr_list,
|
||||
transports) {
|
||||
addr = &transport->ipaddr;
|
||||
if (transport->dead)
|
||||
continue;
|
||||
|
||||
af = sctp_get_af_specific(addr->sa.sa_family);
|
||||
if (af->cmp_addr(addr, primary)) {
|
||||
seq_printf(seq, "*");
|
||||
}
|
||||
af->seq_dump_addr(seq, addr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
|
|
@ -251,7 +261,7 @@ static const struct file_operations sctp_eps_seq_fops = {
|
|||
.open = sctp_eps_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
.release = seq_release_net,
|
||||
};
|
||||
|
||||
/* Set up the proc fs entry for 'eps' object. */
|
||||
|
|
@ -372,7 +382,7 @@ static const struct file_operations sctp_assocs_seq_fops = {
|
|||
.open = sctp_assocs_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
.release = seq_release_net,
|
||||
};
|
||||
|
||||
/* Set up the proc fs entry for 'assocs' object. */
|
||||
|
|
@ -436,12 +446,16 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
|
|||
head = &sctp_assoc_hashtable[hash];
|
||||
sctp_local_bh_disable();
|
||||
read_lock(&head->lock);
|
||||
rcu_read_lock();
|
||||
sctp_for_each_hentry(epb, node, &head->chain) {
|
||||
if (!net_eq(sock_net(epb->sk), seq_file_net(seq)))
|
||||
continue;
|
||||
assoc = sctp_assoc(epb);
|
||||
list_for_each_entry(tsp, &assoc->peer.transport_addr_list,
|
||||
list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list,
|
||||
transports) {
|
||||
if (tsp->dead)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The remote address (ADDR)
|
||||
*/
|
||||
|
|
@ -487,6 +501,7 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
|
|||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
read_unlock(&head->lock);
|
||||
sctp_local_bh_enable();
|
||||
|
||||
|
|
@ -517,7 +532,7 @@ static const struct file_operations sctp_remaddr_seq_fops = {
|
|||
.open = sctp_remaddr_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
.release = seq_release_net,
|
||||
};
|
||||
|
||||
int __net_init sctp_remaddr_proc_init(struct net *net)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ int sysctl_sctp_rmem[3];
|
|||
int sysctl_sctp_wmem[3];
|
||||
|
||||
/* Set up the proc fs entry for the SCTP protocol. */
|
||||
static __net_init int sctp_proc_init(struct net *net)
|
||||
static int __net_init sctp_proc_init(struct net *net)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net);
|
||||
|
|
@ -1165,7 +1165,7 @@ static void sctp_v4_del_protocol(void)
|
|||
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
|
||||
}
|
||||
|
||||
static int sctp_net_init(struct net *net)
|
||||
static int __net_init sctp_net_init(struct net *net)
|
||||
{
|
||||
int status;
|
||||
|
||||
|
|
@ -1190,6 +1190,15 @@ static int sctp_net_init(struct net *net)
|
|||
/* Whether Cookie Preservative is enabled(1) or not(0) */
|
||||
net->sctp.cookie_preserve_enable = 1;
|
||||
|
||||
/* Default sctp sockets to use md5 as their hmac alg */
|
||||
#if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5)
|
||||
net->sctp.sctp_hmac_alg = "md5";
|
||||
#elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1)
|
||||
net->sctp.sctp_hmac_alg = "sha1";
|
||||
#else
|
||||
net->sctp.sctp_hmac_alg = NULL;
|
||||
#endif
|
||||
|
||||
/* Max.Burst - 4 */
|
||||
net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST;
|
||||
|
||||
|
|
@ -1281,7 +1290,7 @@ err_sysctl_register:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void sctp_net_exit(struct net *net)
|
||||
static void __net_exit sctp_net_exit(struct net *net)
|
||||
{
|
||||
/* Free the local address list */
|
||||
sctp_free_addr_wq(net);
|
||||
|
|
|
|||
|
|
@ -804,10 +804,11 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
|
|||
gabs);
|
||||
|
||||
/* Add the duplicate TSN information. */
|
||||
if (num_dup_tsns)
|
||||
if (num_dup_tsns) {
|
||||
aptr->stats.idupchunks += num_dup_tsns;
|
||||
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
|
||||
sctp_tsnmap_get_dups(map));
|
||||
|
||||
}
|
||||
/* Once we have a sack generated, check to see what our sack
|
||||
* generation is, if its 0, reset the transports to 0, and reset
|
||||
* the association generation to 1
|
||||
|
|
@ -1090,6 +1091,25 @@ nodata:
|
|||
return retval;
|
||||
}
|
||||
|
||||
struct sctp_chunk *sctp_make_violation_max_retrans(
|
||||
const struct sctp_association *asoc,
|
||||
const struct sctp_chunk *chunk)
|
||||
{
|
||||
struct sctp_chunk *retval;
|
||||
static const char error[] = "Association exceeded its max_retans count";
|
||||
size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t);
|
||||
|
||||
retval = sctp_make_abort(asoc, chunk, payload_len);
|
||||
if (!retval)
|
||||
goto nodata;
|
||||
|
||||
sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error));
|
||||
sctp_addto_chunk(retval, sizeof(error), error);
|
||||
|
||||
nodata:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Make a HEARTBEAT chunk. */
|
||||
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
|
||||
const struct sctp_transport *transport)
|
||||
|
|
|
|||
|
|
@ -542,6 +542,7 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
|
|||
*/
|
||||
if (!is_hb || transport->hb_sent) {
|
||||
transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
|
||||
sctp_max_rto(asoc, transport);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -577,7 +578,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
|
|||
unsigned int error)
|
||||
{
|
||||
struct sctp_ulpevent *event;
|
||||
|
||||
struct sctp_chunk *abort;
|
||||
/* Cancel any partial delivery in progress. */
|
||||
sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
|
||||
|
||||
|
|
@ -593,6 +594,13 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
|
|||
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
||||
SCTP_ULPEVENT(event));
|
||||
|
||||
if (asoc->overall_error_count >= asoc->max_retrans) {
|
||||
abort = sctp_make_violation_max_retrans(asoc, chunk);
|
||||
if (abort)
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
|
||||
SCTP_CHUNK(abort));
|
||||
}
|
||||
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
|
||||
SCTP_STATE(SCTP_STATE_CLOSED));
|
||||
|
||||
|
|
@ -1268,14 +1276,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
sctp_outq_uncork(&asoc->outqueue);
|
||||
local_cork = 0;
|
||||
}
|
||||
asoc = cmd->obj.ptr;
|
||||
asoc = cmd->obj.asoc;
|
||||
/* Register with the endpoint. */
|
||||
sctp_endpoint_add_asoc(ep, asoc);
|
||||
sctp_hash_established(asoc);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_UPDATE_ASSOC:
|
||||
sctp_assoc_update(asoc, cmd->obj.ptr);
|
||||
sctp_assoc_update(asoc, cmd->obj.asoc);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_PURGE_OUTQUEUE:
|
||||
|
|
@ -1315,7 +1323,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
break;
|
||||
|
||||
case SCTP_CMD_PROCESS_FWDTSN:
|
||||
sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.ptr);
|
||||
sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.chunk);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_GEN_SACK:
|
||||
|
|
@ -1331,7 +1339,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
case SCTP_CMD_PROCESS_SACK:
|
||||
/* Process an inbound SACK. */
|
||||
error = sctp_cmd_process_sack(commands, asoc,
|
||||
cmd->obj.ptr);
|
||||
cmd->obj.chunk);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_GEN_INIT_ACK:
|
||||
|
|
@ -1352,15 +1360,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
* layer which will bail.
|
||||
*/
|
||||
error = sctp_cmd_process_init(commands, asoc, chunk,
|
||||
cmd->obj.ptr, gfp);
|
||||
cmd->obj.init, gfp);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_GEN_COOKIE_ECHO:
|
||||
/* Generate a COOKIE ECHO chunk. */
|
||||
new_obj = sctp_make_cookie_echo(asoc, chunk);
|
||||
if (!new_obj) {
|
||||
if (cmd->obj.ptr)
|
||||
sctp_chunk_free(cmd->obj.ptr);
|
||||
if (cmd->obj.chunk)
|
||||
sctp_chunk_free(cmd->obj.chunk);
|
||||
goto nomem;
|
||||
}
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
|
||||
|
|
@ -1369,9 +1377,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
/* If there is an ERROR chunk to be sent along with
|
||||
* the COOKIE_ECHO, send it, too.
|
||||
*/
|
||||
if (cmd->obj.ptr)
|
||||
if (cmd->obj.chunk)
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
|
||||
SCTP_CHUNK(cmd->obj.ptr));
|
||||
SCTP_CHUNK(cmd->obj.chunk));
|
||||
|
||||
if (new_obj->transport) {
|
||||
new_obj->transport->init_sent_count++;
|
||||
|
|
@ -1417,18 +1425,18 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
case SCTP_CMD_CHUNK_ULP:
|
||||
/* Send a chunk to the sockets layer. */
|
||||
SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
|
||||
"chunk_up:", cmd->obj.ptr,
|
||||
"chunk_up:", cmd->obj.chunk,
|
||||
"ulpq:", &asoc->ulpq);
|
||||
sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.ptr,
|
||||
sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.chunk,
|
||||
GFP_ATOMIC);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_EVENT_ULP:
|
||||
/* Send a notification to the sockets layer. */
|
||||
SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
|
||||
"event_up:",cmd->obj.ptr,
|
||||
"event_up:",cmd->obj.ulpevent,
|
||||
"ulpq:",&asoc->ulpq);
|
||||
sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ptr);
|
||||
sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ulpevent);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_REPLY:
|
||||
|
|
@ -1438,12 +1446,12 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
local_cork = 1;
|
||||
}
|
||||
/* Send a chunk to our peer. */
|
||||
error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr);
|
||||
error = sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_SEND_PKT:
|
||||
/* Send a full packet to our peer. */
|
||||
packet = cmd->obj.ptr;
|
||||
packet = cmd->obj.packet;
|
||||
sctp_packet_transmit(packet);
|
||||
sctp_ootb_pkt_free(packet);
|
||||
break;
|
||||
|
|
@ -1480,7 +1488,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
break;
|
||||
|
||||
case SCTP_CMD_SETUP_T2:
|
||||
sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr);
|
||||
sctp_cmd_setup_t2(commands, asoc, cmd->obj.chunk);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_TIMER_START_ONCE:
|
||||
|
|
@ -1514,7 +1522,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
break;
|
||||
|
||||
case SCTP_CMD_INIT_CHOOSE_TRANSPORT:
|
||||
chunk = cmd->obj.ptr;
|
||||
chunk = cmd->obj.chunk;
|
||||
t = sctp_assoc_choose_alter_transport(asoc,
|
||||
asoc->init_last_sent_to);
|
||||
asoc->init_last_sent_to = t;
|
||||
|
|
@ -1665,17 +1673,16 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
break;
|
||||
|
||||
case SCTP_CMD_PART_DELIVER:
|
||||
sctp_ulpq_partial_delivery(&asoc->ulpq, cmd->obj.ptr,
|
||||
GFP_ATOMIC);
|
||||
sctp_ulpq_partial_delivery(&asoc->ulpq, GFP_ATOMIC);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_RENEGE:
|
||||
sctp_ulpq_renege(&asoc->ulpq, cmd->obj.ptr,
|
||||
sctp_ulpq_renege(&asoc->ulpq, cmd->obj.chunk,
|
||||
GFP_ATOMIC);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_SETUP_T4:
|
||||
sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr);
|
||||
sctp_cmd_setup_t4(commands, asoc, cmd->obj.chunk);
|
||||
break;
|
||||
|
||||
case SCTP_CMD_PROCESS_OPERR:
|
||||
|
|
@ -1734,8 +1741,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
|||
break;
|
||||
|
||||
default:
|
||||
pr_warn("Impossible command: %u, %p\n",
|
||||
cmd->verb, cmd->obj.ptr);
|
||||
pr_warn("Impossible command: %u\n",
|
||||
cmd->verb);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1055,6 +1055,7 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
|
|||
void *arg,
|
||||
sctp_cmd_seq_t *commands)
|
||||
{
|
||||
sctp_paramhdr_t *param_hdr;
|
||||
struct sctp_chunk *chunk = arg;
|
||||
struct sctp_chunk *reply;
|
||||
size_t paylen = 0;
|
||||
|
|
@ -1072,12 +1073,17 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
|
|||
* Information field copied from the received HEARTBEAT chunk.
|
||||
*/
|
||||
chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data;
|
||||
param_hdr = (sctp_paramhdr_t *) chunk->subh.hb_hdr;
|
||||
paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
|
||||
|
||||
if (ntohs(param_hdr->length) > paylen)
|
||||
return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
|
||||
param_hdr, commands);
|
||||
|
||||
if (!pskb_pull(chunk->skb, paylen))
|
||||
goto nomem;
|
||||
|
||||
reply = sctp_make_heartbeat_ack(asoc, chunk,
|
||||
chunk->subh.hb_hdr, paylen);
|
||||
reply = sctp_make_heartbeat_ack(asoc, chunk, param_hdr, paylen);
|
||||
if (!reply)
|
||||
goto nomem;
|
||||
|
||||
|
|
@ -1773,8 +1779,10 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net,
|
|||
|
||||
/* Update the content of current association. */
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
|
||||
SCTP_STATE(SCTP_STATE_ESTABLISHED));
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
|
||||
return SCTP_DISPOSITION_CONSUME;
|
||||
|
||||
nomem_ev:
|
||||
|
|
@ -6127,6 +6135,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
|
|||
/* The TSN is too high--silently discard the chunk and
|
||||
* count on it getting retransmitted later.
|
||||
*/
|
||||
if (chunk->asoc)
|
||||
chunk->asoc->stats.outofseqtsns++;
|
||||
return SCTP_IERROR_HIGH_TSN;
|
||||
} else if (tmp > 0) {
|
||||
/* This is a duplicate. Record it. */
|
||||
|
|
@ -6226,10 +6236,14 @@ static int sctp_eat_data(const struct sctp_association *asoc,
|
|||
/* Note: Some chunks may get overcounted (if we drop) or overcounted
|
||||
* if we renege and the chunk arrives again.
|
||||
*/
|
||||
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
|
||||
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
|
||||
SCTP_INC_STATS(net, SCTP_MIB_INUNORDERCHUNKS);
|
||||
else {
|
||||
if (chunk->asoc)
|
||||
chunk->asoc->stats.iuodchunks++;
|
||||
} else {
|
||||
SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS);
|
||||
if (chunk->asoc)
|
||||
chunk->asoc->stats.iodchunks++;
|
||||
ordered = 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ static int sctp_do_bind(struct sock *, union sctp_addr *, int);
|
|||
static int sctp_autobind(struct sock *sk);
|
||||
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;
|
||||
extern long sysctl_sctp_mem[3];
|
||||
|
|
@ -336,6 +335,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
|
|||
/* Bind a local address either to an endpoint or to an association. */
|
||||
SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
|
||||
{
|
||||
struct net *net = sock_net(sk);
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
struct sctp_endpoint *ep = sp->ep;
|
||||
struct sctp_bind_addr *bp = &ep->base.bind_addr;
|
||||
|
|
@ -379,7 +379,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
|
|||
}
|
||||
}
|
||||
|
||||
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
|
||||
if (snum && snum < PROT_SOCK &&
|
||||
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
|
||||
return -EACCES;
|
||||
|
||||
/* See if the address matches any of the addresses we may have
|
||||
|
|
@ -610,6 +611,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
|
|||
2*asoc->pathmtu, 4380));
|
||||
trans->ssthresh = asoc->peer.i.a_rwnd;
|
||||
trans->rto = asoc->rto_initial;
|
||||
sctp_max_rto(asoc, trans);
|
||||
trans->rtt = trans->srtt = trans->rttvar = 0;
|
||||
sctp_transport_route(trans, NULL,
|
||||
sctp_sk(asoc->base.sk));
|
||||
|
|
@ -974,7 +976,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
|
|||
void *addr_buf;
|
||||
struct sctp_af *af;
|
||||
|
||||
SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p"
|
||||
SCTP_DEBUG_PRINTK("sctp_setsockopt_bindx: sk %p addrs %p"
|
||||
" addrs_size %d opt %d\n", sk, addrs, addrs_size, op);
|
||||
|
||||
if (unlikely(addrs_size <= 0))
|
||||
|
|
@ -1162,7 +1164,7 @@ static int __sctp_connect(struct sock* sk,
|
|||
* be permitted to open new associations.
|
||||
*/
|
||||
if (ep->base.bind_addr.port < PROT_SOCK &&
|
||||
!capable(CAP_NET_BIND_SERVICE)) {
|
||||
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) {
|
||||
err = -EACCES;
|
||||
goto out_free;
|
||||
}
|
||||
|
|
@ -1791,7 +1793,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
|
|||
* associations.
|
||||
*/
|
||||
if (ep->base.bind_addr.port < PROT_SOCK &&
|
||||
!capable(CAP_NET_BIND_SERVICE)) {
|
||||
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) {
|
||||
err = -EACCES;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
@ -1915,8 +1917,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
|
|||
|
||||
/* Break the message into multiple chunks of maximum size. */
|
||||
datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len);
|
||||
if (!datamsg) {
|
||||
err = -ENOMEM;
|
||||
if (IS_ERR(datamsg)) {
|
||||
err = PTR_ERR(datamsg);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
|
|
@ -3890,6 +3892,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
|
|||
sp->default_rcv_context = 0;
|
||||
sp->max_burst = net->sctp.max_burst;
|
||||
|
||||
sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg;
|
||||
|
||||
/* Initialize default setup parameters. These parameters
|
||||
* can be modified with the SCTP_INITMSG socket option or
|
||||
* overridden by the SCTP_INIT CMSG.
|
||||
|
|
@ -5632,6 +5636,71 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SCTP_GET_ASSOC_STATS
|
||||
*
|
||||
* This option retrieves local per endpoint statistics. It is modeled
|
||||
* after OpenSolaris' implementation
|
||||
*/
|
||||
static int sctp_getsockopt_assoc_stats(struct sock *sk, int len,
|
||||
char __user *optval,
|
||||
int __user *optlen)
|
||||
{
|
||||
struct sctp_assoc_stats sas;
|
||||
struct sctp_association *asoc = NULL;
|
||||
|
||||
/* User must provide at least the assoc id */
|
||||
if (len < sizeof(sctp_assoc_t))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&sas, optval, len))
|
||||
return -EFAULT;
|
||||
|
||||
asoc = sctp_id2assoc(sk, sas.sas_assoc_id);
|
||||
if (!asoc)
|
||||
return -EINVAL;
|
||||
|
||||
sas.sas_rtxchunks = asoc->stats.rtxchunks;
|
||||
sas.sas_gapcnt = asoc->stats.gapcnt;
|
||||
sas.sas_outofseqtsns = asoc->stats.outofseqtsns;
|
||||
sas.sas_osacks = asoc->stats.osacks;
|
||||
sas.sas_isacks = asoc->stats.isacks;
|
||||
sas.sas_octrlchunks = asoc->stats.octrlchunks;
|
||||
sas.sas_ictrlchunks = asoc->stats.ictrlchunks;
|
||||
sas.sas_oodchunks = asoc->stats.oodchunks;
|
||||
sas.sas_iodchunks = asoc->stats.iodchunks;
|
||||
sas.sas_ouodchunks = asoc->stats.ouodchunks;
|
||||
sas.sas_iuodchunks = asoc->stats.iuodchunks;
|
||||
sas.sas_idupchunks = asoc->stats.idupchunks;
|
||||
sas.sas_opackets = asoc->stats.opackets;
|
||||
sas.sas_ipackets = asoc->stats.ipackets;
|
||||
|
||||
/* New high max rto observed, will return 0 if not a single
|
||||
* RTO update took place. obs_rto_ipaddr will be bogus
|
||||
* in such a case
|
||||
*/
|
||||
sas.sas_maxrto = asoc->stats.max_obs_rto;
|
||||
memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr,
|
||||
sizeof(struct sockaddr_storage));
|
||||
|
||||
/* Mark beginning of a new observation period */
|
||||
asoc->stats.max_obs_rto = asoc->rto_min;
|
||||
|
||||
/* Allow the struct to grow and fill in as much as possible */
|
||||
len = min_t(size_t, len, sizeof(sas));
|
||||
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
SCTP_DEBUG_PRINTK("sctp_getsockopt_assoc_stat(%d): %d\n",
|
||||
len, sas.sas_assoc_id);
|
||||
|
||||
if (copy_to_user(optval, &sas, len))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
|
|
@ -5773,6 +5842,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
|
|||
case SCTP_PEER_ADDR_THLDS:
|
||||
retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen);
|
||||
break;
|
||||
case SCTP_GET_ASSOC_STATS:
|
||||
retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
|
||||
break;
|
||||
default:
|
||||
retval = -ENOPROTOOPT;
|
||||
break;
|
||||
|
|
@ -5981,13 +6053,15 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
|
|||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
struct sctp_endpoint *ep = sp->ep;
|
||||
struct crypto_hash *tfm = NULL;
|
||||
char alg[32];
|
||||
|
||||
/* Allocate HMAC for generating cookie. */
|
||||
if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
|
||||
tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (!sp->hmac && sp->sctp_hmac_alg) {
|
||||
sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg);
|
||||
tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm)) {
|
||||
net_info_ratelimited("failed to load transform for %s: %ld\n",
|
||||
sctp_hmac_alg, PTR_ERR(tfm));
|
||||
sp->sctp_hmac_alg, PTR_ERR(tfm));
|
||||
return -ENOSYS;
|
||||
}
|
||||
sctp_sk(sk)->hmac = tfm;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,11 @@ extern long sysctl_sctp_mem[3];
|
|||
extern int sysctl_sctp_rmem[3];
|
||||
extern int sysctl_sctp_wmem[3];
|
||||
|
||||
static int proc_sctp_do_hmac_alg(ctl_table *ctl,
|
||||
int write,
|
||||
void __user *buffer, size_t *lenp,
|
||||
|
||||
loff_t *ppos);
|
||||
static ctl_table sctp_table[] = {
|
||||
{
|
||||
.procname = "sctp_mem",
|
||||
|
|
@ -146,6 +151,12 @@ static ctl_table sctp_net_table[] = {
|
|||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "cookie_hmac_alg",
|
||||
.maxlen = 8,
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_sctp_do_hmac_alg,
|
||||
},
|
||||
{
|
||||
.procname = "valid_cookie_life",
|
||||
.data = &init_net.sctp.valid_cookie_life,
|
||||
|
|
@ -289,6 +300,54 @@ static ctl_table sctp_net_table[] = {
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int proc_sctp_do_hmac_alg(ctl_table *ctl,
|
||||
int write,
|
||||
void __user *buffer, size_t *lenp,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct net *net = current->nsproxy->net_ns;
|
||||
char tmp[8];
|
||||
ctl_table tbl;
|
||||
int ret;
|
||||
int changed = 0;
|
||||
char *none = "none";
|
||||
|
||||
memset(&tbl, 0, sizeof(struct ctl_table));
|
||||
|
||||
if (write) {
|
||||
tbl.data = tmp;
|
||||
tbl.maxlen = 8;
|
||||
} else {
|
||||
tbl.data = net->sctp.sctp_hmac_alg ? : none;
|
||||
tbl.maxlen = strlen(tbl.data);
|
||||
}
|
||||
ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
|
||||
|
||||
if (write) {
|
||||
#ifdef CONFIG_CRYPTO_MD5
|
||||
if (!strncmp(tmp, "md5", 3)) {
|
||||
net->sctp.sctp_hmac_alg = "md5";
|
||||
changed = 1;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_CRYPTO_SHA1
|
||||
if (!strncmp(tmp, "sha1", 4)) {
|
||||
net->sctp.sctp_hmac_alg = "sha1";
|
||||
changed = 1;
|
||||
}
|
||||
#endif
|
||||
if (!strncmp(tmp, "none", 4)) {
|
||||
net->sctp.sctp_hmac_alg = NULL;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sctp_sysctl_net_register(struct net *net)
|
||||
{
|
||||
struct ctl_table *table;
|
||||
|
|
@ -307,7 +366,11 @@ int sctp_sysctl_net_register(struct net *net)
|
|||
|
||||
void sctp_sysctl_net_unregister(struct net *net)
|
||||
{
|
||||
struct ctl_table *table;
|
||||
|
||||
table = net->sctp.sysctl_header->ctl_table_arg;
|
||||
unregister_net_sysctl_table(net->sctp.sysctl_header);
|
||||
kfree(table);
|
||||
}
|
||||
|
||||
static struct ctl_table_header * sctp_sysctl_header;
|
||||
|
|
|
|||
|
|
@ -163,13 +163,11 @@ void sctp_transport_free(struct sctp_transport *transport)
|
|||
sctp_transport_put(transport);
|
||||
}
|
||||
|
||||
/* Destroy the transport data structure.
|
||||
* Assumes there are no more users of this structure.
|
||||
*/
|
||||
static void sctp_transport_destroy(struct sctp_transport *transport)
|
||||
static void sctp_transport_destroy_rcu(struct rcu_head *head)
|
||||
{
|
||||
SCTP_ASSERT(transport->dead, "Transport is not dead", return);
|
||||
struct sctp_transport *transport;
|
||||
|
||||
transport = container_of(head, struct sctp_transport, rcu);
|
||||
if (transport->asoc)
|
||||
sctp_association_put(transport->asoc);
|
||||
|
||||
|
|
@ -180,6 +178,16 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
|
|||
SCTP_DBG_OBJCNT_DEC(transport);
|
||||
}
|
||||
|
||||
/* Destroy the transport data structure.
|
||||
* Assumes there are no more users of this structure.
|
||||
*/
|
||||
static void sctp_transport_destroy(struct sctp_transport *transport)
|
||||
{
|
||||
SCTP_ASSERT(transport->dead, "Transport is not dead", return);
|
||||
|
||||
call_rcu(&transport->rcu, sctp_transport_destroy_rcu);
|
||||
}
|
||||
|
||||
/* Start T3_rtx timer if it is not already running and update the heartbeat
|
||||
* timer. This routine is called every time a DATA chunk is sent.
|
||||
*/
|
||||
|
|
@ -331,7 +339,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
|
|||
* 1/8, rto_alpha would be expressed as 3.
|
||||
*/
|
||||
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta)
|
||||
+ ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta);
|
||||
+ (((__u32)abs64((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta);
|
||||
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha)
|
||||
+ (rtt >> net->sctp.rto_alpha);
|
||||
} else {
|
||||
|
|
@ -363,6 +371,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
|
|||
if (tp->rto > tp->asoc->rto_max)
|
||||
tp->rto = tp->asoc->rto_max;
|
||||
|
||||
sctp_max_rto(tp->asoc, tp);
|
||||
tp->rtt = rtt;
|
||||
|
||||
/* Reset rto_pending so that a new RTT measurement is started when a
|
||||
|
|
@ -620,6 +629,7 @@ void sctp_transport_reset(struct sctp_transport *t)
|
|||
t->burst_limited = 0;
|
||||
t->ssthresh = asoc->peer.i.a_rwnd;
|
||||
t->rto = asoc->rto_initial;
|
||||
sctp_max_rto(asoc, t);
|
||||
t->rtt = 0;
|
||||
t->srtt = 0;
|
||||
t->rttvar = 0;
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
|
|||
__u32 max_tsn = map->max_tsn_seen;
|
||||
__u32 base_tsn = map->base_tsn;
|
||||
__u16 pending_data;
|
||||
u32 gap, i;
|
||||
u32 gap;
|
||||
|
||||
pending_data = max_tsn - cum_tsn;
|
||||
gap = max_tsn - base_tsn;
|
||||
|
|
@ -280,11 +280,7 @@ __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
|
|||
if (gap == 0 || gap >= map->len)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < gap+1; i++) {
|
||||
if (test_bit(i, map->tsn_map))
|
||||
pending_data--;
|
||||
}
|
||||
|
||||
pending_data -= bitmap_weight(map->tsn_map, gap + 1);
|
||||
out:
|
||||
return pending_data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -997,7 +997,6 @@ static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed)
|
|||
|
||||
/* Partial deliver the first message as there is pressure on rwnd. */
|
||||
void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
|
||||
struct sctp_chunk *chunk,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct sctp_ulpevent *event;
|
||||
|
|
@ -1060,7 +1059,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
|
|||
sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
|
||||
sctp_ulpq_tail_data(ulpq, chunk, gfp);
|
||||
|
||||
sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
|
||||
sctp_ulpq_partial_delivery(ulpq, gfp);
|
||||
}
|
||||
|
||||
sk_mem_reclaim(asoc->base.sk);
|
||||
|
|
|
|||
Loading…
Reference in a new issue