diff options
Diffstat (limited to 'drivers/net/ovpn')
-rw-r--r-- | drivers/net/ovpn/io.c | 8 | ||||
-rw-r--r-- | drivers/net/ovpn/netlink.c | 16 | ||||
-rw-r--r-- | drivers/net/ovpn/peer.c | 4 | ||||
-rw-r--r-- | drivers/net/ovpn/socket.c | 68 | ||||
-rw-r--r-- | drivers/net/ovpn/socket.h | 4 | ||||
-rw-r--r-- | drivers/net/ovpn/tcp.c | 73 | ||||
-rw-r--r-- | drivers/net/ovpn/tcp.h | 3 | ||||
-rw-r--r-- | drivers/net/ovpn/udp.c | 46 | ||||
-rw-r--r-- | drivers/net/ovpn/udp.h | 4 |
9 files changed, 118 insertions, 108 deletions
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index 10d8afecec55..ebf1e849506b 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -134,7 +134,7 @@ void ovpn_decrypt_post(void *data, int ret) rcu_read_lock(); sock = rcu_dereference(peer->sock); - if (sock && sock->sock->sk->sk_protocol == IPPROTO_UDP) + if (sock && sock->sk->sk_protocol == IPPROTO_UDP) /* check if this peer changed local or remote endpoint */ ovpn_peer_endpoints_update(peer, skb); rcu_read_unlock(); @@ -270,12 +270,12 @@ void ovpn_encrypt_post(void *data, int ret) if (unlikely(!sock)) goto err_unlock; - switch (sock->sock->sk->sk_protocol) { + switch (sock->sk->sk_protocol) { case IPPROTO_UDP: - ovpn_udp_send_skb(peer, sock->sock, skb); + ovpn_udp_send_skb(peer, sock->sk, skb); break; case IPPROTO_TCP: - ovpn_tcp_send_skb(peer, sock->sock, skb); + ovpn_tcp_send_skb(peer, sock->sk, skb); break; default: /* no transport configured yet */ diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index bea03913bfb1..a4ec53def46e 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -501,7 +501,7 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info) /* when using a TCP socket the remote IP is not expected */ rcu_read_lock(); sock = rcu_dereference(peer->sock); - if (sock && sock->sock->sk->sk_protocol == IPPROTO_TCP && + if (sock && sock->sk->sk_protocol == IPPROTO_TCP && (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])) { rcu_read_unlock(); @@ -559,14 +559,14 @@ static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info, goto err_unlock; } - if (!net_eq(genl_info_net(info), sock_net(sock->sock->sk))) { + if (!net_eq(genl_info_net(info), sock_net(sock->sk))) { id = peernet2id_alloc(genl_info_net(info), - sock_net(sock->sock->sk), + sock_net(sock->sk), GFP_ATOMIC); if (nla_put_s32(skb, OVPN_A_PEER_SOCKET_NETNSID, id)) goto err_unlock; } - local_port = inet_sk(sock->sock->sk)->inet_sport; + local_port = inet_sk(sock->sk)->inet_sport; rcu_read_unlock(); if (nla_put_u32(skb, OVPN_A_PEER_ID, peer->id)) @@ -1153,8 +1153,8 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer) ret = -EINVAL; goto err_unlock; } - genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk), - msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); + genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0, + OVPN_NLGRP_PEERS, GFP_ATOMIC); rcu_read_unlock(); return 0; @@ -1218,8 +1218,8 @@ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id) ret = -EINVAL; goto err_unlock; } - genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk), - msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); + genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0, + OVPN_NLGRP_PEERS, GFP_ATOMIC); rcu_read_unlock(); return 0; diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index a1fd27b9c038..4bfcab0c8652 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -1145,7 +1145,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk, if (sk) { ovpn_sock = rcu_access_pointer(peer->sock); - if (!ovpn_sock || ovpn_sock->sock->sk != sk) { + if (!ovpn_sock || ovpn_sock->sk != sk) { spin_unlock_bh(&ovpn->lock); ovpn_peer_put(peer); return; @@ -1175,7 +1175,7 @@ static void ovpn_peers_release_mp(struct ovpn_priv *ovpn, struct sock *sk, if (sk) { rcu_read_lock(); ovpn_sock = rcu_dereference(peer->sock); - remove = ovpn_sock && ovpn_sock->sock->sk == sk; + remove = ovpn_sock && ovpn_sock->sk == sk; rcu_read_unlock(); } diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c index a83cbab72591..9750871ab65c 100644 --- a/drivers/net/ovpn/socket.c +++ b/drivers/net/ovpn/socket.c @@ -24,9 +24,9 @@ static void ovpn_socket_release_kref(struct kref *kref) struct ovpn_socket *sock = container_of(kref, struct ovpn_socket, refcount); - if (sock->sock->sk->sk_protocol == IPPROTO_UDP) + if (sock->sk->sk_protocol == IPPROTO_UDP) ovpn_udp_socket_detach(sock); - else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) + else if (sock->sk->sk_protocol == IPPROTO_TCP) ovpn_tcp_socket_detach(sock); } @@ -75,14 +75,6 @@ void ovpn_socket_release(struct ovpn_peer *peer) if (!sock) return; - /* sanity check: we should not end up here if the socket - * was already closed - */ - if (!sock->sock->sk) { - DEBUG_NET_WARN_ON_ONCE(1); - return; - } - /* Drop the reference while holding the sock lock to avoid * concurrent ovpn_socket_new call to mess up with a partially * detached socket. @@ -90,22 +82,24 @@ void ovpn_socket_release(struct ovpn_peer *peer) * Holding the lock ensures that a socket with refcnt 0 is fully * detached before it can be picked by a concurrent reader. */ - lock_sock(sock->sock->sk); + lock_sock(sock->sk); released = ovpn_socket_put(peer, sock); - release_sock(sock->sock->sk); + release_sock(sock->sk); /* align all readers with sk_user_data being NULL */ synchronize_rcu(); /* following cleanup should happen with lock released */ if (released) { - if (sock->sock->sk->sk_protocol == IPPROTO_UDP) { + if (sock->sk->sk_protocol == IPPROTO_UDP) { netdev_put(sock->ovpn->dev, &sock->dev_tracker); - } else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) { + } else if (sock->sk->sk_protocol == IPPROTO_TCP) { /* wait for TCP jobs to terminate */ ovpn_tcp_socket_wait_finish(sock); ovpn_peer_put(sock->peer); } + /* drop reference acquired in ovpn_socket_new() */ + sock_put(sock->sk); /* we can call plain kfree() because we already waited one RCU * period due to synchronize_rcu() */ @@ -118,12 +112,14 @@ static bool ovpn_socket_hold(struct ovpn_socket *sock) return kref_get_unless_zero(&sock->refcount); } -static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer) +static int ovpn_socket_attach(struct ovpn_socket *ovpn_sock, + struct socket *sock, + struct ovpn_peer *peer) { - if (sock->sock->sk->sk_protocol == IPPROTO_UDP) - return ovpn_udp_socket_attach(sock, peer->ovpn); - else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) - return ovpn_tcp_socket_attach(sock, peer); + if (sock->sk->sk_protocol == IPPROTO_UDP) + return ovpn_udp_socket_attach(ovpn_sock, sock, peer->ovpn); + else if (sock->sk->sk_protocol == IPPROTO_TCP) + return ovpn_tcp_socket_attach(ovpn_sock, peer); return -EOPNOTSUPP; } @@ -138,14 +134,15 @@ static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer) struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) { struct ovpn_socket *ovpn_sock; + struct sock *sk = sock->sk; int ret; - lock_sock(sock->sk); + lock_sock(sk); /* a TCP socket can only be owned by a single peer, therefore there * can't be any other user */ - if (sock->sk->sk_protocol == IPPROTO_TCP && sock->sk->sk_user_data) { + if (sk->sk_protocol == IPPROTO_TCP && sk->sk_user_data) { ovpn_sock = ERR_PTR(-EBUSY); goto sock_release; } @@ -153,8 +150,8 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) /* a UDP socket can be shared across multiple peers, but we must make * sure it is not owned by something else */ - if (sock->sk->sk_protocol == IPPROTO_UDP) { - u8 type = READ_ONCE(udp_sk(sock->sk)->encap_type); + if (sk->sk_protocol == IPPROTO_UDP) { + u8 type = READ_ONCE(udp_sk(sk)->encap_type); /* socket owned by other encapsulation module */ if (type && type != UDP_ENCAP_OVPNINUDP) { @@ -163,7 +160,7 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) } rcu_read_lock(); - ovpn_sock = rcu_dereference_sk_user_data(sock->sk); + ovpn_sock = rcu_dereference_sk_user_data(sk); if (ovpn_sock) { /* socket owned by another ovpn instance, we can't use it */ if (ovpn_sock->ovpn != peer->ovpn) { @@ -200,11 +197,22 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) goto sock_release; } - ovpn_sock->sock = sock; + ovpn_sock->sk = sk; kref_init(&ovpn_sock->refcount); - ret = ovpn_socket_attach(ovpn_sock, peer); + /* the newly created ovpn_socket is holding reference to sk, + * therefore we increase its refcounter. + * + * This ovpn_socket instance is referenced by all peers + * using the same socket. + * + * ovpn_socket_release() will take care of dropping the reference. + */ + sock_hold(sk); + + ret = ovpn_socket_attach(ovpn_sock, sock, peer); if (ret < 0) { + sock_put(sk); kfree(ovpn_sock); ovpn_sock = ERR_PTR(ret); goto sock_release; @@ -213,11 +221,11 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) /* TCP sockets are per-peer, therefore they are linked to their unique * peer */ - if (sock->sk->sk_protocol == IPPROTO_TCP) { + if (sk->sk_protocol == IPPROTO_TCP) { INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work); ovpn_sock->peer = peer; ovpn_peer_hold(peer); - } else if (sock->sk->sk_protocol == IPPROTO_UDP) { + } else if (sk->sk_protocol == IPPROTO_UDP) { /* in UDP we only link the ovpn instance since the socket is * shared among multiple peers */ @@ -226,8 +234,8 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) GFP_KERNEL); } - rcu_assign_sk_user_data(sock->sk, ovpn_sock); + rcu_assign_sk_user_data(sk, ovpn_sock); sock_release: - release_sock(sock->sk); + release_sock(sk); return ovpn_sock; } diff --git a/drivers/net/ovpn/socket.h b/drivers/net/ovpn/socket.h index 00d856b1a5d8..4afcec71040d 100644 --- a/drivers/net/ovpn/socket.h +++ b/drivers/net/ovpn/socket.h @@ -22,7 +22,7 @@ struct ovpn_peer; * @ovpn: ovpn instance owning this socket (UDP only) * @dev_tracker: reference tracker for associated dev (UDP only) * @peer: unique peer transmitting over this socket (TCP only) - * @sock: the low level sock object + * @sk: the low level sock object * @refcount: amount of contexts currently referencing this object * @work: member used to schedule release routine (it may block) * @tcp_tx_work: work for deferring outgoing packet processing (TCP only) @@ -36,7 +36,7 @@ struct ovpn_socket { struct ovpn_peer *peer; }; - struct socket *sock; + struct sock *sk; struct kref refcount; struct work_struct work; struct work_struct tcp_tx_work; diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c index 7c42d84987ad..289f62c5d2c7 100644 --- a/drivers/net/ovpn/tcp.c +++ b/drivers/net/ovpn/tcp.c @@ -124,14 +124,18 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) * this peer, therefore ovpn_peer_hold() is not expected to fail */ if (WARN_ON(!ovpn_peer_hold(peer))) - goto err; + goto err_nopeer; ovpn_recv(peer, skb); return; err: + /* take reference for deferred peer deletion. should never fail */ + if (WARN_ON(!ovpn_peer_hold(peer))) + goto err_nopeer; + schedule_work(&peer->tcp.defer_del_work); dev_dstats_rx_dropped(peer->ovpn->dev); +err_nopeer: kfree_skb(skb); - ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR); } static int ovpn_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, @@ -186,18 +190,18 @@ out: void ovpn_tcp_socket_detach(struct ovpn_socket *ovpn_sock) { struct ovpn_peer *peer = ovpn_sock->peer; - struct socket *sock = ovpn_sock->sock; + struct sock *sk = ovpn_sock->sk; strp_stop(&peer->tcp.strp); skb_queue_purge(&peer->tcp.user_queue); /* restore CBs that were saved in ovpn_sock_set_tcp_cb() */ - sock->sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready; - sock->sk->sk_write_space = peer->tcp.sk_cb.sk_write_space; - sock->sk->sk_prot = peer->tcp.sk_cb.prot; - sock->sk->sk_socket->ops = peer->tcp.sk_cb.ops; + sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready; + sk->sk_write_space = peer->tcp.sk_cb.sk_write_space; + sk->sk_prot = peer->tcp.sk_cb.prot; + sk->sk_socket->ops = peer->tcp.sk_cb.ops; - rcu_assign_sk_user_data(sock->sk, NULL); + rcu_assign_sk_user_data(sk, NULL); } void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock) @@ -283,10 +287,10 @@ void ovpn_tcp_tx_work(struct work_struct *work) sock = container_of(work, struct ovpn_socket, tcp_tx_work); - lock_sock(sock->sock->sk); + lock_sock(sock->sk); if (sock->peer) - ovpn_tcp_send_sock(sock->peer, sock->sock->sk); - release_sock(sock->sock->sk); + ovpn_tcp_send_sock(sock->peer, sock->sk); + release_sock(sock->sk); } static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk, @@ -307,15 +311,15 @@ static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk, ovpn_tcp_send_sock(peer, sk); } -void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock, +void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk, struct sk_buff *skb) { u16 len = skb->len; *(__be16 *)__skb_push(skb, sizeof(u16)) = htons(len); - spin_lock_nested(&sock->sk->sk_lock.slock, OVPN_TCP_DEPTH_NESTING); - if (sock_owned_by_user(sock->sk)) { + spin_lock_nested(&sk->sk_lock.slock, OVPN_TCP_DEPTH_NESTING); + if (sock_owned_by_user(sk)) { if (skb_queue_len(&peer->tcp.out_queue) >= READ_ONCE(net_hotdata.max_backlog)) { dev_dstats_tx_dropped(peer->ovpn->dev); @@ -324,10 +328,10 @@ void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock, } __skb_queue_tail(&peer->tcp.out_queue, skb); } else { - ovpn_tcp_send_sock_skb(peer, sock->sk, skb); + ovpn_tcp_send_sock_skb(peer, sk, skb); } unlock: - spin_unlock(&sock->sk->sk_lock.slock); + spin_unlock(&sk->sk_lock.slock); } static void ovpn_tcp_release(struct sock *sk) @@ -474,7 +478,6 @@ static void ovpn_tcp_peer_del_work(struct work_struct *work) int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock, struct ovpn_peer *peer) { - struct socket *sock = ovpn_sock->sock; struct strp_callbacks cb = { .rcv_msg = ovpn_tcp_rcv, .parse_msg = ovpn_tcp_parse, @@ -482,20 +485,20 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock, int ret; /* make sure no pre-existing encapsulation handler exists */ - if (sock->sk->sk_user_data) + if (ovpn_sock->sk->sk_user_data) return -EBUSY; /* only a fully connected socket is expected. Connection should be * handled in userspace */ - if (sock->sk->sk_state != TCP_ESTABLISHED) { + if (ovpn_sock->sk->sk_state != TCP_ESTABLISHED) { net_err_ratelimited("%s: provided TCP socket is not in ESTABLISHED state: %d\n", netdev_name(peer->ovpn->dev), - sock->sk->sk_state); + ovpn_sock->sk->sk_state); return -EINVAL; } - ret = strp_init(&peer->tcp.strp, sock->sk, &cb); + ret = strp_init(&peer->tcp.strp, ovpn_sock->sk, &cb); if (ret < 0) { DEBUG_NET_WARN_ON_ONCE(1); return ret; @@ -503,31 +506,31 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock, INIT_WORK(&peer->tcp.defer_del_work, ovpn_tcp_peer_del_work); - __sk_dst_reset(sock->sk); + __sk_dst_reset(ovpn_sock->sk); skb_queue_head_init(&peer->tcp.user_queue); skb_queue_head_init(&peer->tcp.out_queue); /* save current CBs so that they can be restored upon socket release */ - peer->tcp.sk_cb.sk_data_ready = sock->sk->sk_data_ready; - peer->tcp.sk_cb.sk_write_space = sock->sk->sk_write_space; - peer->tcp.sk_cb.prot = sock->sk->sk_prot; - peer->tcp.sk_cb.ops = sock->sk->sk_socket->ops; + peer->tcp.sk_cb.sk_data_ready = ovpn_sock->sk->sk_data_ready; + peer->tcp.sk_cb.sk_write_space = ovpn_sock->sk->sk_write_space; + peer->tcp.sk_cb.prot = ovpn_sock->sk->sk_prot; + peer->tcp.sk_cb.ops = ovpn_sock->sk->sk_socket->ops; /* assign our static CBs and prot/ops */ - sock->sk->sk_data_ready = ovpn_tcp_data_ready; - sock->sk->sk_write_space = ovpn_tcp_write_space; + ovpn_sock->sk->sk_data_ready = ovpn_tcp_data_ready; + ovpn_sock->sk->sk_write_space = ovpn_tcp_write_space; - if (sock->sk->sk_family == AF_INET) { - sock->sk->sk_prot = &ovpn_tcp_prot; - sock->sk->sk_socket->ops = &ovpn_tcp_ops; + if (ovpn_sock->sk->sk_family == AF_INET) { + ovpn_sock->sk->sk_prot = &ovpn_tcp_prot; + ovpn_sock->sk->sk_socket->ops = &ovpn_tcp_ops; } else { - sock->sk->sk_prot = &ovpn_tcp6_prot; - sock->sk->sk_socket->ops = &ovpn_tcp6_ops; + ovpn_sock->sk->sk_prot = &ovpn_tcp6_prot; + ovpn_sock->sk->sk_socket->ops = &ovpn_tcp6_ops; } /* avoid using task_frag */ - sock->sk->sk_allocation = GFP_ATOMIC; - sock->sk->sk_use_task_frag = false; + ovpn_sock->sk->sk_allocation = GFP_ATOMIC; + ovpn_sock->sk->sk_use_task_frag = false; /* enqueue the RX worker */ strp_check_rcv(&peer->tcp.strp); diff --git a/drivers/net/ovpn/tcp.h b/drivers/net/ovpn/tcp.h index 10aefa834cf3..a3aa3570ae5e 100644 --- a/drivers/net/ovpn/tcp.h +++ b/drivers/net/ovpn/tcp.h @@ -30,7 +30,8 @@ void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock); * Required by the OpenVPN protocol in order to extract packets from * the TCP stream on the receiver side. */ -void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock, struct sk_buff *skb); +void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk, + struct sk_buff *skb); void ovpn_tcp_tx_work(struct work_struct *work); #endif /* _NET_OVPN_TCP_H_ */ diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index aef8c0406ec9..bff00946eae2 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -43,7 +43,7 @@ static struct ovpn_socket *ovpn_socket_from_udp_sock(struct sock *sk) return NULL; /* make sure that sk matches our stored transport socket */ - if (unlikely(!ovpn_sock->sock || sk != ovpn_sock->sock->sk)) + if (unlikely(!ovpn_sock->sk || sk != ovpn_sock->sk)) return NULL; return ovpn_sock; @@ -335,32 +335,22 @@ out: /** * ovpn_udp_send_skb - prepare skb and send it over via UDP * @peer: the destination peer - * @sock: the RCU protected peer socket + * @sk: peer socket * @skb: the packet to send */ -void ovpn_udp_send_skb(struct ovpn_peer *peer, struct socket *sock, +void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk, struct sk_buff *skb) { - int ret = -1; + int ret; skb->dev = peer->ovpn->dev; /* no checksum performed at this layer */ skb->ip_summed = CHECKSUM_NONE; - /* get socket info */ - if (unlikely(!sock)) { - net_warn_ratelimited("%s: no sock for remote peer %u\n", - netdev_name(peer->ovpn->dev), peer->id); - goto out; - } - /* crypto layer -> transport (UDP) */ - ret = ovpn_udp_output(peer, &peer->dst_cache, sock->sk, skb); -out: - if (unlikely(ret < 0)) { + ret = ovpn_udp_output(peer, &peer->dst_cache, sk, skb); + if (unlikely(ret < 0)) kfree_skb(skb); - return; - } } static void ovpn_udp_encap_destroy(struct sock *sk) @@ -383,6 +373,7 @@ static void ovpn_udp_encap_destroy(struct sock *sk) /** * ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn * @ovpn_sock: socket to configure + * @sock: the socket container to be passed to setup_udp_tunnel_sock() * @ovpn: the openvp instance to link * * After invoking this function, the sock will be controlled by ovpn so that @@ -390,7 +381,7 @@ static void ovpn_udp_encap_destroy(struct sock *sk) * * Return: 0 on success or a negative error code otherwise */ -int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, +int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock, struct ovpn_priv *ovpn) { struct udp_tunnel_sock_cfg cfg = { @@ -398,17 +389,16 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, .encap_rcv = ovpn_udp_encap_recv, .encap_destroy = ovpn_udp_encap_destroy, }; - struct socket *sock = ovpn_sock->sock; struct ovpn_socket *old_data; int ret; /* make sure no pre-existing encapsulation handler exists */ rcu_read_lock(); - old_data = rcu_dereference_sk_user_data(sock->sk); + old_data = rcu_dereference_sk_user_data(ovpn_sock->sk); if (!old_data) { /* socket is currently unused - we can take it */ rcu_read_unlock(); - setup_udp_tunnel_sock(sock_net(sock->sk), sock, &cfg); + setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock, &cfg); return 0; } @@ -421,7 +411,7 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, * Unlikely TCP, a single UDP socket can be used to talk to many remote * hosts and therefore openvpn instantiates one only for all its peers */ - if ((READ_ONCE(udp_sk(sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) && + if ((READ_ONCE(udp_sk(ovpn_sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) && old_data->ovpn == ovpn) { netdev_dbg(ovpn->dev, "provided socket already owned by this interface\n"); @@ -442,8 +432,16 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, */ void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock) { - struct udp_tunnel_sock_cfg cfg = { }; + struct sock *sk = ovpn_sock->sk; + + /* Re-enable multicast loopback */ + inet_set_bit(MC_LOOP, sk); + /* Disable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */ + inet_dec_convert_csum(sk); + + WRITE_ONCE(udp_sk(sk)->encap_type, 0); + WRITE_ONCE(udp_sk(sk)->encap_rcv, NULL); + WRITE_ONCE(udp_sk(sk)->encap_destroy, NULL); - setup_udp_tunnel_sock(sock_net(ovpn_sock->sock->sk), ovpn_sock->sock, - &cfg); + rcu_assign_sk_user_data(sk, NULL); } diff --git a/drivers/net/ovpn/udp.h b/drivers/net/ovpn/udp.h index 9994eb6e0428..fe26fbe25c5a 100644 --- a/drivers/net/ovpn/udp.h +++ b/drivers/net/ovpn/udp.h @@ -15,11 +15,11 @@ struct ovpn_peer; struct ovpn_priv; struct socket; -int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, +int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock, struct ovpn_priv *ovpn); void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock); -void ovpn_udp_send_skb(struct ovpn_peer *peer, struct socket *sock, +void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk, struct sk_buff *skb); #endif /* _NET_OVPN_UDP_H_ */ |