162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * File: socket.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Phonet sockets
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Authors: Sakari Ailus <sakari.ailus@nokia.com>
1062306a36Sopenharmony_ci *          Rémi Denis-Courmont
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/gfp.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/net.h>
1662306a36Sopenharmony_ci#include <linux/poll.h>
1762306a36Sopenharmony_ci#include <linux/sched/signal.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <net/sock.h>
2062306a36Sopenharmony_ci#include <net/tcp_states.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/phonet.h>
2362306a36Sopenharmony_ci#include <linux/export.h>
2462306a36Sopenharmony_ci#include <net/phonet/phonet.h>
2562306a36Sopenharmony_ci#include <net/phonet/pep.h>
2662306a36Sopenharmony_ci#include <net/phonet/pn_dev.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int pn_socket_release(struct socket *sock)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if (sk) {
3362306a36Sopenharmony_ci		sock->sk = NULL;
3462306a36Sopenharmony_ci		sk->sk_prot->close(sk, 0);
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci	return 0;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define PN_HASHSIZE	16
4062306a36Sopenharmony_ci#define PN_HASHMASK	(PN_HASHSIZE-1)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic struct  {
4462306a36Sopenharmony_ci	struct hlist_head hlist[PN_HASHSIZE];
4562306a36Sopenharmony_ci	struct mutex lock;
4662306a36Sopenharmony_ci} pnsocks;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_civoid __init pn_sock_init(void)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	unsigned int i;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	for (i = 0; i < PN_HASHSIZE; i++)
5362306a36Sopenharmony_ci		INIT_HLIST_HEAD(pnsocks.hlist + i);
5462306a36Sopenharmony_ci	mutex_init(&pnsocks.lock);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic struct hlist_head *pn_hash_list(u16 obj)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return pnsocks.hlist + (obj & PN_HASHMASK);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * Find address based on socket address, match only certain fields.
6462306a36Sopenharmony_ci * Also grab sock if it was found. Remember to sock_put it later.
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_cistruct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct sock *sknode;
6962306a36Sopenharmony_ci	struct sock *rval = NULL;
7062306a36Sopenharmony_ci	u16 obj = pn_sockaddr_get_object(spn);
7162306a36Sopenharmony_ci	u8 res = spn->spn_resource;
7262306a36Sopenharmony_ci	struct hlist_head *hlist = pn_hash_list(obj);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	rcu_read_lock();
7562306a36Sopenharmony_ci	sk_for_each_rcu(sknode, hlist) {
7662306a36Sopenharmony_ci		struct pn_sock *pn = pn_sk(sknode);
7762306a36Sopenharmony_ci		BUG_ON(!pn->sobject); /* unbound socket */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		if (!net_eq(sock_net(sknode), net))
8062306a36Sopenharmony_ci			continue;
8162306a36Sopenharmony_ci		if (pn_port(obj)) {
8262306a36Sopenharmony_ci			/* Look up socket by port */
8362306a36Sopenharmony_ci			if (pn_port(pn->sobject) != pn_port(obj))
8462306a36Sopenharmony_ci				continue;
8562306a36Sopenharmony_ci		} else {
8662306a36Sopenharmony_ci			/* If port is zero, look up by resource */
8762306a36Sopenharmony_ci			if (pn->resource != res)
8862306a36Sopenharmony_ci				continue;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci		if (pn_addr(pn->sobject) &&
9162306a36Sopenharmony_ci		    pn_addr(pn->sobject) != pn_addr(obj))
9262306a36Sopenharmony_ci			continue;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		rval = sknode;
9562306a36Sopenharmony_ci		sock_hold(sknode);
9662306a36Sopenharmony_ci		break;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci	rcu_read_unlock();
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return rval;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Deliver a broadcast packet (only in bottom-half) */
10462306a36Sopenharmony_civoid pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct hlist_head *hlist = pnsocks.hlist;
10762306a36Sopenharmony_ci	unsigned int h;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	rcu_read_lock();
11062306a36Sopenharmony_ci	for (h = 0; h < PN_HASHSIZE; h++) {
11162306a36Sopenharmony_ci		struct sock *sknode;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		sk_for_each(sknode, hlist) {
11462306a36Sopenharmony_ci			struct sk_buff *clone;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci			if (!net_eq(sock_net(sknode), net))
11762306a36Sopenharmony_ci				continue;
11862306a36Sopenharmony_ci			if (!sock_flag(sknode, SOCK_BROADCAST))
11962306a36Sopenharmony_ci				continue;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci			clone = skb_clone(skb, GFP_ATOMIC);
12262306a36Sopenharmony_ci			if (clone) {
12362306a36Sopenharmony_ci				sock_hold(sknode);
12462306a36Sopenharmony_ci				sk_receive_skb(sknode, clone, 0);
12562306a36Sopenharmony_ci			}
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci		hlist++;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	rcu_read_unlock();
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciint pn_sock_hash(struct sock *sk)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	mutex_lock(&pnsocks.lock);
13762306a36Sopenharmony_ci	sk_add_node_rcu(sk, hlist);
13862306a36Sopenharmony_ci	mutex_unlock(&pnsocks.lock);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return 0;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ciEXPORT_SYMBOL(pn_sock_hash);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_civoid pn_sock_unhash(struct sock *sk)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	mutex_lock(&pnsocks.lock);
14762306a36Sopenharmony_ci	sk_del_node_init_rcu(sk);
14862306a36Sopenharmony_ci	mutex_unlock(&pnsocks.lock);
14962306a36Sopenharmony_ci	pn_sock_unbind_all_res(sk);
15062306a36Sopenharmony_ci	synchronize_rcu();
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ciEXPORT_SYMBOL(pn_sock_unhash);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic DEFINE_MUTEX(port_mutex);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct sock *sk = sock->sk;
15962306a36Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
16062306a36Sopenharmony_ci	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
16162306a36Sopenharmony_ci	int err;
16262306a36Sopenharmony_ci	u16 handle;
16362306a36Sopenharmony_ci	u8 saddr;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (sk->sk_prot->bind)
16662306a36Sopenharmony_ci		return sk->sk_prot->bind(sk, addr, len);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (len < sizeof(struct sockaddr_pn))
16962306a36Sopenharmony_ci		return -EINVAL;
17062306a36Sopenharmony_ci	if (spn->spn_family != AF_PHONET)
17162306a36Sopenharmony_ci		return -EAFNOSUPPORT;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
17462306a36Sopenharmony_ci	saddr = pn_addr(handle);
17562306a36Sopenharmony_ci	if (saddr && phonet_address_lookup(sock_net(sk), saddr))
17662306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	lock_sock(sk);
17962306a36Sopenharmony_ci	if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
18062306a36Sopenharmony_ci		err = -EINVAL; /* attempt to rebind */
18162306a36Sopenharmony_ci		goto out;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci	WARN_ON(sk_hashed(sk));
18462306a36Sopenharmony_ci	mutex_lock(&port_mutex);
18562306a36Sopenharmony_ci	err = sk->sk_prot->get_port(sk, pn_port(handle));
18662306a36Sopenharmony_ci	if (err)
18762306a36Sopenharmony_ci		goto out_port;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* get_port() sets the port, bind() sets the address if applicable */
19062306a36Sopenharmony_ci	pn->sobject = pn_object(saddr, pn_port(pn->sobject));
19162306a36Sopenharmony_ci	pn->resource = spn->spn_resource;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* Enable RX on the socket */
19462306a36Sopenharmony_ci	err = sk->sk_prot->hash(sk);
19562306a36Sopenharmony_ciout_port:
19662306a36Sopenharmony_ci	mutex_unlock(&port_mutex);
19762306a36Sopenharmony_ciout:
19862306a36Sopenharmony_ci	release_sock(sk);
19962306a36Sopenharmony_ci	return err;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int pn_socket_autobind(struct socket *sock)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct sockaddr_pn sa;
20562306a36Sopenharmony_ci	int err;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	memset(&sa, 0, sizeof(sa));
20862306a36Sopenharmony_ci	sa.spn_family = AF_PHONET;
20962306a36Sopenharmony_ci	err = pn_socket_bind(sock, (struct sockaddr *)&sa,
21062306a36Sopenharmony_ci				sizeof(struct sockaddr_pn));
21162306a36Sopenharmony_ci	if (err != -EINVAL)
21262306a36Sopenharmony_ci		return err;
21362306a36Sopenharmony_ci	BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
21462306a36Sopenharmony_ci	return 0; /* socket was already bound */
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
21862306a36Sopenharmony_ci		int len, int flags)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
22162306a36Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
22262306a36Sopenharmony_ci	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
22362306a36Sopenharmony_ci	struct task_struct *tsk = current;
22462306a36Sopenharmony_ci	long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
22562306a36Sopenharmony_ci	int err;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (pn_socket_autobind(sock))
22862306a36Sopenharmony_ci		return -ENOBUFS;
22962306a36Sopenharmony_ci	if (len < sizeof(struct sockaddr_pn))
23062306a36Sopenharmony_ci		return -EINVAL;
23162306a36Sopenharmony_ci	if (spn->spn_family != AF_PHONET)
23262306a36Sopenharmony_ci		return -EAFNOSUPPORT;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	lock_sock(sk);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	switch (sock->state) {
23762306a36Sopenharmony_ci	case SS_UNCONNECTED:
23862306a36Sopenharmony_ci		if (sk->sk_state != TCP_CLOSE) {
23962306a36Sopenharmony_ci			err = -EISCONN;
24062306a36Sopenharmony_ci			goto out;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci	case SS_CONNECTING:
24462306a36Sopenharmony_ci		err = -EALREADY;
24562306a36Sopenharmony_ci		goto out;
24662306a36Sopenharmony_ci	default:
24762306a36Sopenharmony_ci		err = -EISCONN;
24862306a36Sopenharmony_ci		goto out;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	pn->dobject = pn_sockaddr_get_object(spn);
25262306a36Sopenharmony_ci	pn->resource = pn_sockaddr_get_resource(spn);
25362306a36Sopenharmony_ci	sock->state = SS_CONNECTING;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	err = sk->sk_prot->connect(sk, addr, len);
25662306a36Sopenharmony_ci	if (err) {
25762306a36Sopenharmony_ci		sock->state = SS_UNCONNECTED;
25862306a36Sopenharmony_ci		pn->dobject = 0;
25962306a36Sopenharmony_ci		goto out;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	while (sk->sk_state == TCP_SYN_SENT) {
26362306a36Sopenharmony_ci		DEFINE_WAIT(wait);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		if (!timeo) {
26662306a36Sopenharmony_ci			err = -EINPROGRESS;
26762306a36Sopenharmony_ci			goto out;
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci		if (signal_pending(tsk)) {
27062306a36Sopenharmony_ci			err = sock_intr_errno(timeo);
27162306a36Sopenharmony_ci			goto out;
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
27562306a36Sopenharmony_ci						TASK_INTERRUPTIBLE);
27662306a36Sopenharmony_ci		release_sock(sk);
27762306a36Sopenharmony_ci		timeo = schedule_timeout(timeo);
27862306a36Sopenharmony_ci		lock_sock(sk);
27962306a36Sopenharmony_ci		finish_wait(sk_sleep(sk), &wait);
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
28362306a36Sopenharmony_ci		err = 0;
28462306a36Sopenharmony_ci	else if (sk->sk_state == TCP_CLOSE_WAIT)
28562306a36Sopenharmony_ci		err = -ECONNRESET;
28662306a36Sopenharmony_ci	else
28762306a36Sopenharmony_ci		err = -ECONNREFUSED;
28862306a36Sopenharmony_ci	sock->state = err ? SS_UNCONNECTED : SS_CONNECTED;
28962306a36Sopenharmony_ciout:
29062306a36Sopenharmony_ci	release_sock(sk);
29162306a36Sopenharmony_ci	return err;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int pn_socket_accept(struct socket *sock, struct socket *newsock,
29562306a36Sopenharmony_ci			    int flags, bool kern)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct sock *sk = sock->sk;
29862306a36Sopenharmony_ci	struct sock *newsk;
29962306a36Sopenharmony_ci	int err;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (unlikely(sk->sk_state != TCP_LISTEN))
30262306a36Sopenharmony_ci		return -EINVAL;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	newsk = sk->sk_prot->accept(sk, flags, &err, kern);
30562306a36Sopenharmony_ci	if (!newsk)
30662306a36Sopenharmony_ci		return err;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	lock_sock(newsk);
30962306a36Sopenharmony_ci	sock_graft(newsk, newsock);
31062306a36Sopenharmony_ci	newsock->state = SS_CONNECTED;
31162306a36Sopenharmony_ci	release_sock(newsk);
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
31662306a36Sopenharmony_ci				int peer)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct sock *sk = sock->sk;
31962306a36Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	memset(addr, 0, sizeof(struct sockaddr_pn));
32262306a36Sopenharmony_ci	addr->sa_family = AF_PHONET;
32362306a36Sopenharmony_ci	if (!peer) /* Race with bind() here is userland's problem. */
32462306a36Sopenharmony_ci		pn_sockaddr_set_object((struct sockaddr_pn *)addr,
32562306a36Sopenharmony_ci					pn->sobject);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return sizeof(struct sockaddr_pn);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic __poll_t pn_socket_poll(struct file *file, struct socket *sock,
33162306a36Sopenharmony_ci					poll_table *wait)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct sock *sk = sock->sk;
33462306a36Sopenharmony_ci	struct pep_sock *pn = pep_sk(sk);
33562306a36Sopenharmony_ci	__poll_t mask = 0;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	poll_wait(file, sk_sleep(sk), wait);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (sk->sk_state == TCP_CLOSE)
34062306a36Sopenharmony_ci		return EPOLLERR;
34162306a36Sopenharmony_ci	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
34262306a36Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
34362306a36Sopenharmony_ci	if (!skb_queue_empty_lockless(&pn->ctrlreq_queue))
34462306a36Sopenharmony_ci		mask |= EPOLLPRI;
34562306a36Sopenharmony_ci	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
34662306a36Sopenharmony_ci		return EPOLLHUP;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (sk->sk_state == TCP_ESTABLISHED &&
34962306a36Sopenharmony_ci		refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
35062306a36Sopenharmony_ci		atomic_read(&pn->tx_credits))
35162306a36Sopenharmony_ci		mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return mask;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
35762306a36Sopenharmony_ci				unsigned long arg)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct sock *sk = sock->sk;
36062306a36Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (cmd == SIOCPNGETOBJECT) {
36362306a36Sopenharmony_ci		struct net_device *dev;
36462306a36Sopenharmony_ci		u16 handle;
36562306a36Sopenharmony_ci		u8 saddr;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		if (get_user(handle, (__u16 __user *)arg))
36862306a36Sopenharmony_ci			return -EFAULT;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		lock_sock(sk);
37162306a36Sopenharmony_ci		if (sk->sk_bound_dev_if)
37262306a36Sopenharmony_ci			dev = dev_get_by_index(sock_net(sk),
37362306a36Sopenharmony_ci						sk->sk_bound_dev_if);
37462306a36Sopenharmony_ci		else
37562306a36Sopenharmony_ci			dev = phonet_device_get(sock_net(sk));
37662306a36Sopenharmony_ci		if (dev && (dev->flags & IFF_UP))
37762306a36Sopenharmony_ci			saddr = phonet_address_get(dev, pn_addr(handle));
37862306a36Sopenharmony_ci		else
37962306a36Sopenharmony_ci			saddr = PN_NO_ADDR;
38062306a36Sopenharmony_ci		release_sock(sk);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		dev_put(dev);
38362306a36Sopenharmony_ci		if (saddr == PN_NO_ADDR)
38462306a36Sopenharmony_ci			return -EHOSTUNREACH;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		handle = pn_object(saddr, pn_port(pn->sobject));
38762306a36Sopenharmony_ci		return put_user(handle, (__u16 __user *)arg);
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return sk_ioctl(sk, cmd, (void __user *)arg);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int pn_socket_listen(struct socket *sock, int backlog)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct sock *sk = sock->sk;
39662306a36Sopenharmony_ci	int err = 0;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (pn_socket_autobind(sock))
39962306a36Sopenharmony_ci		return -ENOBUFS;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	lock_sock(sk);
40262306a36Sopenharmony_ci	if (sock->state != SS_UNCONNECTED) {
40362306a36Sopenharmony_ci		err = -EINVAL;
40462306a36Sopenharmony_ci		goto out;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (sk->sk_state != TCP_LISTEN) {
40862306a36Sopenharmony_ci		sk->sk_state = TCP_LISTEN;
40962306a36Sopenharmony_ci		sk->sk_ack_backlog = 0;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	sk->sk_max_ack_backlog = backlog;
41262306a36Sopenharmony_ciout:
41362306a36Sopenharmony_ci	release_sock(sk);
41462306a36Sopenharmony_ci	return err;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic int pn_socket_sendmsg(struct socket *sock, struct msghdr *m,
41862306a36Sopenharmony_ci			     size_t total_len)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (pn_socket_autobind(sock))
42362306a36Sopenharmony_ci		return -EAGAIN;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	return sk->sk_prot->sendmsg(sk, m, total_len);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ciconst struct proto_ops phonet_dgram_ops = {
42962306a36Sopenharmony_ci	.family		= AF_PHONET,
43062306a36Sopenharmony_ci	.owner		= THIS_MODULE,
43162306a36Sopenharmony_ci	.release	= pn_socket_release,
43262306a36Sopenharmony_ci	.bind		= pn_socket_bind,
43362306a36Sopenharmony_ci	.connect	= sock_no_connect,
43462306a36Sopenharmony_ci	.socketpair	= sock_no_socketpair,
43562306a36Sopenharmony_ci	.accept		= sock_no_accept,
43662306a36Sopenharmony_ci	.getname	= pn_socket_getname,
43762306a36Sopenharmony_ci	.poll		= datagram_poll,
43862306a36Sopenharmony_ci	.ioctl		= pn_socket_ioctl,
43962306a36Sopenharmony_ci	.listen		= sock_no_listen,
44062306a36Sopenharmony_ci	.shutdown	= sock_no_shutdown,
44162306a36Sopenharmony_ci	.sendmsg	= pn_socket_sendmsg,
44262306a36Sopenharmony_ci	.recvmsg	= sock_common_recvmsg,
44362306a36Sopenharmony_ci	.mmap		= sock_no_mmap,
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ciconst struct proto_ops phonet_stream_ops = {
44762306a36Sopenharmony_ci	.family		= AF_PHONET,
44862306a36Sopenharmony_ci	.owner		= THIS_MODULE,
44962306a36Sopenharmony_ci	.release	= pn_socket_release,
45062306a36Sopenharmony_ci	.bind		= pn_socket_bind,
45162306a36Sopenharmony_ci	.connect	= pn_socket_connect,
45262306a36Sopenharmony_ci	.socketpair	= sock_no_socketpair,
45362306a36Sopenharmony_ci	.accept		= pn_socket_accept,
45462306a36Sopenharmony_ci	.getname	= pn_socket_getname,
45562306a36Sopenharmony_ci	.poll		= pn_socket_poll,
45662306a36Sopenharmony_ci	.ioctl		= pn_socket_ioctl,
45762306a36Sopenharmony_ci	.listen		= pn_socket_listen,
45862306a36Sopenharmony_ci	.shutdown	= sock_no_shutdown,
45962306a36Sopenharmony_ci	.setsockopt	= sock_common_setsockopt,
46062306a36Sopenharmony_ci	.getsockopt	= sock_common_getsockopt,
46162306a36Sopenharmony_ci	.sendmsg	= pn_socket_sendmsg,
46262306a36Sopenharmony_ci	.recvmsg	= sock_common_recvmsg,
46362306a36Sopenharmony_ci	.mmap		= sock_no_mmap,
46462306a36Sopenharmony_ci};
46562306a36Sopenharmony_ciEXPORT_SYMBOL(phonet_stream_ops);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/* allocate port for a socket */
46862306a36Sopenharmony_ciint pn_sock_get_port(struct sock *sk, unsigned short sport)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	static int port_cur;
47162306a36Sopenharmony_ci	struct net *net = sock_net(sk);
47262306a36Sopenharmony_ci	struct pn_sock *pn = pn_sk(sk);
47362306a36Sopenharmony_ci	struct sockaddr_pn try_sa;
47462306a36Sopenharmony_ci	struct sock *tmpsk;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	memset(&try_sa, 0, sizeof(struct sockaddr_pn));
47762306a36Sopenharmony_ci	try_sa.spn_family = AF_PHONET;
47862306a36Sopenharmony_ci	WARN_ON(!mutex_is_locked(&port_mutex));
47962306a36Sopenharmony_ci	if (!sport) {
48062306a36Sopenharmony_ci		/* search free port */
48162306a36Sopenharmony_ci		int port, pmin, pmax;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		phonet_get_local_port_range(&pmin, &pmax);
48462306a36Sopenharmony_ci		for (port = pmin; port <= pmax; port++) {
48562306a36Sopenharmony_ci			port_cur++;
48662306a36Sopenharmony_ci			if (port_cur < pmin || port_cur > pmax)
48762306a36Sopenharmony_ci				port_cur = pmin;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci			pn_sockaddr_set_port(&try_sa, port_cur);
49062306a36Sopenharmony_ci			tmpsk = pn_find_sock_by_sa(net, &try_sa);
49162306a36Sopenharmony_ci			if (tmpsk == NULL) {
49262306a36Sopenharmony_ci				sport = port_cur;
49362306a36Sopenharmony_ci				goto found;
49462306a36Sopenharmony_ci			} else
49562306a36Sopenharmony_ci				sock_put(tmpsk);
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci	} else {
49862306a36Sopenharmony_ci		/* try to find specific port */
49962306a36Sopenharmony_ci		pn_sockaddr_set_port(&try_sa, sport);
50062306a36Sopenharmony_ci		tmpsk = pn_find_sock_by_sa(net, &try_sa);
50162306a36Sopenharmony_ci		if (tmpsk == NULL)
50262306a36Sopenharmony_ci			/* No sock there! We can use that port... */
50362306a36Sopenharmony_ci			goto found;
50462306a36Sopenharmony_ci		else
50562306a36Sopenharmony_ci			sock_put(tmpsk);
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci	/* the port must be in use already */
50862306a36Sopenharmony_ci	return -EADDRINUSE;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cifound:
51162306a36Sopenharmony_ci	pn->sobject = pn_object(pn_addr(pn->sobject), sport);
51262306a36Sopenharmony_ci	return 0;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ciEXPORT_SYMBOL(pn_sock_get_port);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
51762306a36Sopenharmony_cistatic struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct net *net = seq_file_net(seq);
52062306a36Sopenharmony_ci	struct hlist_head *hlist = pnsocks.hlist;
52162306a36Sopenharmony_ci	struct sock *sknode;
52262306a36Sopenharmony_ci	unsigned int h;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	for (h = 0; h < PN_HASHSIZE; h++) {
52562306a36Sopenharmony_ci		sk_for_each_rcu(sknode, hlist) {
52662306a36Sopenharmony_ci			if (!net_eq(net, sock_net(sknode)))
52762306a36Sopenharmony_ci				continue;
52862306a36Sopenharmony_ci			if (!pos)
52962306a36Sopenharmony_ci				return sknode;
53062306a36Sopenharmony_ci			pos--;
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci		hlist++;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci	return NULL;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct net *net = seq_file_net(seq);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	do
54262306a36Sopenharmony_ci		sk = sk_next(sk);
54362306a36Sopenharmony_ci	while (sk && !net_eq(net, sock_net(sk)));
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	return sk;
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
54962306a36Sopenharmony_ci	__acquires(rcu)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	rcu_read_lock();
55262306a36Sopenharmony_ci	return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct sock *sk;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN)
56062306a36Sopenharmony_ci		sk = pn_sock_get_idx(seq, 0);
56162306a36Sopenharmony_ci	else
56262306a36Sopenharmony_ci		sk = pn_sock_get_next(seq, v);
56362306a36Sopenharmony_ci	(*pos)++;
56462306a36Sopenharmony_ci	return sk;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic void pn_sock_seq_stop(struct seq_file *seq, void *v)
56862306a36Sopenharmony_ci	__releases(rcu)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	rcu_read_unlock();
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int pn_sock_seq_show(struct seq_file *seq, void *v)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	seq_setwidth(seq, 127);
57662306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN)
57762306a36Sopenharmony_ci		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
57862306a36Sopenharmony_ci			"  uid inode ref pointer drops");
57962306a36Sopenharmony_ci	else {
58062306a36Sopenharmony_ci		struct sock *sk = v;
58162306a36Sopenharmony_ci		struct pn_sock *pn = pn_sk(sk);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
58462306a36Sopenharmony_ci			"%d %pK %u",
58562306a36Sopenharmony_ci			sk->sk_protocol, pn->sobject, pn->dobject,
58662306a36Sopenharmony_ci			pn->resource, sk->sk_state,
58762306a36Sopenharmony_ci			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
58862306a36Sopenharmony_ci			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
58962306a36Sopenharmony_ci			sock_i_ino(sk),
59062306a36Sopenharmony_ci			refcount_read(&sk->sk_refcnt), sk,
59162306a36Sopenharmony_ci			atomic_read(&sk->sk_drops));
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	seq_pad(seq, '\n');
59462306a36Sopenharmony_ci	return 0;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ciconst struct seq_operations pn_sock_seq_ops = {
59862306a36Sopenharmony_ci	.start = pn_sock_seq_start,
59962306a36Sopenharmony_ci	.next = pn_sock_seq_next,
60062306a36Sopenharmony_ci	.stop = pn_sock_seq_stop,
60162306a36Sopenharmony_ci	.show = pn_sock_seq_show,
60262306a36Sopenharmony_ci};
60362306a36Sopenharmony_ci#endif
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic struct  {
60662306a36Sopenharmony_ci	struct sock *sk[256];
60762306a36Sopenharmony_ci} pnres;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/*
61062306a36Sopenharmony_ci * Find and hold socket based on resource.
61162306a36Sopenharmony_ci */
61262306a36Sopenharmony_cistruct sock *pn_find_sock_by_res(struct net *net, u8 res)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct sock *sk;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (!net_eq(net, &init_net))
61762306a36Sopenharmony_ci		return NULL;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	rcu_read_lock();
62062306a36Sopenharmony_ci	sk = rcu_dereference(pnres.sk[res]);
62162306a36Sopenharmony_ci	if (sk)
62262306a36Sopenharmony_ci		sock_hold(sk);
62362306a36Sopenharmony_ci	rcu_read_unlock();
62462306a36Sopenharmony_ci	return sk;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic DEFINE_MUTEX(resource_mutex);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ciint pn_sock_bind_res(struct sock *sk, u8 res)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	int ret = -EADDRINUSE;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	if (!net_eq(sock_net(sk), &init_net))
63462306a36Sopenharmony_ci		return -ENOIOCTLCMD;
63562306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
63662306a36Sopenharmony_ci		return -EPERM;
63762306a36Sopenharmony_ci	if (pn_socket_autobind(sk->sk_socket))
63862306a36Sopenharmony_ci		return -EAGAIN;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	mutex_lock(&resource_mutex);
64162306a36Sopenharmony_ci	if (pnres.sk[res] == NULL) {
64262306a36Sopenharmony_ci		sock_hold(sk);
64362306a36Sopenharmony_ci		rcu_assign_pointer(pnres.sk[res], sk);
64462306a36Sopenharmony_ci		ret = 0;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	mutex_unlock(&resource_mutex);
64762306a36Sopenharmony_ci	return ret;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ciint pn_sock_unbind_res(struct sock *sk, u8 res)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	int ret = -ENOENT;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
65562306a36Sopenharmony_ci		return -EPERM;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	mutex_lock(&resource_mutex);
65862306a36Sopenharmony_ci	if (pnres.sk[res] == sk) {
65962306a36Sopenharmony_ci		RCU_INIT_POINTER(pnres.sk[res], NULL);
66062306a36Sopenharmony_ci		ret = 0;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci	mutex_unlock(&resource_mutex);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (ret == 0) {
66562306a36Sopenharmony_ci		synchronize_rcu();
66662306a36Sopenharmony_ci		sock_put(sk);
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	return ret;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_civoid pn_sock_unbind_all_res(struct sock *sk)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	unsigned int res, match = 0;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	mutex_lock(&resource_mutex);
67662306a36Sopenharmony_ci	for (res = 0; res < 256; res++) {
67762306a36Sopenharmony_ci		if (pnres.sk[res] == sk) {
67862306a36Sopenharmony_ci			RCU_INIT_POINTER(pnres.sk[res], NULL);
67962306a36Sopenharmony_ci			match++;
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci	mutex_unlock(&resource_mutex);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	while (match > 0) {
68562306a36Sopenharmony_ci		__sock_put(sk);
68662306a36Sopenharmony_ci		match--;
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci	/* Caller is responsible for RCU sync before final sock_put() */
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
69262306a36Sopenharmony_cistatic struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct net *net = seq_file_net(seq);
69562306a36Sopenharmony_ci	unsigned int i;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (!net_eq(net, &init_net))
69862306a36Sopenharmony_ci		return NULL;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
70162306a36Sopenharmony_ci		if (pnres.sk[i] == NULL)
70262306a36Sopenharmony_ci			continue;
70362306a36Sopenharmony_ci		if (!pos)
70462306a36Sopenharmony_ci			return pnres.sk + i;
70562306a36Sopenharmony_ci		pos--;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci	return NULL;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct net *net = seq_file_net(seq);
71362306a36Sopenharmony_ci	unsigned int i;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	BUG_ON(!net_eq(net, &init_net));
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	for (i = (sk - pnres.sk) + 1; i < 256; i++)
71862306a36Sopenharmony_ci		if (pnres.sk[i])
71962306a36Sopenharmony_ci			return pnres.sk + i;
72062306a36Sopenharmony_ci	return NULL;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
72462306a36Sopenharmony_ci	__acquires(resource_mutex)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	mutex_lock(&resource_mutex);
72762306a36Sopenharmony_ci	return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct sock **sk;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN)
73562306a36Sopenharmony_ci		sk = pn_res_get_idx(seq, 0);
73662306a36Sopenharmony_ci	else
73762306a36Sopenharmony_ci		sk = pn_res_get_next(seq, v);
73862306a36Sopenharmony_ci	(*pos)++;
73962306a36Sopenharmony_ci	return sk;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic void pn_res_seq_stop(struct seq_file *seq, void *v)
74362306a36Sopenharmony_ci	__releases(resource_mutex)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	mutex_unlock(&resource_mutex);
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic int pn_res_seq_show(struct seq_file *seq, void *v)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	seq_setwidth(seq, 63);
75162306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN)
75262306a36Sopenharmony_ci		seq_puts(seq, "rs   uid inode");
75362306a36Sopenharmony_ci	else {
75462306a36Sopenharmony_ci		struct sock **psk = v;
75562306a36Sopenharmony_ci		struct sock *sk = *psk;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		seq_printf(seq, "%02X %5u %lu",
75862306a36Sopenharmony_ci			   (int) (psk - pnres.sk),
75962306a36Sopenharmony_ci			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
76062306a36Sopenharmony_ci			   sock_i_ino(sk));
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci	seq_pad(seq, '\n');
76362306a36Sopenharmony_ci	return 0;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ciconst struct seq_operations pn_res_seq_ops = {
76762306a36Sopenharmony_ci	.start = pn_res_seq_start,
76862306a36Sopenharmony_ci	.next = pn_res_seq_next,
76962306a36Sopenharmony_ci	.stop = pn_res_seq_stop,
77062306a36Sopenharmony_ci	.show = pn_res_seq_show,
77162306a36Sopenharmony_ci};
77262306a36Sopenharmony_ci#endif
773