summaryrefslogtreecommitdiff
path: root/net/sctp
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-12-29 13:09:40 +0100
committerIngo Molnar <mingo@elte.hu>2008-12-29 13:09:40 +0100
commit75329f1f0c0e2e2ad611734a2ef08309391a4d9f (patch)
tree67ca1a13f51fbf2f5af8557e6ff0bb722efab3e6 /net/sctp
parentb6b301aa9fba57b114c3a00f5f43abf672bd4ecd (diff)
parent3c92ec8ae91ecf59d88c798301833d7cf83f2179 (diff)
Merge branch 'linus' into x86/cleanups
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/ipv6.c35
-rw-r--r--net/sctp/protocol.c29
-rw-r--r--net/sctp/sm_statefuns.c24
-rw-r--r--net/sctp/socket.c206
-rw-r--r--net/sctp/sysctl.c82
5 files changed, 262 insertions, 114 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 4124bbb99947..ceaa4aa066ea 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -223,10 +223,9 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
}
- SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
- "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
+ SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
__func__, skb, skb->len,
- NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
+ &fl.fl6_src, &fl.fl6_dst);
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
@@ -252,23 +251,19 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
fl.oif = daddr->v6.sin6_scope_id;
- SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
- __func__, NIP6(fl.fl6_dst));
+ SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst);
if (saddr) {
ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK(
- "SRC=" NIP6_FMT " - ",
- NIP6(fl.fl6_src));
+ SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src);
}
dst = ip6_route_output(&init_net, NULL, &fl);
if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
- SCTP_DEBUG_PRINTK(
- "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
- NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
+ SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
+ &rt->rt6i_dst.addr, &rt->rt6i_src.addr);
return dst;
}
SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -314,9 +309,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
__u8 matchlen = 0;
__u8 bmatchlen;
- SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
- "daddr:" NIP6_FMT " ",
- __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+ SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
+ __func__, asoc, dst, &daddr->v6.sin6_addr);
if (!asoc) {
ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
@@ -324,8 +318,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
&daddr->v6.sin6_addr,
inet6_sk(&sk->inet.sk)->srcprefs,
&saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
- NIP6(saddr->v6.sin6_addr));
+ SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
+ &saddr->v6.sin6_addr);
return;
}
@@ -353,12 +347,11 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
if (baddr) {
memcpy(saddr, baddr, sizeof(union sctp_addr));
- SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
- NIP6(saddr->v6.sin6_addr));
+ SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
} else {
printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
- "address for the dest:" NIP6_FMT "\n",
- __func__, asoc, NIP6(daddr->v6.sin6_addr));
+ "address for the dest:%pI6\n",
+ __func__, asoc, &daddr->v6.sin6_addr);
}
rcu_read_unlock();
@@ -727,7 +720,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, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
+ seq_printf(seq, "%pI6 ", &addr->v6.sin6_addr);
}
static void sctp_v6_ecn_capable(struct sock *sk)
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 0b65354aaf64..b78e3be69013 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -102,6 +102,8 @@ struct sock *sctp_get_ctl_sock(void)
/* Set up the proc fs entry for the SCTP protocol. */
static __init int sctp_proc_init(void)
{
+ if (percpu_counter_init(&sctp_sockets_allocated, 0))
+ goto out_nomem;
#ifdef CONFIG_PROC_FS
if (!proc_net_sctp) {
struct proc_dir_entry *ent;
@@ -110,7 +112,7 @@ static __init int sctp_proc_init(void)
ent->owner = THIS_MODULE;
proc_net_sctp = ent;
} else
- goto out_nomem;
+ goto out_free_percpu;
}
if (sctp_snmp_proc_init())
@@ -135,11 +137,14 @@ out_snmp_proc_init:
proc_net_sctp = NULL;
remove_proc_entry("sctp", init_net.proc_net);
}
-out_nomem:
- return -ENOMEM;
+out_free_percpu:
+ percpu_counter_destroy(&sctp_sockets_allocated);
#else
return 0;
#endif /* CONFIG_PROC_FS */
+
+out_nomem:
+ return -ENOMEM;
}
/* Clean up the proc fs entry for the SCTP protocol.
@@ -482,9 +487,8 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
if (saddr)
fl.fl4_src = saddr->v4.sin_addr.s_addr;
- SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
- __func__, NIPQUAD(fl.fl4_dst),
- NIPQUAD(fl.fl4_src));
+ SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
+ __func__, &fl.fl4_dst, &fl.fl4_src);
if (!ip_route_output_key(&init_net, &rt, &fl)) {
dst = &rt->u.dst;
@@ -540,8 +544,8 @@ out_unlock:
rcu_read_unlock();
out:
if (dst)
- SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
- NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_src));
+ SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n",
+ &rt->rt_dst, &rt->rt_src);
else
SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -646,7 +650,7 @@ static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
/* Dump the v4 addr to the seq file. */
static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
{
- seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
+ seq_printf(seq, "%pI4 ", &addr->v4.sin_addr);
}
static void sctp_v4_ecn_capable(struct sock *sk)
@@ -866,11 +870,10 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
{
struct inet_sock *inet = inet_sk(skb->sk);
- SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
- "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
+ SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n",
__func__, skb, skb->len,
- NIPQUAD(skb->rtable->rt_src),
- NIPQUAD(skb->rtable->rt_dst));
+ &skb->rtable->rt_src,
+ &skb->rtable->rt_dst);
inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index a6a0ea71ae93..1c4e5d6c29c0 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1123,19 +1123,17 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
if (from_addr.sa.sa_family == AF_INET6) {
if (net_ratelimit())
printk(KERN_WARNING
- "%s association %p could not find address "
- NIP6_FMT "\n",
+ "%s association %p could not find address %pI6\n",
__func__,
asoc,
- NIP6(from_addr.v6.sin6_addr));
+ &from_addr.v6.sin6_addr);
} else {
if (net_ratelimit())
printk(KERN_WARNING
- "%s association %p could not find address "
- NIPQUAD_FMT "\n",
+ "%s association %p could not find address %pI4\n",
__func__,
asoc,
- NIPQUAD(from_addr.v4.sin_addr.s_addr));
+ &from_addr.v4.sin_addr.s_addr);
}
return SCTP_DISPOSITION_DISCARD;
}
@@ -3691,6 +3689,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
{
struct sctp_chunk *chunk = arg;
struct sctp_fwdtsn_hdr *fwdtsn_hdr;
+ struct sctp_fwdtsn_skip *skip;
__u16 len;
__u32 tsn;
@@ -3720,6 +3719,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0)
goto discard_noforce;
+ /* Silently discard the chunk if stream-id is not valid */
+ sctp_walk_fwdtsn(skip, chunk) {
+ if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams)
+ goto discard_noforce;
+ }
+
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
if (len > sizeof(struct sctp_fwdtsn_hdr))
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN,
@@ -3751,6 +3756,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
{
struct sctp_chunk *chunk = arg;
struct sctp_fwdtsn_hdr *fwdtsn_hdr;
+ struct sctp_fwdtsn_skip *skip;
__u16 len;
__u32 tsn;
@@ -3780,6 +3786,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0)
goto gen_shutdown;
+ /* Silently discard the chunk if stream-id is not valid */
+ sctp_walk_fwdtsn(skip, chunk) {
+ if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams)
+ goto gen_shutdown;
+ }
+
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
if (len > sizeof(struct sctp_fwdtsn_hdr))
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN,
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1b904529d5e..b14a8f33e42d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -114,7 +114,7 @@ extern int sysctl_sctp_wmem[3];
static int sctp_memory_pressure;
static atomic_t sctp_memory_allocated;
-static atomic_t sctp_sockets_allocated;
+struct percpu_counter sctp_sockets_allocated;
static void sctp_enter_memory_pressure(struct sock *sk)
{
@@ -2404,9 +2404,9 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
if (params.sack_delay == 0 && params.sack_freq == 0)
return 0;
} else if (optlen == sizeof(struct sctp_assoc_value)) {
- printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+ printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
"in delayed_ack socket option deprecated\n");
- printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+ printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
@@ -2778,32 +2778,77 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op
}
/*
- * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
- *
- * This socket option specifies the maximum size to put in any outgoing
- * SCTP chunk. If a message is larger than this size it will be
+ * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
+ * This option will get or set the maximum size to put in any outgoing
+ * SCTP DATA chunk. If a message is larger than this size it will be
* fragmented by SCTP into the specified size. Note that the underlying
* SCTP implementation may fragment into smaller sized chunks when the
* PMTU of the underlying association is smaller than the value set by
- * the user.
+ * the user. The default value for this option is '0' which indicates
+ * the user is NOT limiting fragmentation and only the PMTU will effect
+ * SCTP's choice of DATA chunk size. Note also that values set larger
+ * than the maximum size of an IP datagram will effectively let SCTP
+ * control fragmentation (i.e. the same as setting this option to 0).
+ *
+ * The following structure is used to access and modify this parameter:
+ *
+ * struct sctp_assoc_value {
+ * sctp_assoc_t assoc_id;
+ * uint32_t assoc_value;
+ * };
+ *
+ * assoc_id: This parameter is ignored for one-to-one style sockets.
+ * For one-to-many style sockets this parameter indicates which
+ * association the user is performing an action upon. Note that if
+ * this field's value is zero then the endpoints default value is
+ * changed (effecting future associations only).
+ * assoc_value: This parameter specifies the maximum size in bytes.
*/
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen)
{
+ struct sctp_assoc_value params;
struct sctp_association *asoc;
struct sctp_sock *sp = sctp_sk(sk);
int val;
- if (optlen < sizeof(int))
+ if (optlen == sizeof(int)) {
+ printk(KERN_WARNING
+ "SCTP: Use of int in maxseg socket option deprecated\n");
+ printk(KERN_WARNING
+ "SCTP: Use struct sctp_assoc_value instead\n");
+ if (copy_from_user(&val, optval, optlen))
+ return -EFAULT;
+ params.assoc_id = 0;
+ } else if (optlen == sizeof(struct sctp_assoc_value)) {
+ if (copy_from_user(&params, optval, optlen))
+ return -EFAULT;
+ val = params.assoc_value;
+ } else
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
+
if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
return -EINVAL;
- sp->user_frag = val;
- /* Update the frag_point of the existing associations. */
- list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
- asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
+ asoc = sctp_id2assoc(sk, params.assoc_id);
+ if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
+
+ if (asoc) {
+ if (val == 0) {
+ val = asoc->pathmtu;
+ val -= sp->pf->af->net_header_len;
+ val -= sizeof(struct sctphdr) +
+ sizeof(struct sctp_data_chunk);
+ }
+
+ asoc->frag_point = val;
+ } else {
+ sp->user_frag = val;
+
+ /* Update the frag_point of the existing associations. */
+ list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+ asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
+ }
}
return 0;
@@ -2965,14 +3010,21 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk,
}
/*
- * 7.1.25. Set or Get the sctp partial delivery point
+ * 8.1.21. Set or Get the SCTP Partial Delivery Point
* (SCTP_PARTIAL_DELIVERY_POINT)
+ *
* This option will set or get the SCTP partial delivery point. This
* point is the size of a message where the partial delivery API will be
* invoked to help free up rwnd space for the peer. Setting this to a
- * lower value will cause partial delivery's to happen more often. The
+ * lower value will cause partial deliveries to happen more often. The
* calls argument is an integer that sets or gets the partial delivery
- * point.
+ * point. Note also that the call will fail if the user attempts to set
+ * this value larger than the socket receive buffer size.
+ *
+ * Note that any single message having a length smaller than or equal to
+ * the SCTP partial delivery point will be delivered in one single read
+ * call as long as the user provided buffer is large enough to hold the
+ * message.
*/
static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
char __user *optval,
@@ -2985,6 +3037,12 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
if (get_user(val, (int __user *)optval))
return -EFAULT;
+ /* Note: We double the receive buffer from what the user sets
+ * it to be, also initial rwnd is based on rcvbuf/2.
+ */
+ if (val > (sk->sk_rcvbuf >> 1))
+ return -EINVAL;
+
sctp_sk(sk)->pd_point = val;
return 0; /* is this the right error code? */
@@ -3613,7 +3671,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->hmac = NULL;
SCTP_DBG_OBJCNT_INC(sock);
- atomic_inc(&sctp_sockets_allocated);
+ percpu_counter_inc(&sctp_sockets_allocated);
+
+ local_bh_disable();
+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+ local_bh_enable();
+
return 0;
}
@@ -3627,7 +3690,10 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
/* Release our hold on the endpoint. */
ep = sctp_sk(sk)->ep;
sctp_endpoint_free(ep);
- atomic_dec(&sctp_sockets_allocated);
+ percpu_counter_dec(&sctp_sockets_allocated);
+ local_bh_disable();
+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+ local_bh_enable();
}
/* API 4.1.7 shutdown() - TCP Style Syntax
@@ -4168,9 +4234,9 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
if (copy_from_user(&params, optval, len))
return -EFAULT;
} else if (len == sizeof(struct sctp_assoc_value)) {
- printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+ printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
"in delayed_ack socket option deprecated\n");
- printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+ printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
if (copy_from_user(&params, optval, len))
return -EFAULT;
} else
@@ -5092,30 +5158,69 @@ static int sctp_getsockopt_context(struct sock *sk, int len,
}
/*
- * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
- *
- * This socket option specifies the maximum size to put in any outgoing
- * SCTP chunk. If a message is larger than this size it will be
+ * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
+ * This option will get or set the maximum size to put in any outgoing
+ * SCTP DATA chunk. If a message is larger than this size it will be
* fragmented by SCTP into the specified size. Note that the underlying
* SCTP implementation may fragment into smaller sized chunks when the
* PMTU of the underlying association is smaller than the value set by
- * the user.
+ * the user. The default value for this option is '0' which indicates
+ * the user is NOT limiting fragmentation and only the PMTU will effect
+ * SCTP's choice of DATA chunk size. Note also that values set larger
+ * than the maximum size of an IP datagram will effectively let SCTP
+ * control fragmentation (i.e. the same as setting this option to 0).
+ *
+ * The following structure is used to access and modify this parameter:
+ *
+ * struct sctp_assoc_value {
+ * sctp_assoc_t assoc_id;
+ * uint32_t assoc_value;
+ * };
+ *
+ * assoc_id: This parameter is ignored for one-to-one style sockets.
+ * For one-to-many style sockets this parameter indicates which
+ * association the user is performing an action upon. Note that if
+ * this field's value is zero then the endpoints default value is
+ * changed (effecting future associations only).
+ * assoc_value: This parameter specifies the maximum size in bytes.
*/
static int sctp_getsockopt_maxseg(struct sock *sk, int len,
char __user *optval, int __user *optlen)
{
- int val;
+ struct sctp_assoc_value params;
+ struct sctp_association *asoc;
- if (len < sizeof(int))
+ if (len == sizeof(int)) {
+ printk(KERN_WARNING
+ "SCTP: Use of int in maxseg socket option deprecated\n");
+ printk(KERN_WARNING
+ "SCTP: Use struct sctp_assoc_value instead\n");
+ params.assoc_id = 0;
+ } else if (len >= sizeof(struct sctp_assoc_value)) {
+ len = sizeof(struct sctp_assoc_value);
+ if (copy_from_user(&params, optval, sizeof(params)))
+ return -EFAULT;
+ } else
return -EINVAL;
- len = sizeof(int);
+ asoc = sctp_id2assoc(sk, params.assoc_id);
+ if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
+
+ if (asoc)
+ params.assoc_value = asoc->frag_point;
+ else
+ params.assoc_value = sctp_sk(sk)->user_frag;
- val = sctp_sk(sk)->user_frag;
if (put_user(len, optlen))
return -EFAULT;
- if (copy_to_user(optval, &val, len))
- return -EFAULT;
+ if (len == sizeof(int)) {
+ if (copy_to_user(optval, &params.assoc_value, len))
+ return -EFAULT;
+ } else {
+ if (copy_to_user(optval, &params, len))
+ return -EFAULT;
+ }
return 0;
}
@@ -5368,6 +5473,38 @@ num:
return 0;
}
+/*
+ * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER)
+ * This option gets the current number of associations that are attached
+ * to a one-to-many style socket. The option value is an uint32_t.
+ */
+static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_sock *sp = sctp_sk(sk);
+ struct sctp_association *asoc;
+ u32 val = 0;
+
+ if (sctp_style(sk, TCP))
+ return -EOPNOTSUPP;
+
+ if (len < sizeof(u32))
+ return -EINVAL;
+
+ len = sizeof(u32);
+
+ list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+ val++;
+ }
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &val, len))
+ return -EFAULT;
+
+ return 0;
+}
+
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
@@ -5510,6 +5647,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
optlen);
break;
+ case SCTP_GET_ASSOC_NUMBER:
+ retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 52910697e104..f58e994e6852 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -63,8 +63,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_rto_initial,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &timer_max
},
@@ -74,8 +74,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_rto_min,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &timer_max
},
@@ -85,8 +85,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_rto_max,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &timer_max
},
@@ -96,8 +96,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_valid_cookie_life,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &timer_max
},
@@ -107,8 +107,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_max_burst,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &zero,
.extra2 = &int_max
},
@@ -118,8 +118,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_max_retrans_association,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &int_max
},
@@ -129,8 +129,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_sndbuf_policy,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_RCVBUF_POLICY,
@@ -138,8 +138,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_rcvbuf_policy,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_PATH_MAX_RETRANS,
@@ -147,8 +147,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_max_retrans_path,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &int_max
},
@@ -158,8 +158,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_max_retrans_init,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &int_max
},
@@ -169,8 +169,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_hb_interval,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &one,
.extra2 = &timer_max
},
@@ -180,8 +180,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_cookie_preserve_enable,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_RTO_ALPHA,
@@ -189,8 +189,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_rto_alpha,
.maxlen = sizeof(int),
.mode = 0444,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_RTO_BETA,
@@ -198,8 +198,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_rto_beta,
.maxlen = sizeof(int),
.mode = 0444,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_ADDIP_ENABLE,
@@ -207,8 +207,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_addip_enable,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_PRSCTP_ENABLE,
@@ -216,8 +216,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_prsctp_enable,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = NET_SCTP_SACK_TIMEOUT,
@@ -225,8 +225,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_sack_timeout,
.maxlen = sizeof(long),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
+ .strategy = sysctl_intvec,
.extra1 = &sack_timer_min,
.extra2 = &sack_timer_max,
},
@@ -236,7 +236,7 @@ static ctl_table sctp_table[] = {
.data = &sysctl_sctp_mem,
.maxlen = sizeof(sysctl_sctp_mem),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
@@ -244,7 +244,7 @@ static ctl_table sctp_table[] = {
.data = &sysctl_sctp_rmem,
.maxlen = sizeof(sysctl_sctp_rmem),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
@@ -252,7 +252,7 @@ static ctl_table sctp_table[] = {
.data = &sysctl_sctp_wmem,
.maxlen = sizeof(sysctl_sctp_wmem),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
@@ -260,8 +260,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_auth_enable,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{
.ctl_name = CTL_UNNUMBERED,
@@ -269,8 +269,8 @@ static ctl_table sctp_table[] = {
.data = &sctp_addip_noauth,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec
+ .proc_handler = proc_dointvec,
+ .strategy = sysctl_intvec
},
{ .ctl_name = 0 }
};