diff options
author | Pavel Emelyanov <xemul@parallels.com> | 2011-12-06 02:59:52 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-06 13:58:02 -0500 |
commit | 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 (patch) | |
tree | 1746f3acd306c55bff845a56e783ec6f1bd6fc6e /net/core/sock_diag.c | |
parent | a029fe26b67f815eddd432d9e702b9f2edbc2535 (diff) |
sock_diag: Move the sock_ code to net/core/
This patch moves the sock_ code from inet_diag.c to generic sock_diag.c
file and provides necessary request_module-s calls and a pointer on
inet_diag_compat dumping routine.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/sock_diag.c')
-rw-r--r-- | net/core/sock_diag.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c new file mode 100644 index 000000000000..fbaf01ce12f2 --- /dev/null +++ b/net/core/sock_diag.c | |||
@@ -0,0 +1,150 @@ | |||
1 | #include <linux/mutex.h> | ||
2 | #include <linux/socket.h> | ||
3 | #include <linux/skbuff.h> | ||
4 | #include <net/netlink.h> | ||
5 | #include <net/net_namespace.h> | ||
6 | #include <linux/module.h> | ||
7 | |||
8 | #include <linux/inet_diag.h> | ||
9 | #include <linux/sock_diag.h> | ||
10 | |||
11 | static struct sock_diag_handler *sock_diag_handlers[AF_MAX]; | ||
12 | static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); | ||
13 | static DEFINE_MUTEX(sock_diag_table_mutex); | ||
14 | |||
15 | void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) | ||
16 | { | ||
17 | mutex_lock(&sock_diag_table_mutex); | ||
18 | inet_rcv_compat = fn; | ||
19 | mutex_unlock(&sock_diag_table_mutex); | ||
20 | } | ||
21 | EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat); | ||
22 | |||
23 | void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) | ||
24 | { | ||
25 | mutex_lock(&sock_diag_table_mutex); | ||
26 | inet_rcv_compat = NULL; | ||
27 | mutex_unlock(&sock_diag_table_mutex); | ||
28 | } | ||
29 | EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); | ||
30 | |||
31 | int sock_diag_register(struct sock_diag_handler *hndl) | ||
32 | { | ||
33 | int err = 0; | ||
34 | |||
35 | if (hndl->family > AF_MAX) | ||
36 | return -EINVAL; | ||
37 | |||
38 | mutex_lock(&sock_diag_table_mutex); | ||
39 | if (sock_diag_handlers[hndl->family]) | ||
40 | err = -EBUSY; | ||
41 | else | ||
42 | sock_diag_handlers[hndl->family] = hndl; | ||
43 | mutex_unlock(&sock_diag_table_mutex); | ||
44 | |||
45 | return err; | ||
46 | } | ||
47 | EXPORT_SYMBOL_GPL(sock_diag_register); | ||
48 | |||
49 | void sock_diag_unregister(struct sock_diag_handler *hnld) | ||
50 | { | ||
51 | int family = hnld->family; | ||
52 | |||
53 | if (family > AF_MAX) | ||
54 | return; | ||
55 | |||
56 | mutex_lock(&sock_diag_table_mutex); | ||
57 | BUG_ON(sock_diag_handlers[family] != hnld); | ||
58 | sock_diag_handlers[family] = NULL; | ||
59 | mutex_unlock(&sock_diag_table_mutex); | ||
60 | } | ||
61 | EXPORT_SYMBOL_GPL(sock_diag_unregister); | ||
62 | |||
63 | static inline struct sock_diag_handler *sock_diag_lock_handler(int family) | ||
64 | { | ||
65 | if (sock_diag_handlers[family] == NULL) | ||
66 | request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, | ||
67 | NETLINK_SOCK_DIAG, IPPROTO_IP); | ||
68 | |||
69 | mutex_lock(&sock_diag_table_mutex); | ||
70 | return sock_diag_handlers[family]; | ||
71 | } | ||
72 | |||
73 | static inline void sock_diag_unlock_handler(struct sock_diag_handler *h) | ||
74 | { | ||
75 | mutex_unlock(&sock_diag_table_mutex); | ||
76 | } | ||
77 | |||
78 | static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||
79 | { | ||
80 | int err; | ||
81 | struct sock_diag_req *req = NLMSG_DATA(nlh); | ||
82 | struct sock_diag_handler *hndl; | ||
83 | |||
84 | if (nlmsg_len(nlh) < sizeof(*req)) | ||
85 | return -EINVAL; | ||
86 | |||
87 | hndl = sock_diag_lock_handler(req->sdiag_family); | ||
88 | if (hndl == NULL) | ||
89 | err = -ENOENT; | ||
90 | else | ||
91 | err = hndl->dump(skb, nlh); | ||
92 | sock_diag_unlock_handler(hndl); | ||
93 | |||
94 | return err; | ||
95 | } | ||
96 | |||
97 | static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||
98 | { | ||
99 | int ret; | ||
100 | |||
101 | switch (nlh->nlmsg_type) { | ||
102 | case TCPDIAG_GETSOCK: | ||
103 | case DCCPDIAG_GETSOCK: | ||
104 | if (inet_rcv_compat == NULL) | ||
105 | request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, | ||
106 | NETLINK_SOCK_DIAG, IPPROTO_IP); | ||
107 | |||
108 | mutex_lock(&sock_diag_table_mutex); | ||
109 | if (inet_rcv_compat != NULL) | ||
110 | ret = inet_rcv_compat(skb, nlh); | ||
111 | else | ||
112 | ret = -EOPNOTSUPP; | ||
113 | mutex_unlock(&sock_diag_table_mutex); | ||
114 | |||
115 | return ret; | ||
116 | case SOCK_DIAG_BY_FAMILY: | ||
117 | return __sock_diag_rcv_msg(skb, nlh); | ||
118 | default: | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static DEFINE_MUTEX(sock_diag_mutex); | ||
124 | |||
125 | static void sock_diag_rcv(struct sk_buff *skb) | ||
126 | { | ||
127 | mutex_lock(&sock_diag_mutex); | ||
128 | netlink_rcv_skb(skb, &sock_diag_rcv_msg); | ||
129 | mutex_unlock(&sock_diag_mutex); | ||
130 | } | ||
131 | |||
132 | struct sock *sock_diag_nlsk; | ||
133 | EXPORT_SYMBOL_GPL(sock_diag_nlsk); | ||
134 | |||
135 | static int __init sock_diag_init(void) | ||
136 | { | ||
137 | sock_diag_nlsk = netlink_kernel_create(&init_net, NETLINK_SOCK_DIAG, 0, | ||
138 | sock_diag_rcv, NULL, THIS_MODULE); | ||
139 | return sock_diag_nlsk == NULL ? -ENOMEM : 0; | ||
140 | } | ||
141 | |||
142 | static void __exit sock_diag_exit(void) | ||
143 | { | ||
144 | netlink_kernel_release(sock_diag_nlsk); | ||
145 | } | ||
146 | |||
147 | module_init(sock_diag_init); | ||
148 | module_exit(sock_diag_exit); | ||
149 | MODULE_LICENSE("GPL"); | ||
150 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG); | ||