Blame view

net/phonet/socket.c 16.3 KB
2b27bdcc2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
ba113a94b   Remi Denis-Courmont   Phonet: common so...
2
3
4
5
6
7
8
  /*
   * File: socket.c
   *
   * Phonet sockets
   *
   * Copyright (C) 2008 Nokia Corporation.
   *
31fdc5553   Rémi Denis-Courmont   net: remove my fu...
9
10
   * Authors: Sakari Ailus <sakari.ailus@nokia.com>
   *          Rémi Denis-Courmont
ba113a94b   Remi Denis-Courmont   Phonet: common so...
11
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/gfp.h>
ba113a94b   Remi Denis-Courmont   Phonet: common so...
13
14
  #include <linux/kernel.h>
  #include <linux/net.h>
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
15
  #include <linux/poll.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
16
  #include <linux/sched/signal.h>
ba113a94b   Remi Denis-Courmont   Phonet: common so...
17
18
19
20
  #include <net/sock.h>
  #include <net/tcp_states.h>
  
  #include <linux/phonet.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
21
  #include <linux/export.h>
ba113a94b   Remi Denis-Courmont   Phonet: common so...
22
  #include <net/phonet/phonet.h>
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
23
  #include <net/phonet/pep.h>
ba113a94b   Remi Denis-Courmont   Phonet: common so...
24
25
26
27
28
29
30
31
32
33
34
35
  #include <net/phonet/pn_dev.h>
  
  static int pn_socket_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
  
  	if (sk) {
  		sock->sk = NULL;
  		sk->sk_prot->close(sk, 0);
  	}
  	return 0;
  }
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
36
37
  #define PN_HASHSIZE	16
  #define PN_HASHMASK	(PN_HASHSIZE-1)
ba113a94b   Remi Denis-Courmont   Phonet: common so...
38
  static struct  {
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
39
  	struct hlist_head hlist[PN_HASHSIZE];
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
40
  	struct mutex lock;
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
41
42
43
44
  } pnsocks;
  
  void __init pn_sock_init(void)
  {
95c961747   Eric Dumazet   net: cleanup unsi...
45
  	unsigned int i;
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
46
47
48
  
  	for (i = 0; i < PN_HASHSIZE; i++)
  		INIT_HLIST_HEAD(pnsocks.hlist + i);
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
49
  	mutex_init(&pnsocks.lock);
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
50
51
52
53
54
55
  }
  
  static struct hlist_head *pn_hash_list(u16 obj)
  {
  	return pnsocks.hlist + (obj & PN_HASHMASK);
  }
ba113a94b   Remi Denis-Courmont   Phonet: common so...
56
57
58
59
60
  
  /*
   * Find address based on socket address, match only certain fields.
   * Also grab sock if it was found. Remember to sock_put it later.
   */
524048819   Rémi Denis-Courmont   Phonet: basic net...
61
  struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
