xref: /OK3568_Linux_fs/kernel/net/phonet/socket.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * File: socket.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Phonet sockets
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 2008 Nokia Corporation.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Authors: Sakari Ailus <sakari.ailus@nokia.com>
10*4882a593Smuzhiyun  *          Rémi Denis-Courmont
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/gfp.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/net.h>
16*4882a593Smuzhiyun #include <linux/poll.h>
17*4882a593Smuzhiyun #include <linux/sched/signal.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <net/sock.h>
20*4882a593Smuzhiyun #include <net/tcp_states.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <linux/phonet.h>
23*4882a593Smuzhiyun #include <linux/export.h>
24*4882a593Smuzhiyun #include <net/phonet/phonet.h>
25*4882a593Smuzhiyun #include <net/phonet/pep.h>
26*4882a593Smuzhiyun #include <net/phonet/pn_dev.h>
27*4882a593Smuzhiyun 
pn_socket_release(struct socket * sock)28*4882a593Smuzhiyun static int pn_socket_release(struct socket *sock)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	if (sk) {
33*4882a593Smuzhiyun 		sock->sk = NULL;
34*4882a593Smuzhiyun 		sk->sk_prot->close(sk, 0);
35*4882a593Smuzhiyun 	}
36*4882a593Smuzhiyun 	return 0;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define PN_HASHSIZE	16
40*4882a593Smuzhiyun #define PN_HASHMASK	(PN_HASHSIZE-1)
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static struct  {
44*4882a593Smuzhiyun 	struct hlist_head hlist[PN_HASHSIZE];
45*4882a593Smuzhiyun 	struct mutex lock;
46*4882a593Smuzhiyun } pnsocks;
47*4882a593Smuzhiyun 
pn_sock_init(void)48*4882a593Smuzhiyun void __init pn_sock_init(void)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	unsigned int i;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	for (i = 0; i < PN_HASHSIZE; i++)
53*4882a593Smuzhiyun 		INIT_HLIST_HEAD(pnsocks.hlist + i);
54*4882a593Smuzhiyun 	mutex_init(&pnsocks.lock);
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
pn_hash_list(u16 obj)57*4882a593Smuzhiyun static struct hlist_head *pn_hash_list(u16 obj)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	return pnsocks.hlist + (obj & PN_HASHMASK);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun  * Find address based on socket address, match only certain fields.
64*4882a593Smuzhiyun  * Also grab sock if it was found. Remember to sock_put it later.
65*4882a593Smuzhiyun  */
pn_find_sock_by_sa(struct net * net,const struct sockaddr_pn * spn)66*4882a593Smuzhiyun struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct sock *sknode;
69*4882a593Smuzhiyun 	struct sock *rval = NULL;
70*4882a593Smuzhiyun 	u16 obj = pn_sockaddr_get_object(spn);
71*4882a593Smuzhiyun 	u8 res = spn->spn_resource;
72*4882a593Smuzhiyun 	struct hlist_head *hlist = pn_hash_list(obj);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	rcu_read_lock();
75*4882a593Smuzhiyun 	sk_for_each_rcu(sknode, hlist) {
76*4882a593Smuzhiyun 		struct pn_sock *pn = pn_sk(sknode);
77*4882a593Smuzhiyun 		BUG_ON(!pn->sobject); /* unbound socket */
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		if (!net_eq(sock_net(sknode), net))
80*4882a593Smuzhiyun 			continue;
81*4882a593Smuzhiyun 		if (pn_port(obj)) {
82*4882a593Smuzhiyun 			/* Look up socket by port */
83*4882a593Smuzhiyun 			if (pn_port(pn->sobject) != pn_port(obj))
84*4882a593Smuzhiyun 				continue;
85*4882a593Smuzhiyun 		} else {
86*4882a593Smuzhiyun 			/* If port is zero, look up by resource */
87*4882a593Smuzhiyun 			if (pn->resource != res)
88*4882a593Smuzhiyun 				continue;
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 		if (pn_addr(pn->sobject) &&
91*4882a593Smuzhiyun 		    pn_addr(pn->sobject) != pn_addr(obj))
92*4882a593Smuzhiyun 			continue;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 		rval = sknode;
95*4882a593Smuzhiyun 		sock_hold(sknode);
96*4882a593Smuzhiyun 		break;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 	rcu_read_unlock();
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return rval;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /* Deliver a broadcast packet (only in bottom-half) */
pn_deliver_sock_broadcast(struct net * net,struct sk_buff * skb)104*4882a593Smuzhiyun void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	struct hlist_head *hlist = pnsocks.hlist;
107*4882a593Smuzhiyun 	unsigned int h;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	rcu_read_lock();
110*4882a593Smuzhiyun 	for (h = 0; h < PN_HASHSIZE; h++) {
111*4882a593Smuzhiyun 		struct sock *sknode;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		sk_for_each(sknode, hlist) {
114*4882a593Smuzhiyun 			struct sk_buff *clone;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 			if (!net_eq(sock_net(sknode), net))
117*4882a593Smuzhiyun 				continue;
118*4882a593Smuzhiyun 			if (!sock_flag(sknode, SOCK_BROADCAST))
119*4882a593Smuzhiyun 				continue;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 			clone = skb_clone(skb, GFP_ATOMIC);
122*4882a593Smuzhiyun 			if (clone) {
123*4882a593Smuzhiyun 				sock_hold(sknode);
124*4882a593Smuzhiyun 				sk_receive_skb(sknode, clone, 0);
125*4882a593Smuzhiyun 			}
126*4882a593Smuzhiyun 		}
127*4882a593Smuzhiyun 		hlist++;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 	rcu_read_unlock();
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
pn_sock_hash(struct sock * sk)132*4882a593Smuzhiyun int pn_sock_hash(struct sock *sk)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	mutex_lock(&pnsocks.lock);
137*4882a593Smuzhiyun 	sk_add_node_rcu(sk, hlist);
138*4882a593Smuzhiyun 	mutex_unlock(&pnsocks.lock);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	return 0;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun EXPORT_SYMBOL(pn_sock_hash);
143*4882a593Smuzhiyun 
pn_sock_unhash(struct sock * sk)144*4882a593Smuzhiyun void pn_sock_unhash(struct sock *sk)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	mutex_lock(&pnsocks.lock);
147*4882a593Smuzhiyun 	sk_del_node_init_rcu(sk);
148*4882a593Smuzhiyun 	mutex_unlock(&pnsocks.lock);
149*4882a593Smuzhiyun 	pn_sock_unbind_all_res(sk);
150*4882a593Smuzhiyun 	synchronize_rcu();
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun EXPORT_SYMBOL(pn_sock_unhash);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun static DEFINE_MUTEX(port_mutex);
155*4882a593Smuzhiyun 
pn_socket_bind(struct socket * sock,struct sockaddr * addr,int len)156*4882a593Smuzhiyun static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
159*4882a593Smuzhiyun 	struct pn_sock *pn = pn_sk(sk);
160*4882a593Smuzhiyun 	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
161*4882a593Smuzhiyun 	int err;
162*4882a593Smuzhiyun 	u16 handle;
163*4882a593Smuzhiyun 	u8 saddr;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (sk->sk_prot->bind)
166*4882a593Smuzhiyun 		return sk->sk_prot->bind(sk, addr, len);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	if (len < sizeof(struct sockaddr_pn))
169*4882a593Smuzhiyun 		return -EINVAL;
170*4882a593Smuzhiyun 	if (spn->spn_family != AF_PHONET)
171*4882a593Smuzhiyun 		return -EAFNOSUPPORT;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
174*4882a593Smuzhiyun 	saddr = pn_addr(handle);
175*4882a593Smuzhiyun 	if (saddr && phonet_address_lookup(sock_net(sk), saddr))
176*4882a593Smuzhiyun 		return -EADDRNOTAVAIL;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	lock_sock(sk);
179*4882a593Smuzhiyun 	if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
180*4882a593Smuzhiyun 		err = -EINVAL; /* attempt to rebind */
181*4882a593Smuzhiyun 		goto out;
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 	WARN_ON(sk_hashed(sk));
184*4882a593Smuzhiyun 	mutex_lock(&port_mutex);
185*4882a593Smuzhiyun 	err = sk->sk_prot->get_port(sk, pn_port(handle));
186*4882a593Smuzhiyun 	if (err)
187*4882a593Smuzhiyun 		goto out_port;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	/* get_port() sets the port, bind() sets the address if applicable */
190*4882a593Smuzhiyun 	pn->sobject = pn_object(saddr, pn_port(pn->sobject));
191*4882a593Smuzhiyun 	pn->resource = spn->spn_resource;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	/* Enable RX on the socket */
194*4882a593Smuzhiyun 	err = sk->sk_prot->hash(sk);
195*4882a593Smuzhiyun out_port:
196*4882a593Smuzhiyun 	mutex_unlock(&port_mutex);
197*4882a593Smuzhiyun out:
198*4882a593Smuzhiyun 	release_sock(sk);
199*4882a593Smuzhiyun 	return err;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
pn_socket_autobind(struct socket * sock)202*4882a593Smuzhiyun static int pn_socket_autobind(struct socket *sock)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct sockaddr_pn sa;
205*4882a593Smuzhiyun 	int err;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	memset(&sa, 0, sizeof(sa));
208*4882a593Smuzhiyun 	sa.spn_family = AF_PHONET;
209*4882a593Smuzhiyun 	err = pn_socket_bind(sock, (struct sockaddr *)&sa,
210*4882a593Smuzhiyun 				sizeof(struct sockaddr_pn));
211*4882a593Smuzhiyun 	if (err != -EINVAL)
212*4882a593Smuzhiyun 		return err;
213*4882a593Smuzhiyun 	BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
214*4882a593Smuzhiyun 	return 0; /* socket was already bound */
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
pn_socket_connect(struct socket * sock,struct sockaddr * addr,int len,int flags)217*4882a593Smuzhiyun static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
218*4882a593Smuzhiyun 		int len, int flags)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
221*4882a593Smuzhiyun 	struct pn_sock *pn = pn_sk(sk);
222*4882a593Smuzhiyun 	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
223*4882a593Smuzhiyun 	struct task_struct *tsk = current;
224*4882a593Smuzhiyun 	long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
225*4882a593Smuzhiyun 	int err;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	if (pn_socket_autobind(sock))
228*4882a593Smuzhiyun 		return -ENOBUFS;
229*4882a593Smuzhiyun 	if (len < sizeof(struct sockaddr_pn))
230*4882a593Smuzhiyun 		return -EINVAL;
231*4882a593Smuzhiyun 	if (spn->spn_family != AF_PHONET)
232*4882a593Smuzhiyun 		return -EAFNOSUPPORT;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	lock_sock(sk);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	switch (sock->state) {
237*4882a593Smuzhiyun 	case SS_UNCONNECTED:
238*4882a593Smuzhiyun 		if (sk->sk_state != TCP_CLOSE) {
239*4882a593Smuzhiyun 			err = -EISCONN;
240*4882a593Smuzhiyun 			goto out;
241*4882a593Smuzhiyun 		}
242*4882a593Smuzhiyun 		break;
243*4882a593Smuzhiyun 	case SS_CONNECTING:
244*4882a593Smuzhiyun 		err = -EALREADY;
245*4882a593Smuzhiyun 		goto out;
246*4882a593Smuzhiyun 	default:
247*4882a593Smuzhiyun 		err = -EISCONN;
248*4882a593Smuzhiyun 		goto out;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	pn->dobject = pn_sockaddr_get_object(spn);
252*4882a593Smuzhiyun 	pn->resource = pn_sockaddr_get_resource(spn);
253*4882a593Smuzhiyun 	sock->state = SS_CONNECTING;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	err = sk->sk_prot->connect(sk, addr, len);
256*4882a593Smuzhiyun 	if (err) {
257*4882a593Smuzhiyun 		sock->state = SS_UNCONNECTED;
258*4882a593Smuzhiyun 		pn->dobject = 0;
259*4882a593Smuzhiyun 		goto out;
260*4882a593Smuzhiyun 	}
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	while (sk->sk_state == TCP_SYN_SENT) {
263*4882a593Smuzhiyun 		DEFINE_WAIT(wait);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 		if (!timeo) {
266*4882a593Smuzhiyun 			err = -EINPROGRESS;
267*4882a593Smuzhiyun 			goto out;
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun 		if (signal_pending(tsk)) {
270*4882a593Smuzhiyun 			err = sock_intr_errno(timeo);
271*4882a593Smuzhiyun 			goto out;
272*4882a593Smuzhiyun 		}
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
275*4882a593Smuzhiyun 						TASK_INTERRUPTIBLE);
276*4882a593Smuzhiyun 		release_sock(sk);
277*4882a593Smuzhiyun 		timeo = schedule_timeout(timeo);
278*4882a593Smuzhiyun 		lock_sock(sk);
279*4882a593Smuzhiyun 		finish_wait(sk_sleep(sk), &wait);
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
283*4882a593Smuzhiyun 		err = 0;
284*4882a593Smuzhiyun 	else if (sk->sk_state == TCP_CLOSE_WAIT)
285*4882a593Smuzhiyun 		err = -ECONNRESET;
286*4882a593Smuzhiyun 	else
287*4882a593Smuzhiyun 		err = -ECONNREFUSED;
288*4882a593Smuzhiyun 	sock->state = err ? SS_UNCONNECTED : SS_CONNECTED;
289*4882a593Smuzhiyun out:
290*4882a593Smuzhiyun 	release_sock(sk);
291*4882a593Smuzhiyun 	return err;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
pn_socket_accept(struct socket * sock,struct socket * newsock,int flags,bool kern)294*4882a593Smuzhiyun static int pn_socket_accept(struct socket *sock, struct socket *newsock,
295*4882a593Smuzhiyun 			    int flags, bool kern)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
298*4882a593Smuzhiyun 	struct sock *newsk;
299*4882a593Smuzhiyun 	int err;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (unlikely(sk->sk_state != TCP_LISTEN))
302*4882a593Smuzhiyun 		return -EINVAL;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	newsk = sk->sk_prot->accept(sk, flags, &err, kern);
305*4882a593Smuzhiyun 	if (!newsk)
306*4882a593Smuzhiyun 		return err;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	lock_sock(newsk);
309*4882a593Smuzhiyun 	sock_graft(newsk, newsock);
310*4882a593Smuzhiyun 	newsock->state = SS_CONNECTED;
311*4882a593Smuzhiyun 	release_sock(newsk);
312*4882a593Smuzhiyun 	return 0;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
pn_socket_getname(struct socket * sock,struct sockaddr * addr,int peer)315*4882a593Smuzhiyun static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
316*4882a593Smuzhiyun 				int peer)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
319*4882a593Smuzhiyun 	struct pn_sock *pn = pn_sk(sk);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	memset(addr, 0, sizeof(struct sockaddr_pn));
322*4882a593Smuzhiyun 	addr->sa_family = AF_PHONET;
323*4882a593Smuzhiyun 	if (!peer) /* Race with bind() here is userland's problem. */
324*4882a593Smuzhiyun 		pn_sockaddr_set_object((struct sockaddr_pn *)addr,
325*4882a593Smuzhiyun 					pn->sobject);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	return sizeof(struct sockaddr_pn);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
pn_socket_poll(struct file * file,struct socket * sock,poll_table * wait)330*4882a593Smuzhiyun static __poll_t pn_socket_poll(struct file *file, struct socket *sock,
331*4882a593Smuzhiyun 					poll_table *wait)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
334*4882a593Smuzhiyun 	struct pep_sock *pn = pep_sk(sk);
335*4882a593Smuzhiyun 	__poll_t mask = 0;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	poll_wait(file, sk_sleep(sk), wait);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (sk->sk_state == TCP_CLOSE)
340*4882a593Smuzhiyun 		return EPOLLERR;
341*4882a593Smuzhiyun 	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
342*4882a593Smuzhiyun 		mask |= EPOLLIN | EPOLLRDNORM;
343*4882a593Smuzhiyun 	if (!skb_queue_empty_lockless(&pn->ctrlreq_queue))
344*4882a593Smuzhiyun 		mask |= EPOLLPRI;
345*4882a593Smuzhiyun 	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
346*4882a593Smuzhiyun 		return EPOLLHUP;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (sk->sk_state == TCP_ESTABLISHED &&
349*4882a593Smuzhiyun 		refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
350*4882a593Smuzhiyun 		atomic_read(&pn->tx_credits))
351*4882a593Smuzhiyun 		mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	return mask;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
pn_socket_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)356*4882a593Smuzhiyun static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
357*4882a593Smuzhiyun 				unsigned long arg)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
360*4882a593Smuzhiyun 	struct pn_sock *pn = pn_sk(sk);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (cmd == SIOCPNGETOBJECT) {
363*4882a593Smuzhiyun 		struct net_device *dev;
364*4882a593Smuzhiyun 		u16 handle;
365*4882a593Smuzhiyun 		u8 saddr;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 		if (get_user(handle, (__u16 __user *)arg))
368*4882a593Smuzhiyun 			return -EFAULT;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 		lock_sock(sk);
371*4882a593Smuzhiyun 		if (sk->sk_bound_dev_if)
372*4882a593Smuzhiyun 			dev = dev_get_by_index(sock_net(sk),
373*4882a593Smuzhiyun 						sk->sk_bound_dev_if);
374*4882a593Smuzhiyun 		else
375*4882a593Smuzhiyun 			dev = phonet_device_get(sock_net(sk));
376*4882a593Smuzhiyun 		if (dev && (dev->flags & IFF_UP))
377*4882a593Smuzhiyun 			saddr = phonet_address_get(dev, pn_addr(handle));
378*4882a593Smuzhiyun 		else
379*4882a593Smuzhiyun 			saddr = PN_NO_ADDR;
380*4882a593Smuzhiyun 		release_sock(sk);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		if (dev)
383*4882a593Smuzhiyun 			dev_put(dev);
384*4882a593Smuzhiyun 		if (saddr == PN_NO_ADDR)
385*4882a593Smuzhiyun 			return -EHOSTUNREACH;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 		handle = pn_object(saddr, pn_port(pn->sobject));
388*4882a593Smuzhiyun 		return put_user(handle, (__u16 __user *)arg);
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	return sk->sk_prot->ioctl(sk, cmd, arg);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
pn_socket_listen(struct socket * sock,int backlog)394*4882a593Smuzhiyun static int pn_socket_listen(struct socket *sock, int backlog)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
397*4882a593Smuzhiyun 	int err = 0;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	if (pn_socket_autobind(sock))
400*4882a593Smuzhiyun 		return -ENOBUFS;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	lock_sock(sk);
403*4882a593Smuzhiyun 	if (sock->state != SS_UNCONNECTED) {
404*4882a593Smuzhiyun 		err = -EINVAL;
405*4882a593Smuzhiyun 		goto out;
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (sk->sk_state != TCP_LISTEN) {
409*4882a593Smuzhiyun 		sk->sk_state = TCP_LISTEN;
410*4882a593Smuzhiyun 		sk->sk_ack_backlog = 0;
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 	sk->sk_max_ack_backlog = backlog;
413*4882a593Smuzhiyun out:
414*4882a593Smuzhiyun 	release_sock(sk);
415*4882a593Smuzhiyun 	return err;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
pn_socket_sendmsg(struct socket * sock,struct msghdr * m,size_t total_len)418*4882a593Smuzhiyun static int pn_socket_sendmsg(struct socket *sock, struct msghdr *m,
419*4882a593Smuzhiyun 			     size_t total_len)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	struct sock *sk = sock->sk;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	if (pn_socket_autobind(sock))
424*4882a593Smuzhiyun 		return -EAGAIN;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return sk->sk_prot->sendmsg(sk, m, total_len);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun const struct proto_ops phonet_dgram_ops = {
430*4882a593Smuzhiyun 	.family		= AF_PHONET,
431*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
432*4882a593Smuzhiyun 	.release	= pn_socket_release,
433*4882a593Smuzhiyun 	.bind		= pn_socket_bind,
434*4882a593Smuzhiyun 	.connect	= sock_no_connect,
435*4882a593Smuzhiyun 	.socketpair	= sock_no_socketpair,
436*4882a593Smuzhiyun 	.accept		= sock_no_accept,
437*4882a593Smuzhiyun 	.getname	= pn_socket_getname,
438*4882a593Smuzhiyun 	.poll		= datagram_poll,
439*4882a593Smuzhiyun 	.ioctl		= pn_socket_ioctl,
440*4882a593Smuzhiyun 	.listen		= sock_no_listen,
441*4882a593Smuzhiyun 	.shutdown	= sock_no_shutdown,
442*4882a593Smuzhiyun 	.sendmsg	= pn_socket_sendmsg,
443*4882a593Smuzhiyun 	.recvmsg	= sock_common_recvmsg,
444*4882a593Smuzhiyun 	.mmap		= sock_no_mmap,
445*4882a593Smuzhiyun 	.sendpage	= sock_no_sendpage,
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun const struct proto_ops phonet_stream_ops = {
449*4882a593Smuzhiyun 	.family		= AF_PHONET,
450*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
451*4882a593Smuzhiyun 	.release	= pn_socket_release,
452*4882a593Smuzhiyun 	.bind		= pn_socket_bind,
453*4882a593Smuzhiyun 	.connect	= pn_socket_connect,
454*4882a593Smuzhiyun 	.socketpair	= sock_no_socketpair,
455*4882a593Smuzhiyun 	.accept		= pn_socket_accept,
456*4882a593Smuzhiyun 	.getname	= pn_socket_getname,
457*4882a593Smuzhiyun 	.poll		= pn_socket_poll,
458*4882a593Smuzhiyun 	.ioctl		= pn_socket_ioctl,
459*4882a593Smuzhiyun 	.listen		= pn_socket_listen,
460*4882a593Smuzhiyun 	.shutdown	= sock_no_shutdown,
461*4882a593Smuzhiyun 	.setsockopt	= sock_common_setsockopt,
462*4882a593Smuzhiyun 	.getsockopt	= sock_common_getsockopt,
463*4882a593Smuzhiyun 	.sendmsg	= pn_socket_sendmsg,
464*4882a593Smuzhiyun 	.recvmsg	= sock_common_recvmsg,
465*4882a593Smuzhiyun 	.mmap		= sock_no_mmap,
466*4882a593Smuzhiyun 	.sendpage	= sock_no_sendpage,
467*4882a593Smuzhiyun };
468*4882a593Smuzhiyun EXPORT_SYMBOL(phonet_stream_ops);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun /* allocate port for a socket */
pn_sock_get_port(struct sock * sk,unsigned short sport)471*4882a593Smuzhiyun int pn_sock_get_port(struct sock *sk, unsigned short sport)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	static int port_cur;
474*4882a593Smuzhiyun 	struct net *net = sock_net(sk);
475*4882a593Smuzhiyun 	struct pn_sock *pn = pn_sk(sk);
476*4882a593Smuzhiyun 	struct sockaddr_pn try_sa;
477*4882a593Smuzhiyun 	struct sock *tmpsk;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	memset(&try_sa, 0, sizeof(struct sockaddr_pn));
480*4882a593Smuzhiyun 	try_sa.spn_family = AF_PHONET;
481*4882a593Smuzhiyun 	WARN_ON(!mutex_is_locked(&port_mutex));
482*4882a593Smuzhiyun 	if (!sport) {
483*4882a593Smuzhiyun 		/* search free port */
484*4882a593Smuzhiyun 		int port, pmin, pmax;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 		phonet_get_local_port_range(&pmin, &pmax);
487*4882a593Smuzhiyun 		for (port = pmin; port <= pmax; port++) {
488*4882a593Smuzhiyun 			port_cur++;
489*4882a593Smuzhiyun 			if (port_cur < pmin || port_cur > pmax)
490*4882a593Smuzhiyun 				port_cur = pmin;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 			pn_sockaddr_set_port(&try_sa, port_cur);
493*4882a593Smuzhiyun 			tmpsk = pn_find_sock_by_sa(net, &try_sa);
494*4882a593Smuzhiyun 			if (tmpsk == NULL) {
495*4882a593Smuzhiyun 				sport = port_cur;
496*4882a593Smuzhiyun 				goto found;
497*4882a593Smuzhiyun 			} else
498*4882a593Smuzhiyun 				sock_put(tmpsk);
499*4882a593Smuzhiyun 		}
500*4882a593Smuzhiyun 	} else {
501*4882a593Smuzhiyun 		/* try to find specific port */
502*4882a593Smuzhiyun 		pn_sockaddr_set_port(&try_sa, sport);
503*4882a593Smuzhiyun 		tmpsk = pn_find_sock_by_sa(net, &try_sa);
504*4882a593Smuzhiyun 		if (tmpsk == NULL)
505*4882a593Smuzhiyun 			/* No sock there! We can use that port... */
506*4882a593Smuzhiyun 			goto found;
507*4882a593Smuzhiyun 		else
508*4882a593Smuzhiyun 			sock_put(tmpsk);
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 	/* the port must be in use already */
511*4882a593Smuzhiyun 	return -EADDRINUSE;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun found:
514*4882a593Smuzhiyun 	pn->sobject = pn_object(pn_addr(pn->sobject), sport);
515*4882a593Smuzhiyun 	return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun EXPORT_SYMBOL(pn_sock_get_port);
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun #ifdef CONFIG_PROC_FS
pn_sock_get_idx(struct seq_file * seq,loff_t pos)520*4882a593Smuzhiyun static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	struct net *net = seq_file_net(seq);
523*4882a593Smuzhiyun 	struct hlist_head *hlist = pnsocks.hlist;
524*4882a593Smuzhiyun 	struct sock *sknode;
525*4882a593Smuzhiyun 	unsigned int h;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	for (h = 0; h < PN_HASHSIZE; h++) {
528*4882a593Smuzhiyun 		sk_for_each_rcu(sknode, hlist) {
529*4882a593Smuzhiyun 			if (!net_eq(net, sock_net(sknode)))
530*4882a593Smuzhiyun 				continue;
531*4882a593Smuzhiyun 			if (!pos)
532*4882a593Smuzhiyun 				return sknode;
533*4882a593Smuzhiyun 			pos--;
534*4882a593Smuzhiyun 		}
535*4882a593Smuzhiyun 		hlist++;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 	return NULL;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
pn_sock_get_next(struct seq_file * seq,struct sock * sk)540*4882a593Smuzhiyun static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun 	struct net *net = seq_file_net(seq);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	do
545*4882a593Smuzhiyun 		sk = sk_next(sk);
546*4882a593Smuzhiyun 	while (sk && !net_eq(net, sock_net(sk)));
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	return sk;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
pn_sock_seq_start(struct seq_file * seq,loff_t * pos)551*4882a593Smuzhiyun static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
552*4882a593Smuzhiyun 	__acquires(rcu)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	rcu_read_lock();
555*4882a593Smuzhiyun 	return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
pn_sock_seq_next(struct seq_file * seq,void * v,loff_t * pos)558*4882a593Smuzhiyun static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct sock *sk;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	if (v == SEQ_START_TOKEN)
563*4882a593Smuzhiyun 		sk = pn_sock_get_idx(seq, 0);
564*4882a593Smuzhiyun 	else
565*4882a593Smuzhiyun 		sk = pn_sock_get_next(seq, v);
566*4882a593Smuzhiyun 	(*pos)++;
567*4882a593Smuzhiyun 	return sk;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
pn_sock_seq_stop(struct seq_file * seq,void * v)570*4882a593Smuzhiyun static void pn_sock_seq_stop(struct seq_file *seq, void *v)
571*4882a593Smuzhiyun 	__releases(rcu)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	rcu_read_unlock();
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
pn_sock_seq_show(struct seq_file * seq,void * v)576*4882a593Smuzhiyun static int pn_sock_seq_show(struct seq_file *seq, void *v)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	seq_setwidth(seq, 127);
579*4882a593Smuzhiyun 	if (v == SEQ_START_TOKEN)
580*4882a593Smuzhiyun 		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
581*4882a593Smuzhiyun 			"  uid inode ref pointer drops");
582*4882a593Smuzhiyun 	else {
583*4882a593Smuzhiyun 		struct sock *sk = v;
584*4882a593Smuzhiyun 		struct pn_sock *pn = pn_sk(sk);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
587*4882a593Smuzhiyun 			"%d %pK %u",
588*4882a593Smuzhiyun 			sk->sk_protocol, pn->sobject, pn->dobject,
589*4882a593Smuzhiyun 			pn->resource, sk->sk_state,
590*4882a593Smuzhiyun 			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
591*4882a593Smuzhiyun 			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
592*4882a593Smuzhiyun 			sock_i_ino(sk),
593*4882a593Smuzhiyun 			refcount_read(&sk->sk_refcnt), sk,
594*4882a593Smuzhiyun 			atomic_read(&sk->sk_drops));
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 	seq_pad(seq, '\n');
597*4882a593Smuzhiyun 	return 0;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun const struct seq_operations pn_sock_seq_ops = {
601*4882a593Smuzhiyun 	.start = pn_sock_seq_start,
602*4882a593Smuzhiyun 	.next = pn_sock_seq_next,
603*4882a593Smuzhiyun 	.stop = pn_sock_seq_stop,
604*4882a593Smuzhiyun 	.show = pn_sock_seq_show,
605*4882a593Smuzhiyun };
606*4882a593Smuzhiyun #endif
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun static struct  {
609*4882a593Smuzhiyun 	struct sock *sk[256];
610*4882a593Smuzhiyun } pnres;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun /*
613*4882a593Smuzhiyun  * Find and hold socket based on resource.
614*4882a593Smuzhiyun  */
pn_find_sock_by_res(struct net * net,u8 res)615*4882a593Smuzhiyun struct sock *pn_find_sock_by_res(struct net *net, u8 res)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	struct sock *sk;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	if (!net_eq(net, &init_net))
620*4882a593Smuzhiyun 		return NULL;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	rcu_read_lock();
623*4882a593Smuzhiyun 	sk = rcu_dereference(pnres.sk[res]);
624*4882a593Smuzhiyun 	if (sk)
625*4882a593Smuzhiyun 		sock_hold(sk);
626*4882a593Smuzhiyun 	rcu_read_unlock();
627*4882a593Smuzhiyun 	return sk;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun static DEFINE_MUTEX(resource_mutex);
631*4882a593Smuzhiyun 
pn_sock_bind_res(struct sock * sk,u8 res)632*4882a593Smuzhiyun int pn_sock_bind_res(struct sock *sk, u8 res)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun 	int ret = -EADDRINUSE;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	if (!net_eq(sock_net(sk), &init_net))
637*4882a593Smuzhiyun 		return -ENOIOCTLCMD;
638*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
639*4882a593Smuzhiyun 		return -EPERM;
640*4882a593Smuzhiyun 	if (pn_socket_autobind(sk->sk_socket))
641*4882a593Smuzhiyun 		return -EAGAIN;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	mutex_lock(&resource_mutex);
644*4882a593Smuzhiyun 	if (pnres.sk[res] == NULL) {
645*4882a593Smuzhiyun 		sock_hold(sk);
646*4882a593Smuzhiyun 		rcu_assign_pointer(pnres.sk[res], sk);
647*4882a593Smuzhiyun 		ret = 0;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 	mutex_unlock(&resource_mutex);
650*4882a593Smuzhiyun 	return ret;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun 
pn_sock_unbind_res(struct sock * sk,u8 res)653*4882a593Smuzhiyun int pn_sock_unbind_res(struct sock *sk, u8 res)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	int ret = -ENOENT;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
658*4882a593Smuzhiyun 		return -EPERM;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	mutex_lock(&resource_mutex);
661*4882a593Smuzhiyun 	if (pnres.sk[res] == sk) {
662*4882a593Smuzhiyun 		RCU_INIT_POINTER(pnres.sk[res], NULL);
663*4882a593Smuzhiyun 		ret = 0;
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 	mutex_unlock(&resource_mutex);
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	if (ret == 0) {
668*4882a593Smuzhiyun 		synchronize_rcu();
669*4882a593Smuzhiyun 		sock_put(sk);
670*4882a593Smuzhiyun 	}
671*4882a593Smuzhiyun 	return ret;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
pn_sock_unbind_all_res(struct sock * sk)674*4882a593Smuzhiyun void pn_sock_unbind_all_res(struct sock *sk)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun 	unsigned int res, match = 0;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	mutex_lock(&resource_mutex);
679*4882a593Smuzhiyun 	for (res = 0; res < 256; res++) {
680*4882a593Smuzhiyun 		if (pnres.sk[res] == sk) {
681*4882a593Smuzhiyun 			RCU_INIT_POINTER(pnres.sk[res], NULL);
682*4882a593Smuzhiyun 			match++;
683*4882a593Smuzhiyun 		}
684*4882a593Smuzhiyun 	}
685*4882a593Smuzhiyun 	mutex_unlock(&resource_mutex);
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	while (match > 0) {
688*4882a593Smuzhiyun 		__sock_put(sk);
689*4882a593Smuzhiyun 		match--;
690*4882a593Smuzhiyun 	}
691*4882a593Smuzhiyun 	/* Caller is responsible for RCU sync before final sock_put() */
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun #ifdef CONFIG_PROC_FS
pn_res_get_idx(struct seq_file * seq,loff_t pos)695*4882a593Smuzhiyun static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	struct net *net = seq_file_net(seq);
698*4882a593Smuzhiyun 	unsigned int i;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	if (!net_eq(net, &init_net))
701*4882a593Smuzhiyun 		return NULL;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	for (i = 0; i < 256; i++) {
704*4882a593Smuzhiyun 		if (pnres.sk[i] == NULL)
705*4882a593Smuzhiyun 			continue;
706*4882a593Smuzhiyun 		if (!pos)
707*4882a593Smuzhiyun 			return pnres.sk + i;
708*4882a593Smuzhiyun 		pos--;
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun 	return NULL;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
pn_res_get_next(struct seq_file * seq,struct sock ** sk)713*4882a593Smuzhiyun static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	struct net *net = seq_file_net(seq);
716*4882a593Smuzhiyun 	unsigned int i;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	BUG_ON(!net_eq(net, &init_net));
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	for (i = (sk - pnres.sk) + 1; i < 256; i++)
721*4882a593Smuzhiyun 		if (pnres.sk[i])
722*4882a593Smuzhiyun 			return pnres.sk + i;
723*4882a593Smuzhiyun 	return NULL;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
pn_res_seq_start(struct seq_file * seq,loff_t * pos)726*4882a593Smuzhiyun static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
727*4882a593Smuzhiyun 	__acquires(resource_mutex)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun 	mutex_lock(&resource_mutex);
730*4882a593Smuzhiyun 	return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun 
pn_res_seq_next(struct seq_file * seq,void * v,loff_t * pos)733*4882a593Smuzhiyun static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	struct sock **sk;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	if (v == SEQ_START_TOKEN)
738*4882a593Smuzhiyun 		sk = pn_res_get_idx(seq, 0);
739*4882a593Smuzhiyun 	else
740*4882a593Smuzhiyun 		sk = pn_res_get_next(seq, v);
741*4882a593Smuzhiyun 	(*pos)++;
742*4882a593Smuzhiyun 	return sk;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun 
pn_res_seq_stop(struct seq_file * seq,void * v)745*4882a593Smuzhiyun static void pn_res_seq_stop(struct seq_file *seq, void *v)
746*4882a593Smuzhiyun 	__releases(resource_mutex)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	mutex_unlock(&resource_mutex);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
pn_res_seq_show(struct seq_file * seq,void * v)751*4882a593Smuzhiyun static int pn_res_seq_show(struct seq_file *seq, void *v)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun 	seq_setwidth(seq, 63);
754*4882a593Smuzhiyun 	if (v == SEQ_START_TOKEN)
755*4882a593Smuzhiyun 		seq_puts(seq, "rs   uid inode");
756*4882a593Smuzhiyun 	else {
757*4882a593Smuzhiyun 		struct sock **psk = v;
758*4882a593Smuzhiyun 		struct sock *sk = *psk;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 		seq_printf(seq, "%02X %5u %lu",
761*4882a593Smuzhiyun 			   (int) (psk - pnres.sk),
762*4882a593Smuzhiyun 			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
763*4882a593Smuzhiyun 			   sock_i_ino(sk));
764*4882a593Smuzhiyun 	}
765*4882a593Smuzhiyun 	seq_pad(seq, '\n');
766*4882a593Smuzhiyun 	return 0;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun const struct seq_operations pn_res_seq_ops = {
770*4882a593Smuzhiyun 	.start = pn_res_seq_start,
771*4882a593Smuzhiyun 	.next = pn_res_seq_next,
772*4882a593Smuzhiyun 	.stop = pn_res_seq_stop,
773*4882a593Smuzhiyun 	.show = pn_res_seq_show,
774*4882a593Smuzhiyun };
775*4882a593Smuzhiyun #endif
776