aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/inet_diag.c67
1 files changed, 46 insertions, 21 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 6b3fffb554b6..e468e7a7aac4 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -51,6 +51,29 @@ static struct sock *idiagnl;
51#define INET_DIAG_PUT(skb, attrtype, attrlen) \ 51#define INET_DIAG_PUT(skb, attrtype, attrlen) \
52 RTA_DATA(__RTA_PUT(skb, attrtype, attrlen)) 52 RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
53 53
54static DEFINE_MUTEX(inet_diag_table_mutex);
55
56static const struct inet_diag_handler *inet_diag_lock_handler(int type)
57{
58#ifdef CONFIG_KMOD
59 if (!inet_diag_table[type])
60 request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
61 NETLINK_INET_DIAG, type);
62#endif
63
64 mutex_lock(&inet_diag_table_mutex);
65 if (!inet_diag_table[type])
66 return ERR_PTR(-ENOENT);
67
68 return inet_diag_table[type];
69}
70
71static inline void inet_diag_unlock_handler(
72 const struct inet_diag_handler *handler)
73{
74 mutex_unlock(&inet_diag_table_mutex);
75}
76
54static int inet_csk_diag_fill(struct sock *sk, 77static int inet_csk_diag_fill(struct sock *sk,
55 struct sk_buff *skb, 78 struct sk_buff *skb,
56 int ext, u32 pid, u32 seq, u16 nlmsg_flags, 79 int ext, u32 pid, u32 seq, u16 nlmsg_flags,
@@ -235,9 +258,12 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
235 struct inet_hashinfo *hashinfo; 258 struct inet_hashinfo *hashinfo;
236 const struct inet_diag_handler *handler; 259 const struct inet_diag_handler *handler;
237 260
238 handler = inet_diag_table[nlh->nlmsg_type]; 261 handler = inet_diag_lock_handler(nlh->nlmsg_type);
239 BUG_ON(handler == NULL); 262 if (!handler)
263 return -ENOENT;
264
240 hashinfo = handler->idiag_hashinfo; 265 hashinfo = handler->idiag_hashinfo;
266 err = -EINVAL;
241 267
242 if (req->idiag_family == AF_INET) { 268 if (req->idiag_family == AF_INET) {
243 sk = inet_lookup(hashinfo, req->id.idiag_dst[0], 269 sk = inet_lookup(hashinfo, req->id.idiag_dst[0],
@@ -255,11 +281,12 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
255 } 281 }
256#endif 282#endif
257 else { 283 else {
258 return -EINVAL; 284 goto unlock;
259 } 285 }
260 286
287 err = -ENOENT;
261 if (sk == NULL) 288 if (sk == NULL)
262 return -ENOENT; 289 goto unlock;
263 290
264 err = -ESTALE; 291 err = -ESTALE;
265 if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE || 292 if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE ||
@@ -296,6 +323,8 @@ out:
296 else 323 else
297 sock_put(sk); 324 sock_put(sk);
298 } 325 }
326unlock:
327 inet_diag_unlock_handler(handler);
299 return err; 328 return err;
300} 329}
301 330
@@ -678,8 +707,10 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
678 const struct inet_diag_handler *handler; 707 const struct inet_diag_handler *handler;
679 struct inet_hashinfo *hashinfo; 708 struct inet_hashinfo *hashinfo;
680 709
681 handler = inet_diag_table[cb->nlh->nlmsg_type]; 710 handler = inet_diag_lock_handler(cb->nlh->nlmsg_type);
682 BUG_ON(handler == NULL); 711 if (!handler)
712 goto no_handler;
713
683 hashinfo = handler->idiag_hashinfo; 714 hashinfo = handler->idiag_hashinfo;
684 715
685 s_i = cb->args[1]; 716 s_i = cb->args[1];
@@ -743,7 +774,7 @@ skip_listen_ht:
743 } 774 }
744 775
745 if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV))) 776 if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
746 return skb->len; 777 goto unlock;
747 778
748 for (i = s_i; i < hashinfo->ehash_size; i++) { 779 for (i = s_i; i < hashinfo->ehash_size; i++) {
749 struct inet_ehash_bucket *head = &hashinfo->ehash[i]; 780 struct inet_ehash_bucket *head = &hashinfo->ehash[i];
@@ -805,6 +836,9 @@ next_dying:
805done: 836done:
806 cb->args[1] = i; 837 cb->args[1] = i;
807 cb->args[2] = num; 838 cb->args[2] = num;
839unlock:
840 inet_diag_unlock_handler(handler);
841no_handler:
808 return skb->len; 842 return skb->len;
809} 843}
810 844
@@ -816,15 +850,6 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
816 nlmsg_len(nlh) < hdrlen) 850 nlmsg_len(nlh) < hdrlen)
817 return -EINVAL; 851 return -EINVAL;
818 852
819#ifdef CONFIG_KMOD
820 if (inet_diag_table[nlh->nlmsg_type] == NULL)
821 request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
822 NETLINK_INET_DIAG, nlh->nlmsg_type);
823#endif
824
825 if (inet_diag_table[nlh->nlmsg_type] == NULL)
826 return -ENOENT;
827
828 if (nlh->nlmsg_flags & NLM_F_DUMP) { 853 if (nlh->nlmsg_flags & NLM_F_DUMP) {
829 if (nlmsg_attrlen(nlh, hdrlen)) { 854 if (nlmsg_attrlen(nlh, hdrlen)) {
830 struct nlattr *attr; 855 struct nlattr *attr;
@@ -861,13 +886,13 @@ int inet_diag_register(const struct inet_diag_handler *h)
861 if (type >= INET_DIAG_GETSOCK_MAX) 886 if (type >= INET_DIAG_GETSOCK_MAX)
862 goto out; 887 goto out;
863 888
864 mutex_lock(&inet_diag_mutex); 889 mutex_lock(&inet_diag_table_mutex);
865 err = -EEXIST; 890 err = -EEXIST;
866 if (inet_diag_table[type] == NULL) { 891 if (inet_diag_table[type] == NULL) {
867 inet_diag_table[type] = h; 892 inet_diag_table[type] = h;
868 err = 0; 893 err = 0;
869 } 894 }
870 mutex_unlock(&inet_diag_mutex); 895 mutex_unlock(&inet_diag_table_mutex);
871out: 896out:
872 return err; 897 return err;
873} 898}
@@ -880,9 +905,9 @@ void inet_diag_unregister(const struct inet_diag_handler *h)
880 if (type >= INET_DIAG_GETSOCK_MAX) 905 if (type >= INET_DIAG_GETSOCK_MAX)
881 return; 906 return;
882 907
883 mutex_lock(&inet_diag_mutex); 908 mutex_lock(&inet_diag_table_mutex);
884 inet_diag_table[type] = NULL; 909 inet_diag_table[type] = NULL;
885 mutex_unlock(&inet_diag_mutex); 910 mutex_unlock(&inet_diag_table_mutex);
886} 911}
887EXPORT_SYMBOL_GPL(inet_diag_unregister); 912EXPORT_SYMBOL_GPL(inet_diag_unregister);
888 913
@@ -897,7 +922,7 @@ static int __init inet_diag_init(void)
897 goto out; 922 goto out;
898 923
899 idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0, 924 idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0,
900 inet_diag_rcv, &inet_diag_mutex, THIS_MODULE); 925 inet_diag_rcv, NULL, THIS_MODULE);
901 if (idiagnl == NULL) 926 if (idiagnl == NULL)
902 goto out_free_table; 927 goto out_free_table;
903 err = 0; 928 err = 0;