ba113a94b   Remi Denis-Courmont   Phonet: common so...
62
  {
ba113a94b   Remi Denis-Courmont   Phonet: common so...
63
64
65
66
  	struct sock *sknode;
  	struct sock *rval = NULL;
  	u16 obj = pn_sockaddr_get_object(spn);
  	u8 res = spn->spn_resource;
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
67
  	struct hlist_head *hlist = pn_hash_list(obj);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
68

44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
69
  	rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
70
  	sk_for_each_rcu(sknode, hlist) {
ba113a94b   Remi Denis-Courmont   Phonet: common so...
71
72
  		struct pn_sock *pn = pn_sk(sknode);
  		BUG_ON(!pn->sobject); /* unbound socket */
524048819   Rémi Denis-Courmont   Phonet: basic net...
73
74
  		if (!net_eq(sock_net(sknode), net))
  			continue;
ba113a94b   Remi Denis-Courmont   Phonet: common so...
75
76
77
78
79
80
81
82
83
  		if (pn_port(obj)) {
  			/* Look up socket by port */
  			if (pn_port(pn->sobject) != pn_port(obj))
  				continue;
  		} else {
  			/* If port is zero, look up by resource */
  			if (pn->resource != res)
  				continue;
  		}
f64f9e719   Joe Perches   net: Move && and ...
84
85
  		if (pn_addr(pn->sobject) &&
  		    pn_addr(pn->sobject) != pn_addr(obj))
ba113a94b   Remi Denis-Courmont   Phonet: common so...
86
87
88
89
90
91
  			continue;
  
  		rval = sknode;
  		sock_hold(sknode);
  		break;
  	}
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
92
  	rcu_read_unlock();
ba113a94b   Remi Denis-Courmont   Phonet: common so...
93
94
  
  	return rval;
f14001fcd   Rémi Denis-Courmont   Phonet: deliver b...
95
96
97
98
99
  }
  
  /* Deliver a broadcast packet (only in bottom-half) */
  void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
  {
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
100
  	struct hlist_head *hlist = pnsocks.hlist;
95c961747   Eric Dumazet   net: cleanup unsi...
101
  	unsigned int h;
f14001fcd   Rémi Denis-Courmont   Phonet: deliver b...
102

44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
103
  	rcu_read_lock();
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
104
  	for (h = 0; h < PN_HASHSIZE; h++) {
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
105
  		struct sock *sknode;
f14001fcd   Rémi Denis-Courmont   Phonet: deliver b...
106

b67bfe0d4   Sasha Levin   hlist: drop the n...
107
  		sk_for_each(sknode, hlist) {
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
108
  			struct sk_buff *clone;
ba113a94b   Remi Denis-Courmont   Phonet: common so...
109

6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
110
111
112
113
114
115
116
117
118
119
  			if (!net_eq(sock_net(sknode), net))
  				continue;
  			if (!sock_flag(sknode, SOCK_BROADCAST))
  				continue;
  
  			clone = skb_clone(skb, GFP_ATOMIC);
  			if (clone) {
  				sock_hold(sknode);
  				sk_receive_skb(sknode, clone, 0);
  			}
21912d1ca   Rémi Denis-Courmont   Phonet: hold sock...
120
  		}
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
121
  		hlist++;
f14001fcd   Rémi Denis-Courmont   Phonet: deliver b...
122
  	}
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
123
  	rcu_read_unlock();
ba113a94b   Remi Denis-Courmont   Phonet: common so...
124
  }
086c653f5   Craig Gallek   sock: struct prot...
125
  int pn_sock_hash(struct sock *sk)
ba113a94b   Remi Denis-Courmont   Phonet: common so...
126
  {
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
127
  	struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
128
129
130
  	mutex_lock(&pnsocks.lock);
  	sk_add_node_rcu(sk, hlist);
  	mutex_unlock(&pnsocks.lock);
086c653f5   Craig Gallek   sock: struct prot...
131
132
  
  	return 0;
ba113a94b   Remi Denis-Courmont   Phonet: common so...
133
134
135
136
137
  }
  EXPORT_SYMBOL(pn_sock_hash);
  
  void pn_sock_unhash(struct sock *sk)
  {
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
138
139
140
  	mutex_lock(&pnsocks.lock);
  	sk_del_node_init_rcu(sk);
  	mutex_unlock(&pnsocks.lock);
7417fa83c   Rémi Denis-Courmont   Phonet: hook reso...
141
  	pn_sock_unbind_all_res(sk);
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
142
  	synchronize_rcu();
ba113a94b   Remi Denis-Courmont   Phonet: common so...
143
144
  }
  EXPORT_SYMBOL(pn_sock_unhash);
582b0b611   Rémi Denis-Courmont   Phonet: fix race ...
145
  static DEFINE_MUTEX(port_mutex);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
  {
  	struct sock *sk = sock->sk;
  	struct pn_sock *pn = pn_sk(sk);
  	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
  	int err;
  	u16 handle;
  	u8 saddr;
  
  	if (sk->sk_prot->bind)
  		return sk->sk_prot->bind(sk, addr, len);
  
  	if (len < sizeof(struct sockaddr_pn))
  		return -EINVAL;
  	if (spn->spn_family != AF_PHONET)
  		return -EAFNOSUPPORT;
  
  	handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
  	saddr = pn_addr(handle);
524048819   Rémi Denis-Courmont   Phonet: basic net...
165
  	if (saddr && phonet_address_lookup(sock_net(sk), saddr))
ba113a94b   Remi Denis-Courmont   Phonet: common so...
166
167
168
169
170
171
172
  		return -EADDRNOTAVAIL;
  
  	lock_sock(sk);
  	if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
  		err = -EINVAL; /* attempt to rebind */
  		goto out;
  	}
