aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet
diff options
context:
space:
mode:
Diffstat (limited to 'net/phonet')
-rw-r--r--net/phonet/socket.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 7c91f739f138..4c29a23e9007 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -565,3 +565,91 @@ const struct file_operations pn_sock_seq_fops = {
565 .release = seq_release_net, 565 .release = seq_release_net,
566}; 566};
567#endif 567#endif
568
569static struct {
570 struct sock *sk[256];
571} pnres;
572
573/*
574 * Find and hold socket based on resource.
575 */
576struct sock *pn_find_sock_by_res(struct net *net, u8 res)
577{
578 struct sock *sk;
579
580 if (!net_eq(net, &init_net))
581 return NULL;
582
583 rcu_read_lock();
584 sk = rcu_dereference(pnres.sk[res]);
585 if (sk)
586 sock_hold(sk);
587 rcu_read_unlock();
588 return sk;
589}
590
591static DEFINE_MUTEX(resource_mutex);
592
593int pn_sock_bind_res(struct sock *sk, u8 res)
594{
595 int ret = -EADDRINUSE;
596
597 if (!net_eq(sock_net(sk), &init_net))
598 return -ENOIOCTLCMD;
599 if (!capable(CAP_SYS_ADMIN))
600 return -EPERM;
601 if (pn_socket_autobind(sk->sk_socket))
602 return -EAGAIN;
603
604 mutex_lock(&resource_mutex);
605 if (pnres.sk[res] == NULL) {
606 sock_hold(sk);
607 rcu_assign_pointer(pnres.sk[res], sk);
608 ret = 0;
609 }
610 mutex_unlock(&resource_mutex);
611 return ret;
612}
613
614int pn_sock_unbind_res(struct sock *sk, u8 res)
615{
616 int ret = -ENOENT;
617
618 if (!capable(CAP_SYS_ADMIN))
619 return -EPERM;
620
621 mutex_lock(&resource_mutex);
622 if (pnres.sk[res] == sk) {
623 rcu_assign_pointer(pnres.sk[res], NULL);
624 ret = 0;
625 }
626 mutex_unlock(&resource_mutex);
627
628 if (ret == 0) {
629 synchronize_rcu();
630 sock_put(sk);
631 }
632 return ret;
633}
634
635void pn_sock_unbind_all_res(struct sock *sk)
636{
637 unsigned res, match = 0;
638
639 mutex_lock(&resource_mutex);
640 for (res = 0; res < 256; res++) {
641 if (pnres.sk[res] == sk) {
642 rcu_assign_pointer(pnres.sk[res], NULL);
643 match++;
644 }
645 }
646 mutex_unlock(&resource_mutex);
647
648 if (match == 0)
649 return;
650 synchronize_rcu();
651 while (match > 0) {
652 sock_put(sk);
653 match--;
654 }
655}