X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsctp%2Fsocket.c;h=6f66ee490784602c0811c9a2be3ceaf8aff7c859;hb=6c6294c4656749c1eeed12df7ae48e2bf5a394b3;hp=5219c3ba49fc6a73e8db0cb2429249246fa3b9d4;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5219c3ba4..6f66ee490 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -86,8 +86,6 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); -static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, size_t msg_len); @@ -95,7 +93,8 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); static void sctp_wait_for_close(struct sock *sk, long timeo); -static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); +static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, + union sctp_addr *addr, int len); static int sctp_bindx_add(struct sock *, struct sockaddr *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); @@ -109,7 +108,64 @@ static void sctp_sock_migrate(struct sock *, struct sock *, static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; extern kmem_cache_t *sctp_bucket_cachep; -extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc); + +/* Get the sndbuf space available at the time on the association. */ +static inline int sctp_wspace(struct sctp_association *asoc) +{ + struct sock *sk = asoc->base.sk; + int amt = 0; + + amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (amt < 0) + amt = 0; + return amt; +} + +/* Increment the used sndbuf space count of the corresponding association by + * the size of the outgoing data chunk. + * Also, set the skb destructor for sndbuf accounting later. + * + * Since it is always 1-1 between chunk and skb, and also a new skb is always + * allocated for chunk bundling in sctp_packet_transmit(), we can use the + * destructor in the data chunk skb for the purpose of the sndbuf space + * tracking. + */ +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) +{ + struct sctp_association *asoc = chunk->asoc; + struct sock *sk = asoc->base.sk; + + /* The sndbuf space is tracked per association. */ + sctp_association_hold(asoc); + + chunk->skb->destructor = sctp_wfree; + /* Save the chunk pointer in skb for sctp_wfree to use later. */ + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; + + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); +} + +/* Verify that this is a valid address. */ +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, + int len) +{ + struct sctp_af *af; + + /* Verify basic sockaddr. */ + af = sctp_sockaddr_af(sctp_sk(sk), addr, len); + if (!af) + return -EINVAL; + + /* Is this a valid SCTP address? */ + if (!af->addr_valid(addr, sctp_sk(sk))) + return -EINVAL; + + if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) + return -EINVAL; + + return 0; +} /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. @@ -152,7 +208,7 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) * id are specified, the associations matching the address and the id should be * the same. */ -struct sctp_transport *sctp_addr_id2transport(struct sock *sk, +static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, struct sockaddr_storage *addr, sctp_assoc_t id) { @@ -189,7 +245,7 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk, * sockaddr_in6 [RFC 2553]), * addr_len - the size of the address structure. */ -int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { int retval = 0; @@ -213,7 +269,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) static long sctp_get_port_local(struct sock *, union sctp_addr *); /* Verify this is a valid sockaddr. */ -static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, +static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, union sctp_addr *addr, int len) { struct sctp_af *af; @@ -238,7 +294,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *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 sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; struct sctp_bind_addr *bp = &ep->base.bind_addr; struct sctp_af *af; @@ -287,8 +343,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) } /* Refresh ephemeral port. */ - if (!snum) - snum = inet_sk(sk)->num; + if (!bp->port) + bp->port = inet_sk(sk)->num; /* Add the address to the bind address list. */ sctp_local_bh_disable(); @@ -298,8 +354,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) addr->v4.sin_port = ntohs(addr->v4.sin_port); ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC); addr->v4.sin_port = htons(addr->v4.sin_port); - if (!ret && !bp->port) - bp->port = snum; sctp_write_unlock(&ep->base.addr_lock); sctp_local_bh_enable(); @@ -413,7 +467,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, struct sockaddr *addrs, int addrcnt) { - struct sctp_opt *sp; + struct sctp_sock *sp; struct sctp_endpoint *ep; struct sctp_association *asoc; struct sctp_bind_addr *bp; @@ -518,7 +572,7 @@ out: */ int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) { - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; int cnt; struct sctp_bind_addr *bp = &ep->base.bind_addr; @@ -602,7 +656,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, struct sockaddr *addrs, int addrcnt) { - struct sctp_opt *sp; + struct sctp_sock *sp; struct sctp_endpoint *ep; struct sctp_association *asoc; struct sctp_bind_addr *bp; @@ -765,7 +819,8 @@ out: * * Returns 0 if ok, <0 errno code on error. */ -SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs, +SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, + struct sockaddr __user *addrs, int addrs_size, int op) { struct sockaddr *kaddrs; @@ -944,11 +999,11 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) sctp_local_bh_disable(); sctp_bh_lock_sock(sk); - /* Hold the sock, since inet_sock_release() will put sock_put() + /* Hold the sock, since sk_common_release() will put sock_put() * and we have just a little more cleanup. */ sock_hold(sk); - inet_sock_release(sk); + sk_common_release(sk); sctp_bh_unlock_sock(sk); sctp_local_bh_enable(); @@ -989,14 +1044,14 @@ static int sctp_error(struct sock *sk, int flags, int err) * Note: This function could use a rewrite especially when explicit * connect support comes in. */ -/* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */ +/* BUG: We do not implement the equivalent of sk_stream_wait_memory(). */ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t msg_len) { - struct sctp_opt *sp; + struct sctp_sock *sp; struct sctp_endpoint *ep; struct sctp_association *new_asoc=NULL, *asoc=NULL; struct sctp_transport *transport, *chunk_tp; @@ -1006,8 +1061,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct sctp_sndrcvinfo default_sinfo = { 0 }; struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; - sctp_assoc_t associd = NULL; - sctp_cmsgs_t cmsgs = { 0 }; + sctp_assoc_t associd = 0; + sctp_cmsgs_t cmsgs = { NULL }; int err; sctp_scope_t scope; long timeo; @@ -1163,6 +1218,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, if (!asoc) { SCTP_DEBUG_PRINTK("There is no association yet.\n"); + if (sinfo_flags & (MSG_EOF | MSG_ABORT)) { + err = -EINVAL; + goto out_unlock; + } + /* Check for invalid stream against the stream counts, * either the default or the user specified stream counts. */ @@ -1224,7 +1284,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, } if (sinit->sinit_max_init_timeo) { asoc->max_init_timeo = - MSECS_TO_JIFFIES(sinit->sinit_max_init_timeo); + msecs_to_jiffies(sinit->sinit_max_init_timeo); } } @@ -1432,7 +1492,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, int flags, int *addr_len) { struct sctp_ulpevent *event = NULL; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); struct sk_buff *skb; int copied; int err = 0; @@ -1538,14 +1598,14 @@ out: * instead a error will be indicated to the user. */ static int sctp_setsockopt_disable_fragments(struct sock *sk, - char *optval, int optlen) + char __user *optval, int optlen) { int val; if (optlen < sizeof(int)) return -EINVAL; - if (get_user(val, (int *)optval)) + if (get_user(val, (int __user *)optval)) return -EFAULT; sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1; @@ -1553,7 +1613,7 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, return 0; } -static int sctp_setsockopt_events(struct sock *sk, char *optval, +static int sctp_setsockopt_events(struct sock *sk, char __user *optval, int optlen) { if (optlen != sizeof(struct sctp_event_subscribe)) @@ -1574,10 +1634,10 @@ static int sctp_setsockopt_events(struct sock *sk, char *optval, * integer defining the number of seconds of idle time before an * association is closed. */ -static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, +static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, int optlen) { - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); /* Applicable to UDP-style socket only */ if (sctp_style(sk, TCP)) @@ -1623,7 +1683,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, * considered unreachable. */ static int sctp_setsockopt_peer_addr_params(struct sock *sk, - char *optval, int optlen) + char __user *optval, int optlen) { struct sctp_paddrparams params; struct sctp_transport *trans; @@ -1634,6 +1694,35 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, if (copy_from_user(¶ms, optval, optlen)) return -EFAULT; + /* + * API 7. Socket Options (setting the default value for the endpoint) + * All options that support specific settings on an association by + * filling in either an association id variable or a sockaddr_storage + * SHOULD also support setting of the same value for the entire endpoint + * (i.e. future associations). To accomplish this the following logic is + * used when setting one of these options: + + * c) If neither the sockaddr_storage or association identification is + * set i.e. the sockaddr_storage is set to all 0's (INADDR_ANY) and + * the association identification is 0, the settings are a default + * and to be applied to the endpoint (all future associations). + */ + + /* update default value for endpoint (all future associations) */ + if (!params.spp_assoc_id && + sctp_is_any(( union sctp_addr *)¶ms.spp_address)) { + /* Manual heartbeat on an endpoint is invalid. */ + if (0xffffffff == params.spp_hbinterval) + return -EINVAL; + else if (params.spp_hbinterval) + sctp_sk(sk)->paddrparam.spp_hbinterval = + params.spp_hbinterval; + if (params.spp_pathmaxrxt) + sctp_sk(sk)->paddrparam.spp_pathmaxrxt = + params.spp_pathmaxrxt; + return 0; + } + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, params.spp_assoc_id); if (!trans) @@ -1662,7 +1751,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, if (params.spp_hbinterval) { trans->hb_allowed = 1; trans->hb_interval = - MSECS_TO_JIFFIES(params.spp_hbinterval); + msecs_to_jiffies(params.spp_hbinterval); } else trans->hb_allowed = 0; } @@ -1670,7 +1759,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, /* spp_pathmaxrxt contains the maximum number of retransmissions * before this address shall be considered unreachable. */ - trans->error_threshold = params.spp_pathmaxrxt; + if (params.spp_pathmaxrxt) + trans->max_retrans = params.spp_pathmaxrxt; return 0; } @@ -1686,10 +1776,10 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, * 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 *optval, int optlen) +static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int optlen) { struct sctp_initmsg sinit; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (optlen != sizeof(struct sctp_initmsg)) return -EINVAL; @@ -1723,11 +1813,11 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) * to this call if the caller is using the UDP model. */ static int sctp_setsockopt_default_send_param(struct sock *sk, - char *optval, int optlen) + char __user *optval, int optlen) { struct sctp_sndrcvinfo info; struct sctp_association *asoc; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (optlen != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -1761,7 +1851,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, * the association primary. The enclosed address must be one of the * association peer's addresses. */ -static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval, +static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, int optlen) { struct sctp_prim prim; @@ -1790,14 +1880,14 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval, * introduced, at the cost of more packets in the network. Expects an * integer boolean flag. */ -static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, +static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, int optlen) { int val; if (optlen < sizeof(int)) return -EINVAL; - if (get_user(val, (int *)optval)) + if (get_user(val, (int __user *)optval)) return -EFAULT; sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; @@ -1816,7 +1906,7 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, * be changed. * */ -static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { +static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int optlen) { struct sctp_rtoinfo rtoinfo; struct sctp_association *asoc; @@ -1835,16 +1925,16 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { if (asoc) { if (rtoinfo.srto_initial != 0) asoc->rto_initial = - MSECS_TO_JIFFIES(rtoinfo.srto_initial); + msecs_to_jiffies(rtoinfo.srto_initial); if (rtoinfo.srto_max != 0) - asoc->rto_max = MSECS_TO_JIFFIES(rtoinfo.srto_max); + asoc->rto_max = msecs_to_jiffies(rtoinfo.srto_max); if (rtoinfo.srto_min != 0) - asoc->rto_min = MSECS_TO_JIFFIES(rtoinfo.srto_min); + asoc->rto_min = msecs_to_jiffies(rtoinfo.srto_min); } else { /* If there is no association or the association-id = 0 * set the values to the endpoint. */ - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (rtoinfo.srto_initial != 0) sp->rtoinfo.srto_initial = rtoinfo.srto_initial; @@ -1868,7 +1958,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { * See [SCTP] for more information. * */ -static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) +static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int optlen) { struct sctp_assocparams assocparams; @@ -1897,7 +1987,7 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) } } else { /* Set the values to the endpoint */ - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (assocparams.sasoc_asocmaxrxt != 0) sp->assocparams.sasoc_asocmaxrxt = @@ -1919,14 +2009,14 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) * 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 *optval, int optlen) +static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int optlen) { int val; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (optlen < sizeof(int)) return -EINVAL; - if (get_user(val, (int *)optval)) + if (get_user(val, (int __user *)optval)) return -EFAULT; if (val) sp->v4mapped = 1; @@ -1946,16 +2036,16 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen) * PMTU of the underlying association is smaller than the value set by * the user. */ -static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen) +static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) { struct sctp_association *asoc; struct list_head *pos; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); int val; if (optlen < sizeof(int)) return -EINVAL; - if (get_user(val, (int *)optval)) + if (get_user(val, (int __user *)optval)) return -EFAULT; if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) return -EINVAL; @@ -1981,10 +2071,10 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen) * locally bound addresses. The following structure is used to make a * set primary request: */ -static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, +static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, int optlen) { - struct sctp_opt *sp; + struct sctp_sock *sp; struct sctp_endpoint *ep; struct sctp_association *asoc = NULL; struct sctp_setpeerprim prim; @@ -2032,6 +2122,20 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, return err; } +static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval, + int optlen) +{ + __u32 val; + + if (optlen < sizeof(__u32)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(__u32))) + return -EFAULT; + + sctp_sk(sk)->adaption_ind = val; + + return 0; +} /* API 6.2 setsockopt(), getsockopt() * @@ -2041,9 +2145,9 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, * * The syntax is: * - * ret = getsockopt(int sd, int level, int optname, void *optval, - * int *optlen); - * ret = setsockopt(int sd, int level, int optname, const void *optval, + * ret = getsockopt(int sd, int level, int optname, void __user *optval, + * int __user *optlen); + * ret = setsockopt(int sd, int level, int optname, const void __user *optval, * int optlen); * * sd - the socket descript. @@ -2053,7 +2157,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, * optlen - the size of the buffer. */ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, - char *optval, int optlen) + char __user *optval, int optlen) { int retval = 0; @@ -2077,13 +2181,13 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, switch (optname) { case SCTP_SOCKOPT_BINDX_ADD: /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval, + retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, optlen, SCTP_BINDX_ADD_ADDR); break; case SCTP_SOCKOPT_BINDX_REM: /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval, + retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, optlen, SCTP_BINDX_REM_ADDR); break; @@ -2131,6 +2235,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_MAXSEG: retval = sctp_setsockopt_maxseg(sk, optval, optlen); break; + case SCTP_ADAPTION_LAYER: + retval = sctp_setsockopt_adaption_layer(sk, optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -2161,7 +2269,7 @@ out_nounlock: SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - struct sctp_opt *sp; + struct sctp_sock *sp; struct sctp_endpoint *ep; struct sctp_association *asoc; struct sctp_transport *transport; @@ -2282,7 +2390,7 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags) */ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) { - struct sctp_opt *sp; + struct sctp_sock *sp; struct sctp_endpoint *ep; struct sock *newsk = NULL; struct sctp_association *asoc; @@ -2345,7 +2453,7 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) SCTP_STATIC int sctp_init_sock(struct sock *sk) { struct sctp_endpoint *ep; - struct sctp_opt *sp; + struct sctp_sock *sp; SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); @@ -2379,14 +2487,14 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; sp->initmsg.sinit_max_instreams = sctp_max_instreams; sp->initmsg.sinit_max_attempts = sctp_max_retrans_init; - sp->initmsg.sinit_max_init_timeo = JIFFIES_TO_MSECS(sctp_rto_max); + sp->initmsg.sinit_max_init_timeo = jiffies_to_msecs(sctp_rto_max); /* Initialize default RTO related parameters. These parameters can * be modified for with the SCTP_RTOINFO socket option. */ - sp->rtoinfo.srto_initial = JIFFIES_TO_MSECS(sctp_rto_initial); - sp->rtoinfo.srto_max = JIFFIES_TO_MSECS(sctp_rto_max); - sp->rtoinfo.srto_min = JIFFIES_TO_MSECS(sctp_rto_min); + sp->rtoinfo.srto_initial = jiffies_to_msecs(sctp_rto_initial); + sp->rtoinfo.srto_max = jiffies_to_msecs(sctp_rto_max); + sp->rtoinfo.srto_min = jiffies_to_msecs(sctp_rto_min); /* Initialize default association related parameters. These parameters * can be modified with the SCTP_ASSOCINFO socket option. @@ -2396,7 +2504,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->assocparams.sasoc_peer_rwnd = 0; sp->assocparams.sasoc_local_rwnd = 0; sp->assocparams.sasoc_cookie_life = - JIFFIES_TO_MSECS(sctp_valid_cookie_life); + jiffies_to_msecs(sctp_valid_cookie_life); /* Initialize default event subscriptions. By default, all the * options are off. @@ -2406,7 +2514,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) /* Default Peer Address Parameters. These defaults can * be modified via SCTP_PEER_ADDR_PARAMS */ - sp->paddrparam.spp_hbinterval = JIFFIES_TO_MSECS(sctp_hb_interval); + sp->paddrparam.spp_hbinterval = jiffies_to_msecs(sctp_hb_interval); sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path; /* If enabled no SCTP message fragmentation will be performed. @@ -2430,6 +2538,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) /* User specified fragmentation limit. */ sp->user_frag = 0; + sp->adaption_ind = 0; + sp->pf = sctp_get_pf_specific(sk->sk_family); /* Control variables for partial data delivery. */ @@ -2506,8 +2616,9 @@ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how) * number of unacked data chunks, and number of data chunks pending * receipt. This information is read-only. */ -static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, - int *optlen) +static int sctp_getsockopt_sctp_status(struct sock *sk, int len, + char __user *optval, + int __user *optlen) { struct sctp_status status; struct sctp_association *asoc = NULL; @@ -2552,7 +2663,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; - status.sstat_primary.spinfo_rto = JIFFIES_TO_MSECS(transport->rto); + status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); status.sstat_primary.spinfo_mtu = transport->pmtu; if (put_user(len, optlen)) { @@ -2560,7 +2671,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, goto out; } - SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", + SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %d\n", len, status.sstat_state, status.sstat_rwnd, status.sstat_assoc_id); @@ -2582,7 +2693,8 @@ out: * read-only. */ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, + int __user *optlen) { struct sctp_paddrinfo pinfo; struct sctp_transport *transport; @@ -2607,7 +2719,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, pinfo.spinfo_state = transport->active; pinfo.spinfo_cwnd = transport->cwnd; pinfo.spinfo_srtt = transport->srtt; - pinfo.spinfo_rto = JIFFIES_TO_MSECS(transport->rto); + pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); pinfo.spinfo_mtu = transport->pmtu; if (put_user(len, optlen)) { @@ -2632,7 +2744,7 @@ out: * instead a error will be indicated to the user. */ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { int val; @@ -2653,8 +2765,8 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, * This socket option is used to specify various notifications and * ancillary data the user wishes to receive. */ -static int sctp_getsockopt_events(struct sock *sk, int len, char *optval, - int *optlen) +static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, + int __user *optlen) { if (len != sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -2674,7 +2786,7 @@ static int sctp_getsockopt_events(struct sock *sk, int len, char *optval, * integer defining the number of seconds of idle time before an * association is closed. */ -static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen) { /* Applicable to UDP-style socket only */ if (sctp_style(sk, TCP)) @@ -2714,7 +2826,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, return err; } -static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) { sctp_peeloff_arg_t peeloff; struct socket *newsock; @@ -2789,16 +2901,27 @@ out: * considered unreachable. */ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { struct sctp_paddrparams params; struct sctp_transport *trans; if (len != sizeof(struct sctp_paddrparams)) return -EINVAL; - if (copy_from_user(¶ms, optval, *optlen)) + if (copy_from_user(¶ms, optval, len)) return -EFAULT; + /* If no association id is specified retrieve the default value + * for the endpoint that will be used for all future associations + */ + if (!params.spp_assoc_id && + sctp_is_any(( union sctp_addr *)¶ms.spp_address)) { + params.spp_hbinterval = sctp_sk(sk)->paddrparam.spp_hbinterval; + params.spp_pathmaxrxt = sctp_sk(sk)->paddrparam.spp_pathmaxrxt; + + goto done; + } + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, params.spp_assoc_id); if (!trans) @@ -2811,13 +2934,14 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, if (!trans->hb_allowed) params.spp_hbinterval = 0; else - params.spp_hbinterval = JIFFIES_TO_MSECS(trans->hb_interval); + params.spp_hbinterval = jiffies_to_msecs(trans->hb_interval); /* spp_pathmaxrxt contains the maximum number of retransmissions * before this address shall be considered unreachable. */ - params.spp_pathmaxrxt = trans->error_threshold; + params.spp_pathmaxrxt = trans->max_retrans; +done: if (copy_to_user(optval, ¶ms, len)) return -EFAULT; @@ -2838,7 +2962,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, * by the change). With TCP-style sockets, this option is inherited by * sockets derived from a listener socket. */ -static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) { if (len != sizeof(struct sctp_initmsg)) return -EINVAL; @@ -2848,7 +2972,7 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int * } static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { sctp_assoc_t id; struct sctp_association *asoc; @@ -2874,16 +2998,16 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, } static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; struct sctp_transport *from; - void *to; + void __user *to; union sctp_addr temp; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); int addrlen; if (len != sizeof(struct sctp_getaddrs)) @@ -2899,7 +3023,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, if (!asoc) return -EINVAL; - to = (void *)getaddrs.addrs; + to = (void __user *)getaddrs.addrs; list_for_each(pos, &asoc->peer.transport_addr_list) { from = list_entry(pos, struct sctp_transport, transports); memcpy(&temp, &from->ipaddr, sizeof(temp)); @@ -2920,12 +3044,16 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, } static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, + int __user *optlen) { sctp_assoc_t id; struct sctp_bind_addr *bp; struct sctp_association *asoc; struct list_head *pos; + struct sctp_sockaddr_entry *addr; + rwlock_t *addr_lock; + unsigned long flags; int cnt = 0; if (len != sizeof(sctp_assoc_t)) @@ -2942,33 +3070,104 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, */ if (0 == id) { bp = &sctp_sk(sk)->ep->base.bind_addr; + addr_lock = &sctp_sk(sk)->ep->base.addr_lock; } else { asoc = sctp_id2assoc(sk, id); if (!asoc) return -EINVAL; bp = &asoc->base.bind_addr; + addr_lock = &asoc->base.addr_lock; + } + + sctp_read_lock(addr_lock); + + /* 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(&addr->a)) { + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); + list_for_each(pos, &sctp_local_addr_list) { + addr = list_entry(pos, + struct sctp_sockaddr_entry, + list); + if ((PF_INET == sk->sk_family) && + (AF_INET6 == addr->a.sa.sa_family)) + continue; + cnt++; + } + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, + flags); + } else { + cnt = 1; + } + goto done; } list_for_each(pos, &bp->address_list) { cnt ++; } +done: + sctp_read_unlock(addr_lock); + return cnt; +} + +/* Helper function that copies local addresses to user and returns the number + * of addresses copied. + */ +static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs, + void __user *to) +{ + struct list_head *pos; + struct sctp_sockaddr_entry *addr; + unsigned long flags; + union sctp_addr temp; + int cnt = 0; + int addrlen; + + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); + list_for_each(pos, &sctp_local_addr_list) { + addr = list_entry(pos, struct sctp_sockaddr_entry, list); + if ((PF_INET == sk->sk_family) && + (AF_INET6 == addr->a.sa.sa_family)) + continue; + memcpy(&temp, &addr->a, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + &temp); + addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; + temp.v4.sin_port = htons(port); + if (copy_to_user(to, &temp, addrlen)) { + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, + flags); + return -EFAULT; + } + to += addrlen; + cnt ++; + if (cnt >= max_addrs) break; + } + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); + return cnt; } static int sctp_getsockopt_local_addrs(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { struct sctp_bind_addr *bp; struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; - struct sctp_sockaddr_entry *from; - void *to; + struct sctp_sockaddr_entry *addr; + void __user *to; union sctp_addr temp; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); int addrlen; + rwlock_t *addr_lock; + int err = 0; if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2985,33 +3184,59 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, */ if (0 == getaddrs.assoc_id) { bp = &sctp_sk(sk)->ep->base.bind_addr; + addr_lock = &sctp_sk(sk)->ep->base.addr_lock; } else { asoc = sctp_id2assoc(sk, getaddrs.assoc_id); if (!asoc) return -EINVAL; bp = &asoc->base.bind_addr; + addr_lock = &asoc->base.addr_lock; + } + + to = getaddrs.addrs; + + sctp_read_lock(addr_lock); + + /* 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(&addr->a)) { + cnt = sctp_copy_laddrs_to_user(sk, bp->port, + getaddrs.addr_num, to); + if (cnt < 0) { + err = cnt; + goto unlock; + } + goto copy_getaddrs; + } } - to = (void *)getaddrs.addrs; list_for_each(pos, &bp->address_list) { - from = list_entry(pos, - struct sctp_sockaddr_entry, - list); - memcpy(&temp, &from->a, sizeof(temp)); + addr = list_entry(pos, struct sctp_sockaddr_entry, 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; temp.v4.sin_port = htons(temp.v4.sin_port); - if (copy_to_user(to, &temp, addrlen)) - return -EFAULT; + if (copy_to_user(to, &temp, addrlen)) { + err = -EFAULT; + goto unlock; + } to += addrlen; cnt ++; if (cnt >= getaddrs.addr_num) break; } + +copy_getaddrs: getaddrs.addr_num = cnt; if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) - return -EFAULT; + err = -EFAULT; - return 0; +unlock: + sctp_read_unlock(addr_lock); + return err; } /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) @@ -3021,11 +3246,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, * association peer's addresses. */ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { struct sctp_prim prim; struct sctp_association *asoc; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (len != sizeof(struct sctp_prim)) return -EINVAL; @@ -3056,6 +3281,29 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, return 0; } +/* + * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +static int sctp_getsockopt_adaption_layer(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + __u32 val; + + if (len < sizeof(__u32)) + return -EINVAL; + + len = sizeof(__u32); + val = sctp_sk(sk)->adaption_ind; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; +} + /* * * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) @@ -3076,11 +3324,12 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, * For getsockopt, it get the default sctp_sndrcvinfo structure. */ static int sctp_getsockopt_default_send_param(struct sock *sk, - int len, char *optval, int *optlen) + int len, char __user *optval, + int __user *optlen) { struct sctp_sndrcvinfo info; struct sctp_association *asoc; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (len != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -3122,7 +3371,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, */ static int sctp_getsockopt_nodelay(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { int val; @@ -3150,8 +3399,9 @@ static int sctp_getsockopt_nodelay(struct sock *sk, int len, * be changed. * */ -static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, - int *optlen) { +static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, + char __user *optval, + int __user *optlen) { struct sctp_rtoinfo rtoinfo; struct sctp_association *asoc; @@ -3168,12 +3418,12 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, /* Values corresponding to the specific association. */ if (asoc) { - rtoinfo.srto_initial = JIFFIES_TO_MSECS(asoc->rto_initial); - rtoinfo.srto_max = JIFFIES_TO_MSECS(asoc->rto_max); - rtoinfo.srto_min = JIFFIES_TO_MSECS(asoc->rto_min); + rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial); + rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max); + rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min); } else { /* Values corresponding to the endpoint. */ - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); rtoinfo.srto_initial = sp->rtoinfo.srto_initial; rtoinfo.srto_max = sp->rtoinfo.srto_max; @@ -3200,8 +3450,9 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, * See [SCTP] for more information. * */ -static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval, - int *optlen) +static int sctp_getsockopt_associnfo(struct sock *sk, int len, + char __user *optval, + int __user *optlen) { struct sctp_assocparams assocparams; @@ -3238,7 +3489,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval, assocparams.sasoc_number_peer_destinations = cnt; } else { /* Values corresponding to the endpoint */ - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; @@ -3270,10 +3521,10 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval, * addresses on the socket. */ static int sctp_getsockopt_mappedv4(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { int val; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); if (len < sizeof(int)) return -EINVAL; @@ -3299,7 +3550,7 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len, * the user. */ static int sctp_getsockopt_maxseg(struct sock *sk, int len, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { int val; @@ -3318,7 +3569,7 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len, } SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { int retval = 0; int len; @@ -3409,6 +3660,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_peer_addr_info(sk, len, optval, optlen); break; + case SCTP_ADAPTION_LAYER: + retval = sctp_getsockopt_adaption_layer(sk, len, optval, + optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -3621,7 +3876,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum) */ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) { - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; /* Only UDP style sockets that are not peeled off are allowed to @@ -3670,7 +3925,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) */ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) { - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; /* If backlog is zero, disable listening. */ @@ -3771,7 +4026,7 @@ cleanup: unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; - struct sctp_opt *sp = sctp_sk(sk); + struct sctp_sock *sp = sctp_sk(sk); unsigned int mask; poll_wait(file, sk->sk_sleep, wait); @@ -3945,12 +4200,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { - /* Check for minimum length. The SCM code has this check. */ - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) return -EINVAL; - } /* Should we parse this header or ignore? */ if (cmsg->cmsg_level != IPPROTO_SCTP) @@ -4132,64 +4383,6 @@ no_packet: return NULL; } -/* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, - int len) -{ - struct sctp_af *af; - - /* Verify basic sockaddr. */ - af = sctp_sockaddr_af(sctp_sk(sk), addr, len); - if (!af) - return -EINVAL; - - /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr, sctp_sk(sk))) - return -EINVAL; - - if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) - return -EINVAL; - - return 0; -} - -/* Get the sndbuf space available at the time on the association. */ -static inline int sctp_wspace(struct sctp_association *asoc) -{ - struct sock *sk = asoc->base.sk; - int amt = 0; - - amt = sk->sk_sndbuf - asoc->sndbuf_used; - if (amt < 0) - amt = 0; - return amt; -} - -/* Increment the used sndbuf space count of the corresponding association by - * the size of the outgoing data chunk. - * Also, set the skb destructor for sndbuf accounting later. - * - * Since it is always 1-1 between chunk and skb, and also a new skb is always - * allocated for chunk bundling in sctp_packet_transmit(), we can use the - * destructor in the data chunk skb for the purpose of the sndbuf space - * tracking. - */ -static inline void sctp_set_owner_w(struct sctp_chunk *chunk) -{ - struct sctp_association *asoc = chunk->asoc; - struct sock *sk = asoc->base.sk; - - /* The sndbuf space is tracked per association. */ - sctp_association_hold(asoc); - - chunk->skb->destructor = sctp_wfree; - /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; - - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); -} - /* If sndbuf has changed, wake up per association sndbuf waiters. */ static void __sctp_write_space(struct sctp_association *asoc) { @@ -4381,7 +4574,11 @@ out: return err; do_error: - err = -ECONNREFUSED; + if (asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1 >= + asoc->max_init_attempts) + err = -ETIMEDOUT; + else + err = -ECONNREFUSED; goto out; do_interrupted: @@ -4457,8 +4654,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, struct sctp_association *assoc, sctp_socket_type_t type) { - struct sctp_opt *oldsp = sctp_sk(oldsk); - struct sctp_opt *newsp = sctp_sk(newsk); + struct sctp_sock *oldsp = sctp_sk(oldsk); + struct sctp_sock *newsp = sctp_sk(newsk); struct sctp_bind_bucket *pp; /* hash list port iterator */ struct sctp_endpoint *newep = newsp->ep; struct sk_buff *skb, *tmp; @@ -4470,7 +4667,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsk->sk_sndbuf = oldsk->sk_sndbuf; newsk->sk_rcvbuf = oldsk->sk_rcvbuf; /* Brute force copy old sctp opt. */ - memcpy(newsp, oldsp, sizeof(struct sctp_opt)); + inet_sk_copy_descendant(newsk, oldsk); /* Restore the ep value that was overwritten with the above structure * copy. @@ -4499,7 +4696,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, * delivery. Three cases: * 1) No partial deliver; no work. * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. - * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue. + * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. */ skb_queue_head_init(&newsp->pd_lobby); sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode; @@ -4553,6 +4750,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", + .owner = THIS_MODULE, .close = sctp_close, .connect = sctp_connect, .disconnect = sctp_disconnect, @@ -4570,4 +4768,30 @@ struct proto sctp_prot = { .hash = sctp_hash, .unhash = sctp_unhash, .get_port = sctp_get_port, + .slab_obj_size = sizeof(struct sctp_sock), +}; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +struct proto sctpv6_prot = { + .name = "SCTPv6", + .owner = THIS_MODULE, + .close = sctp_close, + .connect = sctp_connect, + .disconnect = sctp_disconnect, + .accept = sctp_accept, + .ioctl = sctp_ioctl, + .init = sctp_init_sock, + .destroy = sctp_destroy_sock, + .shutdown = sctp_shutdown, + .setsockopt = sctp_setsockopt, + .getsockopt = sctp_getsockopt, + .sendmsg = sctp_sendmsg, + .recvmsg = sctp_recvmsg, + .bind = sctp_bind, + .backlog_rcv = sctp_backlog_rcv, + .hash = sctp_hash, + .unhash = sctp_unhash, + .get_port = sctp_get_port, + .slab_obj_size = sizeof(struct sctp6_sock), }; +#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */