aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/inet_diag.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2011-12-06 02:58:03 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-06 13:58:01 -0500
commitd366477a52f1df29fa066ffb18e4e6101ee2ad04 (patch)
tree267a65f626108423f73ef6dc0040b3b3171f7b45 /net/ipv4/inet_diag.c
parentf13c95f0e255e6d21762259875295cc212e6bc32 (diff)
sock_diag: Initial skeleton
When receiving the SOCK_DIAG_BY_FAMILY message we have to find the handler for provided family and pass the nl message to it. This patch describes an infrastructure to work with such nandlers and implements stubs for AF_INET(6) ones. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/inet_diag.c')
-rw-r--r--net/ipv4/inet_diag.c102
1 files changed, 100 insertions, 2 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 58caecc343b1..877875ea3d71 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -33,6 +33,7 @@
33#include <linux/stddef.h> 33#include <linux/stddef.h>
34 34
35#include <linux/inet_diag.h> 35#include <linux/inet_diag.h>
36#include <linux/sock_diag.h>
36 37
37static const struct inet_diag_handler **inet_diag_table; 38static const struct inet_diag_handler **inet_diag_table;
38 39
@@ -887,9 +888,91 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
887 return inet_diag_get_exact(skb, nlh); 888 return inet_diag_get_exact(skb, nlh);
888} 889}
889 890
891static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
892{
893 int hdrlen = sizeof(struct inet_diag_req);
894
895 if (nlmsg_len(h) < hdrlen)
896 return -EINVAL;
897
898 if (h->nlmsg_flags & NLM_F_DUMP) {
899 return -EAFNOSUPPORT;
900 }
901
902 return -EAFNOSUPPORT;
903}
904
905static struct sock_diag_handler inet_diag_handler = {
906 .family = AF_INET,
907 .dump = inet_diag_handler_dump,
908};
909
910static struct sock_diag_handler inet6_diag_handler = {
911 .family = AF_INET6,
912 .dump = inet_diag_handler_dump,
913};
914
915static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
916static DEFINE_MUTEX(sock_diag_table_mutex);
917
918int sock_diag_register(struct sock_diag_handler *hndl)
919{
920 int err = 0;
921
922 if (hndl->family > AF_MAX)
923 return -EINVAL;
924
925 mutex_lock(&sock_diag_table_mutex);
926 if (sock_diag_handlers[hndl->family])
927 err = -EBUSY;
928 else
929 sock_diag_handlers[hndl->family] = hndl;
930 mutex_unlock(&sock_diag_table_mutex);
931
932 return err;
933}
934
935void sock_diag_unregister(struct sock_diag_handler *hnld)
936{
937 int family = hnld->family;
938
939 if (family > AF_MAX)
940 return;
941
942 mutex_lock(&sock_diag_table_mutex);
943 BUG_ON(sock_diag_handlers[family] != hnld);
944 sock_diag_handlers[family] = NULL;
945 mutex_unlock(&sock_diag_table_mutex);
946}
947
948static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
949{
950 mutex_lock(&sock_diag_table_mutex);
951 return sock_diag_handlers[family];
952}
953
954static inline void sock_diag_unlock_handler(struct sock_diag_handler *h)
955{
956 mutex_unlock(&sock_diag_table_mutex);
957}
958
890static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 959static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
891{ 960{
892 return -EOPNOTSUPP; 961 int err;
962 struct sock_diag_req *req = NLMSG_DATA(nlh);
963 struct sock_diag_handler *hndl;
964
965 if (nlmsg_len(nlh) < sizeof(*req))
966 return -EINVAL;
967
968 hndl = sock_diag_lock_handler(req->sdiag_family);
969 if (hndl == NULL)
970 err = -ENOENT;
971 else
972 err = hndl->dump(skb, nlh);
973 sock_diag_unlock_handler(hndl);
974
975 return err;
893} 976}
894 977
895static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 978static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
@@ -961,9 +1044,22 @@ static int __init inet_diag_init(void)
961 sock_diag_rcv, NULL, THIS_MODULE); 1044 sock_diag_rcv, NULL, THIS_MODULE);
962 if (sdiagnl == NULL) 1045 if (sdiagnl == NULL)
963 goto out_free_table; 1046 goto out_free_table;
964 err = 0; 1047
1048 err = sock_diag_register(&inet_diag_handler);
1049 if (err)
1050 goto out_free_nl;
1051
1052 err = sock_diag_register(&inet6_diag_handler);
1053 if (err)
1054 goto out_free_inet;
1055
965out: 1056out:
966 return err; 1057 return err;
1058
1059out_free_inet:
1060 sock_diag_unregister(&inet_diag_handler);
1061out_free_nl:
1062 netlink_kernel_release(sdiagnl);
967out_free_table: 1063out_free_table:
968 kfree(inet_diag_table); 1064 kfree(inet_diag_table);
969 goto out; 1065 goto out;
@@ -971,6 +1067,8 @@ out_free_table:
971 1067
972static void __exit inet_diag_exit(void) 1068static void __exit inet_diag_exit(void)
973{ 1069{
1070 sock_diag_unregister(&inet6_diag_handler);
1071 sock_diag_unregister(&inet_diag_handler);
974 netlink_kernel_release(sdiagnl); 1072 netlink_kernel_release(sdiagnl);
975 kfree(inet_diag_table); 1073 kfree(inet_diag_table);
976} 1074}