18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Kernel Connection Multiplexor
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Tom Herbert <tom@herbertland.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bpf.h>
98c2ecf20Sopenharmony_ci#include <linux/errno.h>
108c2ecf20Sopenharmony_ci#include <linux/errqueue.h>
118c2ecf20Sopenharmony_ci#include <linux/file.h>
128c2ecf20Sopenharmony_ci#include <linux/in.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/net.h>
168c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
178c2ecf20Sopenharmony_ci#include <linux/poll.h>
188c2ecf20Sopenharmony_ci#include <linux/rculist.h>
198c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
208c2ecf20Sopenharmony_ci#include <linux/socket.h>
218c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
228c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
238c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
248c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <net/kcm.h>
278c2ecf20Sopenharmony_ci#include <net/netns/generic.h>
288c2ecf20Sopenharmony_ci#include <net/sock.h>
298c2ecf20Sopenharmony_ci#include <uapi/linux/kcm.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciunsigned int kcm_net_id;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic struct kmem_cache *kcm_psockp __read_mostly;
348c2ecf20Sopenharmony_cistatic struct kmem_cache *kcm_muxp __read_mostly;
358c2ecf20Sopenharmony_cistatic struct workqueue_struct *kcm_wq;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline struct kcm_sock *kcm_sk(const struct sock *sk)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	return (struct kcm_sock *)sk;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline struct kcm_tx_msg *kcm_tx_msg(struct sk_buff *skb)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	return (struct kcm_tx_msg *)skb->cb;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic void report_csk_error(struct sock *csk, int err)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	csk->sk_err = EPIPE;
508c2ecf20Sopenharmony_ci	csk->sk_error_report(csk);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void kcm_abort_tx_psock(struct kcm_psock *psock, int err,
548c2ecf20Sopenharmony_ci			       bool wakeup_kcm)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct sock *csk = psock->sk;
578c2ecf20Sopenharmony_ci	struct kcm_mux *mux = psock->mux;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* Unrecoverable error in transmit */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (psock->tx_stopped) {
648c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
658c2ecf20Sopenharmony_ci		return;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	psock->tx_stopped = 1;
698c2ecf20Sopenharmony_ci	KCM_STATS_INCR(psock->stats.tx_aborts);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (!psock->tx_kcm) {
728c2ecf20Sopenharmony_ci		/* Take off psocks_avail list */
738c2ecf20Sopenharmony_ci		list_del(&psock->psock_avail_list);
748c2ecf20Sopenharmony_ci	} else if (wakeup_kcm) {
758c2ecf20Sopenharmony_ci		/* In this case psock is being aborted while outside of
768c2ecf20Sopenharmony_ci		 * write_msgs and psock is reserved. Schedule tx_work
778c2ecf20Sopenharmony_ci		 * to handle the failure there. Need to commit tx_stopped
788c2ecf20Sopenharmony_ci		 * before queuing work.
798c2ecf20Sopenharmony_ci		 */
808c2ecf20Sopenharmony_ci		smp_mb();
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		queue_work(kcm_wq, &psock->tx_kcm->tx_work);
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	/* Report error on lower socket */
888c2ecf20Sopenharmony_ci	report_csk_error(csk, err);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* RX mux lock held. */
928c2ecf20Sopenharmony_cistatic void kcm_update_rx_mux_stats(struct kcm_mux *mux,
938c2ecf20Sopenharmony_ci				    struct kcm_psock *psock)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	STRP_STATS_ADD(mux->stats.rx_bytes,
968c2ecf20Sopenharmony_ci		       psock->strp.stats.bytes -
978c2ecf20Sopenharmony_ci		       psock->saved_rx_bytes);
988c2ecf20Sopenharmony_ci	mux->stats.rx_msgs +=
998c2ecf20Sopenharmony_ci		psock->strp.stats.msgs - psock->saved_rx_msgs;
1008c2ecf20Sopenharmony_ci	psock->saved_rx_msgs = psock->strp.stats.msgs;
1018c2ecf20Sopenharmony_ci	psock->saved_rx_bytes = psock->strp.stats.bytes;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void kcm_update_tx_mux_stats(struct kcm_mux *mux,
1058c2ecf20Sopenharmony_ci				    struct kcm_psock *psock)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	KCM_STATS_ADD(mux->stats.tx_bytes,
1088c2ecf20Sopenharmony_ci		      psock->stats.tx_bytes - psock->saved_tx_bytes);
1098c2ecf20Sopenharmony_ci	mux->stats.tx_msgs +=
1108c2ecf20Sopenharmony_ci		psock->stats.tx_msgs - psock->saved_tx_msgs;
1118c2ecf20Sopenharmony_ci	psock->saved_tx_msgs = psock->stats.tx_msgs;
1128c2ecf20Sopenharmony_ci	psock->saved_tx_bytes = psock->stats.tx_bytes;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* KCM is ready to receive messages on its queue-- either the KCM is new or
1188c2ecf20Sopenharmony_ci * has become unblocked after being blocked on full socket buffer. Queue any
1198c2ecf20Sopenharmony_ci * pending ready messages on a psock. RX mux lock held.
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_cistatic void kcm_rcv_ready(struct kcm_sock *kcm)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
1248c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
1258c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (unlikely(kcm->rx_wait || kcm->rx_psock || kcm->rx_disabled))
1288c2ecf20Sopenharmony_ci		return;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	while (unlikely((skb = __skb_dequeue(&mux->rx_hold_queue)))) {
1318c2ecf20Sopenharmony_ci		if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
1328c2ecf20Sopenharmony_ci			/* Assuming buffer limit has been reached */
1338c2ecf20Sopenharmony_ci			skb_queue_head(&mux->rx_hold_queue, skb);
1348c2ecf20Sopenharmony_ci			WARN_ON(!sk_rmem_alloc_get(&kcm->sk));
1358c2ecf20Sopenharmony_ci			return;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	while (!list_empty(&mux->psocks_ready)) {
1408c2ecf20Sopenharmony_ci		psock = list_first_entry(&mux->psocks_ready, struct kcm_psock,
1418c2ecf20Sopenharmony_ci					 psock_ready_list);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		if (kcm_queue_rcv_skb(&kcm->sk, psock->ready_rx_msg)) {
1448c2ecf20Sopenharmony_ci			/* Assuming buffer limit has been reached */
1458c2ecf20Sopenharmony_ci			WARN_ON(!sk_rmem_alloc_get(&kcm->sk));
1468c2ecf20Sopenharmony_ci			return;
1478c2ecf20Sopenharmony_ci		}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		/* Consumed the ready message on the psock. Schedule rx_work to
1508c2ecf20Sopenharmony_ci		 * get more messages.
1518c2ecf20Sopenharmony_ci		 */
1528c2ecf20Sopenharmony_ci		list_del(&psock->psock_ready_list);
1538c2ecf20Sopenharmony_ci		psock->ready_rx_msg = NULL;
1548c2ecf20Sopenharmony_ci		/* Commit clearing of ready_rx_msg for queuing work */
1558c2ecf20Sopenharmony_ci		smp_mb();
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		strp_unpause(&psock->strp);
1588c2ecf20Sopenharmony_ci		strp_check_rcv(&psock->strp);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Buffer limit is okay now, add to ready list */
1628c2ecf20Sopenharmony_ci	list_add_tail(&kcm->wait_rx_list,
1638c2ecf20Sopenharmony_ci		      &kcm->mux->kcm_rx_waiters);
1648c2ecf20Sopenharmony_ci	/* paired with lockless reads in kcm_rfree() */
1658c2ecf20Sopenharmony_ci	WRITE_ONCE(kcm->rx_wait, true);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic void kcm_rfree(struct sk_buff *skb)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct sock *sk = skb->sk;
1718c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sk);
1728c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
1738c2ecf20Sopenharmony_ci	unsigned int len = skb->truesize;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	sk_mem_uncharge(sk, len);
1768c2ecf20Sopenharmony_ci	atomic_sub(len, &sk->sk_rmem_alloc);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* For reading rx_wait and rx_psock without holding lock */
1798c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (!READ_ONCE(kcm->rx_wait) && !READ_ONCE(kcm->rx_psock) &&
1828c2ecf20Sopenharmony_ci	    sk_rmem_alloc_get(sk) < sk->sk_rcvlowat) {
1838c2ecf20Sopenharmony_ci		spin_lock_bh(&mux->rx_lock);
1848c2ecf20Sopenharmony_ci		kcm_rcv_ready(kcm);
1858c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->rx_lock);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct sk_buff_head *list = &sk->sk_receive_queue;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
1948c2ecf20Sopenharmony_ci		return -ENOMEM;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (!sk_rmem_schedule(sk, skb, skb->truesize))
1978c2ecf20Sopenharmony_ci		return -ENOBUFS;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	skb->dev = NULL;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	skb_orphan(skb);
2028c2ecf20Sopenharmony_ci	skb->sk = sk;
2038c2ecf20Sopenharmony_ci	skb->destructor = kcm_rfree;
2048c2ecf20Sopenharmony_ci	atomic_add(skb->truesize, &sk->sk_rmem_alloc);
2058c2ecf20Sopenharmony_ci	sk_mem_charge(sk, skb->truesize);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	skb_queue_tail(list, skb);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD))
2108c2ecf20Sopenharmony_ci		sk->sk_data_ready(sk);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/* Requeue received messages for a kcm socket to other kcm sockets. This is
2168c2ecf20Sopenharmony_ci * called with a kcm socket is receive disabled.
2178c2ecf20Sopenharmony_ci * RX mux lock held.
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_cistatic void requeue_rx_msgs(struct kcm_mux *mux, struct sk_buff_head *head)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2228c2ecf20Sopenharmony_ci	struct kcm_sock *kcm;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(head))) {
2258c2ecf20Sopenharmony_ci		/* Reset destructor to avoid calling kcm_rcv_ready */
2268c2ecf20Sopenharmony_ci		skb->destructor = sock_rfree;
2278c2ecf20Sopenharmony_ci		skb_orphan(skb);
2288c2ecf20Sopenharmony_citry_again:
2298c2ecf20Sopenharmony_ci		if (list_empty(&mux->kcm_rx_waiters)) {
2308c2ecf20Sopenharmony_ci			skb_queue_tail(&mux->rx_hold_queue, skb);
2318c2ecf20Sopenharmony_ci			continue;
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		kcm = list_first_entry(&mux->kcm_rx_waiters,
2358c2ecf20Sopenharmony_ci				       struct kcm_sock, wait_rx_list);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
2388c2ecf20Sopenharmony_ci			/* Should mean socket buffer full */
2398c2ecf20Sopenharmony_ci			list_del(&kcm->wait_rx_list);
2408c2ecf20Sopenharmony_ci			/* paired with lockless reads in kcm_rfree() */
2418c2ecf20Sopenharmony_ci			WRITE_ONCE(kcm->rx_wait, false);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci			/* Commit rx_wait to read in kcm_free */
2448c2ecf20Sopenharmony_ci			smp_wmb();
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci			goto try_again;
2478c2ecf20Sopenharmony_ci		}
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Lower sock lock held */
2528c2ecf20Sopenharmony_cistatic struct kcm_sock *reserve_rx_kcm(struct kcm_psock *psock,
2538c2ecf20Sopenharmony_ci				       struct sk_buff *head)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct kcm_mux *mux = psock->mux;
2568c2ecf20Sopenharmony_ci	struct kcm_sock *kcm;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	WARN_ON(psock->ready_rx_msg);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (psock->rx_kcm)
2618c2ecf20Sopenharmony_ci		return psock->rx_kcm;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (psock->rx_kcm) {
2668c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->rx_lock);
2678c2ecf20Sopenharmony_ci		return psock->rx_kcm;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	kcm_update_rx_mux_stats(mux, psock);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (list_empty(&mux->kcm_rx_waiters)) {
2738c2ecf20Sopenharmony_ci		psock->ready_rx_msg = head;
2748c2ecf20Sopenharmony_ci		strp_pause(&psock->strp);
2758c2ecf20Sopenharmony_ci		list_add_tail(&psock->psock_ready_list,
2768c2ecf20Sopenharmony_ci			      &mux->psocks_ready);
2778c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->rx_lock);
2788c2ecf20Sopenharmony_ci		return NULL;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	kcm = list_first_entry(&mux->kcm_rx_waiters,
2828c2ecf20Sopenharmony_ci			       struct kcm_sock, wait_rx_list);
2838c2ecf20Sopenharmony_ci	list_del(&kcm->wait_rx_list);
2848c2ecf20Sopenharmony_ci	/* paired with lockless reads in kcm_rfree() */
2858c2ecf20Sopenharmony_ci	WRITE_ONCE(kcm->rx_wait, false);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	psock->rx_kcm = kcm;
2888c2ecf20Sopenharmony_ci	/* paired with lockless reads in kcm_rfree() */
2898c2ecf20Sopenharmony_ci	WRITE_ONCE(kcm->rx_psock, psock);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	return kcm;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic void kcm_done(struct kcm_sock *kcm);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic void kcm_done_work(struct work_struct *w)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	kcm_done(container_of(w, struct kcm_sock, done_work));
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/* Lower sock held */
3048c2ecf20Sopenharmony_cistatic void unreserve_rx_kcm(struct kcm_psock *psock,
3058c2ecf20Sopenharmony_ci			     bool rcv_ready)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = psock->rx_kcm;
3088c2ecf20Sopenharmony_ci	struct kcm_mux *mux = psock->mux;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (!kcm)
3118c2ecf20Sopenharmony_ci		return;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	psock->rx_kcm = NULL;
3168c2ecf20Sopenharmony_ci	/* paired with lockless reads in kcm_rfree() */
3178c2ecf20Sopenharmony_ci	WRITE_ONCE(kcm->rx_psock, NULL);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* Commit kcm->rx_psock before sk_rmem_alloc_get to sync with
3208c2ecf20Sopenharmony_ci	 * kcm_rfree
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	smp_mb();
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (unlikely(kcm->done)) {
3258c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->rx_lock);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		/* Need to run kcm_done in a task since we need to qcquire
3288c2ecf20Sopenharmony_ci		 * callback locks which may already be held here.
3298c2ecf20Sopenharmony_ci		 */
3308c2ecf20Sopenharmony_ci		INIT_WORK(&kcm->done_work, kcm_done_work);
3318c2ecf20Sopenharmony_ci		schedule_work(&kcm->done_work);
3328c2ecf20Sopenharmony_ci		return;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (unlikely(kcm->rx_disabled)) {
3368c2ecf20Sopenharmony_ci		requeue_rx_msgs(mux, &kcm->sk.sk_receive_queue);
3378c2ecf20Sopenharmony_ci	} else if (rcv_ready || unlikely(!sk_rmem_alloc_get(&kcm->sk))) {
3388c2ecf20Sopenharmony_ci		/* Check for degenerative race with rx_wait that all
3398c2ecf20Sopenharmony_ci		 * data was dequeued (accounted for in kcm_rfree).
3408c2ecf20Sopenharmony_ci		 */
3418c2ecf20Sopenharmony_ci		kcm_rcv_ready(kcm);
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci/* Lower sock lock held */
3478c2ecf20Sopenharmony_cistatic void psock_data_ready(struct sock *sk)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	psock = (struct kcm_psock *)sk->sk_user_data;
3548c2ecf20Sopenharmony_ci	if (likely(psock))
3558c2ecf20Sopenharmony_ci		strp_data_ready(&psock->strp);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/* Called with lower sock held */
3618c2ecf20Sopenharmony_cistatic void kcm_rcv_strparser(struct strparser *strp, struct sk_buff *skb)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct kcm_psock *psock = container_of(strp, struct kcm_psock, strp);
3648c2ecf20Sopenharmony_ci	struct kcm_sock *kcm;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_citry_queue:
3678c2ecf20Sopenharmony_ci	kcm = reserve_rx_kcm(psock, skb);
3688c2ecf20Sopenharmony_ci	if (!kcm) {
3698c2ecf20Sopenharmony_ci		 /* Unable to reserve a KCM, message is held in psock and strp
3708c2ecf20Sopenharmony_ci		  * is paused.
3718c2ecf20Sopenharmony_ci		  */
3728c2ecf20Sopenharmony_ci		return;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
3768c2ecf20Sopenharmony_ci		/* Should mean socket buffer full */
3778c2ecf20Sopenharmony_ci		unreserve_rx_kcm(psock, false);
3788c2ecf20Sopenharmony_ci		goto try_queue;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic int kcm_parse_func_strparser(struct strparser *strp, struct sk_buff *skb)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct kcm_psock *psock = container_of(strp, struct kcm_psock, strp);
3858c2ecf20Sopenharmony_ci	struct bpf_prog *prog = psock->bpf_prog;
3868c2ecf20Sopenharmony_ci	int res;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	res = bpf_prog_run_pin_on_cpu(prog, skb);
3898c2ecf20Sopenharmony_ci	return res;
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int kcm_read_sock_done(struct strparser *strp, int err)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct kcm_psock *psock = container_of(strp, struct kcm_psock, strp);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	unreserve_rx_kcm(psock, true);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return err;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic void psock_state_change(struct sock *sk)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	/* TCP only does a EPOLLIN for a half close. Do a EPOLLHUP here
4048c2ecf20Sopenharmony_ci	 * since application will normally not poll with EPOLLIN
4058c2ecf20Sopenharmony_ci	 * on the TCP sockets.
4068c2ecf20Sopenharmony_ci	 */
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	report_csk_error(sk, EPIPE);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic void psock_write_space(struct sock *sk)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
4148c2ecf20Sopenharmony_ci	struct kcm_mux *mux;
4158c2ecf20Sopenharmony_ci	struct kcm_sock *kcm;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	psock = (struct kcm_psock *)sk->sk_user_data;
4208c2ecf20Sopenharmony_ci	if (unlikely(!psock))
4218c2ecf20Sopenharmony_ci		goto out;
4228c2ecf20Sopenharmony_ci	mux = psock->mux;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* Check if the socket is reserved so someone is waiting for sending. */
4278c2ecf20Sopenharmony_ci	kcm = psock->tx_kcm;
4288c2ecf20Sopenharmony_ci	if (kcm && !unlikely(kcm->tx_stopped))
4298c2ecf20Sopenharmony_ci		queue_work(kcm_wq, &kcm->tx_work);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
4328c2ecf20Sopenharmony_ciout:
4338c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic void unreserve_psock(struct kcm_sock *kcm);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/* kcm sock is locked. */
4398c2ecf20Sopenharmony_cistatic struct kcm_psock *reserve_psock(struct kcm_sock *kcm)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
4428c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	psock = kcm->tx_psock;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	smp_rmb(); /* Must read tx_psock before tx_wait */
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (psock) {
4498c2ecf20Sopenharmony_ci		WARN_ON(kcm->tx_wait);
4508c2ecf20Sopenharmony_ci		if (unlikely(psock->tx_stopped))
4518c2ecf20Sopenharmony_ci			unreserve_psock(kcm);
4528c2ecf20Sopenharmony_ci		else
4538c2ecf20Sopenharmony_ci			return kcm->tx_psock;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* Check again under lock to see if psock was reserved for this
4598c2ecf20Sopenharmony_ci	 * psock via psock_unreserve.
4608c2ecf20Sopenharmony_ci	 */
4618c2ecf20Sopenharmony_ci	psock = kcm->tx_psock;
4628c2ecf20Sopenharmony_ci	if (unlikely(psock)) {
4638c2ecf20Sopenharmony_ci		WARN_ON(kcm->tx_wait);
4648c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
4658c2ecf20Sopenharmony_ci		return kcm->tx_psock;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (!list_empty(&mux->psocks_avail)) {
4698c2ecf20Sopenharmony_ci		psock = list_first_entry(&mux->psocks_avail,
4708c2ecf20Sopenharmony_ci					 struct kcm_psock,
4718c2ecf20Sopenharmony_ci					 psock_avail_list);
4728c2ecf20Sopenharmony_ci		list_del(&psock->psock_avail_list);
4738c2ecf20Sopenharmony_ci		if (kcm->tx_wait) {
4748c2ecf20Sopenharmony_ci			list_del(&kcm->wait_psock_list);
4758c2ecf20Sopenharmony_ci			kcm->tx_wait = false;
4768c2ecf20Sopenharmony_ci		}
4778c2ecf20Sopenharmony_ci		kcm->tx_psock = psock;
4788c2ecf20Sopenharmony_ci		psock->tx_kcm = kcm;
4798c2ecf20Sopenharmony_ci		KCM_STATS_INCR(psock->stats.reserved);
4808c2ecf20Sopenharmony_ci	} else if (!kcm->tx_wait) {
4818c2ecf20Sopenharmony_ci		list_add_tail(&kcm->wait_psock_list,
4828c2ecf20Sopenharmony_ci			      &mux->kcm_tx_waiters);
4838c2ecf20Sopenharmony_ci		kcm->tx_wait = true;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return psock;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci/* mux lock held */
4928c2ecf20Sopenharmony_cistatic void psock_now_avail(struct kcm_psock *psock)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct kcm_mux *mux = psock->mux;
4958c2ecf20Sopenharmony_ci	struct kcm_sock *kcm;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (list_empty(&mux->kcm_tx_waiters)) {
4988c2ecf20Sopenharmony_ci		list_add_tail(&psock->psock_avail_list,
4998c2ecf20Sopenharmony_ci			      &mux->psocks_avail);
5008c2ecf20Sopenharmony_ci	} else {
5018c2ecf20Sopenharmony_ci		kcm = list_first_entry(&mux->kcm_tx_waiters,
5028c2ecf20Sopenharmony_ci				       struct kcm_sock,
5038c2ecf20Sopenharmony_ci				       wait_psock_list);
5048c2ecf20Sopenharmony_ci		list_del(&kcm->wait_psock_list);
5058c2ecf20Sopenharmony_ci		kcm->tx_wait = false;
5068c2ecf20Sopenharmony_ci		psock->tx_kcm = kcm;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		/* Commit before changing tx_psock since that is read in
5098c2ecf20Sopenharmony_ci		 * reserve_psock before queuing work.
5108c2ecf20Sopenharmony_ci		 */
5118c2ecf20Sopenharmony_ci		smp_mb();
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		kcm->tx_psock = psock;
5148c2ecf20Sopenharmony_ci		KCM_STATS_INCR(psock->stats.reserved);
5158c2ecf20Sopenharmony_ci		queue_work(kcm_wq, &kcm->tx_work);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/* kcm sock is locked. */
5208c2ecf20Sopenharmony_cistatic void unreserve_psock(struct kcm_sock *kcm)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
5238c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	psock = kcm->tx_psock;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (WARN_ON(!psock)) {
5308c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
5318c2ecf20Sopenharmony_ci		return;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	smp_rmb(); /* Read tx_psock before tx_wait */
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	kcm_update_tx_mux_stats(mux, psock);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	WARN_ON(kcm->tx_wait);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	kcm->tx_psock = NULL;
5418c2ecf20Sopenharmony_ci	psock->tx_kcm = NULL;
5428c2ecf20Sopenharmony_ci	KCM_STATS_INCR(psock->stats.unreserved);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (unlikely(psock->tx_stopped)) {
5458c2ecf20Sopenharmony_ci		if (psock->done) {
5468c2ecf20Sopenharmony_ci			/* Deferred free */
5478c2ecf20Sopenharmony_ci			list_del(&psock->psock_list);
5488c2ecf20Sopenharmony_ci			mux->psocks_cnt--;
5498c2ecf20Sopenharmony_ci			sock_put(psock->sk);
5508c2ecf20Sopenharmony_ci			fput(psock->sk->sk_socket->file);
5518c2ecf20Sopenharmony_ci			kmem_cache_free(kcm_psockp, psock);
5528c2ecf20Sopenharmony_ci		}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		/* Don't put back on available list */
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		return;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	psock_now_avail(psock);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic void kcm_report_tx_retry(struct kcm_sock *kcm)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
5718c2ecf20Sopenharmony_ci	KCM_STATS_INCR(mux->stats.tx_retries);
5728c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/* Write any messages ready on the kcm socket.  Called with kcm sock lock
5768c2ecf20Sopenharmony_ci * held.  Return bytes actually sent or error.
5778c2ecf20Sopenharmony_ci */
5788c2ecf20Sopenharmony_cistatic int kcm_write_msgs(struct kcm_sock *kcm)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct sock *sk = &kcm->sk;
5818c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
5828c2ecf20Sopenharmony_ci	struct sk_buff *skb, *head;
5838c2ecf20Sopenharmony_ci	struct kcm_tx_msg *txm;
5848c2ecf20Sopenharmony_ci	unsigned short fragidx, frag_offset;
5858c2ecf20Sopenharmony_ci	unsigned int sent, total_sent = 0;
5868c2ecf20Sopenharmony_ci	int ret = 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	kcm->tx_wait_more = false;
5898c2ecf20Sopenharmony_ci	psock = kcm->tx_psock;
5908c2ecf20Sopenharmony_ci	if (unlikely(psock && psock->tx_stopped)) {
5918c2ecf20Sopenharmony_ci		/* A reserved psock was aborted asynchronously. Unreserve
5928c2ecf20Sopenharmony_ci		 * it and we'll retry the message.
5938c2ecf20Sopenharmony_ci		 */
5948c2ecf20Sopenharmony_ci		unreserve_psock(kcm);
5958c2ecf20Sopenharmony_ci		kcm_report_tx_retry(kcm);
5968c2ecf20Sopenharmony_ci		if (skb_queue_empty(&sk->sk_write_queue))
5978c2ecf20Sopenharmony_ci			return 0;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		kcm_tx_msg(skb_peek(&sk->sk_write_queue))->sent = 0;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	} else if (skb_queue_empty(&sk->sk_write_queue)) {
6028c2ecf20Sopenharmony_ci		return 0;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	head = skb_peek(&sk->sk_write_queue);
6068c2ecf20Sopenharmony_ci	txm = kcm_tx_msg(head);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (txm->sent) {
6098c2ecf20Sopenharmony_ci		/* Send of first skbuff in queue already in progress */
6108c2ecf20Sopenharmony_ci		if (WARN_ON(!psock)) {
6118c2ecf20Sopenharmony_ci			ret = -EINVAL;
6128c2ecf20Sopenharmony_ci			goto out;
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci		sent = txm->sent;
6158c2ecf20Sopenharmony_ci		frag_offset = txm->frag_offset;
6168c2ecf20Sopenharmony_ci		fragidx = txm->fragidx;
6178c2ecf20Sopenharmony_ci		skb = txm->frag_skb;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		goto do_frag;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_citry_again:
6238c2ecf20Sopenharmony_ci	psock = reserve_psock(kcm);
6248c2ecf20Sopenharmony_ci	if (!psock)
6258c2ecf20Sopenharmony_ci		goto out;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	do {
6288c2ecf20Sopenharmony_ci		skb = head;
6298c2ecf20Sopenharmony_ci		txm = kcm_tx_msg(head);
6308c2ecf20Sopenharmony_ci		sent = 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cido_frag_list:
6338c2ecf20Sopenharmony_ci		if (WARN_ON(!skb_shinfo(skb)->nr_frags)) {
6348c2ecf20Sopenharmony_ci			ret = -EINVAL;
6358c2ecf20Sopenharmony_ci			goto out;
6368c2ecf20Sopenharmony_ci		}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci		for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags;
6398c2ecf20Sopenharmony_ci		     fragidx++) {
6408c2ecf20Sopenharmony_ci			skb_frag_t *frag;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci			frag_offset = 0;
6438c2ecf20Sopenharmony_cido_frag:
6448c2ecf20Sopenharmony_ci			frag = &skb_shinfo(skb)->frags[fragidx];
6458c2ecf20Sopenharmony_ci			if (WARN_ON(!skb_frag_size(frag))) {
6468c2ecf20Sopenharmony_ci				ret = -EINVAL;
6478c2ecf20Sopenharmony_ci				goto out;
6488c2ecf20Sopenharmony_ci			}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci			ret = kernel_sendpage(psock->sk->sk_socket,
6518c2ecf20Sopenharmony_ci					      skb_frag_page(frag),
6528c2ecf20Sopenharmony_ci					      skb_frag_off(frag) + frag_offset,
6538c2ecf20Sopenharmony_ci					      skb_frag_size(frag) - frag_offset,
6548c2ecf20Sopenharmony_ci					      MSG_DONTWAIT);
6558c2ecf20Sopenharmony_ci			if (ret <= 0) {
6568c2ecf20Sopenharmony_ci				if (ret == -EAGAIN) {
6578c2ecf20Sopenharmony_ci					/* Save state to try again when there's
6588c2ecf20Sopenharmony_ci					 * write space on the socket
6598c2ecf20Sopenharmony_ci					 */
6608c2ecf20Sopenharmony_ci					txm->sent = sent;
6618c2ecf20Sopenharmony_ci					txm->frag_offset = frag_offset;
6628c2ecf20Sopenharmony_ci					txm->fragidx = fragidx;
6638c2ecf20Sopenharmony_ci					txm->frag_skb = skb;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci					ret = 0;
6668c2ecf20Sopenharmony_ci					goto out;
6678c2ecf20Sopenharmony_ci				}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci				/* Hard failure in sending message, abort this
6708c2ecf20Sopenharmony_ci				 * psock since it has lost framing
6718c2ecf20Sopenharmony_ci				 * synchonization and retry sending the
6728c2ecf20Sopenharmony_ci				 * message from the beginning.
6738c2ecf20Sopenharmony_ci				 */
6748c2ecf20Sopenharmony_ci				kcm_abort_tx_psock(psock, ret ? -ret : EPIPE,
6758c2ecf20Sopenharmony_ci						   true);
6768c2ecf20Sopenharmony_ci				unreserve_psock(kcm);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci				txm->sent = 0;
6798c2ecf20Sopenharmony_ci				kcm_report_tx_retry(kcm);
6808c2ecf20Sopenharmony_ci				ret = 0;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci				goto try_again;
6838c2ecf20Sopenharmony_ci			}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci			sent += ret;
6868c2ecf20Sopenharmony_ci			frag_offset += ret;
6878c2ecf20Sopenharmony_ci			KCM_STATS_ADD(psock->stats.tx_bytes, ret);
6888c2ecf20Sopenharmony_ci			if (frag_offset < skb_frag_size(frag)) {
6898c2ecf20Sopenharmony_ci				/* Not finished with this frag */
6908c2ecf20Sopenharmony_ci				goto do_frag;
6918c2ecf20Sopenharmony_ci			}
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		if (skb == head) {
6958c2ecf20Sopenharmony_ci			if (skb_has_frag_list(skb)) {
6968c2ecf20Sopenharmony_ci				skb = skb_shinfo(skb)->frag_list;
6978c2ecf20Sopenharmony_ci				goto do_frag_list;
6988c2ecf20Sopenharmony_ci			}
6998c2ecf20Sopenharmony_ci		} else if (skb->next) {
7008c2ecf20Sopenharmony_ci			skb = skb->next;
7018c2ecf20Sopenharmony_ci			goto do_frag_list;
7028c2ecf20Sopenharmony_ci		}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		/* Successfully sent the whole packet, account for it. */
7058c2ecf20Sopenharmony_ci		skb_dequeue(&sk->sk_write_queue);
7068c2ecf20Sopenharmony_ci		kfree_skb(head);
7078c2ecf20Sopenharmony_ci		sk->sk_wmem_queued -= sent;
7088c2ecf20Sopenharmony_ci		total_sent += sent;
7098c2ecf20Sopenharmony_ci		KCM_STATS_INCR(psock->stats.tx_msgs);
7108c2ecf20Sopenharmony_ci	} while ((head = skb_peek(&sk->sk_write_queue)));
7118c2ecf20Sopenharmony_ciout:
7128c2ecf20Sopenharmony_ci	if (!head) {
7138c2ecf20Sopenharmony_ci		/* Done with all queued messages. */
7148c2ecf20Sopenharmony_ci		WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
7158c2ecf20Sopenharmony_ci		unreserve_psock(kcm);
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* Check if write space is available */
7198c2ecf20Sopenharmony_ci	sk->sk_write_space(sk);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	return total_sent ? : ret;
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic void kcm_tx_work(struct work_struct *w)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = container_of(w, struct kcm_sock, tx_work);
7278c2ecf20Sopenharmony_ci	struct sock *sk = &kcm->sk;
7288c2ecf20Sopenharmony_ci	int err;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	lock_sock(sk);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	/* Primarily for SOCK_DGRAM sockets, also handle asynchronous tx
7338c2ecf20Sopenharmony_ci	 * aborts
7348c2ecf20Sopenharmony_ci	 */
7358c2ecf20Sopenharmony_ci	err = kcm_write_msgs(kcm);
7368c2ecf20Sopenharmony_ci	if (err < 0) {
7378c2ecf20Sopenharmony_ci		/* Hard failure in write, report error on KCM socket */
7388c2ecf20Sopenharmony_ci		pr_warn("KCM: Hard failure on kcm_write_msgs %d\n", err);
7398c2ecf20Sopenharmony_ci		report_csk_error(&kcm->sk, -err);
7408c2ecf20Sopenharmony_ci		goto out;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	/* Primarily for SOCK_SEQPACKET sockets */
7448c2ecf20Sopenharmony_ci	if (likely(sk->sk_socket) &&
7458c2ecf20Sopenharmony_ci	    test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
7468c2ecf20Sopenharmony_ci		clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
7478c2ecf20Sopenharmony_ci		sk->sk_write_space(sk);
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ciout:
7518c2ecf20Sopenharmony_ci	release_sock(sk);
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic void kcm_push(struct kcm_sock *kcm)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	if (kcm->tx_wait_more)
7578c2ecf20Sopenharmony_ci		kcm_write_msgs(kcm);
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cistatic ssize_t kcm_sendpage(struct socket *sock, struct page *page,
7618c2ecf20Sopenharmony_ci			    int offset, size_t size, int flags)
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7658c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sk);
7668c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL, *head = NULL;
7678c2ecf20Sopenharmony_ci	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
7688c2ecf20Sopenharmony_ci	bool eor;
7698c2ecf20Sopenharmony_ci	int err = 0;
7708c2ecf20Sopenharmony_ci	int i;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	if (flags & MSG_SENDPAGE_NOTLAST)
7738c2ecf20Sopenharmony_ci		flags |= MSG_MORE;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/* No MSG_EOR from splice, only look at MSG_MORE */
7768c2ecf20Sopenharmony_ci	eor = !(flags & MSG_MORE);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	lock_sock(sk);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	err = -EPIPE;
7838c2ecf20Sopenharmony_ci	if (sk->sk_err)
7848c2ecf20Sopenharmony_ci		goto out_error;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (kcm->seq_skb) {
7878c2ecf20Sopenharmony_ci		/* Previously opened message */
7888c2ecf20Sopenharmony_ci		head = kcm->seq_skb;
7898c2ecf20Sopenharmony_ci		skb = kcm_tx_msg(head)->last_skb;
7908c2ecf20Sopenharmony_ci		i = skb_shinfo(skb)->nr_frags;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		if (skb_can_coalesce(skb, i, page, offset)) {
7938c2ecf20Sopenharmony_ci			skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size);
7948c2ecf20Sopenharmony_ci			skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
7958c2ecf20Sopenharmony_ci			goto coalesced;
7968c2ecf20Sopenharmony_ci		}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		if (i >= MAX_SKB_FRAGS) {
7998c2ecf20Sopenharmony_ci			struct sk_buff *tskb;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci			tskb = alloc_skb(0, sk->sk_allocation);
8028c2ecf20Sopenharmony_ci			while (!tskb) {
8038c2ecf20Sopenharmony_ci				kcm_push(kcm);
8048c2ecf20Sopenharmony_ci				err = sk_stream_wait_memory(sk, &timeo);
8058c2ecf20Sopenharmony_ci				if (err)
8068c2ecf20Sopenharmony_ci					goto out_error;
8078c2ecf20Sopenharmony_ci			}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci			if (head == skb)
8108c2ecf20Sopenharmony_ci				skb_shinfo(head)->frag_list = tskb;
8118c2ecf20Sopenharmony_ci			else
8128c2ecf20Sopenharmony_ci				skb->next = tskb;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci			skb = tskb;
8158c2ecf20Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
8168c2ecf20Sopenharmony_ci			i = 0;
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci	} else {
8198c2ecf20Sopenharmony_ci		/* Call the sk_stream functions to manage the sndbuf mem. */
8208c2ecf20Sopenharmony_ci		if (!sk_stream_memory_free(sk)) {
8218c2ecf20Sopenharmony_ci			kcm_push(kcm);
8228c2ecf20Sopenharmony_ci			set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
8238c2ecf20Sopenharmony_ci			err = sk_stream_wait_memory(sk, &timeo);
8248c2ecf20Sopenharmony_ci			if (err)
8258c2ecf20Sopenharmony_ci				goto out_error;
8268c2ecf20Sopenharmony_ci		}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		head = alloc_skb(0, sk->sk_allocation);
8298c2ecf20Sopenharmony_ci		while (!head) {
8308c2ecf20Sopenharmony_ci			kcm_push(kcm);
8318c2ecf20Sopenharmony_ci			err = sk_stream_wait_memory(sk, &timeo);
8328c2ecf20Sopenharmony_ci			if (err)
8338c2ecf20Sopenharmony_ci				goto out_error;
8348c2ecf20Sopenharmony_ci		}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		skb = head;
8378c2ecf20Sopenharmony_ci		i = 0;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	get_page(page);
8418c2ecf20Sopenharmony_ci	skb_fill_page_desc(skb, i, page, offset, size);
8428c2ecf20Sopenharmony_ci	skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cicoalesced:
8458c2ecf20Sopenharmony_ci	skb->len += size;
8468c2ecf20Sopenharmony_ci	skb->data_len += size;
8478c2ecf20Sopenharmony_ci	skb->truesize += size;
8488c2ecf20Sopenharmony_ci	sk->sk_wmem_queued += size;
8498c2ecf20Sopenharmony_ci	sk_mem_charge(sk, size);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (head != skb) {
8528c2ecf20Sopenharmony_ci		head->len += size;
8538c2ecf20Sopenharmony_ci		head->data_len += size;
8548c2ecf20Sopenharmony_ci		head->truesize += size;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	if (eor) {
8588c2ecf20Sopenharmony_ci		bool not_busy = skb_queue_empty(&sk->sk_write_queue);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci		/* Message complete, queue it on send buffer */
8618c2ecf20Sopenharmony_ci		__skb_queue_tail(&sk->sk_write_queue, head);
8628c2ecf20Sopenharmony_ci		kcm->seq_skb = NULL;
8638c2ecf20Sopenharmony_ci		KCM_STATS_INCR(kcm->stats.tx_msgs);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		if (flags & MSG_BATCH) {
8668c2ecf20Sopenharmony_ci			kcm->tx_wait_more = true;
8678c2ecf20Sopenharmony_ci		} else if (kcm->tx_wait_more || not_busy) {
8688c2ecf20Sopenharmony_ci			err = kcm_write_msgs(kcm);
8698c2ecf20Sopenharmony_ci			if (err < 0) {
8708c2ecf20Sopenharmony_ci				/* We got a hard error in write_msgs but have
8718c2ecf20Sopenharmony_ci				 * already queued this message. Report an error
8728c2ecf20Sopenharmony_ci				 * in the socket, but don't affect return value
8738c2ecf20Sopenharmony_ci				 * from sendmsg
8748c2ecf20Sopenharmony_ci				 */
8758c2ecf20Sopenharmony_ci				pr_warn("KCM: Hard failure on kcm_write_msgs\n");
8768c2ecf20Sopenharmony_ci				report_csk_error(&kcm->sk, -err);
8778c2ecf20Sopenharmony_ci			}
8788c2ecf20Sopenharmony_ci		}
8798c2ecf20Sopenharmony_ci	} else {
8808c2ecf20Sopenharmony_ci		/* Message not complete, save state */
8818c2ecf20Sopenharmony_ci		kcm->seq_skb = head;
8828c2ecf20Sopenharmony_ci		kcm_tx_msg(head)->last_skb = skb;
8838c2ecf20Sopenharmony_ci	}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	KCM_STATS_ADD(kcm->stats.tx_bytes, size);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	release_sock(sk);
8888c2ecf20Sopenharmony_ci	return size;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ciout_error:
8918c2ecf20Sopenharmony_ci	kcm_push(kcm);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	err = sk_stream_error(sk, flags, err);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* make sure we wake any epoll edge trigger waiter */
8968c2ecf20Sopenharmony_ci	if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
8978c2ecf20Sopenharmony_ci		sk->sk_write_space(sk);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	release_sock(sk);
9008c2ecf20Sopenharmony_ci	return err;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_cistatic int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
9068c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sk);
9078c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL, *head = NULL;
9088c2ecf20Sopenharmony_ci	size_t copy, copied = 0;
9098c2ecf20Sopenharmony_ci	long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
9108c2ecf20Sopenharmony_ci	int eor = (sock->type == SOCK_DGRAM) ?
9118c2ecf20Sopenharmony_ci		  !(msg->msg_flags & MSG_MORE) : !!(msg->msg_flags & MSG_EOR);
9128c2ecf20Sopenharmony_ci	int err = -EPIPE;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	lock_sock(sk);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* Per tcp_sendmsg this should be in poll */
9178c2ecf20Sopenharmony_ci	sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	if (sk->sk_err)
9208c2ecf20Sopenharmony_ci		goto out_error;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (kcm->seq_skb) {
9238c2ecf20Sopenharmony_ci		/* Previously opened message */
9248c2ecf20Sopenharmony_ci		head = kcm->seq_skb;
9258c2ecf20Sopenharmony_ci		skb = kcm_tx_msg(head)->last_skb;
9268c2ecf20Sopenharmony_ci		goto start;
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	/* Call the sk_stream functions to manage the sndbuf mem. */
9308c2ecf20Sopenharmony_ci	if (!sk_stream_memory_free(sk)) {
9318c2ecf20Sopenharmony_ci		kcm_push(kcm);
9328c2ecf20Sopenharmony_ci		set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
9338c2ecf20Sopenharmony_ci		err = sk_stream_wait_memory(sk, &timeo);
9348c2ecf20Sopenharmony_ci		if (err)
9358c2ecf20Sopenharmony_ci			goto out_error;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (msg_data_left(msg)) {
9398c2ecf20Sopenharmony_ci		/* New message, alloc head skb */
9408c2ecf20Sopenharmony_ci		head = alloc_skb(0, sk->sk_allocation);
9418c2ecf20Sopenharmony_ci		while (!head) {
9428c2ecf20Sopenharmony_ci			kcm_push(kcm);
9438c2ecf20Sopenharmony_ci			err = sk_stream_wait_memory(sk, &timeo);
9448c2ecf20Sopenharmony_ci			if (err)
9458c2ecf20Sopenharmony_ci				goto out_error;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci			head = alloc_skb(0, sk->sk_allocation);
9488c2ecf20Sopenharmony_ci		}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci		skb = head;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		/* Set ip_summed to CHECKSUM_UNNECESSARY to avoid calling
9538c2ecf20Sopenharmony_ci		 * csum_and_copy_from_iter from skb_do_copy_data_nocache.
9548c2ecf20Sopenharmony_ci		 */
9558c2ecf20Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistart:
9598c2ecf20Sopenharmony_ci	while (msg_data_left(msg)) {
9608c2ecf20Sopenharmony_ci		bool merge = true;
9618c2ecf20Sopenharmony_ci		int i = skb_shinfo(skb)->nr_frags;
9628c2ecf20Sopenharmony_ci		struct page_frag *pfrag = sk_page_frag(sk);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci		if (!sk_page_frag_refill(sk, pfrag))
9658c2ecf20Sopenharmony_ci			goto wait_for_memory;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		if (!skb_can_coalesce(skb, i, pfrag->page,
9688c2ecf20Sopenharmony_ci				      pfrag->offset)) {
9698c2ecf20Sopenharmony_ci			if (i == MAX_SKB_FRAGS) {
9708c2ecf20Sopenharmony_ci				struct sk_buff *tskb;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci				tskb = alloc_skb(0, sk->sk_allocation);
9738c2ecf20Sopenharmony_ci				if (!tskb)
9748c2ecf20Sopenharmony_ci					goto wait_for_memory;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci				if (head == skb)
9778c2ecf20Sopenharmony_ci					skb_shinfo(head)->frag_list = tskb;
9788c2ecf20Sopenharmony_ci				else
9798c2ecf20Sopenharmony_ci					skb->next = tskb;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci				skb = tskb;
9828c2ecf20Sopenharmony_ci				skb->ip_summed = CHECKSUM_UNNECESSARY;
9838c2ecf20Sopenharmony_ci				continue;
9848c2ecf20Sopenharmony_ci			}
9858c2ecf20Sopenharmony_ci			merge = false;
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		copy = min_t(int, msg_data_left(msg),
9898c2ecf20Sopenharmony_ci			     pfrag->size - pfrag->offset);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci		if (!sk_wmem_schedule(sk, copy))
9928c2ecf20Sopenharmony_ci			goto wait_for_memory;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
9958c2ecf20Sopenharmony_ci					       pfrag->page,
9968c2ecf20Sopenharmony_ci					       pfrag->offset,
9978c2ecf20Sopenharmony_ci					       copy);
9988c2ecf20Sopenharmony_ci		if (err)
9998c2ecf20Sopenharmony_ci			goto out_error;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci		/* Update the skb. */
10028c2ecf20Sopenharmony_ci		if (merge) {
10038c2ecf20Sopenharmony_ci			skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
10048c2ecf20Sopenharmony_ci		} else {
10058c2ecf20Sopenharmony_ci			skb_fill_page_desc(skb, i, pfrag->page,
10068c2ecf20Sopenharmony_ci					   pfrag->offset, copy);
10078c2ecf20Sopenharmony_ci			get_page(pfrag->page);
10088c2ecf20Sopenharmony_ci		}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		pfrag->offset += copy;
10118c2ecf20Sopenharmony_ci		copied += copy;
10128c2ecf20Sopenharmony_ci		if (head != skb) {
10138c2ecf20Sopenharmony_ci			head->len += copy;
10148c2ecf20Sopenharmony_ci			head->data_len += copy;
10158c2ecf20Sopenharmony_ci		}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci		continue;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ciwait_for_memory:
10208c2ecf20Sopenharmony_ci		kcm_push(kcm);
10218c2ecf20Sopenharmony_ci		err = sk_stream_wait_memory(sk, &timeo);
10228c2ecf20Sopenharmony_ci		if (err)
10238c2ecf20Sopenharmony_ci			goto out_error;
10248c2ecf20Sopenharmony_ci	}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (eor) {
10278c2ecf20Sopenharmony_ci		bool not_busy = skb_queue_empty(&sk->sk_write_queue);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		if (head) {
10308c2ecf20Sopenharmony_ci			/* Message complete, queue it on send buffer */
10318c2ecf20Sopenharmony_ci			__skb_queue_tail(&sk->sk_write_queue, head);
10328c2ecf20Sopenharmony_ci			kcm->seq_skb = NULL;
10338c2ecf20Sopenharmony_ci			KCM_STATS_INCR(kcm->stats.tx_msgs);
10348c2ecf20Sopenharmony_ci		}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci		if (msg->msg_flags & MSG_BATCH) {
10378c2ecf20Sopenharmony_ci			kcm->tx_wait_more = true;
10388c2ecf20Sopenharmony_ci		} else if (kcm->tx_wait_more || not_busy) {
10398c2ecf20Sopenharmony_ci			err = kcm_write_msgs(kcm);
10408c2ecf20Sopenharmony_ci			if (err < 0) {
10418c2ecf20Sopenharmony_ci				/* We got a hard error in write_msgs but have
10428c2ecf20Sopenharmony_ci				 * already queued this message. Report an error
10438c2ecf20Sopenharmony_ci				 * in the socket, but don't affect return value
10448c2ecf20Sopenharmony_ci				 * from sendmsg
10458c2ecf20Sopenharmony_ci				 */
10468c2ecf20Sopenharmony_ci				pr_warn("KCM: Hard failure on kcm_write_msgs\n");
10478c2ecf20Sopenharmony_ci				report_csk_error(&kcm->sk, -err);
10488c2ecf20Sopenharmony_ci			}
10498c2ecf20Sopenharmony_ci		}
10508c2ecf20Sopenharmony_ci	} else {
10518c2ecf20Sopenharmony_ci		/* Message not complete, save state */
10528c2ecf20Sopenharmony_cipartial_message:
10538c2ecf20Sopenharmony_ci		if (head) {
10548c2ecf20Sopenharmony_ci			kcm->seq_skb = head;
10558c2ecf20Sopenharmony_ci			kcm_tx_msg(head)->last_skb = skb;
10568c2ecf20Sopenharmony_ci		}
10578c2ecf20Sopenharmony_ci	}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	KCM_STATS_ADD(kcm->stats.tx_bytes, copied);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	release_sock(sk);
10628c2ecf20Sopenharmony_ci	return copied;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ciout_error:
10658c2ecf20Sopenharmony_ci	kcm_push(kcm);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (sock->type == SOCK_SEQPACKET) {
10688c2ecf20Sopenharmony_ci		/* Wrote some bytes before encountering an
10698c2ecf20Sopenharmony_ci		 * error, return partial success.
10708c2ecf20Sopenharmony_ci		 */
10718c2ecf20Sopenharmony_ci		if (copied)
10728c2ecf20Sopenharmony_ci			goto partial_message;
10738c2ecf20Sopenharmony_ci		if (head != kcm->seq_skb)
10748c2ecf20Sopenharmony_ci			kfree_skb(head);
10758c2ecf20Sopenharmony_ci	} else {
10768c2ecf20Sopenharmony_ci		kfree_skb(head);
10778c2ecf20Sopenharmony_ci		kcm->seq_skb = NULL;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	err = sk_stream_error(sk, msg->msg_flags, err);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	/* make sure we wake any epoll edge trigger waiter */
10838c2ecf20Sopenharmony_ci	if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
10848c2ecf20Sopenharmony_ci		sk->sk_write_space(sk);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	release_sock(sk);
10878c2ecf20Sopenharmony_ci	return err;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistatic int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
10918c2ecf20Sopenharmony_ci		       size_t len, int flags)
10928c2ecf20Sopenharmony_ci{
10938c2ecf20Sopenharmony_ci	int noblock = flags & MSG_DONTWAIT;
10948c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
10958c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sk);
10968c2ecf20Sopenharmony_ci	int err = 0;
10978c2ecf20Sopenharmony_ci	struct strp_msg *stm;
10988c2ecf20Sopenharmony_ci	int copied = 0;
10998c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, noblock, &err);
11028c2ecf20Sopenharmony_ci	if (!skb)
11038c2ecf20Sopenharmony_ci		goto out;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	/* Okay, have a message on the receive queue */
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	stm = strp_msg(skb);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	if (len > stm->full_len)
11108c2ecf20Sopenharmony_ci		len = stm->full_len;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	err = skb_copy_datagram_msg(skb, stm->offset, msg, len);
11138c2ecf20Sopenharmony_ci	if (err < 0)
11148c2ecf20Sopenharmony_ci		goto out;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	copied = len;
11178c2ecf20Sopenharmony_ci	if (likely(!(flags & MSG_PEEK))) {
11188c2ecf20Sopenharmony_ci		KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
11198c2ecf20Sopenharmony_ci		if (copied < stm->full_len) {
11208c2ecf20Sopenharmony_ci			if (sock->type == SOCK_DGRAM) {
11218c2ecf20Sopenharmony_ci				/* Truncated message */
11228c2ecf20Sopenharmony_ci				msg->msg_flags |= MSG_TRUNC;
11238c2ecf20Sopenharmony_ci				goto msg_finished;
11248c2ecf20Sopenharmony_ci			}
11258c2ecf20Sopenharmony_ci			stm->offset += copied;
11268c2ecf20Sopenharmony_ci			stm->full_len -= copied;
11278c2ecf20Sopenharmony_ci		} else {
11288c2ecf20Sopenharmony_cimsg_finished:
11298c2ecf20Sopenharmony_ci			/* Finished with message */
11308c2ecf20Sopenharmony_ci			msg->msg_flags |= MSG_EOR;
11318c2ecf20Sopenharmony_ci			KCM_STATS_INCR(kcm->stats.rx_msgs);
11328c2ecf20Sopenharmony_ci		}
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ciout:
11368c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
11378c2ecf20Sopenharmony_ci	return copied ? : err;
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_cistatic ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
11418c2ecf20Sopenharmony_ci			       struct pipe_inode_info *pipe, size_t len,
11428c2ecf20Sopenharmony_ci			       unsigned int flags)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	int noblock = flags & MSG_DONTWAIT;
11458c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11468c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sk);
11478c2ecf20Sopenharmony_ci	struct strp_msg *stm;
11488c2ecf20Sopenharmony_ci	int err = 0;
11498c2ecf20Sopenharmony_ci	ssize_t copied;
11508c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	/* Only support splice for SOCKSEQPACKET */
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, noblock, &err);
11558c2ecf20Sopenharmony_ci	if (!skb)
11568c2ecf20Sopenharmony_ci		goto err_out;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	/* Okay, have a message on the receive queue */
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	stm = strp_msg(skb);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (len > stm->full_len)
11638c2ecf20Sopenharmony_ci		len = stm->full_len;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	copied = skb_splice_bits(skb, sk, stm->offset, pipe, len, flags);
11668c2ecf20Sopenharmony_ci	if (copied < 0) {
11678c2ecf20Sopenharmony_ci		err = copied;
11688c2ecf20Sopenharmony_ci		goto err_out;
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	stm->offset += copied;
11748c2ecf20Sopenharmony_ci	stm->full_len -= copied;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	/* We have no way to return MSG_EOR. If all the bytes have been
11778c2ecf20Sopenharmony_ci	 * read we still leave the message in the receive socket buffer.
11788c2ecf20Sopenharmony_ci	 * A subsequent recvmsg needs to be done to return MSG_EOR and
11798c2ecf20Sopenharmony_ci	 * finish reading the message.
11808c2ecf20Sopenharmony_ci	 */
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
11838c2ecf20Sopenharmony_ci	return copied;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cierr_out:
11868c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
11878c2ecf20Sopenharmony_ci	return err;
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci/* kcm sock lock held */
11918c2ecf20Sopenharmony_cistatic void kcm_recv_disable(struct kcm_sock *kcm)
11928c2ecf20Sopenharmony_ci{
11938c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (kcm->rx_disabled)
11968c2ecf20Sopenharmony_ci		return;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	kcm->rx_disabled = 1;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	/* If a psock is reserved we'll do cleanup in unreserve */
12038c2ecf20Sopenharmony_ci	if (!kcm->rx_psock) {
12048c2ecf20Sopenharmony_ci		if (kcm->rx_wait) {
12058c2ecf20Sopenharmony_ci			list_del(&kcm->wait_rx_list);
12068c2ecf20Sopenharmony_ci			/* paired with lockless reads in kcm_rfree() */
12078c2ecf20Sopenharmony_ci			WRITE_ONCE(kcm->rx_wait, false);
12088c2ecf20Sopenharmony_ci		}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci		requeue_rx_msgs(mux, &kcm->sk.sk_receive_queue);
12118c2ecf20Sopenharmony_ci	}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci/* kcm sock lock held */
12178c2ecf20Sopenharmony_cistatic void kcm_recv_enable(struct kcm_sock *kcm)
12188c2ecf20Sopenharmony_ci{
12198c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (!kcm->rx_disabled)
12228c2ecf20Sopenharmony_ci		return;
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	kcm->rx_disabled = 0;
12278c2ecf20Sopenharmony_ci	kcm_rcv_ready(kcm);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cistatic int kcm_setsockopt(struct socket *sock, int level, int optname,
12338c2ecf20Sopenharmony_ci			  sockptr_t optval, unsigned int optlen)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sock->sk);
12368c2ecf20Sopenharmony_ci	int val, valbool;
12378c2ecf20Sopenharmony_ci	int err = 0;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	if (level != SOL_KCM)
12408c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (optlen < sizeof(int))
12438c2ecf20Sopenharmony_ci		return -EINVAL;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	if (copy_from_sockptr(&val, optval, sizeof(int)))
12468c2ecf20Sopenharmony_ci		return -EFAULT;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	valbool = val ? 1 : 0;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	switch (optname) {
12518c2ecf20Sopenharmony_ci	case KCM_RECV_DISABLE:
12528c2ecf20Sopenharmony_ci		lock_sock(&kcm->sk);
12538c2ecf20Sopenharmony_ci		if (valbool)
12548c2ecf20Sopenharmony_ci			kcm_recv_disable(kcm);
12558c2ecf20Sopenharmony_ci		else
12568c2ecf20Sopenharmony_ci			kcm_recv_enable(kcm);
12578c2ecf20Sopenharmony_ci		release_sock(&kcm->sk);
12588c2ecf20Sopenharmony_ci		break;
12598c2ecf20Sopenharmony_ci	default:
12608c2ecf20Sopenharmony_ci		err = -ENOPROTOOPT;
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return err;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic int kcm_getsockopt(struct socket *sock, int level, int optname,
12678c2ecf20Sopenharmony_ci			  char __user *optval, int __user *optlen)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sock->sk);
12708c2ecf20Sopenharmony_ci	int val, len;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	if (level != SOL_KCM)
12738c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	if (get_user(len, optlen))
12768c2ecf20Sopenharmony_ci		return -EFAULT;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	len = min_t(unsigned int, len, sizeof(int));
12798c2ecf20Sopenharmony_ci	if (len < 0)
12808c2ecf20Sopenharmony_ci		return -EINVAL;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	switch (optname) {
12838c2ecf20Sopenharmony_ci	case KCM_RECV_DISABLE:
12848c2ecf20Sopenharmony_ci		val = kcm->rx_disabled;
12858c2ecf20Sopenharmony_ci		break;
12868c2ecf20Sopenharmony_ci	default:
12878c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
12888c2ecf20Sopenharmony_ci	}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	if (put_user(len, optlen))
12918c2ecf20Sopenharmony_ci		return -EFAULT;
12928c2ecf20Sopenharmony_ci	if (copy_to_user(optval, &val, len))
12938c2ecf20Sopenharmony_ci		return -EFAULT;
12948c2ecf20Sopenharmony_ci	return 0;
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistatic void init_kcm_sock(struct kcm_sock *kcm, struct kcm_mux *mux)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct kcm_sock *tkcm;
13008c2ecf20Sopenharmony_ci	struct list_head *head;
13018c2ecf20Sopenharmony_ci	int index = 0;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	/* For SOCK_SEQPACKET sock type, datagram_poll checks the sk_state, so
13048c2ecf20Sopenharmony_ci	 * we set sk_state, otherwise epoll_wait always returns right away with
13058c2ecf20Sopenharmony_ci	 * EPOLLHUP
13068c2ecf20Sopenharmony_ci	 */
13078c2ecf20Sopenharmony_ci	kcm->sk.sk_state = TCP_ESTABLISHED;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	/* Add to mux's kcm sockets list */
13108c2ecf20Sopenharmony_ci	kcm->mux = mux;
13118c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	head = &mux->kcm_socks;
13148c2ecf20Sopenharmony_ci	list_for_each_entry(tkcm, &mux->kcm_socks, kcm_sock_list) {
13158c2ecf20Sopenharmony_ci		if (tkcm->index != index)
13168c2ecf20Sopenharmony_ci			break;
13178c2ecf20Sopenharmony_ci		head = &tkcm->kcm_sock_list;
13188c2ecf20Sopenharmony_ci		index++;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	list_add(&kcm->kcm_sock_list, head);
13228c2ecf20Sopenharmony_ci	kcm->index = index;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	mux->kcm_socks_cnt++;
13258c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	INIT_WORK(&kcm->tx_work, kcm_tx_work);
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
13308c2ecf20Sopenharmony_ci	kcm_rcv_ready(kcm);
13318c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
13328c2ecf20Sopenharmony_ci}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_cistatic int kcm_attach(struct socket *sock, struct socket *csock,
13358c2ecf20Sopenharmony_ci		      struct bpf_prog *prog)
13368c2ecf20Sopenharmony_ci{
13378c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sock->sk);
13388c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
13398c2ecf20Sopenharmony_ci	struct sock *csk;
13408c2ecf20Sopenharmony_ci	struct kcm_psock *psock = NULL, *tpsock;
13418c2ecf20Sopenharmony_ci	struct list_head *head;
13428c2ecf20Sopenharmony_ci	int index = 0;
13438c2ecf20Sopenharmony_ci	static const struct strp_callbacks cb = {
13448c2ecf20Sopenharmony_ci		.rcv_msg = kcm_rcv_strparser,
13458c2ecf20Sopenharmony_ci		.parse_msg = kcm_parse_func_strparser,
13468c2ecf20Sopenharmony_ci		.read_sock_done = kcm_read_sock_done,
13478c2ecf20Sopenharmony_ci	};
13488c2ecf20Sopenharmony_ci	int err = 0;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	csk = csock->sk;
13518c2ecf20Sopenharmony_ci	if (!csk)
13528c2ecf20Sopenharmony_ci		return -EINVAL;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	lock_sock(csk);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* Only allow TCP sockets to be attached for now */
13578c2ecf20Sopenharmony_ci	if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) ||
13588c2ecf20Sopenharmony_ci	    csk->sk_protocol != IPPROTO_TCP) {
13598c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
13608c2ecf20Sopenharmony_ci		goto out;
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	/* Don't allow listeners or closed sockets */
13648c2ecf20Sopenharmony_ci	if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) {
13658c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
13668c2ecf20Sopenharmony_ci		goto out;
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
13708c2ecf20Sopenharmony_ci	if (!psock) {
13718c2ecf20Sopenharmony_ci		err = -ENOMEM;
13728c2ecf20Sopenharmony_ci		goto out;
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	psock->mux = mux;
13768c2ecf20Sopenharmony_ci	psock->sk = csk;
13778c2ecf20Sopenharmony_ci	psock->bpf_prog = prog;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	write_lock_bh(&csk->sk_callback_lock);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	/* Check if sk_user_data is aready by KCM or someone else.
13828c2ecf20Sopenharmony_ci	 * Must be done under lock to prevent race conditions.
13838c2ecf20Sopenharmony_ci	 */
13848c2ecf20Sopenharmony_ci	if (csk->sk_user_data) {
13858c2ecf20Sopenharmony_ci		write_unlock_bh(&csk->sk_callback_lock);
13868c2ecf20Sopenharmony_ci		kmem_cache_free(kcm_psockp, psock);
13878c2ecf20Sopenharmony_ci		err = -EALREADY;
13888c2ecf20Sopenharmony_ci		goto out;
13898c2ecf20Sopenharmony_ci	}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	err = strp_init(&psock->strp, csk, &cb);
13928c2ecf20Sopenharmony_ci	if (err) {
13938c2ecf20Sopenharmony_ci		write_unlock_bh(&csk->sk_callback_lock);
13948c2ecf20Sopenharmony_ci		kmem_cache_free(kcm_psockp, psock);
13958c2ecf20Sopenharmony_ci		goto out;
13968c2ecf20Sopenharmony_ci	}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	psock->save_data_ready = csk->sk_data_ready;
13998c2ecf20Sopenharmony_ci	psock->save_write_space = csk->sk_write_space;
14008c2ecf20Sopenharmony_ci	psock->save_state_change = csk->sk_state_change;
14018c2ecf20Sopenharmony_ci	csk->sk_user_data = psock;
14028c2ecf20Sopenharmony_ci	csk->sk_data_ready = psock_data_ready;
14038c2ecf20Sopenharmony_ci	csk->sk_write_space = psock_write_space;
14048c2ecf20Sopenharmony_ci	csk->sk_state_change = psock_state_change;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	write_unlock_bh(&csk->sk_callback_lock);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	sock_hold(csk);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* Finished initialization, now add the psock to the MUX. */
14118c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
14128c2ecf20Sopenharmony_ci	head = &mux->psocks;
14138c2ecf20Sopenharmony_ci	list_for_each_entry(tpsock, &mux->psocks, psock_list) {
14148c2ecf20Sopenharmony_ci		if (tpsock->index != index)
14158c2ecf20Sopenharmony_ci			break;
14168c2ecf20Sopenharmony_ci		head = &tpsock->psock_list;
14178c2ecf20Sopenharmony_ci		index++;
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	list_add(&psock->psock_list, head);
14218c2ecf20Sopenharmony_ci	psock->index = index;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	KCM_STATS_INCR(mux->stats.psock_attach);
14248c2ecf20Sopenharmony_ci	mux->psocks_cnt++;
14258c2ecf20Sopenharmony_ci	psock_now_avail(psock);
14268c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	/* Schedule RX work in case there are already bytes queued */
14298c2ecf20Sopenharmony_ci	strp_check_rcv(&psock->strp);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ciout:
14328c2ecf20Sopenharmony_ci	release_sock(csk);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	return err;
14358c2ecf20Sopenharmony_ci}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_cistatic int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info)
14388c2ecf20Sopenharmony_ci{
14398c2ecf20Sopenharmony_ci	struct socket *csock;
14408c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
14418c2ecf20Sopenharmony_ci	int err;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	csock = sockfd_lookup(info->fd, &err);
14448c2ecf20Sopenharmony_ci	if (!csock)
14458c2ecf20Sopenharmony_ci		return -ENOENT;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	prog = bpf_prog_get_type(info->bpf_fd, BPF_PROG_TYPE_SOCKET_FILTER);
14488c2ecf20Sopenharmony_ci	if (IS_ERR(prog)) {
14498c2ecf20Sopenharmony_ci		err = PTR_ERR(prog);
14508c2ecf20Sopenharmony_ci		goto out;
14518c2ecf20Sopenharmony_ci	}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	err = kcm_attach(sock, csock, prog);
14548c2ecf20Sopenharmony_ci	if (err) {
14558c2ecf20Sopenharmony_ci		bpf_prog_put(prog);
14568c2ecf20Sopenharmony_ci		goto out;
14578c2ecf20Sopenharmony_ci	}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	/* Keep reference on file also */
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	return 0;
14628c2ecf20Sopenharmony_ciout:
14638c2ecf20Sopenharmony_ci	fput(csock->file);
14648c2ecf20Sopenharmony_ci	return err;
14658c2ecf20Sopenharmony_ci}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_cistatic void kcm_unattach(struct kcm_psock *psock)
14688c2ecf20Sopenharmony_ci{
14698c2ecf20Sopenharmony_ci	struct sock *csk = psock->sk;
14708c2ecf20Sopenharmony_ci	struct kcm_mux *mux = psock->mux;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	lock_sock(csk);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	/* Stop getting callbacks from TCP socket. After this there should
14758c2ecf20Sopenharmony_ci	 * be no way to reserve a kcm for this psock.
14768c2ecf20Sopenharmony_ci	 */
14778c2ecf20Sopenharmony_ci	write_lock_bh(&csk->sk_callback_lock);
14788c2ecf20Sopenharmony_ci	csk->sk_user_data = NULL;
14798c2ecf20Sopenharmony_ci	csk->sk_data_ready = psock->save_data_ready;
14808c2ecf20Sopenharmony_ci	csk->sk_write_space = psock->save_write_space;
14818c2ecf20Sopenharmony_ci	csk->sk_state_change = psock->save_state_change;
14828c2ecf20Sopenharmony_ci	strp_stop(&psock->strp);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	if (WARN_ON(psock->rx_kcm)) {
14858c2ecf20Sopenharmony_ci		write_unlock_bh(&csk->sk_callback_lock);
14868c2ecf20Sopenharmony_ci		release_sock(csk);
14878c2ecf20Sopenharmony_ci		return;
14888c2ecf20Sopenharmony_ci	}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* Stop receiver activities. After this point psock should not be
14938c2ecf20Sopenharmony_ci	 * able to get onto ready list either through callbacks or work.
14948c2ecf20Sopenharmony_ci	 */
14958c2ecf20Sopenharmony_ci	if (psock->ready_rx_msg) {
14968c2ecf20Sopenharmony_ci		list_del(&psock->psock_ready_list);
14978c2ecf20Sopenharmony_ci		kfree_skb(psock->ready_rx_msg);
14988c2ecf20Sopenharmony_ci		psock->ready_rx_msg = NULL;
14998c2ecf20Sopenharmony_ci		KCM_STATS_INCR(mux->stats.rx_ready_drops);
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	write_unlock_bh(&csk->sk_callback_lock);
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	/* Call strp_done without sock lock */
15078c2ecf20Sopenharmony_ci	release_sock(csk);
15088c2ecf20Sopenharmony_ci	strp_done(&psock->strp);
15098c2ecf20Sopenharmony_ci	lock_sock(csk);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	bpf_prog_put(psock->bpf_prog);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	aggregate_psock_stats(&psock->stats, &mux->aggregate_psock_stats);
15168c2ecf20Sopenharmony_ci	save_strp_stats(&psock->strp, &mux->aggregate_strp_stats);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	KCM_STATS_INCR(mux->stats.psock_unattach);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	if (psock->tx_kcm) {
15218c2ecf20Sopenharmony_ci		/* psock was reserved.  Just mark it finished and we will clean
15228c2ecf20Sopenharmony_ci		 * up in the kcm paths, we need kcm lock which can not be
15238c2ecf20Sopenharmony_ci		 * acquired here.
15248c2ecf20Sopenharmony_ci		 */
15258c2ecf20Sopenharmony_ci		KCM_STATS_INCR(mux->stats.psock_unattach_rsvd);
15268c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci		/* We are unattaching a socket that is reserved. Abort the
15298c2ecf20Sopenharmony_ci		 * socket since we may be out of sync in sending on it. We need
15308c2ecf20Sopenharmony_ci		 * to do this without the mux lock.
15318c2ecf20Sopenharmony_ci		 */
15328c2ecf20Sopenharmony_ci		kcm_abort_tx_psock(psock, EPIPE, false);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci		spin_lock_bh(&mux->lock);
15358c2ecf20Sopenharmony_ci		if (!psock->tx_kcm) {
15368c2ecf20Sopenharmony_ci			/* psock now unreserved in window mux was unlocked */
15378c2ecf20Sopenharmony_ci			goto no_reserved;
15388c2ecf20Sopenharmony_ci		}
15398c2ecf20Sopenharmony_ci		psock->done = 1;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci		/* Commit done before queuing work to process it */
15428c2ecf20Sopenharmony_ci		smp_mb();
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci		/* Queue tx work to make sure psock->done is handled */
15458c2ecf20Sopenharmony_ci		queue_work(kcm_wq, &psock->tx_kcm->tx_work);
15468c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
15478c2ecf20Sopenharmony_ci	} else {
15488c2ecf20Sopenharmony_cino_reserved:
15498c2ecf20Sopenharmony_ci		if (!psock->tx_stopped)
15508c2ecf20Sopenharmony_ci			list_del(&psock->psock_avail_list);
15518c2ecf20Sopenharmony_ci		list_del(&psock->psock_list);
15528c2ecf20Sopenharmony_ci		mux->psocks_cnt--;
15538c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci		sock_put(csk);
15568c2ecf20Sopenharmony_ci		fput(csk->sk_socket->file);
15578c2ecf20Sopenharmony_ci		kmem_cache_free(kcm_psockp, psock);
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	release_sock(csk);
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_cistatic int kcm_unattach_ioctl(struct socket *sock, struct kcm_unattach *info)
15648c2ecf20Sopenharmony_ci{
15658c2ecf20Sopenharmony_ci	struct kcm_sock *kcm = kcm_sk(sock->sk);
15668c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
15678c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
15688c2ecf20Sopenharmony_ci	struct socket *csock;
15698c2ecf20Sopenharmony_ci	struct sock *csk;
15708c2ecf20Sopenharmony_ci	int err;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	csock = sockfd_lookup(info->fd, &err);
15738c2ecf20Sopenharmony_ci	if (!csock)
15748c2ecf20Sopenharmony_ci		return -ENOENT;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	csk = csock->sk;
15778c2ecf20Sopenharmony_ci	if (!csk) {
15788c2ecf20Sopenharmony_ci		err = -EINVAL;
15798c2ecf20Sopenharmony_ci		goto out;
15808c2ecf20Sopenharmony_ci	}
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	err = -ENOENT;
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	list_for_each_entry(psock, &mux->psocks, psock_list) {
15878c2ecf20Sopenharmony_ci		if (psock->sk != csk)
15888c2ecf20Sopenharmony_ci			continue;
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci		/* Found the matching psock */
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci		if (psock->unattaching || WARN_ON(psock->done)) {
15938c2ecf20Sopenharmony_ci			err = -EALREADY;
15948c2ecf20Sopenharmony_ci			break;
15958c2ecf20Sopenharmony_ci		}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci		psock->unattaching = 1;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->lock);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		/* Lower socket lock should already be held */
16028c2ecf20Sopenharmony_ci		kcm_unattach(psock);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci		err = 0;
16058c2ecf20Sopenharmony_ci		goto out;
16068c2ecf20Sopenharmony_ci	}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ciout:
16118c2ecf20Sopenharmony_ci	fput(csock->file);
16128c2ecf20Sopenharmony_ci	return err;
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_cistatic struct proto kcm_proto = {
16168c2ecf20Sopenharmony_ci	.name	= "KCM",
16178c2ecf20Sopenharmony_ci	.owner	= THIS_MODULE,
16188c2ecf20Sopenharmony_ci	.obj_size = sizeof(struct kcm_sock),
16198c2ecf20Sopenharmony_ci};
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci/* Clone a kcm socket. */
16228c2ecf20Sopenharmony_cistatic struct file *kcm_clone(struct socket *osock)
16238c2ecf20Sopenharmony_ci{
16248c2ecf20Sopenharmony_ci	struct socket *newsock;
16258c2ecf20Sopenharmony_ci	struct sock *newsk;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	newsock = sock_alloc();
16288c2ecf20Sopenharmony_ci	if (!newsock)
16298c2ecf20Sopenharmony_ci		return ERR_PTR(-ENFILE);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	newsock->type = osock->type;
16328c2ecf20Sopenharmony_ci	newsock->ops = osock->ops;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	__module_get(newsock->ops->owner);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL,
16378c2ecf20Sopenharmony_ci			 &kcm_proto, false);
16388c2ecf20Sopenharmony_ci	if (!newsk) {
16398c2ecf20Sopenharmony_ci		sock_release(newsock);
16408c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
16418c2ecf20Sopenharmony_ci	}
16428c2ecf20Sopenharmony_ci	sock_init_data(newsock, newsk);
16438c2ecf20Sopenharmony_ci	init_kcm_sock(kcm_sk(newsk), kcm_sk(osock->sk)->mux);
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	return sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name);
16468c2ecf20Sopenharmony_ci}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_cistatic int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
16498c2ecf20Sopenharmony_ci{
16508c2ecf20Sopenharmony_ci	int err;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	switch (cmd) {
16538c2ecf20Sopenharmony_ci	case SIOCKCMATTACH: {
16548c2ecf20Sopenharmony_ci		struct kcm_attach info;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci		if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
16578c2ecf20Sopenharmony_ci			return -EFAULT;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci		err = kcm_attach_ioctl(sock, &info);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci		break;
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci	case SIOCKCMUNATTACH: {
16648c2ecf20Sopenharmony_ci		struct kcm_unattach info;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci		if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
16678c2ecf20Sopenharmony_ci			return -EFAULT;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci		err = kcm_unattach_ioctl(sock, &info);
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci		break;
16728c2ecf20Sopenharmony_ci	}
16738c2ecf20Sopenharmony_ci	case SIOCKCMCLONE: {
16748c2ecf20Sopenharmony_ci		struct kcm_clone info;
16758c2ecf20Sopenharmony_ci		struct file *file;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci		info.fd = get_unused_fd_flags(0);
16788c2ecf20Sopenharmony_ci		if (unlikely(info.fd < 0))
16798c2ecf20Sopenharmony_ci			return info.fd;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci		file = kcm_clone(sock);
16828c2ecf20Sopenharmony_ci		if (IS_ERR(file)) {
16838c2ecf20Sopenharmony_ci			put_unused_fd(info.fd);
16848c2ecf20Sopenharmony_ci			return PTR_ERR(file);
16858c2ecf20Sopenharmony_ci		}
16868c2ecf20Sopenharmony_ci		if (copy_to_user((void __user *)arg, &info,
16878c2ecf20Sopenharmony_ci				 sizeof(info))) {
16888c2ecf20Sopenharmony_ci			put_unused_fd(info.fd);
16898c2ecf20Sopenharmony_ci			fput(file);
16908c2ecf20Sopenharmony_ci			return -EFAULT;
16918c2ecf20Sopenharmony_ci		}
16928c2ecf20Sopenharmony_ci		fd_install(info.fd, file);
16938c2ecf20Sopenharmony_ci		err = 0;
16948c2ecf20Sopenharmony_ci		break;
16958c2ecf20Sopenharmony_ci	}
16968c2ecf20Sopenharmony_ci	default:
16978c2ecf20Sopenharmony_ci		err = -ENOIOCTLCMD;
16988c2ecf20Sopenharmony_ci		break;
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	return err;
17028c2ecf20Sopenharmony_ci}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cistatic void free_mux(struct rcu_head *rcu)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	struct kcm_mux *mux = container_of(rcu,
17078c2ecf20Sopenharmony_ci	    struct kcm_mux, rcu);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	kmem_cache_free(kcm_muxp, mux);
17108c2ecf20Sopenharmony_ci}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_cistatic void release_mux(struct kcm_mux *mux)
17138c2ecf20Sopenharmony_ci{
17148c2ecf20Sopenharmony_ci	struct kcm_net *knet = mux->knet;
17158c2ecf20Sopenharmony_ci	struct kcm_psock *psock, *tmp_psock;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	/* Release psocks */
17188c2ecf20Sopenharmony_ci	list_for_each_entry_safe(psock, tmp_psock,
17198c2ecf20Sopenharmony_ci				 &mux->psocks, psock_list) {
17208c2ecf20Sopenharmony_ci		if (!WARN_ON(psock->unattaching))
17218c2ecf20Sopenharmony_ci			kcm_unattach(psock);
17228c2ecf20Sopenharmony_ci	}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	if (WARN_ON(mux->psocks_cnt))
17258c2ecf20Sopenharmony_ci		return;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	__skb_queue_purge(&mux->rx_hold_queue);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	mutex_lock(&knet->mutex);
17308c2ecf20Sopenharmony_ci	aggregate_mux_stats(&mux->stats, &knet->aggregate_mux_stats);
17318c2ecf20Sopenharmony_ci	aggregate_psock_stats(&mux->aggregate_psock_stats,
17328c2ecf20Sopenharmony_ci			      &knet->aggregate_psock_stats);
17338c2ecf20Sopenharmony_ci	aggregate_strp_stats(&mux->aggregate_strp_stats,
17348c2ecf20Sopenharmony_ci			     &knet->aggregate_strp_stats);
17358c2ecf20Sopenharmony_ci	list_del_rcu(&mux->kcm_mux_list);
17368c2ecf20Sopenharmony_ci	knet->count--;
17378c2ecf20Sopenharmony_ci	mutex_unlock(&knet->mutex);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	call_rcu(&mux->rcu, free_mux);
17408c2ecf20Sopenharmony_ci}
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_cistatic void kcm_done(struct kcm_sock *kcm)
17438c2ecf20Sopenharmony_ci{
17448c2ecf20Sopenharmony_ci	struct kcm_mux *mux = kcm->mux;
17458c2ecf20Sopenharmony_ci	struct sock *sk = &kcm->sk;
17468c2ecf20Sopenharmony_ci	int socks_cnt;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->rx_lock);
17498c2ecf20Sopenharmony_ci	if (kcm->rx_psock) {
17508c2ecf20Sopenharmony_ci		/* Cleanup in unreserve_rx_kcm */
17518c2ecf20Sopenharmony_ci		WARN_ON(kcm->done);
17528c2ecf20Sopenharmony_ci		kcm->rx_disabled = 1;
17538c2ecf20Sopenharmony_ci		kcm->done = 1;
17548c2ecf20Sopenharmony_ci		spin_unlock_bh(&mux->rx_lock);
17558c2ecf20Sopenharmony_ci		return;
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	if (kcm->rx_wait) {
17598c2ecf20Sopenharmony_ci		list_del(&kcm->wait_rx_list);
17608c2ecf20Sopenharmony_ci		/* paired with lockless reads in kcm_rfree() */
17618c2ecf20Sopenharmony_ci		WRITE_ONCE(kcm->rx_wait, false);
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci	/* Move any pending receive messages to other kcm sockets */
17648c2ecf20Sopenharmony_ci	requeue_rx_msgs(mux, &sk->sk_receive_queue);
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->rx_lock);
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	if (WARN_ON(sk_rmem_alloc_get(sk)))
17698c2ecf20Sopenharmony_ci		return;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	/* Detach from MUX */
17728c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	list_del(&kcm->kcm_sock_list);
17758c2ecf20Sopenharmony_ci	mux->kcm_socks_cnt--;
17768c2ecf20Sopenharmony_ci	socks_cnt = mux->kcm_socks_cnt;
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	if (!socks_cnt) {
17818c2ecf20Sopenharmony_ci		/* We are done with the mux now. */
17828c2ecf20Sopenharmony_ci		release_mux(mux);
17838c2ecf20Sopenharmony_ci	}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	WARN_ON(kcm->rx_wait);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	sock_put(&kcm->sk);
17888c2ecf20Sopenharmony_ci}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci/* Called by kcm_release to close a KCM socket.
17918c2ecf20Sopenharmony_ci * If this is the last KCM socket on the MUX, destroy the MUX.
17928c2ecf20Sopenharmony_ci */
17938c2ecf20Sopenharmony_cistatic int kcm_release(struct socket *sock)
17948c2ecf20Sopenharmony_ci{
17958c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
17968c2ecf20Sopenharmony_ci	struct kcm_sock *kcm;
17978c2ecf20Sopenharmony_ci	struct kcm_mux *mux;
17988c2ecf20Sopenharmony_ci	struct kcm_psock *psock;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	if (!sk)
18018c2ecf20Sopenharmony_ci		return 0;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	kcm = kcm_sk(sk);
18048c2ecf20Sopenharmony_ci	mux = kcm->mux;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	lock_sock(sk);
18078c2ecf20Sopenharmony_ci	sock_orphan(sk);
18088c2ecf20Sopenharmony_ci	kfree_skb(kcm->seq_skb);
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	/* Purge queue under lock to avoid race condition with tx_work trying
18118c2ecf20Sopenharmony_ci	 * to act when queue is nonempty. If tx_work runs after this point
18128c2ecf20Sopenharmony_ci	 * it will just return.
18138c2ecf20Sopenharmony_ci	 */
18148c2ecf20Sopenharmony_ci	__skb_queue_purge(&sk->sk_write_queue);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	/* Set tx_stopped. This is checked when psock is bound to a kcm and we
18178c2ecf20Sopenharmony_ci	 * get a writespace callback. This prevents further work being queued
18188c2ecf20Sopenharmony_ci	 * from the callback (unbinding the psock occurs after canceling work.
18198c2ecf20Sopenharmony_ci	 */
18208c2ecf20Sopenharmony_ci	kcm->tx_stopped = 1;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	release_sock(sk);
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	spin_lock_bh(&mux->lock);
18258c2ecf20Sopenharmony_ci	if (kcm->tx_wait) {
18268c2ecf20Sopenharmony_ci		/* Take of tx_wait list, after this point there should be no way
18278c2ecf20Sopenharmony_ci		 * that a psock will be assigned to this kcm.
18288c2ecf20Sopenharmony_ci		 */
18298c2ecf20Sopenharmony_ci		list_del(&kcm->wait_psock_list);
18308c2ecf20Sopenharmony_ci		kcm->tx_wait = false;
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci	spin_unlock_bh(&mux->lock);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	/* Cancel work. After this point there should be no outside references
18358c2ecf20Sopenharmony_ci	 * to the kcm socket.
18368c2ecf20Sopenharmony_ci	 */
18378c2ecf20Sopenharmony_ci	cancel_work_sync(&kcm->tx_work);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	lock_sock(sk);
18408c2ecf20Sopenharmony_ci	psock = kcm->tx_psock;
18418c2ecf20Sopenharmony_ci	if (psock) {
18428c2ecf20Sopenharmony_ci		/* A psock was reserved, so we need to kill it since it
18438c2ecf20Sopenharmony_ci		 * may already have some bytes queued from a message. We
18448c2ecf20Sopenharmony_ci		 * need to do this after removing kcm from tx_wait list.
18458c2ecf20Sopenharmony_ci		 */
18468c2ecf20Sopenharmony_ci		kcm_abort_tx_psock(psock, EPIPE, false);
18478c2ecf20Sopenharmony_ci		unreserve_psock(kcm);
18488c2ecf20Sopenharmony_ci	}
18498c2ecf20Sopenharmony_ci	release_sock(sk);
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	WARN_ON(kcm->tx_wait);
18528c2ecf20Sopenharmony_ci	WARN_ON(kcm->tx_psock);
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	sock->sk = NULL;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	kcm_done(kcm);
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	return 0;
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cistatic const struct proto_ops kcm_dgram_ops = {
18628c2ecf20Sopenharmony_ci	.family =	PF_KCM,
18638c2ecf20Sopenharmony_ci	.owner =	THIS_MODULE,
18648c2ecf20Sopenharmony_ci	.release =	kcm_release,
18658c2ecf20Sopenharmony_ci	.bind =		sock_no_bind,
18668c2ecf20Sopenharmony_ci	.connect =	sock_no_connect,
18678c2ecf20Sopenharmony_ci	.socketpair =	sock_no_socketpair,
18688c2ecf20Sopenharmony_ci	.accept =	sock_no_accept,
18698c2ecf20Sopenharmony_ci	.getname =	sock_no_getname,
18708c2ecf20Sopenharmony_ci	.poll =		datagram_poll,
18718c2ecf20Sopenharmony_ci	.ioctl =	kcm_ioctl,
18728c2ecf20Sopenharmony_ci	.listen =	sock_no_listen,
18738c2ecf20Sopenharmony_ci	.shutdown =	sock_no_shutdown,
18748c2ecf20Sopenharmony_ci	.setsockopt =	kcm_setsockopt,
18758c2ecf20Sopenharmony_ci	.getsockopt =	kcm_getsockopt,
18768c2ecf20Sopenharmony_ci	.sendmsg =	kcm_sendmsg,
18778c2ecf20Sopenharmony_ci	.recvmsg =	kcm_recvmsg,
18788c2ecf20Sopenharmony_ci	.mmap =		sock_no_mmap,
18798c2ecf20Sopenharmony_ci	.sendpage =	kcm_sendpage,
18808c2ecf20Sopenharmony_ci};
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_cistatic const struct proto_ops kcm_seqpacket_ops = {
18838c2ecf20Sopenharmony_ci	.family =	PF_KCM,
18848c2ecf20Sopenharmony_ci	.owner =	THIS_MODULE,
18858c2ecf20Sopenharmony_ci	.release =	kcm_release,
18868c2ecf20Sopenharmony_ci	.bind =		sock_no_bind,
18878c2ecf20Sopenharmony_ci	.connect =	sock_no_connect,
18888c2ecf20Sopenharmony_ci	.socketpair =	sock_no_socketpair,
18898c2ecf20Sopenharmony_ci	.accept =	sock_no_accept,
18908c2ecf20Sopenharmony_ci	.getname =	sock_no_getname,
18918c2ecf20Sopenharmony_ci	.poll =		datagram_poll,
18928c2ecf20Sopenharmony_ci	.ioctl =	kcm_ioctl,
18938c2ecf20Sopenharmony_ci	.listen =	sock_no_listen,
18948c2ecf20Sopenharmony_ci	.shutdown =	sock_no_shutdown,
18958c2ecf20Sopenharmony_ci	.setsockopt =	kcm_setsockopt,
18968c2ecf20Sopenharmony_ci	.getsockopt =	kcm_getsockopt,
18978c2ecf20Sopenharmony_ci	.sendmsg =	kcm_sendmsg,
18988c2ecf20Sopenharmony_ci	.recvmsg =	kcm_recvmsg,
18998c2ecf20Sopenharmony_ci	.mmap =		sock_no_mmap,
19008c2ecf20Sopenharmony_ci	.sendpage =	kcm_sendpage,
19018c2ecf20Sopenharmony_ci	.splice_read =	kcm_splice_read,
19028c2ecf20Sopenharmony_ci};
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci/* Create proto operation for kcm sockets */
19058c2ecf20Sopenharmony_cistatic int kcm_create(struct net *net, struct socket *sock,
19068c2ecf20Sopenharmony_ci		      int protocol, int kern)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	struct kcm_net *knet = net_generic(net, kcm_net_id);
19098c2ecf20Sopenharmony_ci	struct sock *sk;
19108c2ecf20Sopenharmony_ci	struct kcm_mux *mux;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	switch (sock->type) {
19138c2ecf20Sopenharmony_ci	case SOCK_DGRAM:
19148c2ecf20Sopenharmony_ci		sock->ops = &kcm_dgram_ops;
19158c2ecf20Sopenharmony_ci		break;
19168c2ecf20Sopenharmony_ci	case SOCK_SEQPACKET:
19178c2ecf20Sopenharmony_ci		sock->ops = &kcm_seqpacket_ops;
19188c2ecf20Sopenharmony_ci		break;
19198c2ecf20Sopenharmony_ci	default:
19208c2ecf20Sopenharmony_ci		return -ESOCKTNOSUPPORT;
19218c2ecf20Sopenharmony_ci	}
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	if (protocol != KCMPROTO_CONNECTED)
19248c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	sk = sk_alloc(net, PF_KCM, GFP_KERNEL, &kcm_proto, kern);
19278c2ecf20Sopenharmony_ci	if (!sk)
19288c2ecf20Sopenharmony_ci		return -ENOMEM;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	/* Allocate a kcm mux, shared between KCM sockets */
19318c2ecf20Sopenharmony_ci	mux = kmem_cache_zalloc(kcm_muxp, GFP_KERNEL);
19328c2ecf20Sopenharmony_ci	if (!mux) {
19338c2ecf20Sopenharmony_ci		sk_free(sk);
19348c2ecf20Sopenharmony_ci		return -ENOMEM;
19358c2ecf20Sopenharmony_ci	}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	spin_lock_init(&mux->lock);
19388c2ecf20Sopenharmony_ci	spin_lock_init(&mux->rx_lock);
19398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mux->kcm_socks);
19408c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mux->kcm_rx_waiters);
19418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mux->kcm_tx_waiters);
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mux->psocks);
19448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mux->psocks_ready);
19458c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mux->psocks_avail);
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	mux->knet = knet;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	/* Add new MUX to list */
19508c2ecf20Sopenharmony_ci	mutex_lock(&knet->mutex);
19518c2ecf20Sopenharmony_ci	list_add_rcu(&mux->kcm_mux_list, &knet->mux_list);
19528c2ecf20Sopenharmony_ci	knet->count++;
19538c2ecf20Sopenharmony_ci	mutex_unlock(&knet->mutex);
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	skb_queue_head_init(&mux->rx_hold_queue);
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	/* Init KCM socket */
19588c2ecf20Sopenharmony_ci	sock_init_data(sock, sk);
19598c2ecf20Sopenharmony_ci	init_kcm_sock(kcm_sk(sk), mux);
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	return 0;
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_cistatic const struct net_proto_family kcm_family_ops = {
19658c2ecf20Sopenharmony_ci	.family = PF_KCM,
19668c2ecf20Sopenharmony_ci	.create = kcm_create,
19678c2ecf20Sopenharmony_ci	.owner  = THIS_MODULE,
19688c2ecf20Sopenharmony_ci};
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_cistatic __net_init int kcm_init_net(struct net *net)
19718c2ecf20Sopenharmony_ci{
19728c2ecf20Sopenharmony_ci	struct kcm_net *knet = net_generic(net, kcm_net_id);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	INIT_LIST_HEAD_RCU(&knet->mux_list);
19758c2ecf20Sopenharmony_ci	mutex_init(&knet->mutex);
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	return 0;
19788c2ecf20Sopenharmony_ci}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_cistatic __net_exit void kcm_exit_net(struct net *net)
19818c2ecf20Sopenharmony_ci{
19828c2ecf20Sopenharmony_ci	struct kcm_net *knet = net_generic(net, kcm_net_id);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	/* All KCM sockets should be closed at this point, which should mean
19858c2ecf20Sopenharmony_ci	 * that all multiplexors and psocks have been destroyed.
19868c2ecf20Sopenharmony_ci	 */
19878c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&knet->mux_list));
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	mutex_destroy(&knet->mutex);
19908c2ecf20Sopenharmony_ci}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_cistatic struct pernet_operations kcm_net_ops = {
19938c2ecf20Sopenharmony_ci	.init = kcm_init_net,
19948c2ecf20Sopenharmony_ci	.exit = kcm_exit_net,
19958c2ecf20Sopenharmony_ci	.id   = &kcm_net_id,
19968c2ecf20Sopenharmony_ci	.size = sizeof(struct kcm_net),
19978c2ecf20Sopenharmony_ci};
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_cistatic int __init kcm_init(void)
20008c2ecf20Sopenharmony_ci{
20018c2ecf20Sopenharmony_ci	int err = -ENOMEM;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	kcm_muxp = kmem_cache_create("kcm_mux_cache",
20048c2ecf20Sopenharmony_ci				     sizeof(struct kcm_mux), 0,
20058c2ecf20Sopenharmony_ci				     SLAB_HWCACHE_ALIGN, NULL);
20068c2ecf20Sopenharmony_ci	if (!kcm_muxp)
20078c2ecf20Sopenharmony_ci		goto fail;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	kcm_psockp = kmem_cache_create("kcm_psock_cache",
20108c2ecf20Sopenharmony_ci				       sizeof(struct kcm_psock), 0,
20118c2ecf20Sopenharmony_ci					SLAB_HWCACHE_ALIGN, NULL);
20128c2ecf20Sopenharmony_ci	if (!kcm_psockp)
20138c2ecf20Sopenharmony_ci		goto fail;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	kcm_wq = create_singlethread_workqueue("kkcmd");
20168c2ecf20Sopenharmony_ci	if (!kcm_wq)
20178c2ecf20Sopenharmony_ci		goto fail;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	err = proto_register(&kcm_proto, 1);
20208c2ecf20Sopenharmony_ci	if (err)
20218c2ecf20Sopenharmony_ci		goto fail;
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	err = register_pernet_device(&kcm_net_ops);
20248c2ecf20Sopenharmony_ci	if (err)
20258c2ecf20Sopenharmony_ci		goto net_ops_fail;
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	err = sock_register(&kcm_family_ops);
20288c2ecf20Sopenharmony_ci	if (err)
20298c2ecf20Sopenharmony_ci		goto sock_register_fail;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	err = kcm_proc_init();
20328c2ecf20Sopenharmony_ci	if (err)
20338c2ecf20Sopenharmony_ci		goto proc_init_fail;
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	return 0;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ciproc_init_fail:
20388c2ecf20Sopenharmony_ci	sock_unregister(PF_KCM);
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_cisock_register_fail:
20418c2ecf20Sopenharmony_ci	unregister_pernet_device(&kcm_net_ops);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_cinet_ops_fail:
20448c2ecf20Sopenharmony_ci	proto_unregister(&kcm_proto);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_cifail:
20478c2ecf20Sopenharmony_ci	kmem_cache_destroy(kcm_muxp);
20488c2ecf20Sopenharmony_ci	kmem_cache_destroy(kcm_psockp);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	if (kcm_wq)
20518c2ecf20Sopenharmony_ci		destroy_workqueue(kcm_wq);
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	return err;
20548c2ecf20Sopenharmony_ci}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_cistatic void __exit kcm_exit(void)
20578c2ecf20Sopenharmony_ci{
20588c2ecf20Sopenharmony_ci	kcm_proc_exit();
20598c2ecf20Sopenharmony_ci	sock_unregister(PF_KCM);
20608c2ecf20Sopenharmony_ci	unregister_pernet_device(&kcm_net_ops);
20618c2ecf20Sopenharmony_ci	proto_unregister(&kcm_proto);
20628c2ecf20Sopenharmony_ci	destroy_workqueue(kcm_wq);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	kmem_cache_destroy(kcm_muxp);
20658c2ecf20Sopenharmony_ci	kmem_cache_destroy(kcm_psockp);
20668c2ecf20Sopenharmony_ci}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_cimodule_init(kcm_init);
20698c2ecf20Sopenharmony_cimodule_exit(kcm_exit);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
20728c2ecf20Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_KCM);
2073