582b0b611   Rémi Denis-Courmont   Phonet: fix race ...
173
174
  	WARN_ON(sk_hashed(sk));
  	mutex_lock(&port_mutex);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
175
176
  	err = sk->sk_prot->get_port(sk, pn_port(handle));
  	if (err)
582b0b611   Rémi Denis-Courmont   Phonet: fix race ...
177
  		goto out_port;
ba113a94b   Remi Denis-Courmont   Phonet: common so...
178
179
180
181
182
183
  
  	/* get_port() sets the port, bind() sets the address if applicable */
  	pn->sobject = pn_object(saddr, pn_port(pn->sobject));
  	pn->resource = spn->spn_resource;
  
  	/* Enable RX on the socket */
086c653f5   Craig Gallek   sock: struct prot...
184
  	err = sk->sk_prot->hash(sk);
582b0b611   Rémi Denis-Courmont   Phonet: fix race ...
185
186
  out_port:
  	mutex_unlock(&port_mutex);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  out:
  	release_sock(sk);
  	return err;
  }
  
  static int pn_socket_autobind(struct socket *sock)
  {
  	struct sockaddr_pn sa;
  	int err;
  
  	memset(&sa, 0, sizeof(sa));
  	sa.spn_family = AF_PHONET;
  	err = pn_socket_bind(sock, (struct sockaddr *)&sa,
  				sizeof(struct sockaddr_pn));
  	if (err != -EINVAL)
  		return err;
  	BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
  	return 0; /* socket was already bound */
  }
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
206
207
208
209
  static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
  		int len, int flags)
  {
  	struct sock *sk = sock->sk;
297edb600   Rémi Denis-Courmont   Phonet: support a...
210
  	struct pn_sock *pn = pn_sk(sk);
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
211
  	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
297edb600   Rémi Denis-Courmont   Phonet: support a...
212
213
  	struct task_struct *tsk = current;
  	long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
214
  	int err;
297edb600   Rémi Denis-Courmont   Phonet: support a...
215
216
  	if (pn_socket_autobind(sock))
  		return -ENOBUFS;
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
217
218
219
220
221
222
223
224
225
  	if (len < sizeof(struct sockaddr_pn))
  		return -EINVAL;
  	if (spn->spn_family != AF_PHONET)
  		return -EAFNOSUPPORT;
  
  	lock_sock(sk);
  
  	switch (sock->state) {
  	case SS_UNCONNECTED:
297edb600   Rémi Denis-Courmont   Phonet: support a...
226
  		if (sk->sk_state != TCP_CLOSE) {
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
227
228
  			err = -EISCONN;
  			goto out;
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
229
230
  		}
  		break;
297edb600   Rémi Denis-Courmont   Phonet: support a...
231
232
233
234
235
236
  	case SS_CONNECTING:
  		err = -EALREADY;
  		goto out;
  	default:
  		err = -EISCONN;
  		goto out;
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
237
  	}
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
238

297edb600   Rémi Denis-Courmont   Phonet: support a...
239
240
  	pn->dobject = pn_sockaddr_get_object(spn);
  	pn->resource = pn_sockaddr_get_resource(spn);
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
241
  	sock->state = SS_CONNECTING;
297edb600   Rémi Denis-Courmont   Phonet: support a...
242

b3d625538   Kumar Sanghvi   Phonet: 'connect'...
243
  	err = sk->sk_prot->connect(sk, addr, len);
297edb600   Rémi Denis-Courmont   Phonet: support a...
244
  	if (err) {
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
245
  		sock->state = SS_UNCONNECTED;
297edb600   Rémi Denis-Courmont   Phonet: support a...
246
  		pn->dobject = 0;
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
247
248
  		goto out;
  	}
297edb600   Rémi Denis-Courmont   Phonet: support a...
249
250
  	while (sk->sk_state == TCP_SYN_SENT) {
  		DEFINE_WAIT(wait);
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
251

297edb600   Rémi Denis-Courmont   Phonet: support a...
252
253
254
255
256
257
258
259
  		if (!timeo) {
  			err = -EINPROGRESS;
  			goto out;
  		}
  		if (signal_pending(tsk)) {
  			err = sock_intr_errno(timeo);
  			goto out;
  		}
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
260

297edb600   Rémi Denis-Courmont   Phonet: support a...
261
262
263
264
265
266
  		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
  						TASK_INTERRUPTIBLE);
  		release_sock(sk);
  		timeo = schedule_timeout(timeo);
  		lock_sock(sk);
  		finish_wait(sk_sleep(sk), &wait);
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
267
  	}
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
268

297edb600   Rémi Denis-Courmont   Phonet: support a...
269
270
271
272
273
274
275
  	if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
  		err = 0;
  	else if (sk->sk_state == TCP_CLOSE_WAIT)
  		err = -ECONNRESET;
  	else
  		err = -ECONNREFUSED;
  	sock->state = err ? SS_UNCONNECTED : SS_CONNECTED;
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
276
277
278
279
  out:
  	release_sock(sk);
  	return err;
  }
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
280

9995a32b4   Rémi Denis-Courmont   Phonet: connected...
281
  static int pn_socket_accept(struct socket *sock, struct socket *newsock,
cdfbabfb2   David Howells   net: Work around ...
282
  			    int flags, bool kern)
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
283
284
285
286
  {
  	struct sock *sk = sock->sk;
  	struct sock *newsk;
  	int err;
f7ae8d59f   Rémi Denis-Courmont   Phonet: allocate ...
287
288
  	if (unlikely(sk->sk_state != TCP_LISTEN))
  		return -EINVAL;
cdfbabfb2   David Howells   net: Work around ...
289
  	newsk = sk->sk_prot->accept(sk, flags, &err, kern);
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
290
291
292
293
294
295
296
297
298
  	if (!newsk)
  		return err;
  
  	lock_sock(newsk);
  	sock_graft(newsk, newsock);
  	newsock->state = SS_CONNECTED;
  	release_sock(newsk);
  	return 0;
  }
ba113a94b   Remi Denis-Courmont   Phonet: common so...
299
  static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
9b2c45d47   Denys Vlasenko   net: make getname...
300
  				int peer)
ba113a94b   Remi Denis-Courmont   Phonet: common so...
301
302
303
304
305
306
307
308
309
  {
  	struct sock *sk = sock->sk;
  	struct pn_sock *pn = pn_sk(sk);
  
  	memset(addr, 0, sizeof(struct sockaddr_pn));
  	addr->sa_family = AF_PHONET;
  	if (!peer) /* Race with bind() here is userland's problem. */
  		pn_sockaddr_set_object((struct sockaddr_pn *)addr,
  					pn->sobject);
9b2c45d47   Denys Vlasenko   net: make getname...
310
  	return sizeof(struct sockaddr_pn);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
311
  }
a11e1d432   Linus Torvalds   Revert changes to...
312
313
  static __poll_t pn_socket_poll(struct file *file, struct socket *sock,
  					poll_table *wait)
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
314
315
316
  {
  	struct sock *sk = sock->sk;
  	struct pep_sock *pn = pep_sk(sk);
ade994f4f   Al Viro   net: annotate ->p...
317
  	__poll_t mask = 0;
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
318

a11e1d432   Linus Torvalds   Revert changes to...
319
  	poll_wait(file, sk_sleep(sk), wait);
f7ae8d59f   Rémi Denis-Courmont   Phonet: allocate ...
320
  	if (sk->sk_state == TCP_CLOSE)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
321
  		return EPOLLERR;
3ef7cf57c   Eric Dumazet   net: use skb_queu...
322
  	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
323
  		mask |= EPOLLIN | EPOLLRDNORM;
3ef7cf57c   Eric Dumazet   net: use skb_queu...
324
  	if (!skb_queue_empty_lockless(&pn->ctrlreq_queue))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
325
  		mask |= EPOLLPRI;
c41bd97f8   Rémi Denis-Courmont   Phonet: receive p...
326
  	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
327
  		return EPOLLHUP;
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
328

01b38606b   Rémi Denis-Courmont   Phonet: do not se...
329
  	if (sk->sk_state == TCP_ESTABLISHED &&
14afee4b6   Reshetova, Elena   net: convert sock...
330
  		refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
01b38606b   Rémi Denis-Courmont   Phonet: do not se...
331
  		atomic_read(&pn->tx_credits))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
332
  		mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
333
334
335
  
  	return mask;
  }
ba113a94b   Remi Denis-Courmont   Phonet: common so...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
  				unsigned long arg)
  {
  	struct sock *sk = sock->sk;
  	struct pn_sock *pn = pn_sk(sk);
  
  	if (cmd == SIOCPNGETOBJECT) {
  		struct net_device *dev;
  		u16 handle;
  		u8 saddr;
  
  		if (get_user(handle, (__u16 __user *)arg))
  			return -EFAULT;
  
  		lock_sock(sk);
  		if (sk->sk_bound_dev_if)
  			dev = dev_get_by_index(sock_net(sk),
  						sk->sk_bound_dev_if);
  		else
  			dev = phonet_device_get(sock_net(sk));
  		if (dev && (dev->flags & IFF_UP))
  			saddr = phonet_address_get(dev, pn_addr(handle));
  		else
  			saddr = PN_NO_ADDR;
  		release_sock(sk);
  
  		if (dev)
  			dev_put(dev);
  		if (saddr == PN_NO_ADDR)
  			return -EHOSTUNREACH;
  
  		handle = pn_object(saddr, pn_port(pn->sobject));
  		return put_user(handle, (__u16 __user *)arg);
  	}
  
  	return sk->sk_prot->ioctl(sk, cmd, arg);
  }
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
373
374
375
376
  static int pn_socket_listen(struct socket *sock, int backlog)
  {
  	struct sock *sk = sock->sk;
  	int err = 0;
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
377
378
379
380
  	if (pn_socket_autobind(sock))
  		return -ENOBUFS;
  
  	lock_sock(sk);
96241544c   Rémi Denis-Courmont   Phonet: allow mul...
381
  	if (sock->state != SS_UNCONNECTED) {
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
382
383
384
  		err = -EINVAL;
  		goto out;
  	}
96241544c   Rémi Denis-Courmont   Phonet: allow mul...
385
386
387
388
  	if (sk->sk_state != TCP_LISTEN) {
  		sk->sk_state = TCP_LISTEN;
  		sk->sk_ack_backlog = 0;
  	}
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
389
390
391
392
393
  	sk->sk_max_ack_backlog = backlog;
  out:
  	release_sock(sk);
  	return err;
  }
1b7841404   Ying Xue   net: Remove iocb ...
394
395
  static int pn_socket_sendmsg(struct socket *sock, struct msghdr *m,
  			     size_t total_len)
ba113a94b   Remi Denis-Courmont   Phonet: common so...
396
397
398
399
400
  {
  	struct sock *sk = sock->sk;
  
  	if (pn_socket_autobind(sock))
  		return -EAGAIN;
1b7841404   Ying Xue   net: Remove iocb ...
401
  	return sk->sk_prot->sendmsg(sk, m, total_len);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
402
403
404
405
406
407
408
409
410
411
412
  }
  
  const struct proto_ops phonet_dgram_ops = {
  	.family		= AF_PHONET,
  	.owner		= THIS_MODULE,
  	.release	= pn_socket_release,
  	.bind		= pn_socket_bind,
  	.connect	= sock_no_connect,
  	.socketpair	= sock_no_socketpair,
  	.accept		= sock_no_accept,
  	.getname	= pn_socket_getname,
a11e1d432   Linus Torvalds   Revert changes to...
413
  	.poll		= datagram_poll,
ba113a94b   Remi Denis-Courmont   Phonet: common so...
414
415
416
  	.ioctl		= pn_socket_ioctl,
  	.listen		= sock_no_listen,
  	.shutdown	= sock_no_shutdown,
ba113a94b   Remi Denis-Courmont   Phonet: common so...
417
418
419
420
421
  	.sendmsg	= pn_socket_sendmsg,
  	.recvmsg	= sock_common_recvmsg,
  	.mmap		= sock_no_mmap,
  	.sendpage	= sock_no_sendpage,
  };
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
422
423
424
425
426
  const struct proto_ops phonet_stream_ops = {
  	.family		= AF_PHONET,
  	.owner		= THIS_MODULE,
  	.release	= pn_socket_release,
  	.bind		= pn_socket_bind,
b3d625538   Kumar Sanghvi   Phonet: 'connect'...
427
  	.connect	= pn_socket_connect,
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
428
429
430
  	.socketpair	= sock_no_socketpair,
  	.accept		= pn_socket_accept,
  	.getname	= pn_socket_getname,
a11e1d432   Linus Torvalds   Revert changes to...
431
  	.poll		= pn_socket_poll,
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
432
433
434
  	.ioctl		= pn_socket_ioctl,
  	.listen		= pn_socket_listen,
  	.shutdown	= sock_no_shutdown,
02a47617c   Rémi Denis-Courmont   Phonet: implement...
435
436
  	.setsockopt	= sock_common_setsockopt,
  	.getsockopt	= sock_common_getsockopt,
9995a32b4   Rémi Denis-Courmont   Phonet: connected...
437
438
439
440
441
442
  	.sendmsg	= pn_socket_sendmsg,
  	.recvmsg	= sock_common_recvmsg,
  	.mmap		= sock_no_mmap,
  	.sendpage	= sock_no_sendpage,
  };
  EXPORT_SYMBOL(phonet_stream_ops);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
