#include <linux/poll.h>
#include <linux/init.h>
#include <linux/crypto.h>
+#include <linux/slab.h>
#include <net/ip.h>
#include <net/icmp.h>
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)
{
if (asoc->ep->sndbuf_policy)
amt = asoc->sndbuf_used;
else
- amt = atomic_read(&asoc->base.sk->sk_wmem_alloc);
+ amt = sk_wmem_alloc_get(asoc->base.sk);
if (amt >= asoc->base.sk->sk_sndbuf) {
if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK)
/* Refresh ephemeral port. */
if (!bp->port)
- bp->port = inet_sk(sk)->num;
+ bp->port = inet_sk(sk)->inet_num;
/* Add the address to the bind address list.
* Use GFP_ATOMIC since BHs will be disabled.
/* Copy back into socket for getsockname() use. */
if (!ret) {
- inet_sk(sk)->sport = htons(inet_sk(sk)->num);
+ inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
af->to_sk_saddr(addr, sk);
}
err = -ENOMEM;
goto out_free;
}
+
+ err = sctp_assoc_set_bind_addr_from_ep(asoc, scope,
+ GFP_KERNEL);
+ if (err < 0) {
+ goto out_free;
+ }
+
}
/* Prime the peer's transport structures. */
walk_size += af->sockaddr_len;
}
- err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);
- if (err < 0) {
- goto out_free;
+ /* In case the user of sctp_connectx() wants an association
+ * id back, assign one now.
+ */
+ if (assoc_id) {
+ err = sctp_assoc_set_id(asoc, GFP_KERNEL);
+ if (err < 0)
+ goto out_free;
}
err = sctp_primitive_ASSOCIATE(asoc, NULL);
}
/* Initialize sk's dport and daddr for getpeername() */
- inet_sk(sk)->dport = htons(asoc->peer.port);
+ inet_sk(sk)->inet_dport = htons(asoc->peer.port);
af = sctp_get_af_specific(sa_addr->sa.sa_family);
af->to_sk_daddr(sa_addr, sk);
sk->sk_err = 0;
timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
err = sctp_wait_for_connect(asoc, &timeo);
- if (!err && assoc_id)
+ if ((err == 0 || err == -EINPROGRESS) && assoc_id)
*assoc_id = asoc->assoc_id;
/* Don't free association on exit. */
return assoc_id;
}
+/*
+ * New (hopefully final) interface for the API.
+ * We use the sctp_getaddrs_old structure so that use-space library
+ * can avoid any unnecessary allocations. The only defferent part
+ * is that we store the actual length of the address buffer into the
+ * addrs_num structure member. That way we can re-use the existing
+ * code.
+ */
+SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
+ char __user *optval,
+ int __user *optlen)
+{
+ struct sctp_getaddrs_old param;
+ sctp_assoc_t assoc_id = 0;
+ int err = 0;
+
+ if (len < sizeof(param))
+ return -EINVAL;
+
+ if (copy_from_user(¶m, optval, sizeof(param)))
+ return -EFAULT;
+
+ err = __sctp_setsockopt_connectx(sk,
+ (struct sockaddr __user *)param.addrs,
+ param.addr_num, &assoc_id);
+
+ if (err == 0 || err == -EINPROGRESS) {
+ if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
+ return -EFAULT;
+ if (put_user(sizeof(assoc_id), optlen))
+ return -EFAULT;
+ }
+
+ return err;
+}
+
/* API 3.1.4 close() - UDP Style Syntax
* Applications use close() to perform graceful shutdown (as described in
* Section 10.1 of [SCTP]) on ALL the associations currently represented
sctp_lock_sock(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
+ sk->sk_state = SCTP_SS_CLOSING;
ep = sctp_sk(sk)->ep;
goto out_unlock;
}
asoc = new_asoc;
+ err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL);
+ if (err < 0) {
+ err = -ENOMEM;
+ goto out_free;
+ }
/* If the SCTP_INIT ancillary data is specified, set all
* the association init values accordingly.
err = -ENOMEM;
goto out_free;
}
- err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);
- if (err < 0) {
- err = -ENOMEM;
- goto out_free;
- }
}
/* ASSERT: we have a valid association at this point. */
sctp_set_owner_w(chunk);
chunk->transport = chunk_tp;
-
- /* Send it to the lower layers. Note: all chunks
- * must either fail or succeed. The lower layer
- * works that way today. Keep it that way or this
- * breaks.
- */
- err = sctp_primitive_SEND(asoc, chunk);
- /* Did the lower layer accept the chunk? */
- if (err)
- sctp_chunk_free(chunk);
- SCTP_DEBUG_PRINTK("We sent primitively.\n");
}
- sctp_datamsg_put(datamsg);
+ /* Send it to the lower layers. Note: all chunks
+ * must either fail or succeed. The lower layer
+ * works that way today. Keep it that way or this
+ * breaks.
+ */
+ err = sctp_primitive_SEND(asoc, datamsg);
+ /* Did the lower layer accept the chunk? */
+ if (err)
+ sctp_datamsg_free(datamsg);
+ else
+ sctp_datamsg_put(datamsg);
+
+ SCTP_DEBUG_PRINTK("We sent primitively.\n");
+
if (err)
goto out_free;
else
len -= skb_len;
__skb_pull(skb, skb_len);
- for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
+ skb_walk_frags(skb, list) {
rlen = sctp_skb_pull(list, len);
skb->len -= (len-rlen);
skb->data_len -= (len-rlen);
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (sctp_ulpevent_is_notification(event)) {
msg->msg_flags |= MSG_NOTIFICATION;
sp->pf->event_msgname(event, msg->msg_name, addr_len);
* instead a error will be indicated to the user.
*/
static int sctp_setsockopt_disable_fragments(struct sock *sk,
- char __user *optval, int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
int val;
}
static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
if (optlen > sizeof(struct sctp_event_subscribe))
return -EINVAL;
* association is closed.
*/
static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
return -EINVAL;
if (copy_from_user(&sp->autoclose, optval, optlen))
return -EFAULT;
+ /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */
+ sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ);
return 0;
}
sctp_assoc_sync_pmtu(asoc);
} else if (asoc) {
asoc->pathmtu = params->spp_pathmtu;
- sctp_frag_point(sp, params->spp_pathmtu);
+ sctp_frag_point(asoc, params->spp_pathmtu);
} else {
sp->pathmtu = params->spp_pathmtu;
}
}
}
- /* Note that unless the spp_flag is set to SPP_PMTUD_ENABLE the value
- * of this field is ignored. Note also that a value of zero
- * indicates the current setting should be left unchanged.
+ /* Note that a value of zero indicates the current setting should be
+ left unchanged.
*/
- if ((params->spp_flags & SPP_PMTUD_ENABLE) && params->spp_pathmaxrxt) {
+ if (params->spp_pathmaxrxt) {
if (trans) {
trans->pathmaxrxt = params->spp_pathmaxrxt;
} else if (asoc) {
}
static int sctp_setsockopt_peer_addr_params(struct sock *sk,
- char __user *optval, int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
struct sctp_paddrparams params;
struct sctp_transport *trans = NULL;
pmtud_change == SPP_PMTUD ||
sackdelay_change == SPP_SACKDELAY ||
params.spp_sackdelay > 500 ||
- (params.spp_pathmtu
- && params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
+ (params.spp_pathmtu &&
+ params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
return -EINVAL;
/* If an address other than INADDR_ANY is specified, and
*/
static int sctp_setsockopt_delayed_ack(struct sock *sk,
- char __user *optval, int optlen)
+ char __user *optval, unsigned int optlen)
{
struct sctp_sack_info params;
struct sctp_transport *trans = NULL;
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(¶ms, optval, optlen))
return -EFAULT;
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
-static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int optlen)
+static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen)
{
struct sctp_initmsg sinit;
struct sctp_sock *sp = sctp_sk(sk);
* to this call if the caller is using the UDP model.
*/
static int sctp_setsockopt_default_send_param(struct sock *sk,
- char __user *optval, int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
struct sctp_sndrcvinfo info;
struct sctp_association *asoc;
* association peer's addresses.
*/
static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_prim prim;
struct sctp_transport *trans;
* integer boolean flag.
*/
static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
int val;
* be changed.
*
*/
-static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int optlen) {
+static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen)
+{
struct sctp_rtoinfo rtoinfo;
struct sctp_association *asoc;
* See [SCTP] for more information.
*
*/
-static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int optlen)
+static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen)
{
struct sctp_assocparams assocparams;
paths++;
}
- /* Only validate asocmaxrxt if we have more then
+ /* Only validate asocmaxrxt if we have more than
* one path/transport. We do this because path
* retransmissions are only counted when we have more
* then one path.
* addresses and a user will receive both PF_INET6 and PF_INET type
* addresses on the socket.
*/
-static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int optlen)
+static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen)
{
int val;
struct sctp_sock *sp = sctp_sk(sk);
}
/*
- * 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)
+static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned 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(¶ms, 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->user_frag = val;
+ asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
+ } else {
+ sp->user_frag = val;
}
return 0;
* set primary request:
*/
static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_sock *sp;
struct sctp_endpoint *ep;
}
static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_setadaptation adaptation;
* saved with outbound messages.
*/
static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_assoc_value params;
struct sctp_sock *sp;
*/
static int sctp_setsockopt_fragment_interleave(struct sock *sk,
char __user *optval,
- int optlen)
+ unsigned int optlen)
{
int val;
}
/*
- * 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,
- int optlen)
+ unsigned int optlen)
{
u32 val;
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? */
*/
static int sctp_setsockopt_maxburst(struct sock *sk,
char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_assoc_value params;
struct sctp_sock *sp;
int val;
int assoc_id = 0;
- if (optlen < sizeof(int))
- return -EINVAL;
-
if (optlen == sizeof(int)) {
printk(KERN_WARNING
"SCTP: Use of int in max_burst socket option deprecated\n");
* will only effect future associations on the socket.
*/
static int sctp_setsockopt_auth_chunk(struct sock *sk,
- char __user *optval,
- int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
struct sctp_authchunk val;
* endpoint requires the peer to use.
*/
static int sctp_setsockopt_hmac_ident(struct sock *sk,
- char __user *optval,
- int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
struct sctp_hmacalgo *hmacs;
u32 idents;
*/
static int sctp_setsockopt_auth_key(struct sock *sk,
char __user *optval,
- int optlen)
+ unsigned int optlen)
{
struct sctp_authkey *authkey;
struct sctp_association *asoc;
* the association shared key.
*/
static int sctp_setsockopt_active_key(struct sock *sk,
- char __user *optval,
- int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
struct sctp_authkeyid val;
struct sctp_association *asoc;
* This set option will delete a shared secret key from use.
*/
static int sctp_setsockopt_del_key(struct sock *sk,
- char __user *optval,
- int optlen)
+ char __user *optval,
+ unsigned int optlen)
{
struct sctp_authkeyid val;
struct sctp_association *asoc;
* optlen - the size of the buffer.
*/
SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int optlen)
+ char __user *optval, unsigned int optlen)
{
int retval = 0;
sp->hmac = NULL;
SCTP_DBG_OBJCNT_INC(sock);
- atomic_inc(&sctp_sockets_allocated);
local_bh_disable();
+ percpu_counter_inc(&sctp_sockets_allocated);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
local_bh_enable();
/* Release our hold on the endpoint. */
ep = sctp_sk(sk)->ep;
sctp_endpoint_free(ep);
- atomic_dec(&sctp_sockets_allocated);
+ local_bh_disable();
+ percpu_counter_dec(&sctp_sockets_allocated);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+ local_bh_enable();
}
/* API 4.1.7 shutdown() - TCP Style Syntax
{
struct sock *sk = asoc->base.sk;
struct socket *sock;
- struct inet_sock *inetsk;
struct sctp_af *af;
int err = 0;
if (err < 0)
return err;
- /* Populate the fields of the newsk from the oldsk and migrate the
- * asoc to the newsk.
- */
- sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
+ sctp_copy_sock(sock->sk, sk, asoc);
/* Make peeled-off sockets more like 1-1 accepted sockets.
* Set the daddr and initialize id to something more random
*/
af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family);
af->to_sk_daddr(&asoc->peer.primary_addr, sk);
- inetsk = inet_sk(sock->sk);
- inetsk->id = asoc->next_tsn ^ jiffies;
+
+ /* Populate the fields of the newsk from the oldsk and migrate the
+ * asoc to the newsk.
+ */
+ sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
*sockp = sock;
if (copy_from_user(¶ms, 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(¶ms, optval, len))
return -EFAULT;
} else
return 0;
}
-static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len,
- char __user *optval,
- int __user *optlen)
-{
- sctp_assoc_t id;
- struct sctp_association *asoc;
- struct list_head *pos;
- int cnt = 0;
-
- if (len < sizeof(sctp_assoc_t))
- return -EINVAL;
-
- if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
- return -EFAULT;
-
- printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_NUM_OLD "
- "socket option deprecated\n");
- /* For UDP-style sockets, id specifies the association to query. */
- asoc = sctp_id2assoc(sk, id);
- if (!asoc)
- return -EINVAL;
-
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- cnt ++;
- }
-
- return cnt;
-}
-
-/*
- * Old API for getting list of peer addresses. Does not work for 32-bit
- * programs running on a 64-bit kernel
- */
-static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
- char __user *optval,
- int __user *optlen)
-{
- struct sctp_association *asoc;
- int cnt = 0;
- struct sctp_getaddrs_old getaddrs;
- struct sctp_transport *from;
- void __user *to;
- union sctp_addr temp;
- struct sctp_sock *sp = sctp_sk(sk);
- int addrlen;
-
- if (len < sizeof(struct sctp_getaddrs_old))
- return -EINVAL;
-
- len = sizeof(struct sctp_getaddrs_old);
-
- if (copy_from_user(&getaddrs, optval, len))
- return -EFAULT;
-
- if (getaddrs.addr_num <= 0) return -EINVAL;
-
- printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_OLD "
- "socket option deprecated\n");
-
- /* For UDP-style sockets, id specifies the association to query. */
- asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
- if (!asoc)
- return -EINVAL;
-
- to = (void __user *)getaddrs.addrs;
- list_for_each_entry(from, &asoc->peer.transport_addr_list,
- transports) {
- memcpy(&temp, &from->ipaddr, sizeof(temp));
- sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
- addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
- if (copy_to_user(to, &temp, addrlen))
- return -EFAULT;
- to += addrlen ;
- cnt ++;
- if (cnt >= getaddrs.addr_num) break;
- }
- getaddrs.addr_num = cnt;
- if (put_user(len, optlen))
- return -EFAULT;
- if (copy_to_user(optval, &getaddrs, len))
- return -EFAULT;
-
- return 0;
-}
static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
char __user *optval, int __user *optlen)
transports) {
memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
- addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
+ addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if (space_left < addrlen)
return -ENOMEM;
if (copy_to_user(to, &temp, addrlen))
return 0;
}
-static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
- char __user *optval,
- int __user *optlen)
-{
- sctp_assoc_t id;
- struct sctp_bind_addr *bp;
- struct sctp_association *asoc;
- struct sctp_sockaddr_entry *addr;
- int cnt = 0;
-
- if (len < sizeof(sctp_assoc_t))
- return -EINVAL;
-
- if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
- return -EFAULT;
-
- printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_NUM_OLD "
- "socket option deprecated\n");
-
- /*
- * For UDP-style sockets, id specifies the association to query.
- * If the id field is set to the value '0' then the locally bound
- * addresses are returned without regard to any particular
- * association.
- */
- if (0 == id) {
- bp = &sctp_sk(sk)->ep->base.bind_addr;
- } else {
- asoc = sctp_id2assoc(sk, id);
- if (!asoc)
- return -EINVAL;
- bp = &asoc->base.bind_addr;
- }
-
- /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
- * addresses from the global local address list.
- */
- if (sctp_list_single_entry(&bp->address_list)) {
- addr = list_entry(bp->address_list.next,
- struct sctp_sockaddr_entry, list);
- if (sctp_is_any(sk, &addr->a)) {
- rcu_read_lock();
- list_for_each_entry_rcu(addr,
- &sctp_local_addr_list, list) {
- if (!addr->valid)
- continue;
-
- if ((PF_INET == sk->sk_family) &&
- (AF_INET6 == addr->a.sa.sa_family))
- continue;
-
- if ((PF_INET6 == sk->sk_family) &&
- inet_v6_ipv6only(sk) &&
- (AF_INET == addr->a.sa.sa_family))
- continue;
-
- cnt++;
- }
- rcu_read_unlock();
- } else {
- cnt = 1;
- }
- goto done;
- }
-
- /* Protection on the bound address list is not needed,
- * since in the socket option context we hold the socket lock,
- * so there is no way that the bound address list can change.
- */
- list_for_each_entry(addr, &bp->address_list, list) {
- cnt ++;
- }
-done:
- return cnt;
-}
-
-/* Helper function that copies local addresses to user and returns the number
- * of addresses copied.
- */
-static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
- int max_addrs, void *to,
- int *bytes_copied)
-{
- struct sctp_sockaddr_entry *addr;
- union sctp_addr temp;
- int cnt = 0;
- int addrlen;
-
- rcu_read_lock();
- list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
- if (!addr->valid)
- continue;
-
- if ((PF_INET == sk->sk_family) &&
- (AF_INET6 == addr->a.sa.sa_family))
- continue;
- if ((PF_INET6 == sk->sk_family) &&
- inet_v6_ipv6only(sk) &&
- (AF_INET == addr->a.sa.sa_family))
- continue;
- memcpy(&temp, &addr->a, sizeof(temp));
- if (!temp.v4.sin_port)
- temp.v4.sin_port = htons(port);
-
- sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
- &temp);
- addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- memcpy(to, &temp, addrlen);
-
- to += addrlen;
- *bytes_copied += addrlen;
- cnt ++;
- if (cnt >= max_addrs) break;
- }
- rcu_read_unlock();
-
- return cnt;
-}
-
static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
size_t space_left, int *bytes_copied)
{
return cnt;
}
-/* Old API for getting list of local addresses. Does not work for 32-bit
- * programs running on a 64-bit kernel
- */
-static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
- char __user *optval, int __user *optlen)
+
+static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
{
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
int cnt = 0;
- struct sctp_getaddrs_old getaddrs;
+ struct sctp_getaddrs getaddrs;
struct sctp_sockaddr_entry *addr;
void __user *to;
union sctp_addr temp;
struct sctp_sock *sp = sctp_sk(sk);
int addrlen;
int err = 0;
+ size_t space_left;
+ int bytes_copied = 0;
void *addrs;
void *buf;
- int bytes_copied = 0;
- if (len < sizeof(struct sctp_getaddrs_old))
+ if (len < sizeof(struct sctp_getaddrs))
return -EINVAL;
- len = sizeof(struct sctp_getaddrs_old);
- if (copy_from_user(&getaddrs, optval, len))
- return -EFAULT;
-
- if (getaddrs.addr_num <= 0 ||
- getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
- return -EINVAL;
-
- printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_OLD "
- "socket option deprecated\n");
-
- /*
- * For UDP-style sockets, id specifies the association to query.
- * If the id field is set to the value '0' then the locally bound
- * addresses are returned without regard to any particular
- * association.
- */
- if (0 == getaddrs.assoc_id) {
- bp = &sctp_sk(sk)->ep->base.bind_addr;
- } else {
- asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
- if (!asoc)
- return -EINVAL;
- bp = &asoc->base.bind_addr;
- }
-
- to = getaddrs.addrs;
-
- /* Allocate space for a local instance of packed array to hold all
- * the data. We store addresses here first and then put write them
- * to the user in one shot.
- */
- addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
- GFP_KERNEL);
- if (!addrs)
- return -ENOMEM;
-
- /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
- * addresses from the global local address list.
- */
- if (sctp_list_single_entry(&bp->address_list)) {
- addr = list_entry(bp->address_list.next,
- struct sctp_sockaddr_entry, list);
- if (sctp_is_any(sk, &addr->a)) {
- cnt = sctp_copy_laddrs_old(sk, bp->port,
- getaddrs.addr_num,
- addrs, &bytes_copied);
- goto copy_getaddrs;
- }
- }
-
- buf = addrs;
- /* Protection on the bound address list is not needed since
- * in the socket option context we hold a socket lock and
- * thus the bound address list can't change.
- */
- list_for_each_entry(addr, &bp->address_list, list) {
- memcpy(&temp, &addr->a, sizeof(temp));
- sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
- addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- memcpy(buf, &temp, addrlen);
- buf += addrlen;
- bytes_copied += addrlen;
- cnt ++;
- if (cnt >= getaddrs.addr_num) break;
- }
-
-copy_getaddrs:
- /* copy the entire address list into the user provided space */
- if (copy_to_user(to, addrs, bytes_copied)) {
- err = -EFAULT;
- goto error;
- }
-
- /* copy the leading structure back to user */
- getaddrs.addr_num = cnt;
- if (copy_to_user(optval, &getaddrs, len))
- err = -EFAULT;
-
-error:
- kfree(addrs);
- return err;
-}
-
-static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
- char __user *optval, int __user *optlen)
-{
- struct sctp_bind_addr *bp;
- struct sctp_association *asoc;
- int cnt = 0;
- struct sctp_getaddrs getaddrs;
- struct sctp_sockaddr_entry *addr;
- void __user *to;
- union sctp_addr temp;
- struct sctp_sock *sp = sctp_sk(sk);
- int addrlen;
- int err = 0;
- size_t space_left;
- int bytes_copied = 0;
- void *addrs;
- void *buf;
-
- if (len < sizeof(struct sctp_getaddrs))
- return -EINVAL;
-
- if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
+ if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
return -EFAULT;
/*
}
/*
- * 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(¶ms, 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, ¶ms.assoc_value, len))
+ return -EFAULT;
+ } else {
+ if (copy_to_user(optval, ¶ms, len))
+ return -EFAULT;
+ }
return 0;
}
struct sctp_sock *sp;
struct sctp_association *asoc;
- if (len < sizeof(int))
- return -EINVAL;
-
if (len == sizeof(int)) {
printk(KERN_WARNING
"SCTP: Use of int in max_burst 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)) {
+ } else if (len >= sizeof(struct sctp_assoc_value)) {
+ len = sizeof(struct sctp_assoc_value);
if (copy_from_user(¶ms, optval, len))
return -EFAULT;
} else
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)
{
case SCTP_INITMSG:
retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
break;
- case SCTP_GET_PEER_ADDRS_NUM_OLD:
- retval = sctp_getsockopt_peer_addrs_num_old(sk, len, optval,
- optlen);
- break;
- case SCTP_GET_LOCAL_ADDRS_NUM_OLD:
- retval = sctp_getsockopt_local_addrs_num_old(sk, len, optval,
- optlen);
- break;
- case SCTP_GET_PEER_ADDRS_OLD:
- retval = sctp_getsockopt_peer_addrs_old(sk, len, optval,
- optlen);
- break;
- case SCTP_GET_LOCAL_ADDRS_OLD:
- retval = sctp_getsockopt_local_addrs_old(sk, len, optval,
- optlen);
- break;
case SCTP_GET_PEER_ADDRS:
retval = sctp_getsockopt_peer_addrs(sk, len, optval,
optlen);
retval = sctp_getsockopt_local_addrs(sk, len, optval,
optlen);
break;
+ case SCTP_SOCKOPT_CONNECTX3:
+ retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
+ break;
case SCTP_DEFAULT_SEND_PARAM:
retval = sctp_getsockopt_default_send_param(sk, len,
optval, optlen);
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;
rover++;
if ((rover < low) || (rover > high))
rover = low;
+ if (inet_is_reserved_local_port(rover))
+ continue;
index = sctp_phashfn(rover);
head = &sctp_port_hashtable[index];
sctp_spin_lock(&head->lock);
*/
int reuse = sk->sk_reuse;
struct sock *sk2;
- struct hlist_node *node;
SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
if (pp->fastreuse && sk->sk_reuse &&
*/
success:
if (!sctp_sk(sk)->bind_hash) {
- inet_sk(sk)->num = snum;
+ inet_sk(sk)->inet_num = snum;
sk_add_bind_node(sk, &pp->owner);
sctp_sk(sk)->bind_hash = pp;
}
}
/*
- * 3.1.3 listen() - UDP Style Syntax
- *
- * By default, new associations are not accepted for UDP style sockets.
- * An application uses listen() to mark a socket as being able to
- * accept new associations.
+ * Move a socket to LISTENING state.
*/
-SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
+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;
- /* Only UDP style sockets that are not peeled off are allowed to
- * listen().
- */
- if (!sctp_style(sk, UDP))
- return -EINVAL;
-
- /* If backlog is zero, disable listening. */
- if (!backlog) {
- if (sctp_sstate(sk, CLOSED))
- return 0;
-
- sctp_unhash_endpoint(ep);
- sk->sk_state = SCTP_SS_CLOSED;
- return 0;
+ /* 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 (IS_ERR(tfm)) {
+ if (net_ratelimit()) {
+ printk(KERN_INFO
+ "SCTP: failed to load transform for %s: %ld\n",
+ sctp_hmac_alg, PTR_ERR(tfm));
+ }
+ return -ENOSYS;
+ }
+ sctp_sk(sk)->hmac = tfm;
}
- /* Return if we are already listening. */
- if (sctp_sstate(sk, LISTENING))
- return 0;
-
/*
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
* extensions draft, but follows the practice as seen in TCP
* sockets.
*
- * Additionally, turn off fastreuse flag since we are not listening
*/
sk->sk_state = SCTP_SS_LISTENING;
if (!ep->base.bind_addr.port) {
if (sctp_autobind(sk))
return -EAGAIN;
} else {
- if (sctp_get_port(sk, inet_sk(sk)->num)) {
+ if (sctp_get_port(sk, inet_sk(sk)->inet_num)) {
sk->sk_state = SCTP_SS_CLOSED;
return -EADDRINUSE;
}
- sctp_sk(sk)->bind_hash->fastreuse = 0;
- }
-
- sctp_hash_endpoint(ep);
- return 0;
-}
-
-/*
- * 4.1.3 listen() - TCP Style Syntax
- *
- * Applications uses listen() to ready the SCTP endpoint for accepting
- * inbound associations.
- */
-SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
-{
- struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_endpoint *ep = sp->ep;
-
- /* If backlog is zero, disable listening. */
- if (!backlog) {
- if (sctp_sstate(sk, CLOSED))
- return 0;
-
- sctp_unhash_endpoint(ep);
- sk->sk_state = SCTP_SS_CLOSED;
- return 0;
}
- if (sctp_sstate(sk, LISTENING))
- return 0;
-
- /*
- * If a bind() or sctp_bindx() is not called prior to a listen()
- * call that allows new associations to be accepted, the system
- * picks an ephemeral port and will choose an address set equivalent
- * to binding with a wildcard address.
- *
- * This is not currently spelled out in the SCTP sockets
- * extensions draft, but follows the practice as seen in TCP
- * sockets.
- */
- sk->sk_state = SCTP_SS_LISTENING;
- if (!ep->base.bind_addr.port) {
- if (sctp_autobind(sk))
- return -EAGAIN;
- } else
- sctp_sk(sk)->bind_hash->fastreuse = 0;
-
sk->sk_max_ack_backlog = backlog;
sctp_hash_endpoint(ep);
return 0;
}
/*
+ * 4.1.3 / 5.1.3 listen()
+ *
+ * By default, new associations are not accepted for UDP style sockets.
+ * An application uses listen() to mark a socket as being able to
+ * accept new associations.
+ *
+ * On TCP style sockets, applications use listen() to ready the SCTP
+ * endpoint for accepting inbound associations.
+ *
+ * On both types of endpoints a backlog of '0' disables listening.
+ *
* Move a socket to LISTENING state.
*/
int sctp_inet_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
- struct crypto_hash *tfm = NULL;
+ struct sctp_endpoint *ep = sctp_sk(sk)->ep;
int err = -EINVAL;
if (unlikely(backlog < 0))
- goto out;
+ return err;
sctp_lock_sock(sk);
+ /* Peeled-off sockets are not allowed to listen(). */
+ if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
+ goto out;
+
if (sock->state != SS_UNCONNECTED)
goto out;
- /* 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 (IS_ERR(tfm)) {
- if (net_ratelimit()) {
- printk(KERN_INFO
- "SCTP: failed to load transform for %s: %ld\n",
- sctp_hmac_alg, PTR_ERR(tfm));
- }
- err = -ENOSYS;
+ /* If backlog is zero, disable listening. */
+ if (!backlog) {
+ if (sctp_sstate(sk, CLOSED))
goto out;
- }
- }
- switch (sock->type) {
- case SOCK_SEQPACKET:
- err = sctp_seqpacket_listen(sk, backlog);
- break;
- case SOCK_STREAM:
- err = sctp_stream_listen(sk, backlog);
- break;
- default:
- break;
+ err = 0;
+ sctp_unhash_endpoint(ep);
+ sk->sk_state = SCTP_SS_CLOSED;
+ if (sk->sk_reuse)
+ sctp_sk(sk)->bind_hash->fastreuse = 1;
+ goto out;
}
- if (err)
- goto cleanup;
+ /* If we are already listening, just update the backlog */
+ if (sctp_sstate(sk, LISTENING))
+ sk->sk_max_ack_backlog = backlog;
+ else {
+ err = sctp_listen_start(sk, backlog);
+ if (err)
+ goto out;
+ }
- /* Store away the transform reference. */
- if (!sctp_sk(sk)->hmac)
- sctp_sk(sk)->hmac = tfm;
+ err = 0;
out:
sctp_release_sock(sk);
return err;
-cleanup:
- crypto_free_hash(tfm);
- goto out;
}
/*
struct sctp_sock *sp = sctp_sk(sk);
unsigned int mask;
- poll_wait(file, sk->sk_sleep, wait);
+ poll_wait(file, sk_sleep(sk), wait);
/* A TCP-style listening socket becomes readable when the accept queue
* is not empty.
static inline void __sctp_put_port(struct sock *sk)
{
struct sctp_bind_hashbucket *head =
- &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)];
+ &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->inet_num)];
struct sctp_bind_bucket *pp;
sctp_spin_lock(&head->lock);
pp = sctp_sk(sk)->bind_hash;
__sk_del_bind_node(sk);
sctp_sk(sk)->bind_hash = NULL;
- inet_sk(sk)->num = 0;
+ inet_sk(sk)->inet_num = 0;
sctp_bucket_destroy(pp);
sctp_spin_unlock(&head->lock);
}
/* Initialize a local sockaddr structure to INADDR_ANY. */
af = sctp_sk(sk)->pf->af;
- port = htons(inet_sk(sk)->num);
+ port = htons(inet_sk(sk)->inet_num);
af->inaddr_any(&autoaddr, port);
return sctp_do_bind(sk, &autoaddr, af->sockaddr_len);
int error;
DEFINE_WAIT(wait);
- prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
/* Socket errors? */
error = sock_error(sk);
sctp_lock_sock(sk);
ready:
- finish_wait(sk->sk_sleep, &wait);
+ finish_wait(sk_sleep(sk), &wait);
return 0;
interrupted:
error = sock_intr_errno(*timeo_p);
out:
- finish_wait(sk->sk_sleep, &wait);
+ finish_wait(sk_sleep(sk), &wait);
*err = error;
return error;
}
wake_up_interruptible(&asoc->wait);
if (sctp_writeable(sk)) {
- if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible(sk->sk_sleep);
+ if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+ wake_up_interruptible(sk_sleep(sk));
/* Note that we try to include the Async I/O support
* here by modeling from the current TCP/UDP code.
* We have not tested with it yet.
*/
- if (sock->fasync_list &&
+ if (sock->wq->fasync_list &&
!(sk->sk_shutdown & SEND_SHUTDOWN))
sock_wake_async(sock,
SOCK_WAKE_SPACE, POLL_OUT);
goto out;
}
+void sctp_data_ready(struct sock *sk, int len)
+{
+ struct socket_wq *wq;
+
+ rcu_read_lock();
+ wq = rcu_dereference(sk->sk_wq);
+ if (wq_has_sleeper(wq))
+ wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
+ POLLRDNORM | POLLRDBAND);
+ sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
+ rcu_read_unlock();
+}
+
/* If socket sndbuf has changed, wake up all per association waiters. */
void sctp_write_space(struct sock *sk)
{
{
int amt = 0;
- amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+ amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
if (amt < 0)
amt = 0;
return amt;
for (;;) {
- prepare_to_wait_exclusive(sk->sk_sleep, &wait,
+ prepare_to_wait_exclusive(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
if (list_empty(&ep->asocs)) {
break;
}
- finish_wait(sk->sk_sleep, &wait);
+ finish_wait(sk_sleep(sk), &wait);
return err;
}
DEFINE_WAIT(wait);
do {
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
if (list_empty(&sctp_sk(sk)->ep->asocs))
break;
sctp_release_sock(sk);
sctp_lock_sock(sk);
} while (!signal_pending(current) && timeout);
- finish_wait(sk->sk_sleep, &wait);
-}
-
-static void sctp_sock_rfree_frag(struct sk_buff *skb)
-{
- struct sk_buff *frag;
-
- if (!skb->data_len)
- goto done;
-
- /* Don't forget the fragments. */
- for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
- sctp_sock_rfree_frag(frag);
-
-done:
- sctp_sock_rfree(skb);
+ finish_wait(sk_sleep(sk), &wait);
}
static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
goto done;
/* Don't forget the fragments. */
- for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
+ skb_walk_frags(skb, frag)
sctp_skb_set_owner_r_frag(frag, sk);
done:
sctp_skb_set_owner_r(skb, sk);
}
+void sctp_copy_sock(struct sock *newsk, struct sock *sk,
+ struct sctp_association *asoc)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct inet_sock *newinet;
+
+ newsk->sk_type = sk->sk_type;
+ newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
+ newsk->sk_flags = sk->sk_flags;
+ newsk->sk_no_check = sk->sk_no_check;
+ newsk->sk_reuse = sk->sk_reuse;
+
+ newsk->sk_shutdown = sk->sk_shutdown;
+ newsk->sk_destruct = inet_sock_destruct;
+ newsk->sk_family = sk->sk_family;
+ newsk->sk_protocol = IPPROTO_SCTP;
+ newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+ newsk->sk_sndbuf = sk->sk_sndbuf;
+ newsk->sk_rcvbuf = sk->sk_rcvbuf;
+ newsk->sk_lingertime = sk->sk_lingertime;
+ newsk->sk_rcvtimeo = sk->sk_rcvtimeo;
+ newsk->sk_sndtimeo = sk->sk_sndtimeo;
+
+ newinet = inet_sk(newsk);
+
+ /* Initialize sk's sport, dport, rcv_saddr and daddr for
+ * getsockname() and getpeername()
+ */
+ newinet->inet_sport = inet->inet_sport;
+ newinet->inet_saddr = inet->inet_saddr;
+ newinet->inet_rcv_saddr = inet->inet_rcv_saddr;
+ newinet->inet_dport = htons(asoc->peer.port);
+ newinet->pmtudisc = inet->pmtudisc;
+ newinet->inet_id = asoc->next_tsn ^ jiffies;
+
+ newinet->uc_ttl = inet->uc_ttl;
+ newinet->mc_loop = 1;
+ newinet->mc_ttl = 1;
+ newinet->mc_index = 0;
+ newinet->mc_list = NULL;
+}
+
/* Populate the fields of the newsk from the oldsk and migrate the assoc
* and its messages to the newsk.
*/
newsp->hmac = NULL;
/* Hook this new socket in to the bind_hash list. */
- head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->num)];
+ head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->inet_num)];
sctp_local_bh_disable();
sctp_spin_lock(&head->lock);
pp = sctp_sk(oldsk)->bind_hash;
sk_add_bind_node(newsk, &pp->owner);
sctp_sk(newsk)->bind_hash = pp;
- inet_sk(newsk)->num = inet_sk(oldsk)->num;
+ inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num;
sctp_spin_unlock(&head->lock);
sctp_local_bh_enable();
sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
event = sctp_skb2event(skb);
if (event->asoc == assoc) {
- sctp_sock_rfree_frag(skb);
__skb_unlink(skb, &oldsk->sk_receive_queue);
__skb_queue_tail(&newsk->sk_receive_queue, skb);
sctp_skb_set_owner_r_frag(skb, newsk);
sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
event = sctp_skb2event(skb);
if (event->asoc == assoc) {
- sctp_sock_rfree_frag(skb);
__skb_unlink(skb, &oldsp->pd_lobby);
__skb_queue_tail(queue, skb);
sctp_skb_set_owner_r_frag(skb, newsk);
}
- sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) {
- sctp_sock_rfree_frag(skb);
+ sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp)
sctp_skb_set_owner_r_frag(skb, newsk);
- }
- sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) {
- sctp_sock_rfree_frag(skb);
+ sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp)
sctp_skb_set_owner_r_frag(skb, newsk);
- }
/* Set the type of socket to indicate that it is peeled off from the
* original UDP-style socket or created with the accept() call on a