aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/socket.c
diff options
context:
space:
mode:
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>2010-09-15 08:30:11 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-16 00:31:32 -0400
commit4e3d16ce5e82648d7f4dfd28b6cf8fe2e9a9efc3 (patch)
treed212f0e503a4db4c2b04a0457250bba940205f39 /net/phonet/socket.c
parent6482f554e2b9cbe733d63124765104f29cf0c9ad (diff)
Phonet: resource routing backend
When both destination device and object are nul, Phonet routes the packet according to the resource field. In fact, this is the most common pattern when sending Phonet "request" packets. In this case, the packet is delivered to whichever endpoint (socket) has registered the resource. This adds a new table so that Linux processes can register their Phonet sockets to Phonet resources, if they have adequate privileges. (Namespace support is not implemented at the moment.) Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/phonet/socket.c')
-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}