443
444
445
446
  /* allocate port for a socket */
  int pn_sock_get_port(struct sock *sk, unsigned short sport)
  {
  	static int port_cur;
524048819   Rémi Denis-Courmont   Phonet: basic net...
447
  	struct net *net = sock_net(sk);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
448
449
450
451
452
453
  	struct pn_sock *pn = pn_sk(sk);
  	struct sockaddr_pn try_sa;
  	struct sock *tmpsk;
  
  	memset(&try_sa, 0, sizeof(struct sockaddr_pn));
  	try_sa.spn_family = AF_PHONET;
582b0b611   Rémi Denis-Courmont   Phonet: fix race ...
454
  	WARN_ON(!mutex_is_locked(&port_mutex));
ba113a94b   Remi Denis-Courmont   Phonet: common so...
455
456
  	if (!sport) {
  		/* search free port */
87ab4e20b   Remi Denis-Courmont   Phonet: proc inte...
457
  		int port, pmin, pmax;
ba113a94b   Remi Denis-Courmont   Phonet: common so...
458

87ab4e20b   Remi Denis-Courmont   Phonet: proc inte...
459
  		phonet_get_local_port_range(&pmin, &pmax);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
460
461
462
463
464
465
  		for (port = pmin; port <= pmax; port++) {
  			port_cur++;
  			if (port_cur < pmin || port_cur > pmax)
  				port_cur = pmin;
  
  			pn_sockaddr_set_port(&try_sa, port_cur);
524048819   Rémi Denis-Courmont   Phonet: basic net...
466
  			tmpsk = pn_find_sock_by_sa(net, &try_sa);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
467
468
469
470
471
472
473
474
475
  			if (tmpsk == NULL) {
  				sport = port_cur;
  				goto found;
  			} else
  				sock_put(tmpsk);
  		}
  	} else {
  		/* try to find specific port */
  		pn_sockaddr_set_port(&try_sa, sport);
524048819   Rémi Denis-Courmont   Phonet: basic net...
476
  		tmpsk = pn_find_sock_by_sa(net, &try_sa);
ba113a94b   Remi Denis-Courmont   Phonet: common so...
477
478
479
480
481
482
  		if (tmpsk == NULL)
  			/* No sock there! We can use that port... */
  			goto found;
  		else
  			sock_put(tmpsk);
  	}
ba113a94b   Remi Denis-Courmont   Phonet: common so...
483
484
485
486
  	/* the port must be in use already */
  	return -EADDRINUSE;
  
  found:
ba113a94b   Remi Denis-Courmont   Phonet: common so...
487
488
489
490
  	pn->sobject = pn_object(pn_addr(pn->sobject), sport);
  	return 0;
  }
  EXPORT_SYMBOL(pn_sock_get_port);
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
491

ae6e2aef6   Randy Dunlap   phonet: fix build...
492
  #ifdef CONFIG_PROC_FS
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
493
494
495
  static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
  {
  	struct net *net = seq_file_net(seq);
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
496
  	struct hlist_head *hlist = pnsocks.hlist;
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
497
  	struct sock *sknode;
95c961747   Eric Dumazet   net: cleanup unsi...
498
  	unsigned int h;
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
499

6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
500
  	for (h = 0; h < PN_HASHSIZE; h++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
501
  		sk_for_each_rcu(sknode, hlist) {
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
502
503
504
505
506
507
508
  			if (!net_eq(net, sock_net(sknode)))
  				continue;
  			if (!pos)
  				return sknode;
  			pos--;
  		}
  		hlist++;
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  	}
  	return NULL;
  }
  
  static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
  {
  	struct net *net = seq_file_net(seq);
  
  	do
  		sk = sk_next(sk);
  	while (sk && !net_eq(net, sock_net(sk)));
  
  	return sk;
  }
  
  static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
525
  	__acquires(rcu)
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
526
  {
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
527
  	rcu_read_lock();
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  	return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
  }
  
  static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct sock *sk;
  
  	if (v == SEQ_START_TOKEN)
  		sk = pn_sock_get_idx(seq, 0);
  	else
  		sk = pn_sock_get_next(seq, v);
  	(*pos)++;
  	return sk;
  }
  
  static void pn_sock_seq_stop(struct seq_file *seq, void *v)
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
544
  	__releases(rcu)
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
545
  {
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
546
  	rcu_read_unlock();
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
547
548
549
550
  }
  
  static int pn_sock_seq_show(struct seq_file *seq, void *v)
  {
652586df9   Tetsuo Handa   seq_file: remove ...
551
  	seq_setwidth(seq, 127);
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
552
  	if (v == SEQ_START_TOKEN)
652586df9   Tetsuo Handa   seq_file: remove ...
553
554
  		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
  			"  uid inode ref pointer drops");
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
555
556
557
558
559
  	else {
  		struct sock *sk = v;
  		struct pn_sock *pn = pn_sk(sk);
  
  		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
ea9a03791   Patrick Talbert   net: Treat sock->...
560
  			"%d %pK %u",
a8059512b   Rémi Denis-Courmont   Phonet: implement...
561
562
  			sk->sk_protocol, pn->sobject, pn->dobject,
  			pn->resource, sk->sk_state,
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
563
  			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
a7cb5a49b   Eric W. Biederman   userns: Print out...
564
565
  			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
  			sock_i_ino(sk),
41c6d650f   Reshetova, Elena   net: convert sock...
566
  			refcount_read(&sk->sk_refcnt), sk,
652586df9   Tetsuo Handa   seq_file: remove ...
567
  			atomic_read(&sk->sk_drops));
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
568
  	}
652586df9   Tetsuo Handa   seq_file: remove ...
569
570
  	seq_pad(seq, '
  ');
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
571
572
  	return 0;
  }
c35063722   Christoph Hellwig   proc: introduce p...
573
  const struct seq_operations pn_sock_seq_ops = {
c1dc13e9d   Rémi Denis-Courmont   Phonet: sockets l...
574
575
576
577
578
  	.start = pn_sock_seq_start,
  	.next = pn_sock_seq_next,
  	.stop = pn_sock_seq_stop,
  	.show = pn_sock_seq_show,
  };
ae6e2aef6   Randy Dunlap   phonet: fix build...
579
  #endif
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  
  static struct  {
  	struct sock *sk[256];
  } pnres;
  
  /*
   * Find and hold socket based on resource.
   */
  struct sock *pn_find_sock_by_res(struct net *net, u8 res)
  {
  	struct sock *sk;
  
  	if (!net_eq(net, &init_net))
  		return NULL;
  
  	rcu_read_lock();
  	sk = rcu_dereference(pnres.sk[res]);
  	if (sk)
  		sock_hold(sk);
  	rcu_read_unlock();
  	return sk;
  }
  
  static DEFINE_MUTEX(resource_mutex);
  
  int pn_sock_bind_res(struct sock *sk, u8 res)
  {
  	int ret = -EADDRINUSE;
  
  	if (!net_eq(sock_net(sk), &init_net))
  		return -ENOIOCTLCMD;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (pn_socket_autobind(sk->sk_socket))
  		return -EAGAIN;
  
  	mutex_lock(&resource_mutex);
  	if (pnres.sk[res] == NULL) {
  		sock_hold(sk);
cf778b00e   Eric Dumazet   net: reintroduce ...
619
  		rcu_assign_pointer(pnres.sk[res], sk);
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  		ret = 0;
  	}
  	mutex_unlock(&resource_mutex);
  	return ret;
  }
  
  int pn_sock_unbind_res(struct sock *sk, u8 res)
  {
  	int ret = -ENOENT;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	mutex_lock(&resource_mutex);
  	if (pnres.sk[res] == sk) {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
635
  		RCU_INIT_POINTER(pnres.sk[res], NULL);
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
636
637
638
639
640
641
642
643
644
645
646
647
648
  		ret = 0;
  	}
  	mutex_unlock(&resource_mutex);
  
  	if (ret == 0) {
  		synchronize_rcu();
  		sock_put(sk);
  	}
  	return ret;
  }
  
  void pn_sock_unbind_all_res(struct sock *sk)
  {
95c961747   Eric Dumazet   net: cleanup unsi...
649
  	unsigned int res, match = 0;
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
650
651
652
653
  
  	mutex_lock(&resource_mutex);
  	for (res = 0; res < 256; res++) {
  		if (pnres.sk[res] == sk) {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
654
  			RCU_INIT_POINTER(pnres.sk[res], NULL);
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
655
656
657
658
  			match++;
  		}
  	}
  	mutex_unlock(&resource_mutex);
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
659
  	while (match > 0) {
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
660
  		__sock_put(sk);
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
661
662
  		match--;
  	}
44f4d5a27   Rémi Denis-Courmont   Phonet: convert b...
663
  	/* Caller is responsible for RCU sync before final sock_put() */
4e3d16ce5   Rémi Denis-Courmont   Phonet: resource ...
664
  }
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
665
666
667
668
669
  
  #ifdef CONFIG_PROC_FS
  static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
  {
  	struct net *net = seq_file_net(seq);
95c961747   Eric Dumazet   net: cleanup unsi...
670
  	unsigned int i;
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  
  	if (!net_eq(net, &init_net))
  		return NULL;
  
  	for (i = 0; i < 256; i++) {
  		if (pnres.sk[i] == NULL)
  			continue;
  		if (!pos)
  			return pnres.sk + i;
  		pos--;
  	}
  	return NULL;
  }
  
  static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
  {
  	struct net *net = seq_file_net(seq);
95c961747   Eric Dumazet   net: cleanup unsi...
688
  	unsigned int i;
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
  
  	BUG_ON(!net_eq(net, &init_net));
  
  	for (i = (sk - pnres.sk) + 1; i < 256; i++)
  		if (pnres.sk[i])
  			return pnres.sk + i;
  	return NULL;
  }
  
  static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
  	__acquires(resource_mutex)
  {
  	mutex_lock(&resource_mutex);
  	return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
  }
  
  static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct sock **sk;
  
  	if (v == SEQ_START_TOKEN)
  		sk = pn_res_get_idx(seq, 0);
  	else
  		sk = pn_res_get_next(seq, v);
  	(*pos)++;
  	return sk;
  }
  
  static void pn_res_seq_stop(struct seq_file *seq, void *v)
  	__releases(resource_mutex)
  {
  	mutex_unlock(&resource_mutex);
  }
  
  static int pn_res_seq_show(struct seq_file *seq, void *v)
  {
652586df9   Tetsuo Handa   seq_file: remove ...
725
  	seq_setwidth(seq, 63);
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
726
  	if (v == SEQ_START_TOKEN)
652586df9   Tetsuo Handa   seq_file: remove ...
727
  		seq_puts(seq, "rs   uid inode");
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
728
729
730
  	else {
  		struct sock **psk = v;
  		struct sock *sk = *psk;
652586df9   Tetsuo Handa   seq_file: remove ...
731
  		seq_printf(seq, "%02X %5u %lu",
a7cb5a49b   Eric W. Biederman   userns: Print out...
732
733
  			   (int) (psk - pnres.sk),
  			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
652586df9   Tetsuo Handa   seq_file: remove ...
734
  			   sock_i_ino(sk));
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
735
  	}
652586df9   Tetsuo Handa   seq_file: remove ...
736
737
  	seq_pad(seq, '
  ');
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
738
739
  	return 0;
  }
c35063722   Christoph Hellwig   proc: introduce p...
740
  const struct seq_operations pn_res_seq_ops = {
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
741
742
743
744
745
  	.start = pn_res_seq_start,
  	.next = pn_res_seq_next,
  	.stop = pn_res_seq_stop,
  	.show = pn_res_seq_show,
  };
507215f8d   Rémi Denis-Courmont   Phonet: list subs...
746
  #endif