18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * File: socket.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Phonet sockets
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Authors: Sakari Ailus <sakari.ailus@nokia.com>
108c2ecf20Sopenharmony_ci *          Rémi Denis-Courmont
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/gfp.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/net.h>
168c2ecf20Sopenharmony_ci#include <linux/poll.h>
178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <net/sock.h>
208c2ecf20Sopenharmony_ci#include <net/tcp_states.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/phonet.h>
238c2ecf20Sopenharmony_ci#include <linux/export.h>
248c2ecf20Sopenharmony_ci#include <net/phonet/phonet.h>
258c2ecf20Sopenharmony_ci#include <net/phonet/pep.h>
268c2ecf20Sopenharmony_ci#include <net/phonet/pn_dev.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int pn_socket_release(struct socket *sock)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (sk) {
338c2ecf20Sopenharmony_ci		sock->sk = NULL;
348c2ecf20Sopenharmony_ci		sk->sk_prot->close(sk, 0);
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci	return 0;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define PN_HASHSIZE	16
408c2ecf20Sopenharmony_ci#define PN_HASHMASK	(PN_HASHSIZE-1)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic struct  {
448c2ecf20Sopenharmony_ci	struct hlist_head hlist[PN_HASHSIZE];
458c2ecf20Sopenharmony_ci	struct mutex lock;
468c2ecf20Sopenharmony_ci} pnsocks;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid __init pn_sock_init(void)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	unsigned int i;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	for (i = 0; i < PN_HASHSIZE; i++)
538c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(pnsocks.hlist + i);
548c2ecf20Sopenharmony_ci	mutex_init(&pnsocks.lock);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic struct hlist_head *pn_hash_list(u16 obj)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	return pnsocks.hlist + (obj & PN_HASHMASK);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/*
638c2ecf20Sopenharmony_ci * Find address based on socket address, match only certain fields.
648c2ecf20Sopenharmony_ci * Also grab sock if it was found. Remember to sock_put it later.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_cistruct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	struct sock *sknode;
698c2ecf20Sopenharmony_ci	struct sock *rval = NULL;
708c2ecf20Sopenharmony_ci	u16 obj = pn_sockaddr_get_object(spn);
718c2ecf20Sopenharmony_ci	u8 res = spn->spn_resource;
728c2ecf20Sopenharmony_ci	struct hlist_head *hlist = pn_hash_list(obj);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	rcu_read_lock();
758c2ecf20Sopenharmony_ci	sk_for_each_rcu(sknode, hlist) {
768c2ecf20Sopenharmony_ci		struct pn_sock *pn = pn_sk(sknode);
778c2ecf20Sopenharmony_ci		BUG_ON(!pn->sobject); /* unbound socket */
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci		if (!net_eq(sock_net(sknode), net))
808c2ecf20Sopenharmony_ci			continue;
818c2ecf20Sopenharmony_ci		if (pn_port(obj)) {
828c2ecf20Sopenharmony_ci			/* Look up socket by port */
838c2ecf20Sopenharmony_ci			if (pn_port(pn->sobject) != pn_port(obj))
848c2ecf20Sopenharmony_ci				continue;
858c2ecf20Sopenharmony_ci		} else {
868c2ecf20Sopenharmony_ci			/* If port is zero, look up by resource */
878c2ecf20Sopenharmony_ci			if (pn->resource != res)
888c2ecf20Sopenharmony_ci				continue;
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci		if (pn_addr(pn->sobject) &&
918c2ecf20Sopenharmony_ci		    pn_addr(pn->sobject) != pn_addr(obj))
928c2ecf20Sopenharmony_ci			continue;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		rval = sknode;
958c2ecf20Sopenharmony_ci		sock_hold(sknode);
968c2ecf20Sopenharmony_ci		break;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	rcu_read_unlock();
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return rval;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/* Deliver a broadcast packet (only in bottom-half) */
1048c2ecf20Sopenharmony_civoid pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct hlist_head *hlist = pnsocks.hlist;
1078c2ecf20Sopenharmony_ci	unsigned int h;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	rcu_read_lock();
1108c2ecf20Sopenharmony_ci	for (h = 0; h < PN_HASHSIZE; h++) {
1118c2ecf20Sopenharmony_ci		struct sock *sknode;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		sk_for_each(sknode, hlist) {
1148c2ecf20Sopenharmony_ci			struct sk_buff *clone;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci			if (!net_eq(sock_net(sknode), net))
1178c2ecf20Sopenharmony_ci				continue;
1188c2ecf20Sopenharmony_ci			if (!sock_flag(sknode, SOCK_BROADCAST))
1198c2ecf20Sopenharmony_ci				continue;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci			clone = skb_clone(skb, GFP_ATOMIC);
1228c2ecf20Sopenharmony_ci			if (clone) {
1238c2ecf20Sopenharmony_ci				sock_hold(sknode);
1248c2ecf20Sopenharmony_ci				sk_receive_skb(sknode, clone, 0);
1258c2ecf20Sopenharmony_ci			}
1268c2ecf20Sopenharmony_ci		}
1278c2ecf20Sopenharmony_ci		hlist++;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci	rcu_read_unlock();
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ciint pn_sock_hash(struct sock *sk)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	mutex_lock(&pnsocks.lock);
1378c2ecf20Sopenharmony_ci	sk_add_node_rcu(sk, hlist);
1388c2ecf20Sopenharmony_ci	mutex_unlock(&pnsocks.lock);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pn_sock_hash);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_civoid pn_sock_unhash(struct sock *sk)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	mutex_lock(&pnsocks.lock);
1478c2ecf20Sopenharmony_ci	sk_del_node_init_rcu(sk);
1488c2ecf20Sopenharmony_ci	mutex_unlock(&pnsocks.lock);
1498c2ecf20Sopenharmony_ci	pn_sock_unbind_all_res(sk);
1508c2ecf20Sopenharmony_ci	synchronize_rcu();
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pn_sock_unhash);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(port_mutex);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
1598c2ecf20Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
1608c2ecf20Sopenharmony_ci	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
1618c2ecf20Sopenharmony_ci	int err;
1628c2ecf20Sopenharmony_ci	u16 handle;
1638c2ecf20Sopenharmony_ci	u8 saddr;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (sk->sk_prot->bind)
1668c2ecf20Sopenharmony_ci		return sk->sk_prot->bind(sk, addr, len);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (len < sizeof(struct sockaddr_pn))
1698c2ecf20Sopenharmony_ci		return -EINVAL;
1708c2ecf20Sopenharmony_ci	if (spn->spn_family != AF_PHONET)
1718c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
1748c2ecf20Sopenharmony_ci	saddr = pn_addr(handle);
1758c2ecf20Sopenharmony_ci	if (saddr && phonet_address_lookup(sock_net(sk), saddr))
1768c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	lock_sock(sk);
1798c2ecf20Sopenharmony_ci	if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
1808c2ecf20Sopenharmony_ci		err = -EINVAL; /* attempt to rebind */
1818c2ecf20Sopenharmony_ci		goto out;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci	WARN_ON(sk_hashed(sk));
1848c2ecf20Sopenharmony_ci	mutex_lock(&port_mutex);
1858c2ecf20Sopenharmony_ci	err = sk->sk_prot->get_port(sk, pn_port(handle));
1868c2ecf20Sopenharmony_ci	if (err)
1878c2ecf20Sopenharmony_ci		goto out_port;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* get_port() sets the port, bind() sets the address if applicable */
1908c2ecf20Sopenharmony_ci	pn->sobject = pn_object(saddr, pn_port(pn->sobject));
1918c2ecf20Sopenharmony_ci	pn->resource = spn->spn_resource;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Enable RX on the socket */
1948c2ecf20Sopenharmony_ci	err = sk->sk_prot->hash(sk);
1958c2ecf20Sopenharmony_ciout_port:
1968c2ecf20Sopenharmony_ci	mutex_unlock(&port_mutex);
1978c2ecf20Sopenharmony_ciout:
1988c2ecf20Sopenharmony_ci	release_sock(sk);
1998c2ecf20Sopenharmony_ci	return err;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int pn_socket_autobind(struct socket *sock)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct sockaddr_pn sa;
2058c2ecf20Sopenharmony_ci	int err;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	memset(&sa, 0, sizeof(sa));
2088c2ecf20Sopenharmony_ci	sa.spn_family = AF_PHONET;
2098c2ecf20Sopenharmony_ci	err = pn_socket_bind(sock, (struct sockaddr *)&sa,
2108c2ecf20Sopenharmony_ci				sizeof(struct sockaddr_pn));
2118c2ecf20Sopenharmony_ci	if (err != -EINVAL)
2128c2ecf20Sopenharmony_ci		return err;
2138c2ecf20Sopenharmony_ci	BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
2148c2ecf20Sopenharmony_ci	return 0; /* socket was already bound */
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
2188c2ecf20Sopenharmony_ci		int len, int flags)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
2218c2ecf20Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
2228c2ecf20Sopenharmony_ci	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
2238c2ecf20Sopenharmony_ci	struct task_struct *tsk = current;
2248c2ecf20Sopenharmony_ci	long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
2258c2ecf20Sopenharmony_ci	int err;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (pn_socket_autobind(sock))
2288c2ecf20Sopenharmony_ci		return -ENOBUFS;
2298c2ecf20Sopenharmony_ci	if (len < sizeof(struct sockaddr_pn))
2308c2ecf20Sopenharmony_ci		return -EINVAL;
2318c2ecf20Sopenharmony_ci	if (spn->spn_family != AF_PHONET)
2328c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	lock_sock(sk);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	switch (sock->state) {
2378c2ecf20Sopenharmony_ci	case SS_UNCONNECTED:
2388c2ecf20Sopenharmony_ci		if (sk->sk_state != TCP_CLOSE) {
2398c2ecf20Sopenharmony_ci			err = -EISCONN;
2408c2ecf20Sopenharmony_ci			goto out;
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	case SS_CONNECTING:
2448c2ecf20Sopenharmony_ci		err = -EALREADY;
2458c2ecf20Sopenharmony_ci		goto out;
2468c2ecf20Sopenharmony_ci	default:
2478c2ecf20Sopenharmony_ci		err = -EISCONN;
2488c2ecf20Sopenharmony_ci		goto out;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	pn->dobject = pn_sockaddr_get_object(spn);
2528c2ecf20Sopenharmony_ci	pn->resource = pn_sockaddr_get_resource(spn);
2538c2ecf20Sopenharmony_ci	sock->state = SS_CONNECTING;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	err = sk->sk_prot->connect(sk, addr, len);
2568c2ecf20Sopenharmony_ci	if (err) {
2578c2ecf20Sopenharmony_ci		sock->state = SS_UNCONNECTED;
2588c2ecf20Sopenharmony_ci		pn->dobject = 0;
2598c2ecf20Sopenharmony_ci		goto out;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	while (sk->sk_state == TCP_SYN_SENT) {
2638c2ecf20Sopenharmony_ci		DEFINE_WAIT(wait);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		if (!timeo) {
2668c2ecf20Sopenharmony_ci			err = -EINPROGRESS;
2678c2ecf20Sopenharmony_ci			goto out;
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci		if (signal_pending(tsk)) {
2708c2ecf20Sopenharmony_ci			err = sock_intr_errno(timeo);
2718c2ecf20Sopenharmony_ci			goto out;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
2758c2ecf20Sopenharmony_ci						TASK_INTERRUPTIBLE);
2768c2ecf20Sopenharmony_ci		release_sock(sk);
2778c2ecf20Sopenharmony_ci		timeo = schedule_timeout(timeo);
2788c2ecf20Sopenharmony_ci		lock_sock(sk);
2798c2ecf20Sopenharmony_ci		finish_wait(sk_sleep(sk), &wait);
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
2838c2ecf20Sopenharmony_ci		err = 0;
2848c2ecf20Sopenharmony_ci	else if (sk->sk_state == TCP_CLOSE_WAIT)
2858c2ecf20Sopenharmony_ci		err = -ECONNRESET;
2868c2ecf20Sopenharmony_ci	else
2878c2ecf20Sopenharmony_ci		err = -ECONNREFUSED;
2888c2ecf20Sopenharmony_ci	sock->state = err ? SS_UNCONNECTED : SS_CONNECTED;
2898c2ecf20Sopenharmony_ciout:
2908c2ecf20Sopenharmony_ci	release_sock(sk);
2918c2ecf20Sopenharmony_ci	return err;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int pn_socket_accept(struct socket *sock, struct socket *newsock,
2958c2ecf20Sopenharmony_ci			    int flags, bool kern)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
2988c2ecf20Sopenharmony_ci	struct sock *newsk;
2998c2ecf20Sopenharmony_ci	int err;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (unlikely(sk->sk_state != TCP_LISTEN))
3028c2ecf20Sopenharmony_ci		return -EINVAL;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	newsk = sk->sk_prot->accept(sk, flags, &err, kern);
3058c2ecf20Sopenharmony_ci	if (!newsk)
3068c2ecf20Sopenharmony_ci		return err;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	lock_sock(newsk);
3098c2ecf20Sopenharmony_ci	sock_graft(newsk, newsock);
3108c2ecf20Sopenharmony_ci	newsock->state = SS_CONNECTED;
3118c2ecf20Sopenharmony_ci	release_sock(newsk);
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
3168c2ecf20Sopenharmony_ci				int peer)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3198c2ecf20Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	memset(addr, 0, sizeof(struct sockaddr_pn));
3228c2ecf20Sopenharmony_ci	addr->sa_family = AF_PHONET;
3238c2ecf20Sopenharmony_ci	if (!peer) /* Race with bind() here is userland's problem. */
3248c2ecf20Sopenharmony_ci		pn_sockaddr_set_object((struct sockaddr_pn *)addr,
3258c2ecf20Sopenharmony_ci					pn->sobject);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return sizeof(struct sockaddr_pn);
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic __poll_t pn_socket_poll(struct file *file, struct socket *sock,
3318c2ecf20Sopenharmony_ci					poll_table *wait)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3348c2ecf20Sopenharmony_ci	struct pep_sock *pn = pep_sk(sk);
3358c2ecf20Sopenharmony_ci	__poll_t mask = 0;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	poll_wait(file, sk_sleep(sk), wait);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (sk->sk_state == TCP_CLOSE)
3408c2ecf20Sopenharmony_ci		return EPOLLERR;
3418c2ecf20Sopenharmony_ci	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
3428c2ecf20Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
3438c2ecf20Sopenharmony_ci	if (!skb_queue_empty_lockless(&pn->ctrlreq_queue))
3448c2ecf20Sopenharmony_ci		mask |= EPOLLPRI;
3458c2ecf20Sopenharmony_ci	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
3468c2ecf20Sopenharmony_ci		return EPOLLHUP;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (sk->sk_state == TCP_ESTABLISHED &&
3498c2ecf20Sopenharmony_ci		refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
3508c2ecf20Sopenharmony_ci		atomic_read(&pn->tx_credits))
3518c2ecf20Sopenharmony_ci		mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return mask;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
3578c2ecf20Sopenharmony_ci				unsigned long arg)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3608c2ecf20Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (cmd == SIOCPNGETOBJECT) {
3638c2ecf20Sopenharmony_ci		struct net_device *dev;
3648c2ecf20Sopenharmony_ci		u16 handle;
3658c2ecf20Sopenharmony_ci		u8 saddr;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		if (get_user(handle, (__u16 __user *)arg))
3688c2ecf20Sopenharmony_ci			return -EFAULT;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		lock_sock(sk);
3718c2ecf20Sopenharmony_ci		if (sk->sk_bound_dev_if)
3728c2ecf20Sopenharmony_ci			dev = dev_get_by_index(sock_net(sk),
3738c2ecf20Sopenharmony_ci						sk->sk_bound_dev_if);
3748c2ecf20Sopenharmony_ci		else
3758c2ecf20Sopenharmony_ci			dev = phonet_device_get(sock_net(sk));
3768c2ecf20Sopenharmony_ci		if (dev && (dev->flags & IFF_UP))
3778c2ecf20Sopenharmony_ci			saddr = phonet_address_get(dev, pn_addr(handle));
3788c2ecf20Sopenharmony_ci		else
3798c2ecf20Sopenharmony_ci			saddr = PN_NO_ADDR;
3808c2ecf20Sopenharmony_ci		release_sock(sk);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		if (dev)
3838c2ecf20Sopenharmony_ci			dev_put(dev);
3848c2ecf20Sopenharmony_ci		if (saddr == PN_NO_ADDR)
3858c2ecf20Sopenharmony_ci			return -EHOSTUNREACH;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		handle = pn_object(saddr, pn_port(pn->sobject));
3888c2ecf20Sopenharmony_ci		return put_user(handle, (__u16 __user *)arg);
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return sk->sk_prot->ioctl(sk, cmd, arg);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int pn_socket_listen(struct socket *sock, int backlog)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3978c2ecf20Sopenharmony_ci	int err = 0;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (pn_socket_autobind(sock))
4008c2ecf20Sopenharmony_ci		return -ENOBUFS;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	lock_sock(sk);
4038c2ecf20Sopenharmony_ci	if (sock->state != SS_UNCONNECTED) {
4048c2ecf20Sopenharmony_ci		err = -EINVAL;
4058c2ecf20Sopenharmony_ci		goto out;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (sk->sk_state != TCP_LISTEN) {
4098c2ecf20Sopenharmony_ci		sk->sk_state = TCP_LISTEN;
4108c2ecf20Sopenharmony_ci		sk->sk_ack_backlog = 0;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci	sk->sk_max_ack_backlog = backlog;
4138c2ecf20Sopenharmony_ciout:
4148c2ecf20Sopenharmony_ci	release_sock(sk);
4158c2ecf20Sopenharmony_ci	return err;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic int pn_socket_sendmsg(struct socket *sock, struct msghdr *m,
4198c2ecf20Sopenharmony_ci			     size_t total_len)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (pn_socket_autobind(sock))
4248c2ecf20Sopenharmony_ci		return -EAGAIN;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	return sk->sk_prot->sendmsg(sk, m, total_len);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ciconst struct proto_ops phonet_dgram_ops = {
4308c2ecf20Sopenharmony_ci	.family		= AF_PHONET,
4318c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
4328c2ecf20Sopenharmony_ci	.release	= pn_socket_release,
4338c2ecf20Sopenharmony_ci	.bind		= pn_socket_bind,
4348c2ecf20Sopenharmony_ci	.connect	= sock_no_connect,
4358c2ecf20Sopenharmony_ci	.socketpair	= sock_no_socketpair,
4368c2ecf20Sopenharmony_ci	.accept		= sock_no_accept,
4378c2ecf20Sopenharmony_ci	.getname	= pn_socket_getname,
4388c2ecf20Sopenharmony_ci	.poll		= datagram_poll,
4398c2ecf20Sopenharmony_ci	.ioctl		= pn_socket_ioctl,
4408c2ecf20Sopenharmony_ci	.listen		= sock_no_listen,
4418c2ecf20Sopenharmony_ci	.shutdown	= sock_no_shutdown,
4428c2ecf20Sopenharmony_ci	.sendmsg	= pn_socket_sendmsg,
4438c2ecf20Sopenharmony_ci	.recvmsg	= sock_common_recvmsg,
4448c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
4458c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage,
4468c2ecf20Sopenharmony_ci};
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ciconst struct proto_ops phonet_stream_ops = {
4498c2ecf20Sopenharmony_ci	.family		= AF_PHONET,
4508c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
4518c2ecf20Sopenharmony_ci	.release	= pn_socket_release,
4528c2ecf20Sopenharmony_ci	.bind		= pn_socket_bind,
4538c2ecf20Sopenharmony_ci	.connect	= pn_socket_connect,
4548c2ecf20Sopenharmony_ci	.socketpair	= sock_no_socketpair,
4558c2ecf20Sopenharmony_ci	.accept		= pn_socket_accept,
4568c2ecf20Sopenharmony_ci	.getname	= pn_socket_getname,
4578c2ecf20Sopenharmony_ci	.poll		= pn_socket_poll,
4588c2ecf20Sopenharmony_ci	.ioctl		= pn_socket_ioctl,
4598c2ecf20Sopenharmony_ci	.listen		= pn_socket_listen,
4608c2ecf20Sopenharmony_ci	.shutdown	= sock_no_shutdown,
4618c2ecf20Sopenharmony_ci	.setsockopt	= sock_common_setsockopt,
4628c2ecf20Sopenharmony_ci	.getsockopt	= sock_common_getsockopt,
4638c2ecf20Sopenharmony_ci	.sendmsg	= pn_socket_sendmsg,
4648c2ecf20Sopenharmony_ci	.recvmsg	= sock_common_recvmsg,
4658c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
4668c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage,
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(phonet_stream_ops);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci/* allocate port for a socket */
4718c2ecf20Sopenharmony_ciint pn_sock_get_port(struct sock *sk, unsigned short sport)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	static int port_cur;
4748c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
4758c2ecf20Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
4768c2ecf20Sopenharmony_ci	struct sockaddr_pn try_sa;
4778c2ecf20Sopenharmony_ci	struct sock *tmpsk;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	memset(&try_sa, 0, sizeof(struct sockaddr_pn));
4808c2ecf20Sopenharmony_ci	try_sa.spn_family = AF_PHONET;
4818c2ecf20Sopenharmony_ci	WARN_ON(!mutex_is_locked(&port_mutex));
4828c2ecf20Sopenharmony_ci	if (!sport) {
4838c2ecf20Sopenharmony_ci		/* search free port */
4848c2ecf20Sopenharmony_ci		int port, pmin, pmax;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		phonet_get_local_port_range(&pmin, &pmax);
4878c2ecf20Sopenharmony_ci		for (port = pmin; port <= pmax; port++) {
4888c2ecf20Sopenharmony_ci			port_cur++;
4898c2ecf20Sopenharmony_ci			if (port_cur < pmin || port_cur > pmax)
4908c2ecf20Sopenharmony_ci				port_cur = pmin;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci			pn_sockaddr_set_port(&try_sa, port_cur);
4938c2ecf20Sopenharmony_ci			tmpsk = pn_find_sock_by_sa(net, &try_sa);
4948c2ecf20Sopenharmony_ci			if (tmpsk == NULL) {
4958c2ecf20Sopenharmony_ci				sport = port_cur;
4968c2ecf20Sopenharmony_ci				goto found;
4978c2ecf20Sopenharmony_ci			} else
4988c2ecf20Sopenharmony_ci				sock_put(tmpsk);
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci	} else {
5018c2ecf20Sopenharmony_ci		/* try to find specific port */
5028c2ecf20Sopenharmony_ci		pn_sockaddr_set_port(&try_sa, sport);
5038c2ecf20Sopenharmony_ci		tmpsk = pn_find_sock_by_sa(net, &try_sa);
5048c2ecf20Sopenharmony_ci		if (tmpsk == NULL)
5058c2ecf20Sopenharmony_ci			/* No sock there! We can use that port... */
5068c2ecf20Sopenharmony_ci			goto found;
5078c2ecf20Sopenharmony_ci		else
5088c2ecf20Sopenharmony_ci			sock_put(tmpsk);
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci	/* the port must be in use already */
5118c2ecf20Sopenharmony_ci	return -EADDRINUSE;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cifound:
5148c2ecf20Sopenharmony_ci	pn->sobject = pn_object(pn_addr(pn->sobject), sport);
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pn_sock_get_port);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
5208c2ecf20Sopenharmony_cistatic struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct net *net = seq_file_net(seq);
5238c2ecf20Sopenharmony_ci	struct hlist_head *hlist = pnsocks.hlist;
5248c2ecf20Sopenharmony_ci	struct sock *sknode;
5258c2ecf20Sopenharmony_ci	unsigned int h;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	for (h = 0; h < PN_HASHSIZE; h++) {
5288c2ecf20Sopenharmony_ci		sk_for_each_rcu(sknode, hlist) {
5298c2ecf20Sopenharmony_ci			if (!net_eq(net, sock_net(sknode)))
5308c2ecf20Sopenharmony_ci				continue;
5318c2ecf20Sopenharmony_ci			if (!pos)
5328c2ecf20Sopenharmony_ci				return sknode;
5338c2ecf20Sopenharmony_ci			pos--;
5348c2ecf20Sopenharmony_ci		}
5358c2ecf20Sopenharmony_ci		hlist++;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci	return NULL;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct net *net = seq_file_net(seq);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	do
5458c2ecf20Sopenharmony_ci		sk = sk_next(sk);
5468c2ecf20Sopenharmony_ci	while (sk && !net_eq(net, sock_net(sk)));
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	return sk;
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
5528c2ecf20Sopenharmony_ci	__acquires(rcu)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	rcu_read_lock();
5558c2ecf20Sopenharmony_ci	return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	struct sock *sk;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (v == SEQ_START_TOKEN)
5638c2ecf20Sopenharmony_ci		sk = pn_sock_get_idx(seq, 0);
5648c2ecf20Sopenharmony_ci	else
5658c2ecf20Sopenharmony_ci		sk = pn_sock_get_next(seq, v);
5668c2ecf20Sopenharmony_ci	(*pos)++;
5678c2ecf20Sopenharmony_ci	return sk;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic void pn_sock_seq_stop(struct seq_file *seq, void *v)
5718c2ecf20Sopenharmony_ci	__releases(rcu)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	rcu_read_unlock();
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic int pn_sock_seq_show(struct seq_file *seq, void *v)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	seq_setwidth(seq, 127);
5798c2ecf20Sopenharmony_ci	if (v == SEQ_START_TOKEN)
5808c2ecf20Sopenharmony_ci		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
5818c2ecf20Sopenharmony_ci			"  uid inode ref pointer drops");
5828c2ecf20Sopenharmony_ci	else {
5838c2ecf20Sopenharmony_ci		struct sock *sk = v;
5848c2ecf20Sopenharmony_ci		struct pn_sock *pn = pn_sk(sk);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
5878c2ecf20Sopenharmony_ci			"%d %pK %u",
5888c2ecf20Sopenharmony_ci			sk->sk_protocol, pn->sobject, pn->dobject,
5898c2ecf20Sopenharmony_ci			pn->resource, sk->sk_state,
5908c2ecf20Sopenharmony_ci			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
5918c2ecf20Sopenharmony_ci			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
5928c2ecf20Sopenharmony_ci			sock_i_ino(sk),
5938c2ecf20Sopenharmony_ci			refcount_read(&sk->sk_refcnt), sk,
5948c2ecf20Sopenharmony_ci			atomic_read(&sk->sk_drops));
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci	seq_pad(seq, '\n');
5978c2ecf20Sopenharmony_ci	return 0;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ciconst struct seq_operations pn_sock_seq_ops = {
6018c2ecf20Sopenharmony_ci	.start = pn_sock_seq_start,
6028c2ecf20Sopenharmony_ci	.next = pn_sock_seq_next,
6038c2ecf20Sopenharmony_ci	.stop = pn_sock_seq_stop,
6048c2ecf20Sopenharmony_ci	.show = pn_sock_seq_show,
6058c2ecf20Sopenharmony_ci};
6068c2ecf20Sopenharmony_ci#endif
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic struct  {
6098c2ecf20Sopenharmony_ci	struct sock *sk[256];
6108c2ecf20Sopenharmony_ci} pnres;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci/*
6138c2ecf20Sopenharmony_ci * Find and hold socket based on resource.
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_cistruct sock *pn_find_sock_by_res(struct net *net, u8 res)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct sock *sk;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (!net_eq(net, &init_net))
6208c2ecf20Sopenharmony_ci		return NULL;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	rcu_read_lock();
6238c2ecf20Sopenharmony_ci	sk = rcu_dereference(pnres.sk[res]);
6248c2ecf20Sopenharmony_ci	if (sk)
6258c2ecf20Sopenharmony_ci		sock_hold(sk);
6268c2ecf20Sopenharmony_ci	rcu_read_unlock();
6278c2ecf20Sopenharmony_ci	return sk;
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(resource_mutex);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ciint pn_sock_bind_res(struct sock *sk, u8 res)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	int ret = -EADDRINUSE;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (!net_eq(sock_net(sk), &init_net))
6378c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
6388c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
6398c2ecf20Sopenharmony_ci		return -EPERM;
6408c2ecf20Sopenharmony_ci	if (pn_socket_autobind(sk->sk_socket))
6418c2ecf20Sopenharmony_ci		return -EAGAIN;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	mutex_lock(&resource_mutex);
6448c2ecf20Sopenharmony_ci	if (pnres.sk[res] == NULL) {
6458c2ecf20Sopenharmony_ci		sock_hold(sk);
6468c2ecf20Sopenharmony_ci		rcu_assign_pointer(pnres.sk[res], sk);
6478c2ecf20Sopenharmony_ci		ret = 0;
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci	mutex_unlock(&resource_mutex);
6508c2ecf20Sopenharmony_ci	return ret;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciint pn_sock_unbind_res(struct sock *sk, u8 res)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	int ret = -ENOENT;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
6588c2ecf20Sopenharmony_ci		return -EPERM;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	mutex_lock(&resource_mutex);
6618c2ecf20Sopenharmony_ci	if (pnres.sk[res] == sk) {
6628c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(pnres.sk[res], NULL);
6638c2ecf20Sopenharmony_ci		ret = 0;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci	mutex_unlock(&resource_mutex);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (ret == 0) {
6688c2ecf20Sopenharmony_ci		synchronize_rcu();
6698c2ecf20Sopenharmony_ci		sock_put(sk);
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci	return ret;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_civoid pn_sock_unbind_all_res(struct sock *sk)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	unsigned int res, match = 0;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	mutex_lock(&resource_mutex);
6798c2ecf20Sopenharmony_ci	for (res = 0; res < 256; res++) {
6808c2ecf20Sopenharmony_ci		if (pnres.sk[res] == sk) {
6818c2ecf20Sopenharmony_ci			RCU_INIT_POINTER(pnres.sk[res], NULL);
6828c2ecf20Sopenharmony_ci			match++;
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci	mutex_unlock(&resource_mutex);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	while (match > 0) {
6888c2ecf20Sopenharmony_ci		__sock_put(sk);
6898c2ecf20Sopenharmony_ci		match--;
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci	/* Caller is responsible for RCU sync before final sock_put() */
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
6958c2ecf20Sopenharmony_cistatic struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
6968c2ecf20Sopenharmony_ci{
6978c2ecf20Sopenharmony_ci	struct net *net = seq_file_net(seq);
6988c2ecf20Sopenharmony_ci	unsigned int i;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (!net_eq(net, &init_net))
7018c2ecf20Sopenharmony_ci		return NULL;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
7048c2ecf20Sopenharmony_ci		if (pnres.sk[i] == NULL)
7058c2ecf20Sopenharmony_ci			continue;
7068c2ecf20Sopenharmony_ci		if (!pos)
7078c2ecf20Sopenharmony_ci			return pnres.sk + i;
7088c2ecf20Sopenharmony_ci		pos--;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci	return NULL;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	struct net *net = seq_file_net(seq);
7168c2ecf20Sopenharmony_ci	unsigned int i;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	BUG_ON(!net_eq(net, &init_net));
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	for (i = (sk - pnres.sk) + 1; i < 256; i++)
7218c2ecf20Sopenharmony_ci		if (pnres.sk[i])
7228c2ecf20Sopenharmony_ci			return pnres.sk + i;
7238c2ecf20Sopenharmony_ci	return NULL;
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
7278c2ecf20Sopenharmony_ci	__acquires(resource_mutex)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	mutex_lock(&resource_mutex);
7308c2ecf20Sopenharmony_ci	return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	struct sock **sk;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	if (v == SEQ_START_TOKEN)
7388c2ecf20Sopenharmony_ci		sk = pn_res_get_idx(seq, 0);
7398c2ecf20Sopenharmony_ci	else
7408c2ecf20Sopenharmony_ci		sk = pn_res_get_next(seq, v);
7418c2ecf20Sopenharmony_ci	(*pos)++;
7428c2ecf20Sopenharmony_ci	return sk;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic void pn_res_seq_stop(struct seq_file *seq, void *v)
7468c2ecf20Sopenharmony_ci	__releases(resource_mutex)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	mutex_unlock(&resource_mutex);
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic int pn_res_seq_show(struct seq_file *seq, void *v)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	seq_setwidth(seq, 63);
7548c2ecf20Sopenharmony_ci	if (v == SEQ_START_TOKEN)
7558c2ecf20Sopenharmony_ci		seq_puts(seq, "rs   uid inode");
7568c2ecf20Sopenharmony_ci	else {
7578c2ecf20Sopenharmony_ci		struct sock **psk = v;
7588c2ecf20Sopenharmony_ci		struct sock *sk = *psk;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci		seq_printf(seq, "%02X %5u %lu",
7618c2ecf20Sopenharmony_ci			   (int) (psk - pnres.sk),
7628c2ecf20Sopenharmony_ci			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
7638c2ecf20Sopenharmony_ci			   sock_i_ino(sk));
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci	seq_pad(seq, '\n');
7668c2ecf20Sopenharmony_ci	return 0;
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ciconst struct seq_operations pn_res_seq_ops = {
7708c2ecf20Sopenharmony_ci	.start = pn_res_seq_start,
7718c2ecf20Sopenharmony_ci	.next = pn_res_seq_next,
7728c2ecf20Sopenharmony_ci	.stop = pn_res_seq_stop,
7738c2ecf20Sopenharmony_ci	.show = pn_res_seq_show,
7748c2ecf20Sopenharmony_ci};
7758c2ecf20Sopenharmony_ci#endif
776