Phonet: provide pipe socket option to retrieve the pipe identifier
[deliverable/linux.git] / net / phonet / socket.c
CommitLineData
ba113a94
RDC
1/*
2 * File: socket.c
3 *
4 * Phonet sockets
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
5a0e3ad6 26#include <linux/gfp.h>
ba113a94
RDC
27#include <linux/kernel.h>
28#include <linux/net.h>
9995a32b 29#include <linux/poll.h>
ba113a94
RDC
30#include <net/sock.h>
31#include <net/tcp_states.h>
32
33#include <linux/phonet.h>
34#include <net/phonet/phonet.h>
9995a32b 35#include <net/phonet/pep.h>
ba113a94
RDC
36#include <net/phonet/pn_dev.h>
37
38static int pn_socket_release(struct socket *sock)
39{
40 struct sock *sk = sock->sk;
41
42 if (sk) {
43 sock->sk = NULL;
44 sk->sk_prot->close(sk, 0);
45 }
46 return 0;
47}
48
6b0d07ba
RDC
49#define PN_HASHSIZE 16
50#define PN_HASHMASK (PN_HASHSIZE-1)
51
52
ba113a94 53static struct {
6b0d07ba 54 struct hlist_head hlist[PN_HASHSIZE];
ba113a94 55 spinlock_t lock;
6b0d07ba
RDC
56} pnsocks;
57
58void __init pn_sock_init(void)
59{
60 unsigned i;
61
62 for (i = 0; i < PN_HASHSIZE; i++)
63 INIT_HLIST_HEAD(pnsocks.hlist + i);
64 spin_lock_init(&pnsocks.lock);
65}
66
67static struct hlist_head *pn_hash_list(u16 obj)
68{
69 return pnsocks.hlist + (obj & PN_HASHMASK);
70}
ba113a94
RDC
71
72/*
73 * Find address based on socket address, match only certain fields.
74 * Also grab sock if it was found. Remember to sock_put it later.
75 */
52404881 76struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
ba113a94
RDC
77{
78 struct hlist_node *node;
79 struct sock *sknode;
80 struct sock *rval = NULL;
81 u16 obj = pn_sockaddr_get_object(spn);
82 u8 res = spn->spn_resource;
6b0d07ba 83 struct hlist_head *hlist = pn_hash_list(obj);
ba113a94
RDC
84
85 spin_lock_bh(&pnsocks.lock);
86
6b0d07ba 87 sk_for_each(sknode, node, hlist) {
ba113a94
RDC
88 struct pn_sock *pn = pn_sk(sknode);
89 BUG_ON(!pn->sobject); /* unbound socket */
90
52404881
RDC
91 if (!net_eq(sock_net(sknode), net))
92 continue;
ba113a94
RDC
93 if (pn_port(obj)) {
94 /* Look up socket by port */
95 if (pn_port(pn->sobject) != pn_port(obj))
96 continue;
97 } else {
98 /* If port is zero, look up by resource */
99 if (pn->resource != res)
100 continue;
101 }
f64f9e71
JP
102 if (pn_addr(pn->sobject) &&
103 pn_addr(pn->sobject) != pn_addr(obj))
ba113a94
RDC
104 continue;
105
106 rval = sknode;
107 sock_hold(sknode);
108 break;
109 }
110
111 spin_unlock_bh(&pnsocks.lock);
112
113 return rval;
f14001fc
RDC
114}
115
116/* Deliver a broadcast packet (only in bottom-half) */
117void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
118{
6b0d07ba
RDC
119 struct hlist_head *hlist = pnsocks.hlist;
120 unsigned h;
f14001fc
RDC
121
122 spin_lock(&pnsocks.lock);
6b0d07ba
RDC
123 for (h = 0; h < PN_HASHSIZE; h++) {
124 struct hlist_node *node;
125 struct sock *sknode;
f14001fc 126
6b0d07ba
RDC
127 sk_for_each(sknode, node, hlist) {
128 struct sk_buff *clone;
ba113a94 129
6b0d07ba
RDC
130 if (!net_eq(sock_net(sknode), net))
131 continue;
132 if (!sock_flag(sknode, SOCK_BROADCAST))
133 continue;
134
135 clone = skb_clone(skb, GFP_ATOMIC);
136 if (clone) {
137 sock_hold(sknode);
138 sk_receive_skb(sknode, clone, 0);
139 }
21912d1c 140 }
6b0d07ba 141 hlist++;
f14001fc
RDC
142 }
143 spin_unlock(&pnsocks.lock);
ba113a94
RDC
144}
145
146void pn_sock_hash(struct sock *sk)
147{
6b0d07ba
RDC
148 struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
149
ba113a94 150 spin_lock_bh(&pnsocks.lock);
6b0d07ba 151 sk_add_node(sk, hlist);
ba113a94
RDC
152 spin_unlock_bh(&pnsocks.lock);
153}
154EXPORT_SYMBOL(pn_sock_hash);
155
156void pn_sock_unhash(struct sock *sk)
157{
158 spin_lock_bh(&pnsocks.lock);
159 sk_del_node_init(sk);
160 spin_unlock_bh(&pnsocks.lock);
7417fa83 161 pn_sock_unbind_all_res(sk);
ba113a94
RDC
162}
163EXPORT_SYMBOL(pn_sock_unhash);
164
582b0b61
RDC
165static DEFINE_MUTEX(port_mutex);
166
ba113a94
RDC
167static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
168{
169 struct sock *sk = sock->sk;
170 struct pn_sock *pn = pn_sk(sk);
171 struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
172 int err;
173 u16 handle;
174 u8 saddr;
175
176 if (sk->sk_prot->bind)
177 return sk->sk_prot->bind(sk, addr, len);
178
179 if (len < sizeof(struct sockaddr_pn))
180 return -EINVAL;
181 if (spn->spn_family != AF_PHONET)
182 return -EAFNOSUPPORT;
183
184 handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
185 saddr = pn_addr(handle);
52404881 186 if (saddr && phonet_address_lookup(sock_net(sk), saddr))
ba113a94
RDC
187 return -EADDRNOTAVAIL;
188
189 lock_sock(sk);
190 if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
191 err = -EINVAL; /* attempt to rebind */
192 goto out;
193 }
582b0b61
RDC
194 WARN_ON(sk_hashed(sk));
195 mutex_lock(&port_mutex);
ba113a94
RDC
196 err = sk->sk_prot->get_port(sk, pn_port(handle));
197 if (err)
582b0b61 198 goto out_port;
ba113a94
RDC
199
200 /* get_port() sets the port, bind() sets the address if applicable */
201 pn->sobject = pn_object(saddr, pn_port(pn->sobject));
202 pn->resource = spn->spn_resource;
203
204 /* Enable RX on the socket */
205 sk->sk_prot->hash(sk);
582b0b61
RDC
206out_port:
207 mutex_unlock(&port_mutex);
ba113a94
RDC
208out:
209 release_sock(sk);
210 return err;
211}
212
213static int pn_socket_autobind(struct socket *sock)
214{
215 struct sockaddr_pn sa;
216 int err;
217
218 memset(&sa, 0, sizeof(sa));
219 sa.spn_family = AF_PHONET;
220 err = pn_socket_bind(sock, (struct sockaddr *)&sa,
221 sizeof(struct sockaddr_pn));
222 if (err != -EINVAL)
223 return err;
224 BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
225 return 0; /* socket was already bound */
226}
227
b3d62553
KS
228#ifdef CONFIG_PHONET_PIPECTRLR
229static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
230 int len, int flags)
231{
232 struct sock *sk = sock->sk;
233 struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
234 long timeo;
235 int err;
236
237 if (len < sizeof(struct sockaddr_pn))
238 return -EINVAL;
239 if (spn->spn_family != AF_PHONET)
240 return -EAFNOSUPPORT;
241
242 lock_sock(sk);
243
244 switch (sock->state) {
245 case SS_UNCONNECTED:
246 sk->sk_state = TCP_CLOSE;
247 break;
248 case SS_CONNECTING:
249 switch (sk->sk_state) {
250 case TCP_SYN_RECV:
251 sock->state = SS_CONNECTED;
252 err = -EISCONN;
253 goto out;
254 case TCP_CLOSE:
255 err = -EALREADY;
256 if (flags & O_NONBLOCK)
257 goto out;
258 goto wait_connect;
259 }
260 break;
261 case SS_CONNECTED:
262 switch (sk->sk_state) {
263 case TCP_SYN_RECV:
264 err = -EISCONN;
265 goto out;
266 case TCP_CLOSE:
267 sock->state = SS_UNCONNECTED;
268 break;
269 }
270 break;
271 case SS_DISCONNECTING:
272 case SS_FREE:
273 break;
274 }
275 sk->sk_state = TCP_CLOSE;
276 sk_stream_kill_queues(sk);
277
278 sock->state = SS_CONNECTING;
279 err = sk->sk_prot->connect(sk, addr, len);
280 if (err < 0) {
281 sock->state = SS_UNCONNECTED;
282 sk->sk_state = TCP_CLOSE;
283 goto out;
284 }
285
286 err = -EINPROGRESS;
287wait_connect:
288 if (sk->sk_state != TCP_SYN_RECV && (flags & O_NONBLOCK))
289 goto out;
290
291 timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
292 release_sock(sk);
293
294 err = -ERESTARTSYS;
295 timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
296 sk->sk_state != TCP_CLOSE,
297 timeo);
298
299 lock_sock(sk);
300 if (timeo < 0)
301 goto out; /* -ERESTARTSYS */
302
303 err = -ETIMEDOUT;
304 if (timeo == 0 && sk->sk_state != TCP_SYN_RECV)
305 goto out;
306
307 if (sk->sk_state != TCP_SYN_RECV) {
308 sock->state = SS_UNCONNECTED;
309 err = sock_error(sk);
310 if (!err)
311 err = -ECONNREFUSED;
312 goto out;
313 }
314 sock->state = SS_CONNECTED;
315 err = 0;
316
317out:
318 release_sock(sk);
319 return err;
320}
321#endif
322
9995a32b
RDC
323static int pn_socket_accept(struct socket *sock, struct socket *newsock,
324 int flags)
325{
326 struct sock *sk = sock->sk;
327 struct sock *newsk;
328 int err;
329
f7ae8d59
RDC
330 if (unlikely(sk->sk_state != TCP_LISTEN))
331 return -EINVAL;
332
9995a32b
RDC
333 newsk = sk->sk_prot->accept(sk, flags, &err);
334 if (!newsk)
335 return err;
336
337 lock_sock(newsk);
338 sock_graft(newsk, newsock);
339 newsock->state = SS_CONNECTED;
340 release_sock(newsk);
341 return 0;
342}
343
ba113a94
RDC
344static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
345 int *sockaddr_len, int peer)
346{
347 struct sock *sk = sock->sk;
348 struct pn_sock *pn = pn_sk(sk);
349
350 memset(addr, 0, sizeof(struct sockaddr_pn));
351 addr->sa_family = AF_PHONET;
352 if (!peer) /* Race with bind() here is userland's problem. */
353 pn_sockaddr_set_object((struct sockaddr_pn *)addr,
354 pn->sobject);
355
356 *sockaddr_len = sizeof(struct sockaddr_pn);
357 return 0;
358}
359
9995a32b
RDC
360static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
361 poll_table *wait)
362{
363 struct sock *sk = sock->sk;
364 struct pep_sock *pn = pep_sk(sk);
365 unsigned int mask = 0;
366
43815482 367 poll_wait(file, sk_sleep(sk), wait);
9995a32b 368
f7ae8d59 369 if (sk->sk_state == TCP_CLOSE)
9995a32b 370 return POLLERR;
9995a32b
RDC
371 if (!skb_queue_empty(&sk->sk_receive_queue))
372 mask |= POLLIN | POLLRDNORM;
c41bd97f
RDC
373 if (!skb_queue_empty(&pn->ctrlreq_queue))
374 mask |= POLLPRI;
375 if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
9995a32b
RDC
376 return POLLHUP;
377
01b38606
RDC
378 if (sk->sk_state == TCP_ESTABLISHED &&
379 atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
380 atomic_read(&pn->tx_credits))
9995a32b
RDC
381 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
382
383 return mask;
384}
385
ba113a94
RDC
386static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
387 unsigned long arg)
388{
389 struct sock *sk = sock->sk;
390 struct pn_sock *pn = pn_sk(sk);
391
392 if (cmd == SIOCPNGETOBJECT) {
393 struct net_device *dev;
394 u16 handle;
395 u8 saddr;
396
397 if (get_user(handle, (__u16 __user *)arg))
398 return -EFAULT;
399
400 lock_sock(sk);
401 if (sk->sk_bound_dev_if)
402 dev = dev_get_by_index(sock_net(sk),
403 sk->sk_bound_dev_if);
404 else
405 dev = phonet_device_get(sock_net(sk));
406 if (dev && (dev->flags & IFF_UP))
407 saddr = phonet_address_get(dev, pn_addr(handle));
408 else
409 saddr = PN_NO_ADDR;
410 release_sock(sk);
411
412 if (dev)
413 dev_put(dev);
414 if (saddr == PN_NO_ADDR)
415 return -EHOSTUNREACH;
416
417 handle = pn_object(saddr, pn_port(pn->sobject));
418 return put_user(handle, (__u16 __user *)arg);
419 }
420
421 return sk->sk_prot->ioctl(sk, cmd, arg);
422}
423
9995a32b
RDC
424static int pn_socket_listen(struct socket *sock, int backlog)
425{
426 struct sock *sk = sock->sk;
427 int err = 0;
428
9995a32b
RDC
429 if (pn_socket_autobind(sock))
430 return -ENOBUFS;
431
432 lock_sock(sk);
96241544 433 if (sock->state != SS_UNCONNECTED) {
9995a32b
RDC
434 err = -EINVAL;
435 goto out;
436 }
437
96241544
RDC
438 if (sk->sk_state != TCP_LISTEN) {
439 sk->sk_state = TCP_LISTEN;
440 sk->sk_ack_backlog = 0;
441 }
9995a32b
RDC
442 sk->sk_max_ack_backlog = backlog;
443out:
444 release_sock(sk);
445 return err;
446}
447
ba113a94
RDC
448static int pn_socket_sendmsg(struct kiocb *iocb, struct socket *sock,
449 struct msghdr *m, size_t total_len)
450{
451 struct sock *sk = sock->sk;
452
453 if (pn_socket_autobind(sock))
454 return -EAGAIN;
455
456 return sk->sk_prot->sendmsg(iocb, sk, m, total_len);
457}
458
459const struct proto_ops phonet_dgram_ops = {
460 .family = AF_PHONET,
461 .owner = THIS_MODULE,
462 .release = pn_socket_release,
463 .bind = pn_socket_bind,
464 .connect = sock_no_connect,
465 .socketpair = sock_no_socketpair,
466 .accept = sock_no_accept,
467 .getname = pn_socket_getname,
468 .poll = datagram_poll,
469 .ioctl = pn_socket_ioctl,
470 .listen = sock_no_listen,
471 .shutdown = sock_no_shutdown,
472 .setsockopt = sock_no_setsockopt,
473 .getsockopt = sock_no_getsockopt,
474#ifdef CONFIG_COMPAT
475 .compat_setsockopt = sock_no_setsockopt,
476 .compat_getsockopt = sock_no_getsockopt,
477#endif
478 .sendmsg = pn_socket_sendmsg,
479 .recvmsg = sock_common_recvmsg,
480 .mmap = sock_no_mmap,
481 .sendpage = sock_no_sendpage,
482};
483
9995a32b
RDC
484const struct proto_ops phonet_stream_ops = {
485 .family = AF_PHONET,
486 .owner = THIS_MODULE,
487 .release = pn_socket_release,
488 .bind = pn_socket_bind,
b3d62553
KS
489#ifdef CONFIG_PHONET_PIPECTRLR
490 .connect = pn_socket_connect,
491#else
9995a32b 492 .connect = sock_no_connect,
b3d62553 493#endif
9995a32b
RDC
494 .socketpair = sock_no_socketpair,
495 .accept = pn_socket_accept,
496 .getname = pn_socket_getname,
497 .poll = pn_socket_poll,
498 .ioctl = pn_socket_ioctl,
499 .listen = pn_socket_listen,
500 .shutdown = sock_no_shutdown,
02a47617
RDC
501 .setsockopt = sock_common_setsockopt,
502 .getsockopt = sock_common_getsockopt,
9995a32b 503#ifdef CONFIG_COMPAT
02a47617
RDC
504 .compat_setsockopt = compat_sock_common_setsockopt,
505 .compat_getsockopt = compat_sock_common_getsockopt,
9995a32b
RDC
506#endif
507 .sendmsg = pn_socket_sendmsg,
508 .recvmsg = sock_common_recvmsg,
509 .mmap = sock_no_mmap,
510 .sendpage = sock_no_sendpage,
511};
512EXPORT_SYMBOL(phonet_stream_ops);
513
ba113a94
RDC
514/* allocate port for a socket */
515int pn_sock_get_port(struct sock *sk, unsigned short sport)
516{
517 static int port_cur;
52404881 518 struct net *net = sock_net(sk);
ba113a94
RDC
519 struct pn_sock *pn = pn_sk(sk);
520 struct sockaddr_pn try_sa;
521 struct sock *tmpsk;
522
523 memset(&try_sa, 0, sizeof(struct sockaddr_pn));
524 try_sa.spn_family = AF_PHONET;
582b0b61 525 WARN_ON(!mutex_is_locked(&port_mutex));
ba113a94
RDC
526 if (!sport) {
527 /* search free port */
87ab4e20 528 int port, pmin, pmax;
ba113a94 529
87ab4e20 530 phonet_get_local_port_range(&pmin, &pmax);
ba113a94
RDC
531 for (port = pmin; port <= pmax; port++) {
532 port_cur++;
533 if (port_cur < pmin || port_cur > pmax)
534 port_cur = pmin;
535
536 pn_sockaddr_set_port(&try_sa, port_cur);
52404881 537 tmpsk = pn_find_sock_by_sa(net, &try_sa);
ba113a94
RDC
538 if (tmpsk == NULL) {
539 sport = port_cur;
540 goto found;
541 } else
542 sock_put(tmpsk);
543 }
544 } else {
545 /* try to find specific port */
546 pn_sockaddr_set_port(&try_sa, sport);
52404881 547 tmpsk = pn_find_sock_by_sa(net, &try_sa);
ba113a94
RDC
548 if (tmpsk == NULL)
549 /* No sock there! We can use that port... */
550 goto found;
551 else
552 sock_put(tmpsk);
553 }
ba113a94
RDC
554 /* the port must be in use already */
555 return -EADDRINUSE;
556
557found:
ba113a94
RDC
558 pn->sobject = pn_object(pn_addr(pn->sobject), sport);
559 return 0;
560}
561EXPORT_SYMBOL(pn_sock_get_port);
c1dc13e9 562
ae6e2aef 563#ifdef CONFIG_PROC_FS
c1dc13e9
RDC
564static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
565{
566 struct net *net = seq_file_net(seq);
6b0d07ba 567 struct hlist_head *hlist = pnsocks.hlist;
c1dc13e9
RDC
568 struct hlist_node *node;
569 struct sock *sknode;
6b0d07ba 570 unsigned h;
c1dc13e9 571
6b0d07ba
RDC
572 for (h = 0; h < PN_HASHSIZE; h++) {
573 sk_for_each(sknode, node, hlist) {
574 if (!net_eq(net, sock_net(sknode)))
575 continue;
576 if (!pos)
577 return sknode;
578 pos--;
579 }
580 hlist++;
c1dc13e9
RDC
581 }
582 return NULL;
583}
584
585static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
586{
587 struct net *net = seq_file_net(seq);
588
589 do
590 sk = sk_next(sk);
591 while (sk && !net_eq(net, sock_net(sk)));
592
593 return sk;
594}
595
596static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
597 __acquires(pnsocks.lock)
598{
599 spin_lock_bh(&pnsocks.lock);
600 return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
601}
602
603static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
604{
605 struct sock *sk;
606
607 if (v == SEQ_START_TOKEN)
608 sk = pn_sock_get_idx(seq, 0);
609 else
610 sk = pn_sock_get_next(seq, v);
611 (*pos)++;
612 return sk;
613}
614
615static void pn_sock_seq_stop(struct seq_file *seq, void *v)
616 __releases(pnsocks.lock)
617{
618 spin_unlock_bh(&pnsocks.lock);
619}
620
621static int pn_sock_seq_show(struct seq_file *seq, void *v)
622{
623 int len;
624
625 if (v == SEQ_START_TOKEN)
626 seq_printf(seq, "%s%n", "pt loc rem rs st tx_queue rx_queue "
627 " uid inode ref pointer drops", &len);
628 else {
629 struct sock *sk = v;
630 struct pn_sock *pn = pn_sk(sk);
631
632 seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
633 "%d %p %d%n",
a8059512
RDC
634 sk->sk_protocol, pn->sobject, pn->dobject,
635 pn->resource, sk->sk_state,
c1dc13e9
RDC
636 sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
637 sock_i_uid(sk), sock_i_ino(sk),
638 atomic_read(&sk->sk_refcnt), sk,
639 atomic_read(&sk->sk_drops), &len);
640 }
641 seq_printf(seq, "%*s\n", 127 - len, "");
642 return 0;
643}
644
645static const struct seq_operations pn_sock_seq_ops = {
646 .start = pn_sock_seq_start,
647 .next = pn_sock_seq_next,
648 .stop = pn_sock_seq_stop,
649 .show = pn_sock_seq_show,
650};
651
652static int pn_sock_open(struct inode *inode, struct file *file)
653{
cb7d9e7f
RDC
654 return seq_open_net(inode, file, &pn_sock_seq_ops,
655 sizeof(struct seq_net_private));
c1dc13e9
RDC
656}
657
658const struct file_operations pn_sock_seq_fops = {
659 .owner = THIS_MODULE,
660 .open = pn_sock_open,
661 .read = seq_read,
662 .llseek = seq_lseek,
cb7d9e7f 663 .release = seq_release_net,
c1dc13e9 664};
ae6e2aef 665#endif
4e3d16ce
RDC
666
667static struct {
668 struct sock *sk[256];
669} pnres;
670
671/*
672 * Find and hold socket based on resource.
673 */
674struct sock *pn_find_sock_by_res(struct net *net, u8 res)
675{
676 struct sock *sk;
677
678 if (!net_eq(net, &init_net))
679 return NULL;
680
681 rcu_read_lock();
682 sk = rcu_dereference(pnres.sk[res]);
683 if (sk)
684 sock_hold(sk);
685 rcu_read_unlock();
686 return sk;
687}
688
689static DEFINE_MUTEX(resource_mutex);
690
691int pn_sock_bind_res(struct sock *sk, u8 res)
692{
693 int ret = -EADDRINUSE;
694
695 if (!net_eq(sock_net(sk), &init_net))
696 return -ENOIOCTLCMD;
697 if (!capable(CAP_SYS_ADMIN))
698 return -EPERM;
699 if (pn_socket_autobind(sk->sk_socket))
700 return -EAGAIN;
701
702 mutex_lock(&resource_mutex);
703 if (pnres.sk[res] == NULL) {
704 sock_hold(sk);
705 rcu_assign_pointer(pnres.sk[res], sk);
706 ret = 0;
707 }
708 mutex_unlock(&resource_mutex);
709 return ret;
710}
711
712int pn_sock_unbind_res(struct sock *sk, u8 res)
713{
714 int ret = -ENOENT;
715
716 if (!capable(CAP_SYS_ADMIN))
717 return -EPERM;
718
719 mutex_lock(&resource_mutex);
720 if (pnres.sk[res] == sk) {
721 rcu_assign_pointer(pnres.sk[res], NULL);
722 ret = 0;
723 }
724 mutex_unlock(&resource_mutex);
725
726 if (ret == 0) {
727 synchronize_rcu();
728 sock_put(sk);
729 }
730 return ret;
731}
732
733void pn_sock_unbind_all_res(struct sock *sk)
734{
735 unsigned res, match = 0;
736
737 mutex_lock(&resource_mutex);
738 for (res = 0; res < 256; res++) {
739 if (pnres.sk[res] == sk) {
740 rcu_assign_pointer(pnres.sk[res], NULL);
741 match++;
742 }
743 }
744 mutex_unlock(&resource_mutex);
745
746 if (match == 0)
747 return;
748 synchronize_rcu();
749 while (match > 0) {
750 sock_put(sk);
751 match--;
752 }
753}
507215f8
RDC
754
755#ifdef CONFIG_PROC_FS
756static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
757{
758 struct net *net = seq_file_net(seq);
759 unsigned i;
760
761 if (!net_eq(net, &init_net))
762 return NULL;
763
764 for (i = 0; i < 256; i++) {
765 if (pnres.sk[i] == NULL)
766 continue;
767 if (!pos)
768 return pnres.sk + i;
769 pos--;
770 }
771 return NULL;
772}
773
774static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
775{
776 struct net *net = seq_file_net(seq);
777 unsigned i;
778
779 BUG_ON(!net_eq(net, &init_net));
780
781 for (i = (sk - pnres.sk) + 1; i < 256; i++)
782 if (pnres.sk[i])
783 return pnres.sk + i;
784 return NULL;
785}
786
787static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
788 __acquires(resource_mutex)
789{
790 mutex_lock(&resource_mutex);
791 return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
792}
793
794static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
795{
796 struct sock **sk;
797
798 if (v == SEQ_START_TOKEN)
799 sk = pn_res_get_idx(seq, 0);
800 else
801 sk = pn_res_get_next(seq, v);
802 (*pos)++;
803 return sk;
804}
805
806static void pn_res_seq_stop(struct seq_file *seq, void *v)
807 __releases(resource_mutex)
808{
809 mutex_unlock(&resource_mutex);
810}
811
812static int pn_res_seq_show(struct seq_file *seq, void *v)
813{
814 int len;
815
816 if (v == SEQ_START_TOKEN)
817 seq_printf(seq, "%s%n", "rs uid inode", &len);
818 else {
819 struct sock **psk = v;
820 struct sock *sk = *psk;
821
822 seq_printf(seq, "%02X %5d %lu%n",
9e0064a5
DM
823 (int) (psk - pnres.sk), sock_i_uid(sk),
824 sock_i_ino(sk), &len);
507215f8
RDC
825 }
826 seq_printf(seq, "%*s\n", 63 - len, "");
827 return 0;
828}
829
830static const struct seq_operations pn_res_seq_ops = {
831 .start = pn_res_seq_start,
832 .next = pn_res_seq_next,
833 .stop = pn_res_seq_stop,
834 .show = pn_res_seq_show,
835};
836
837static int pn_res_open(struct inode *inode, struct file *file)
838{
839 return seq_open_net(inode, file, &pn_res_seq_ops,
840 sizeof(struct seq_net_private));
841}
842
843const struct file_operations pn_res_seq_fops = {
844 .owner = THIS_MODULE,
845 .open = pn_res_open,
846 .read = seq_read,
847 .llseek = seq_lseek,
848 .release = seq_release_net,
849};
850#endif
This page took 0.236069 seconds and 5 git commands to generate.