Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1#include <linux/module.h>
  2
  3#include <linux/inet_diag.h>
  4#include <linux/sock_diag.h>
  5
  6#include <net/inet_sock.h>
  7#include <net/raw.h>
  8#include <net/rawv6.h>
  9
 10#ifdef pr_fmt
 11# undef pr_fmt
 12#endif
 13
 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 15
 16static struct raw_hashinfo *
 17raw_get_hashinfo(const struct inet_diag_req_v2 *r)
 18{
 19	if (r->sdiag_family == AF_INET) {
 20		return &raw_v4_hashinfo;
 21#if IS_ENABLED(CONFIG_IPV6)
 22	} else if (r->sdiag_family == AF_INET6) {
 23		return &raw_v6_hashinfo;
 24#endif
 25	} else {
 26		pr_warn_once("Unexpected inet family %d\n",
 27			     r->sdiag_family);
 28		WARN_ON_ONCE(1);
 29		return ERR_PTR(-EINVAL);
 30	}
 31}
 32
 33/*
 34 * Due to requirement of not breaking user API we can't simply
 35 * rename @pad field in inet_diag_req_v2 structure, instead
 36 * use helper to figure it out.
 37 */
 38
 39static struct sock *raw_lookup(struct net *net, struct sock *from,
 40			       const struct inet_diag_req_v2 *req)
 41{
 42	struct inet_diag_req_raw *r = (void *)req;
 43	struct sock *sk = NULL;
 44
 45	if (r->sdiag_family == AF_INET)
 46		sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol,
 47				     r->id.idiag_dst[0],
 48				     r->id.idiag_src[0],
 49				     r->id.idiag_if, 0);
 50#if IS_ENABLED(CONFIG_IPV6)
 51	else
 52		sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol,
 53				     (const struct in6_addr *)r->id.idiag_src,
 54				     (const struct in6_addr *)r->id.idiag_dst,
 55				     r->id.idiag_if, 0);
 56#endif
 57	return sk;
 58}
 59
 60static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
 61{
 62	struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
 63	struct sock *sk = NULL, *s;
 64	int slot;
 65
 66	if (IS_ERR(hashinfo))
 67		return ERR_CAST(hashinfo);
 68
 69	read_lock(&hashinfo->lock);
 70	for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
 71		sk_for_each(s, &hashinfo->ht[slot]) {
 72			sk = raw_lookup(net, s, r);
 73			if (sk) {
 74				/*
 75				 * Grab it and keep until we fill
 76				 * diag meaage to be reported, so
 77				 * caller should call sock_put then.
 78				 * We can do that because we're keeping
 79				 * hashinfo->lock here.
 80				 */
 81				sock_hold(sk);
 82				goto out_unlock;
 83			}
 84		}
 85	}
 86out_unlock:
 87	read_unlock(&hashinfo->lock);
 88
 89	return sk ? sk : ERR_PTR(-ENOENT);
 90}
 91
 92static int raw_diag_dump_one(struct sk_buff *in_skb,
 93			     const struct nlmsghdr *nlh,
 94			     const struct inet_diag_req_v2 *r)
 95{
 96	struct net *net = sock_net(in_skb->sk);
 97	struct sk_buff *rep;
 98	struct sock *sk;
 99	int err;
100
101	sk = raw_sock_get(net, r);
102	if (IS_ERR(sk))
103		return PTR_ERR(sk);
104
105	rep = nlmsg_new(sizeof(struct inet_diag_msg) +
106			sizeof(struct inet_diag_meminfo) + 64,
107			GFP_KERNEL);
108	if (!rep) {
109		sock_put(sk);
110		return -ENOMEM;
111	}
112
113	err = inet_sk_diag_fill(sk, NULL, rep, r,
114				sk_user_ns(NETLINK_CB(in_skb).sk),
115				NETLINK_CB(in_skb).portid,
116				nlh->nlmsg_seq, 0, nlh,
117				netlink_net_capable(in_skb, CAP_NET_ADMIN));
118	sock_put(sk);
119
120	if (err < 0) {
121		kfree_skb(rep);
122		return err;
123	}
124
125	err = netlink_unicast(net->diag_nlsk, rep,
126			      NETLINK_CB(in_skb).portid,
127			      MSG_DONTWAIT);
128	if (err > 0)
129		err = 0;
130	return err;
131}
132
133static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
134			struct netlink_callback *cb,
135			const struct inet_diag_req_v2 *r,
136			struct nlattr *bc, bool net_admin)
137{
138	if (!inet_diag_bc_sk(bc, sk))
139		return 0;
140
141	return inet_sk_diag_fill(sk, NULL, skb, r,
142				 sk_user_ns(NETLINK_CB(cb->skb).sk),
143				 NETLINK_CB(cb->skb).portid,
144				 cb->nlh->nlmsg_seq, NLM_F_MULTI,
145				 cb->nlh, net_admin);
146}
147
148static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
149			  const struct inet_diag_req_v2 *r, struct nlattr *bc)
150{
151	bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
152	struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
153	struct net *net = sock_net(skb->sk);
154	int num, s_num, slot, s_slot;
155	struct sock *sk = NULL;
156
157	if (IS_ERR(hashinfo))
158		return;
159
160	s_slot = cb->args[0];
161	num = s_num = cb->args[1];
162
163	read_lock(&hashinfo->lock);
164	for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) {
165		num = 0;
166
167		sk_for_each(sk, &hashinfo->ht[slot]) {
168			struct inet_sock *inet = inet_sk(sk);
169
170			if (!net_eq(sock_net(sk), net))
171				continue;
172			if (num < s_num)
173				goto next;
174			if (sk->sk_family != r->sdiag_family)
175				goto next;
176			if (r->id.idiag_sport != inet->inet_sport &&
177			    r->id.idiag_sport)
178				goto next;
179			if (r->id.idiag_dport != inet->inet_dport &&
180			    r->id.idiag_dport)
181				goto next;
182			if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0)
183				goto out_unlock;
184next:
185			num++;
186		}
187	}
188
189out_unlock:
190	read_unlock(&hashinfo->lock);
191
192	cb->args[0] = slot;
193	cb->args[1] = num;
194}
195
196static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
197			      void *info)
198{
199	r->idiag_rqueue = sk_rmem_alloc_get(sk);
200	r->idiag_wqueue = sk_wmem_alloc_get(sk);
201}
202
203#ifdef CONFIG_INET_DIAG_DESTROY
204static int raw_diag_destroy(struct sk_buff *in_skb,
205			    const struct inet_diag_req_v2 *r)
206{
207	struct net *net = sock_net(in_skb->sk);
208	struct sock *sk;
209	int err;
210
211	sk = raw_sock_get(net, r);
212	if (IS_ERR(sk))
213		return PTR_ERR(sk);
214	err = sock_diag_destroy(sk, ECONNABORTED);
215	sock_put(sk);
216	return err;
217}
218#endif
219
220static const struct inet_diag_handler raw_diag_handler = {
221	.dump			= raw_diag_dump,
222	.dump_one		= raw_diag_dump_one,
223	.idiag_get_info		= raw_diag_get_info,
224	.idiag_type		= IPPROTO_RAW,
225	.idiag_info_size	= 0,
226#ifdef CONFIG_INET_DIAG_DESTROY
227	.destroy		= raw_diag_destroy,
228#endif
229};
230
231static void __always_unused __check_inet_diag_req_raw(void)
232{
233	/*
234	 * Make sure the two structures are identical,
235	 * except the @pad field.
236	 */
237#define __offset_mismatch(m1, m2)			\
238	(offsetof(struct inet_diag_req_v2, m1) !=	\
239	 offsetof(struct inet_diag_req_raw, m2))
240
241	BUILD_BUG_ON(sizeof(struct inet_diag_req_v2) !=
242		     sizeof(struct inet_diag_req_raw));
243	BUILD_BUG_ON(__offset_mismatch(sdiag_family, sdiag_family));
244	BUILD_BUG_ON(__offset_mismatch(sdiag_protocol, sdiag_protocol));
245	BUILD_BUG_ON(__offset_mismatch(idiag_ext, idiag_ext));
246	BUILD_BUG_ON(__offset_mismatch(pad, sdiag_raw_protocol));
247	BUILD_BUG_ON(__offset_mismatch(idiag_states, idiag_states));
248	BUILD_BUG_ON(__offset_mismatch(id, id));
249#undef __offset_mismatch
250}
251
252static int __init raw_diag_init(void)
253{
254	return inet_diag_register(&raw_diag_handler);
255}
256
257static void __exit raw_diag_exit(void)
258{
259	inet_diag_unregister(&raw_diag_handler);
260}
261
262module_init(raw_diag_init);
263module_exit(raw_diag_exit);
264MODULE_LICENSE("GPL");
265MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */);
266MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */);