mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
sctp: fix the issue that flags are ignored when using kernel_connect
Now sctp uses inet_dgram_connect as its proto_ops .connect, and the flags param can't be passed into its proto .connect where this flags is really needed. sctp works around it by getting flags from socket file in __sctp_connect. It works for connecting from userspace, as inherently the user sock has socket file and it passes f_flags as the flags param into the proto_ops .connect. However, the sock created by sock_create_kern doesn't have a socket file, and it passes the flags (like O_NONBLOCK) by using the flags param in kernel_connect, which calls proto_ops .connect later. So to fix it, this patch defines a new proto_ops .connect for sctp, sctp_inet_connect, which calls __sctp_connect() directly with this flags param. After this, the sctp's proto .connect can be removed. Note that sctp_inet_connect doesn't need to do some checks that are not needed for sctp, which makes thing better than with inet_dgram_connect. Suggested-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Reviewed-by: Michal Kubecek <mkubecek@suse.cz> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6741c4bb38
commit
644fbdeacf
4 changed files with 39 additions and 18 deletions
|
@ -103,6 +103,8 @@ void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int);
|
||||||
/*
|
/*
|
||||||
* sctp/socket.c
|
* sctp/socket.c
|
||||||
*/
|
*/
|
||||||
|
int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
|
||||||
|
int addr_len, int flags);
|
||||||
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
|
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
|
||||||
int sctp_inet_listen(struct socket *sock, int backlog);
|
int sctp_inet_listen(struct socket *sock, int backlog);
|
||||||
void sctp_write_space(struct sock *sk);
|
void sctp_write_space(struct sock *sk);
|
||||||
|
|
|
@ -1006,7 +1006,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.release = inet6_release,
|
.release = inet6_release,
|
||||||
.bind = inet6_bind,
|
.bind = inet6_bind,
|
||||||
.connect = inet_dgram_connect,
|
.connect = sctp_inet_connect,
|
||||||
.socketpair = sock_no_socketpair,
|
.socketpair = sock_no_socketpair,
|
||||||
.accept = inet_accept,
|
.accept = inet_accept,
|
||||||
.getname = sctp_getname,
|
.getname = sctp_getname,
|
||||||
|
|
|
@ -1012,7 +1012,7 @@ static const struct proto_ops inet_seqpacket_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.release = inet_release, /* Needs to be wrapped... */
|
.release = inet_release, /* Needs to be wrapped... */
|
||||||
.bind = inet_bind,
|
.bind = inet_bind,
|
||||||
.connect = inet_dgram_connect,
|
.connect = sctp_inet_connect,
|
||||||
.socketpair = sock_no_socketpair,
|
.socketpair = sock_no_socketpair,
|
||||||
.accept = inet_accept,
|
.accept = inet_accept,
|
||||||
.getname = inet_getname, /* Semantics are different. */
|
.getname = inet_getname, /* Semantics are different. */
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
|
||||||
*/
|
*/
|
||||||
static int __sctp_connect(struct sock *sk,
|
static int __sctp_connect(struct sock *sk,
|
||||||
struct sockaddr *kaddrs,
|
struct sockaddr *kaddrs,
|
||||||
int addrs_size,
|
int addrs_size, int flags,
|
||||||
sctp_assoc_t *assoc_id)
|
sctp_assoc_t *assoc_id)
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
|
@ -1104,7 +1104,6 @@ static int __sctp_connect(struct sock *sk,
|
||||||
union sctp_addr *sa_addr = NULL;
|
union sctp_addr *sa_addr = NULL;
|
||||||
void *addr_buf;
|
void *addr_buf;
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
unsigned int f_flags = 0;
|
|
||||||
|
|
||||||
sp = sctp_sk(sk);
|
sp = sctp_sk(sk);
|
||||||
ep = sp->ep;
|
ep = sp->ep;
|
||||||
|
@ -1254,13 +1253,7 @@ static int __sctp_connect(struct sock *sk,
|
||||||
sp->pf->to_sk_daddr(sa_addr, sk);
|
sp->pf->to_sk_daddr(sa_addr, sk);
|
||||||
sk->sk_err = 0;
|
sk->sk_err = 0;
|
||||||
|
|
||||||
/* in-kernel sockets don't generally have a file allocated to them
|
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
|
||||||
* if all they do is call sock_create_kern().
|
|
||||||
*/
|
|
||||||
if (sk->sk_socket->file)
|
|
||||||
f_flags = sk->sk_socket->file->f_flags;
|
|
||||||
|
|
||||||
timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
|
|
||||||
|
|
||||||
if (assoc_id)
|
if (assoc_id)
|
||||||
*assoc_id = asoc->assoc_id;
|
*assoc_id = asoc->assoc_id;
|
||||||
|
@ -1348,7 +1341,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
|
||||||
sctp_assoc_t *assoc_id)
|
sctp_assoc_t *assoc_id)
|
||||||
{
|
{
|
||||||
struct sockaddr *kaddrs;
|
struct sockaddr *kaddrs;
|
||||||
int err = 0;
|
int err = 0, flags = 0;
|
||||||
|
|
||||||
pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
|
pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
|
||||||
__func__, sk, addrs, addrs_size);
|
__func__, sk, addrs, addrs_size);
|
||||||
|
@ -1367,7 +1360,13 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
|
||||||
if (err)
|
if (err)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
|
/* in-kernel sockets don't generally have a file allocated to them
|
||||||
|
* if all they do is call sock_create_kern().
|
||||||
|
*/
|
||||||
|
if (sk->sk_socket->file)
|
||||||
|
flags = sk->sk_socket->file->f_flags;
|
||||||
|
|
||||||
|
err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
kvfree(kaddrs);
|
kvfree(kaddrs);
|
||||||
|
@ -4397,16 +4396,26 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
|
||||||
* len: the size of the address.
|
* len: the size of the address.
|
||||||
*/
|
*/
|
||||||
static int sctp_connect(struct sock *sk, struct sockaddr *addr,
|
static int sctp_connect(struct sock *sk, struct sockaddr *addr,
|
||||||
int addr_len)
|
int addr_len, int flags)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
struct sctp_af *af;
|
struct sctp_af *af;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
|
||||||
pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
|
pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
|
||||||
addr, addr_len);
|
addr, addr_len);
|
||||||
|
|
||||||
|
/* We may need to bind the socket. */
|
||||||
|
if (!inet->inet_num) {
|
||||||
|
if (sk->sk_prot->get_port(sk, 0)) {
|
||||||
|
release_sock(sk);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
inet->inet_sport = htons(inet->inet_num);
|
||||||
|
}
|
||||||
|
|
||||||
/* Validate addr_len before calling common connect/connectx routine. */
|
/* Validate addr_len before calling common connect/connectx routine. */
|
||||||
af = sctp_get_af_specific(addr->sa_family);
|
af = sctp_get_af_specific(addr->sa_family);
|
||||||
if (!af || addr_len < af->sockaddr_len) {
|
if (!af || addr_len < af->sockaddr_len) {
|
||||||
|
@ -4415,13 +4424,25 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr,
|
||||||
/* Pass correct addr len to common routine (so it knows there
|
/* Pass correct addr len to common routine (so it knows there
|
||||||
* is only one address being passed.
|
* is only one address being passed.
|
||||||
*/
|
*/
|
||||||
err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
|
err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
|
||||||
|
int addr_len, int flags)
|
||||||
|
{
|
||||||
|
if (addr_len < sizeof(uaddr->sa_family))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (uaddr->sa_family == AF_UNSPEC)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return sctp_connect(sock->sk, uaddr, addr_len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: Write comments. */
|
/* FIXME: Write comments. */
|
||||||
static int sctp_disconnect(struct sock *sk, int flags)
|
static int sctp_disconnect(struct sock *sk, int flags)
|
||||||
{
|
{
|
||||||
|
@ -8724,7 +8745,6 @@ struct proto sctp_prot = {
|
||||||
.name = "SCTP",
|
.name = "SCTP",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.close = sctp_close,
|
.close = sctp_close,
|
||||||
.connect = sctp_connect,
|
|
||||||
.disconnect = sctp_disconnect,
|
.disconnect = sctp_disconnect,
|
||||||
.accept = sctp_accept,
|
.accept = sctp_accept,
|
||||||
.ioctl = sctp_ioctl,
|
.ioctl = sctp_ioctl,
|
||||||
|
@ -8767,7 +8787,6 @@ struct proto sctpv6_prot = {
|
||||||
.name = "SCTPv6",
|
.name = "SCTPv6",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.close = sctp_close,
|
.close = sctp_close,
|
||||||
.connect = sctp_connect,
|
|
||||||
.disconnect = sctp_disconnect,
|
.disconnect = sctp_disconnect,
|
||||||
.accept = sctp_accept,
|
.accept = sctp_accept,
|
||||||
.ioctl = sctp_ioctl,
|
.ioctl = sctp_ioctl,
|
||||||
|
|
Loading…
Reference in a new issue