aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/phonet/phonet.h5
-rw-r--r--net/phonet/socket.c88
2 files changed, 93 insertions, 0 deletions
diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h
index 7b114079a51b..d5df797f9540 100644
--- a/include/net/phonet/phonet.h
+++ b/include/net/phonet/phonet.h
@@ -54,6 +54,11 @@ void pn_sock_hash(struct sock *sk);
54void pn_sock_unhash(struct sock *sk); 54void pn_sock_unhash(struct sock *sk);
55int pn_sock_get_port(struct sock *sk, unsigned short sport); 55int pn_sock_get_port(struct sock *sk, unsigned short sport);
56 56
57struct sock *pn_find_sock_by_res(struct net *net, u8 res);
58int pn_sock_bind_res(struct sock *sock, u8 res);
59int pn_sock_unbind_res(struct sock *sk, u8 res);
60void pn_sock_unbind_all_res(struct sock *sk);
61
57int pn_skb_send(struct sock *sk, struct sk_buff *skb, 62int pn_skb_send(struct sock *sk, struct sk_buff *skb,
58 const struct sockaddr_pn *target); 63 const struct sockaddr_pn *target);
59 64
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}