Loading net/sctp/socket.c +86 −115 Original line number Diff line number Diff line Loading @@ -1606,6 +1606,87 @@ static int sctp_error(struct sock *sk, int flags, int err) static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs); static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, struct sctp_cmsgs *cmsgs, union sctp_addr *daddr, struct sctp_transport **tp) { struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct net *net = sock_net(sk); struct sctp_association *asoc; enum sctp_scope scope; int err = -EINVAL; *tp = NULL; if (sflags & (SCTP_EOF | SCTP_ABORT)) return -EINVAL; if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING))) return -EADDRNOTAVAIL; if (sctp_endpoint_is_peeled_off(ep, daddr)) return -EADDRNOTAVAIL; if (!ep->base.bind_addr.port) { if (sctp_autobind(sk)) return -EAGAIN; } else { if (ep->base.bind_addr.port < inet_prot_sock(net) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) return -EACCES; } scope = sctp_scope(daddr); asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); if (!asoc) return -ENOMEM; if (sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL) < 0) { err = -ENOMEM; goto free; } if (cmsgs->init) { struct sctp_initmsg *init = cmsgs->init; if (init->sinit_num_ostreams) { __u16 outcnt = init->sinit_num_ostreams; asoc->c.sinit_num_ostreams = outcnt; /* outcnt has been changed, need to re-init stream */ err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL); if (err) goto free; } if (init->sinit_max_instreams) asoc->c.sinit_max_instreams = init->sinit_max_instreams; if (init->sinit_max_attempts) asoc->max_init_attempts = init->sinit_max_attempts; if (init->sinit_max_init_timeo) asoc->max_init_timeo = msecs_to_jiffies(init->sinit_max_init_timeo); } *tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); if (!*tp) { err = -ENOMEM; goto free; } return 0; free: sctp_association_free(asoc); return err; } static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, struct msghdr *msg, size_t msg_len, struct sctp_transport *transport, Loading Loading @@ -1715,7 +1796,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) struct sctp_initmsg *sinit; sctp_assoc_t associd = 0; struct sctp_cmsgs cmsgs = { NULL }; enum sctp_scope scope; bool fill_sinfo_ttl = false; __u16 sinfo_flags = 0; int err; Loading Loading @@ -1817,20 +1897,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) if (msg_name) { /* Look for a matching association on the endpoint. */ asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); /* If we could not find a matching association on the * endpoint, make sure that it is not a TCP-style * socket that already has an association or there is * no peeled-off association on another socket. */ if (!asoc && ((sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING))) || sctp_endpoint_is_peeled_off(ep, &to))) { err = -EADDRNOTAVAIL; goto out_unlock; } } else { asoc = sctp_id2assoc(sk, associd); if (!asoc) { Loading Loading @@ -1879,108 +1945,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) /* Do we need to create the association? */ if (!asoc) { pr_debug("%s: there is no association yet\n", __func__); if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) { err = -EINVAL; goto out_unlock; } /* Check for invalid stream against the stream counts, * either the default or the user specified stream counts. */ if (sinfo) { if (!sinit || !sinit->sinit_num_ostreams) { /* Check against the defaults. */ if (sinfo->sinfo_stream >= sp->initmsg.sinit_num_ostreams) { err = -EINVAL; goto out_unlock; } } else { /* Check against the requested. */ if (sinfo->sinfo_stream >= sinit->sinit_num_ostreams) { err = -EINVAL; goto out_unlock; } } } /* * API 3.1.2 bind() - UDP Style Syntax * If a bind() or sctp_bindx() is not called prior to a * sendmsg() call that initiates a new association, the * system picks an ephemeral port and will choose an address * set equivalent to binding with a wildcard address. */ if (!ep->base.bind_addr.port) { if (sctp_autobind(sk)) { err = -EAGAIN; goto out_unlock; } } else { /* * If an unprivileged user inherits a one-to-many * style socket with open associations on a privileged * port, it MAY be permitted to accept new associations, * but it SHOULD NOT be permitted to open new * associations. */ if (ep->base.bind_addr.port < inet_prot_sock(net) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { err = -EACCES; goto out_unlock; } } scope = sctp_scope(&to); new_asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); if (!new_asoc) { err = -ENOMEM; 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. */ if (sinit) { if (sinit->sinit_num_ostreams) { __u16 outcnt = sinit->sinit_num_ostreams; asoc->c.sinit_num_ostreams = outcnt; /* outcnt has been changed, so re-init stream */ err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL); err = sctp_sendmsg_new_asoc(sk, sinfo_flags, &cmsgs, &to, &transport); if (err) goto out_free; } if (sinit->sinit_max_instreams) { asoc->c.sinit_max_instreams = sinit->sinit_max_instreams; } if (sinit->sinit_max_attempts) { asoc->max_init_attempts = sinit->sinit_max_attempts; } if (sinit->sinit_max_init_timeo) { asoc->max_init_timeo = msecs_to_jiffies(sinit->sinit_max_init_timeo); } } goto out_unlock; /* Prime the peer's transport structures. */ transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN); if (!transport) { err = -ENOMEM; goto out_free; } asoc = transport->asoc; new_asoc = asoc; } /* ASSERT: we have a valid association at this point. */ Loading Loading
net/sctp/socket.c +86 −115 Original line number Diff line number Diff line Loading @@ -1606,6 +1606,87 @@ static int sctp_error(struct sock *sk, int flags, int err) static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs); static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, struct sctp_cmsgs *cmsgs, union sctp_addr *daddr, struct sctp_transport **tp) { struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct net *net = sock_net(sk); struct sctp_association *asoc; enum sctp_scope scope; int err = -EINVAL; *tp = NULL; if (sflags & (SCTP_EOF | SCTP_ABORT)) return -EINVAL; if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING))) return -EADDRNOTAVAIL; if (sctp_endpoint_is_peeled_off(ep, daddr)) return -EADDRNOTAVAIL; if (!ep->base.bind_addr.port) { if (sctp_autobind(sk)) return -EAGAIN; } else { if (ep->base.bind_addr.port < inet_prot_sock(net) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) return -EACCES; } scope = sctp_scope(daddr); asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); if (!asoc) return -ENOMEM; if (sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL) < 0) { err = -ENOMEM; goto free; } if (cmsgs->init) { struct sctp_initmsg *init = cmsgs->init; if (init->sinit_num_ostreams) { __u16 outcnt = init->sinit_num_ostreams; asoc->c.sinit_num_ostreams = outcnt; /* outcnt has been changed, need to re-init stream */ err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL); if (err) goto free; } if (init->sinit_max_instreams) asoc->c.sinit_max_instreams = init->sinit_max_instreams; if (init->sinit_max_attempts) asoc->max_init_attempts = init->sinit_max_attempts; if (init->sinit_max_init_timeo) asoc->max_init_timeo = msecs_to_jiffies(init->sinit_max_init_timeo); } *tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); if (!*tp) { err = -ENOMEM; goto free; } return 0; free: sctp_association_free(asoc); return err; } static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, struct msghdr *msg, size_t msg_len, struct sctp_transport *transport, Loading Loading @@ -1715,7 +1796,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) struct sctp_initmsg *sinit; sctp_assoc_t associd = 0; struct sctp_cmsgs cmsgs = { NULL }; enum sctp_scope scope; bool fill_sinfo_ttl = false; __u16 sinfo_flags = 0; int err; Loading Loading @@ -1817,20 +1897,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) if (msg_name) { /* Look for a matching association on the endpoint. */ asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); /* If we could not find a matching association on the * endpoint, make sure that it is not a TCP-style * socket that already has an association or there is * no peeled-off association on another socket. */ if (!asoc && ((sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING))) || sctp_endpoint_is_peeled_off(ep, &to))) { err = -EADDRNOTAVAIL; goto out_unlock; } } else { asoc = sctp_id2assoc(sk, associd); if (!asoc) { Loading Loading @@ -1879,108 +1945,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) /* Do we need to create the association? */ if (!asoc) { pr_debug("%s: there is no association yet\n", __func__); if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) { err = -EINVAL; goto out_unlock; } /* Check for invalid stream against the stream counts, * either the default or the user specified stream counts. */ if (sinfo) { if (!sinit || !sinit->sinit_num_ostreams) { /* Check against the defaults. */ if (sinfo->sinfo_stream >= sp->initmsg.sinit_num_ostreams) { err = -EINVAL; goto out_unlock; } } else { /* Check against the requested. */ if (sinfo->sinfo_stream >= sinit->sinit_num_ostreams) { err = -EINVAL; goto out_unlock; } } } /* * API 3.1.2 bind() - UDP Style Syntax * If a bind() or sctp_bindx() is not called prior to a * sendmsg() call that initiates a new association, the * system picks an ephemeral port and will choose an address * set equivalent to binding with a wildcard address. */ if (!ep->base.bind_addr.port) { if (sctp_autobind(sk)) { err = -EAGAIN; goto out_unlock; } } else { /* * If an unprivileged user inherits a one-to-many * style socket with open associations on a privileged * port, it MAY be permitted to accept new associations, * but it SHOULD NOT be permitted to open new * associations. */ if (ep->base.bind_addr.port < inet_prot_sock(net) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { err = -EACCES; goto out_unlock; } } scope = sctp_scope(&to); new_asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); if (!new_asoc) { err = -ENOMEM; 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. */ if (sinit) { if (sinit->sinit_num_ostreams) { __u16 outcnt = sinit->sinit_num_ostreams; asoc->c.sinit_num_ostreams = outcnt; /* outcnt has been changed, so re-init stream */ err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL); err = sctp_sendmsg_new_asoc(sk, sinfo_flags, &cmsgs, &to, &transport); if (err) goto out_free; } if (sinit->sinit_max_instreams) { asoc->c.sinit_max_instreams = sinit->sinit_max_instreams; } if (sinit->sinit_max_attempts) { asoc->max_init_attempts = sinit->sinit_max_attempts; } if (sinit->sinit_max_init_timeo) { asoc->max_init_timeo = msecs_to_jiffies(sinit->sinit_max_init_timeo); } } goto out_unlock; /* Prime the peer's transport structures. */ transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN); if (!transport) { err = -ENOMEM; goto out_free; } asoc = transport->asoc; new_asoc = asoc; } /* ASSERT: we have a valid association at this point. */ Loading