blob: 2c84072b1da73dbc31612bebe4b8be06eddd1e69 [file] [log] [blame]
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001/*
2 * Linux IPv6 multicast routing support for BSD pim6sd
3 * Based on net/ipv4/ipmr.c.
4 *
5 * (c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr>
6 * LSIIT Laboratory, Strasbourg, France
7 * (c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com>
8 * 6WIND, Paris, France
9 * Copyright (C)2007,2008 USAGI/WIDE Project
10 * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 *
17 */
18
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090019#include <asm/uaccess.h>
20#include <linux/types.h>
21#include <linux/sched.h>
22#include <linux/errno.h>
23#include <linux/timer.h>
24#include <linux/mm.h>
25#include <linux/kernel.h>
26#include <linux/fcntl.h>
27#include <linux/stat.h>
28#include <linux/socket.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090029#include <linux/inet.h>
30#include <linux/netdevice.h>
31#include <linux/inetdevice.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090032#include <linux/proc_fs.h>
33#include <linux/seq_file.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090034#include <linux/init.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090035#include <linux/slab.h>
David S. Millere2d57762011-02-03 17:59:32 -080036#include <linux/compat.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090037#include <net/protocol.h>
38#include <linux/skbuff.h>
39#include <net/sock.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <net/raw.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090041#include <linux/notifier.h>
42#include <linux/if_arp.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090043#include <net/checksum.h>
44#include <net/netlink.h>
Patrick McHardyd1db2752010-05-11 14:40:55 +020045#include <net/fib_rules.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090046
47#include <net/ipv6.h>
48#include <net/ip6_route.h>
49#include <linux/mroute6.h>
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +090050#include <linux/pim.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090051#include <net/addrconf.h>
52#include <linux/netfilter_ipv6.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040053#include <linux/export.h>
Dave Jones5d6e4302009-01-31 00:51:49 -080054#include <net/ip6_checksum.h>
Nicolas Dichteld67b8c62012-12-04 01:13:35 +000055#include <linux/netconf.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090056
Patrick McHardy6bd52142010-05-11 14:40:53 +020057struct mr6_table {
Patrick McHardyd1db2752010-05-11 14:40:55 +020058 struct list_head list;
Patrick McHardy6bd52142010-05-11 14:40:53 +020059#ifdef CONFIG_NET_NS
60 struct net *net;
61#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +020062 u32 id;
Patrick McHardy6bd52142010-05-11 14:40:53 +020063 struct sock *mroute6_sk;
64 struct timer_list ipmr_expire_timer;
65 struct list_head mfc6_unres_queue;
66 struct list_head mfc6_cache_array[MFC6_LINES];
67 struct mif_device vif6_table[MAXMIFS];
68 int maxvif;
69 atomic_t cache_resolve_queue_len;
Joe Perches53d68412012-11-25 09:35:30 +000070 bool mroute_do_assert;
71 bool mroute_do_pim;
Patrick McHardy6bd52142010-05-11 14:40:53 +020072#ifdef CONFIG_IPV6_PIMSM_V2
73 int mroute_reg_vif_num;
74#endif
75};
76
Patrick McHardyd1db2752010-05-11 14:40:55 +020077struct ip6mr_rule {
78 struct fib_rule common;
79};
80
81struct ip6mr_result {
82 struct mr6_table *mrt;
83};
84
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090085/* Big lock, protecting vif table, mrt cache and mroute socket state.
86 Note that the changes are semaphored via rtnl_lock.
87 */
88
89static DEFINE_RWLOCK(mrt_lock);
90
91/*
92 * Multicast router control variables
93 */
94
Patrick McHardy6bd52142010-05-11 14:40:53 +020095#define MIF_EXISTS(_mrt, _idx) ((_mrt)->vif6_table[_idx].dev != NULL)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090096
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090097/* Special spinlock for queue of unresolved entries */
98static DEFINE_SPINLOCK(mfc_unres_lock);
99
100/* We return to original Alan's scheme. Hash table of resolved
101 entries is changed only in process context and protected
102 with weak lock mrt_lock. Queue of unresolved entries is protected
103 with strong spinlock mfc_unres_lock.
104
105 In this case data path is free of exclusive locks at all.
106 */
107
108static struct kmem_cache *mrt_cachep __read_mostly;
109
Patrick McHardyd1db2752010-05-11 14:40:55 +0200110static struct mr6_table *ip6mr_new_table(struct net *net, u32 id);
111static void ip6mr_free_table(struct mr6_table *mrt);
112
Patrick McHardy6bd52142010-05-11 14:40:53 +0200113static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
114 struct sk_buff *skb, struct mfc6_cache *cache);
115static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
Benjamin Thery8229efd2008-12-10 16:30:15 -0800116 mifi_t mifi, int assert);
Patrick McHardy5b285ca2010-05-11 14:40:56 +0200117static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
118 struct mfc6_cache *c, struct rtmsg *rtm);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +0000119static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
120 int cmd);
Patrick McHardy5b285ca2010-05-11 14:40:56 +0200121static int ip6mr_rtm_dumproute(struct sk_buff *skb,
122 struct netlink_callback *cb);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200123static void mroute_clean_tables(struct mr6_table *mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200124static void ipmr_expire_process(unsigned long arg);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900125
Patrick McHardyd1db2752010-05-11 14:40:55 +0200126#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
Eric Dumazet8ffb3352010-06-06 15:34:40 -0700127#define ip6mr_for_each_table(mrt, net) \
Patrick McHardyd1db2752010-05-11 14:40:55 +0200128 list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
129
130static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
131{
132 struct mr6_table *mrt;
133
134 ip6mr_for_each_table(mrt, net) {
135 if (mrt->id == id)
136 return mrt;
137 }
138 return NULL;
139}
140
David S. Miller4c9483b2011-03-12 16:22:43 -0500141static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200142 struct mr6_table **mrt)
143{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200144 int err;
Hannes Frederic Sowad6489022014-01-13 02:45:22 +0100145 struct ip6mr_result res;
146 struct fib_lookup_arg arg = {
147 .result = &res,
148 .flags = FIB_LOOKUP_NOREF,
149 };
Patrick McHardyd1db2752010-05-11 14:40:55 +0200150
David S. Miller4c9483b2011-03-12 16:22:43 -0500151 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
152 flowi6_to_flowi(flp6), 0, &arg);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200153 if (err < 0)
154 return err;
155 *mrt = res.mrt;
156 return 0;
157}
158
159static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
160 int flags, struct fib_lookup_arg *arg)
161{
162 struct ip6mr_result *res = arg->result;
163 struct mr6_table *mrt;
164
165 switch (rule->action) {
166 case FR_ACT_TO_TBL:
167 break;
168 case FR_ACT_UNREACHABLE:
169 return -ENETUNREACH;
170 case FR_ACT_PROHIBIT:
171 return -EACCES;
172 case FR_ACT_BLACKHOLE:
173 default:
174 return -EINVAL;
175 }
176
177 mrt = ip6mr_get_table(rule->fr_net, rule->table);
178 if (mrt == NULL)
179 return -EAGAIN;
180 res->mrt = mrt;
181 return 0;
182}
183
184static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
185{
186 return 1;
187}
188
189static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
190 FRA_GENERIC_POLICY,
191};
192
193static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
194 struct fib_rule_hdr *frh, struct nlattr **tb)
195{
196 return 0;
197}
198
199static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
200 struct nlattr **tb)
201{
202 return 1;
203}
204
205static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
206 struct fib_rule_hdr *frh)
207{
208 frh->dst_len = 0;
209 frh->src_len = 0;
210 frh->tos = 0;
211 return 0;
212}
213
Andi Kleen04a6f822012-10-04 17:12:11 -0700214static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200215 .family = RTNL_FAMILY_IP6MR,
216 .rule_size = sizeof(struct ip6mr_rule),
217 .addr_size = sizeof(struct in6_addr),
218 .action = ip6mr_rule_action,
219 .match = ip6mr_rule_match,
220 .configure = ip6mr_rule_configure,
221 .compare = ip6mr_rule_compare,
222 .default_pref = fib_default_rule_pref,
223 .fill = ip6mr_rule_fill,
224 .nlgroup = RTNLGRP_IPV6_RULE,
225 .policy = ip6mr_rule_policy,
226 .owner = THIS_MODULE,
227};
228
229static int __net_init ip6mr_rules_init(struct net *net)
230{
231 struct fib_rules_ops *ops;
232 struct mr6_table *mrt;
233 int err;
234
235 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
236 if (IS_ERR(ops))
237 return PTR_ERR(ops);
238
239 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
240
241 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
242 if (mrt == NULL) {
243 err = -ENOMEM;
244 goto err1;
245 }
246
247 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
248 if (err < 0)
249 goto err2;
250
251 net->ipv6.mr6_rules_ops = ops;
252 return 0;
253
254err2:
255 kfree(mrt);
256err1:
257 fib_rules_unregister(ops);
258 return err;
259}
260
261static void __net_exit ip6mr_rules_exit(struct net *net)
262{
263 struct mr6_table *mrt, *next;
264
Hannes Frederic Sowa69af51c2013-07-22 23:45:53 +0200265 rtnl_lock();
Eric Dumazet035320d2010-06-06 23:48:40 +0000266 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
267 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200268 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000269 }
Hannes Frederic Sowa69af51c2013-07-22 23:45:53 +0200270 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200271 fib_rules_unregister(net->ipv6.mr6_rules_ops);
272}
273#else
274#define ip6mr_for_each_table(mrt, net) \
275 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
276
277static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
278{
279 return net->ipv6.mrt6;
280}
281
David S. Miller4c9483b2011-03-12 16:22:43 -0500282static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200283 struct mr6_table **mrt)
284{
285 *mrt = net->ipv6.mrt6;
286 return 0;
287}
288
289static int __net_init ip6mr_rules_init(struct net *net)
290{
291 net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
292 return net->ipv6.mrt6 ? 0 : -ENOMEM;
293}
294
295static void __net_exit ip6mr_rules_exit(struct net *net)
296{
Hannes Frederic Sowa69af51c2013-07-22 23:45:53 +0200297 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200298 ip6mr_free_table(net->ipv6.mrt6);
Hannes Frederic Sowa69af51c2013-07-22 23:45:53 +0200299 net->ipv6.mrt6 = NULL;
300 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200301}
302#endif
303
304static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
305{
306 struct mr6_table *mrt;
307 unsigned int i;
308
309 mrt = ip6mr_get_table(net, id);
310 if (mrt != NULL)
311 return mrt;
312
313 mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
314 if (mrt == NULL)
315 return NULL;
316 mrt->id = id;
317 write_pnet(&mrt->net, net);
318
319 /* Forwarding cache */
320 for (i = 0; i < MFC6_LINES; i++)
321 INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
322
323 INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
324
325 setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
326 (unsigned long)mrt);
327
328#ifdef CONFIG_IPV6_PIMSM_V2
329 mrt->mroute_reg_vif_num = -1;
330#endif
331#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
332 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
333#endif
334 return mrt;
335}
336
337static void ip6mr_free_table(struct mr6_table *mrt)
338{
339 del_timer(&mrt->ipmr_expire_timer);
340 mroute_clean_tables(mrt);
341 kfree(mrt);
342}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900343
344#ifdef CONFIG_PROC_FS
345
346struct ipmr_mfc_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800347 struct seq_net_private p;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200348 struct mr6_table *mrt;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200349 struct list_head *cache;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900350 int ct;
351};
352
353
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800354static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
355 struct ipmr_mfc_iter *it, loff_t pos)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900356{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200357 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900358 struct mfc6_cache *mfc;
359
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900360 read_lock(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200361 for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200362 it->cache = &mrt->mfc6_cache_array[it->ct];
Patrick McHardyf30a77842010-05-11 14:40:51 +0200363 list_for_each_entry(mfc, it->cache, list)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900364 if (pos-- == 0)
365 return mfc;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200366 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900367 read_unlock(&mrt_lock);
368
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900369 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200370 it->cache = &mrt->mfc6_unres_queue;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200371 list_for_each_entry(mfc, it->cache, list)
Patrick McHardyc476efb2010-05-11 14:40:48 +0200372 if (pos-- == 0)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900373 return mfc;
374 spin_unlock_bh(&mfc_unres_lock);
375
376 it->cache = NULL;
377 return NULL;
378}
379
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900380/*
381 * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
382 */
383
384struct ipmr_vif_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800385 struct seq_net_private p;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200386 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900387 int ct;
388};
389
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800390static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
391 struct ipmr_vif_iter *iter,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900392 loff_t pos)
393{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200394 struct mr6_table *mrt = iter->mrt;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200395
396 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
397 if (!MIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900398 continue;
399 if (pos-- == 0)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200400 return &mrt->vif6_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900401 }
402 return NULL;
403}
404
405static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
406 __acquires(mrt_lock)
407{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200408 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800409 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200410 struct mr6_table *mrt;
411
412 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
413 if (mrt == NULL)
414 return ERR_PTR(-ENOENT);
415
416 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800417
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900418 read_lock(&mrt_lock);
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800419 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
420 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900421}
422
423static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
424{
425 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800426 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200427 struct mr6_table *mrt = iter->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900428
429 ++*pos;
430 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800431 return ip6mr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900432
Patrick McHardy6bd52142010-05-11 14:40:53 +0200433 while (++iter->ct < mrt->maxvif) {
434 if (!MIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900435 continue;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200436 return &mrt->vif6_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900437 }
438 return NULL;
439}
440
441static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
442 __releases(mrt_lock)
443{
444 read_unlock(&mrt_lock);
445}
446
447static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
448{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200449 struct ipmr_vif_iter *iter = seq->private;
450 struct mr6_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800451
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900452 if (v == SEQ_START_TOKEN) {
453 seq_puts(seq,
454 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
455 } else {
456 const struct mif_device *vif = v;
457 const char *name = vif->dev ? vif->dev->name : "none";
458
459 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100460 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Patrick McHardy6bd52142010-05-11 14:40:53 +0200461 vif - mrt->vif6_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900462 name, vif->bytes_in, vif->pkt_in,
463 vif->bytes_out, vif->pkt_out,
464 vif->flags);
465 }
466 return 0;
467}
468
Stephen Hemminger98147d52009-09-01 19:25:02 +0000469static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900470 .start = ip6mr_vif_seq_start,
471 .next = ip6mr_vif_seq_next,
472 .stop = ip6mr_vif_seq_stop,
473 .show = ip6mr_vif_seq_show,
474};
475
476static int ip6mr_vif_open(struct inode *inode, struct file *file)
477{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800478 return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
479 sizeof(struct ipmr_vif_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900480}
481
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000482static const struct file_operations ip6mr_vif_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900483 .owner = THIS_MODULE,
484 .open = ip6mr_vif_open,
485 .read = seq_read,
486 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800487 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900488};
489
490static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
491{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200492 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800493 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200494 struct mr6_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800495
Patrick McHardyd1db2752010-05-11 14:40:55 +0200496 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
497 if (mrt == NULL)
498 return ERR_PTR(-ENOENT);
499
500 it->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800501 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
502 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900503}
504
505static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
506{
507 struct mfc6_cache *mfc = v;
508 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800509 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200510 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900511
512 ++*pos;
513
514 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800515 return ipmr_mfc_seq_idx(net, seq->private, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900516
Patrick McHardyf30a77842010-05-11 14:40:51 +0200517 if (mfc->list.next != it->cache)
518 return list_entry(mfc->list.next, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900519
Patrick McHardy6bd52142010-05-11 14:40:53 +0200520 if (it->cache == &mrt->mfc6_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900521 goto end_of_list;
522
Patrick McHardy6bd52142010-05-11 14:40:53 +0200523 BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900524
Benjamin Thery4a6258a2008-12-10 16:24:07 -0800525 while (++it->ct < MFC6_LINES) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200526 it->cache = &mrt->mfc6_cache_array[it->ct];
Patrick McHardyf30a77842010-05-11 14:40:51 +0200527 if (list_empty(it->cache))
528 continue;
529 return list_first_entry(it->cache, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900530 }
531
532 /* exhausted cache_array, show unresolved */
533 read_unlock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200534 it->cache = &mrt->mfc6_unres_queue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900535 it->ct = 0;
536
537 spin_lock_bh(&mfc_unres_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200538 if (!list_empty(it->cache))
539 return list_first_entry(it->cache, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900540
541 end_of_list:
542 spin_unlock_bh(&mfc_unres_lock);
543 it->cache = NULL;
544
545 return NULL;
546}
547
548static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
549{
550 struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200551 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900552
Patrick McHardy6bd52142010-05-11 14:40:53 +0200553 if (it->cache == &mrt->mfc6_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900554 spin_unlock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200555 else if (it->cache == mrt->mfc6_cache_array)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900556 read_unlock(&mrt_lock);
557}
558
559static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
560{
561 int n;
562
563 if (v == SEQ_START_TOKEN) {
564 seq_puts(seq,
565 "Group "
566 "Origin "
567 "Iif Pkts Bytes Wrong Oifs\n");
568 } else {
569 const struct mfc6_cache *mfc = v;
570 const struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200571 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900572
Benjamin Thery999890b2008-12-03 22:22:16 -0800573 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700574 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800575 mfc->mf6c_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900576
Patrick McHardy6bd52142010-05-11 14:40:53 +0200577 if (it->cache != &mrt->mfc6_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800578 seq_printf(seq, " %8lu %8lu %8lu",
579 mfc->mfc_un.res.pkt,
580 mfc->mfc_un.res.bytes,
581 mfc->mfc_un.res.wrong_if);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900582 for (n = mfc->mfc_un.res.minvif;
583 n < mfc->mfc_un.res.maxvif; n++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200584 if (MIF_EXISTS(mrt, n) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900585 mfc->mfc_un.res.ttls[n] < 255)
586 seq_printf(seq,
587 " %2d:%-3d",
588 n, mfc->mfc_un.res.ttls[n]);
589 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800590 } else {
591 /* unresolved mfc_caches don't contain
592 * pkt, bytes and wrong_if values
593 */
594 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900595 }
596 seq_putc(seq, '\n');
597 }
598 return 0;
599}
600
James Morris88e9d342009-09-22 16:43:43 -0700601static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900602 .start = ipmr_mfc_seq_start,
603 .next = ipmr_mfc_seq_next,
604 .stop = ipmr_mfc_seq_stop,
605 .show = ipmr_mfc_seq_show,
606};
607
608static int ipmr_mfc_open(struct inode *inode, struct file *file)
609{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800610 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
611 sizeof(struct ipmr_mfc_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900612}
613
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000614static const struct file_operations ip6mr_mfc_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900615 .owner = THIS_MODULE,
616 .open = ipmr_mfc_open,
617 .read = seq_read,
618 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800619 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900620};
621#endif
622
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900623#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900624
625static int pim6_rcv(struct sk_buff *skb)
626{
627 struct pimreghdr *pim;
628 struct ipv6hdr *encap;
629 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800630 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200631 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500632 struct flowi6 fl6 = {
633 .flowi6_iif = skb->dev->ifindex,
634 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200635 };
636 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900637
638 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
639 goto drop;
640
641 pim = (struct pimreghdr *)skb_transport_header(skb);
642 if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
643 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800644 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
645 sizeof(*pim), IPPROTO_PIM,
646 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700647 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900648 goto drop;
649
650 /* check if the inner packet is destined to mcast group */
651 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
652 sizeof(*pim));
653
654 if (!ipv6_addr_is_multicast(&encap->daddr) ||
655 encap->payload_len == 0 ||
656 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
657 goto drop;
658
David S. Miller4c9483b2011-03-12 16:22:43 -0500659 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200660 goto drop;
661 reg_vif_num = mrt->mroute_reg_vif_num;
662
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900663 read_lock(&mrt_lock);
664 if (reg_vif_num >= 0)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200665 reg_dev = mrt->vif6_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900666 if (reg_dev)
667 dev_hold(reg_dev);
668 read_unlock(&mrt_lock);
669
670 if (reg_dev == NULL)
671 goto drop;
672
673 skb->mac_header = skb->network_header;
674 skb_pull(skb, (u8 *)encap - skb->data);
675 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800676 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000677 skb->ip_summed = CHECKSUM_NONE;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900678 skb->pkt_type = PACKET_HOST;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700679
680 skb_tunnel_rx(skb, reg_dev);
681
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000682 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000683
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900684 dev_put(reg_dev);
685 return 0;
686 drop:
687 kfree_skb(skb);
688 return 0;
689}
690
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000691static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900692 .handler = pim6_rcv,
693};
694
695/* Service routines creating virtual interfaces: PIMREG */
696
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000697static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
698 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900699{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800700 struct net *net = dev_net(dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200701 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500702 struct flowi6 fl6 = {
703 .flowi6_oif = dev->ifindex,
704 .flowi6_iif = skb->skb_iif,
705 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200706 };
707 int err;
708
David S. Miller4c9483b2011-03-12 16:22:43 -0500709 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000710 if (err < 0) {
711 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200712 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000713 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800714
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900715 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700716 dev->stats.tx_bytes += skb->len;
717 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200718 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900719 read_unlock(&mrt_lock);
720 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000721 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900722}
723
Stephen Hemminger007c3832008-11-20 20:28:35 -0800724static const struct net_device_ops reg_vif_netdev_ops = {
725 .ndo_start_xmit = reg_vif_xmit,
726};
727
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900728static void reg_vif_setup(struct net_device *dev)
729{
730 dev->type = ARPHRD_PIMREG;
731 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
732 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800733 dev->netdev_ops = &reg_vif_netdev_ops;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900734 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700735 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900736}
737
Patrick McHardyd1db2752010-05-11 14:40:55 +0200738static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900739{
740 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200741 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900742
Patrick McHardyd1db2752010-05-11 14:40:55 +0200743 if (mrt->id == RT6_TABLE_DFLT)
744 sprintf(name, "pim6reg");
745 else
746 sprintf(name, "pim6reg%u", mrt->id);
747
748 dev = alloc_netdev(0, name, reg_vif_setup);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900749 if (dev == NULL)
750 return NULL;
751
Benjamin Thery8229efd2008-12-10 16:30:15 -0800752 dev_net_set(dev, net);
753
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900754 if (register_netdevice(dev)) {
755 free_netdev(dev);
756 return NULL;
757 }
758 dev->iflink = 0;
759
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900760 if (dev_open(dev))
761 goto failure;
762
Wang Chen7af3db72008-07-14 20:54:54 -0700763 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900764 return dev;
765
766failure:
767 /* allow the register to be completed before unregistering. */
768 rtnl_unlock();
769 rtnl_lock();
770
771 unregister_netdevice(dev);
772 return NULL;
773}
774#endif
775
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900776/*
777 * Delete a VIF entry
778 */
779
Patrick McHardy6bd52142010-05-11 14:40:53 +0200780static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900781{
782 struct mif_device *v;
783 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800784 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200785
786 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900787 return -EADDRNOTAVAIL;
788
Patrick McHardy6bd52142010-05-11 14:40:53 +0200789 v = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900790
791 write_lock_bh(&mrt_lock);
792 dev = v->dev;
793 v->dev = NULL;
794
795 if (!dev) {
796 write_unlock_bh(&mrt_lock);
797 return -EADDRNOTAVAIL;
798 }
799
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900800#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200801 if (vifi == mrt->mroute_reg_vif_num)
802 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900803#endif
804
Patrick McHardy6bd52142010-05-11 14:40:53 +0200805 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900806 int tmp;
807 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200808 if (MIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900809 break;
810 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200811 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900812 }
813
814 write_unlock_bh(&mrt_lock);
815
816 dev_set_allmulti(dev, -1);
817
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800818 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000819 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800820 in6_dev->cnf.mc_forwarding--;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000821 inet6_netconf_notify_devconf(dev_net(dev),
822 NETCONFA_MC_FORWARDING,
823 dev->ifindex, &in6_dev->cnf);
824 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800825
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900826 if (v->flags & MIFF_REGISTER)
Eric Dumazetc871e662009-10-28 04:48:11 +0000827 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900828
829 dev_put(dev);
830 return 0;
831}
832
Benjamin Thery58701ad2008-12-10 16:22:34 -0800833static inline void ip6mr_cache_free(struct mfc6_cache *c)
834{
Benjamin Thery58701ad2008-12-10 16:22:34 -0800835 kmem_cache_free(mrt_cachep, c);
836}
837
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900838/* Destroy an unresolved cache entry, killing queued skbs
839 and reporting error to netlink readers.
840 */
841
Patrick McHardy6bd52142010-05-11 14:40:53 +0200842static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900843{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200844 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900845 struct sk_buff *skb;
846
Patrick McHardy6bd52142010-05-11 14:40:53 +0200847 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900848
849 while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
850 if (ipv6_hdr(skb)->version == 0) {
851 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
852 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000853 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900854 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000855 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000856 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900857 } else
858 kfree_skb(skb);
859 }
860
Benjamin Thery58701ad2008-12-10 16:22:34 -0800861 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900862}
863
864
Patrick McHardyc476efb2010-05-11 14:40:48 +0200865/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900866
Patrick McHardy6bd52142010-05-11 14:40:53 +0200867static void ipmr_do_expire_process(struct mr6_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900868{
869 unsigned long now = jiffies;
870 unsigned long expires = 10 * HZ;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200871 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900872
Patrick McHardy6bd52142010-05-11 14:40:53 +0200873 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900874 if (time_after(c->mfc_un.unres.expires, now)) {
875 /* not yet... */
876 unsigned long interval = c->mfc_un.unres.expires - now;
877 if (interval < expires)
878 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900879 continue;
880 }
881
Patrick McHardyf30a77842010-05-11 14:40:51 +0200882 list_del(&c->list);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +0000883 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200884 ip6mr_destroy_unres(mrt, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900885 }
886
Patrick McHardy6bd52142010-05-11 14:40:53 +0200887 if (!list_empty(&mrt->mfc6_unres_queue))
888 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900889}
890
Patrick McHardyc476efb2010-05-11 14:40:48 +0200891static void ipmr_expire_process(unsigned long arg)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900892{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200893 struct mr6_table *mrt = (struct mr6_table *)arg;
Patrick McHardyc476efb2010-05-11 14:40:48 +0200894
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900895 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200896 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900897 return;
898 }
899
Patrick McHardy6bd52142010-05-11 14:40:53 +0200900 if (!list_empty(&mrt->mfc6_unres_queue))
901 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900902
903 spin_unlock(&mfc_unres_lock);
904}
905
906/* Fill oifs list. It is called under write locked mrt_lock. */
907
Patrick McHardy6bd52142010-05-11 14:40:53 +0200908static void ip6mr_update_thresholds(struct mr6_table *mrt, struct mfc6_cache *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200909 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900910{
911 int vifi;
912
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300913 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900914 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300915 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900916
Patrick McHardy6bd52142010-05-11 14:40:53 +0200917 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
918 if (MIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800919 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900920 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
921 if (cache->mfc_un.res.minvif > vifi)
922 cache->mfc_un.res.minvif = vifi;
923 if (cache->mfc_un.res.maxvif <= vifi)
924 cache->mfc_un.res.maxvif = vifi + 1;
925 }
926 }
927}
928
Patrick McHardy6bd52142010-05-11 14:40:53 +0200929static int mif6_add(struct net *net, struct mr6_table *mrt,
930 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900931{
932 int vifi = vifc->mif6c_mifi;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200933 struct mif_device *v = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900934 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800935 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700936 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900937
938 /* Is vif busy ? */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200939 if (MIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900940 return -EADDRINUSE;
941
942 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900943#ifdef CONFIG_IPV6_PIMSM_V2
944 case MIFF_REGISTER:
945 /*
946 * Special Purpose VIF in PIM
947 * All the packets will be sent to the daemon
948 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200949 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900950 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200951 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900952 if (!dev)
953 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700954 err = dev_set_allmulti(dev, 1);
955 if (err) {
956 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700957 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700958 return err;
959 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900960 break;
961#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900962 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800963 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900964 if (!dev)
965 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700966 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700967 if (err) {
968 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700969 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700970 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900971 break;
972 default:
973 return -EINVAL;
974 }
975
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800976 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000977 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800978 in6_dev->cnf.mc_forwarding++;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000979 inet6_netconf_notify_devconf(dev_net(dev),
980 NETCONFA_MC_FORWARDING,
981 dev->ifindex, &in6_dev->cnf);
982 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800983
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900984 /*
985 * Fill in the VIF structures
986 */
987 v->rate_limit = vifc->vifc_rate_limit;
988 v->flags = vifc->mif6c_flags;
989 if (!mrtsock)
990 v->flags |= VIFF_STATIC;
991 v->threshold = vifc->vifc_threshold;
992 v->bytes_in = 0;
993 v->bytes_out = 0;
994 v->pkt_in = 0;
995 v->pkt_out = 0;
996 v->link = dev->ifindex;
997 if (v->flags & MIFF_REGISTER)
998 v->link = dev->iflink;
999
1000 /* And finish update writing critical data */
1001 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001002 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001003#ifdef CONFIG_IPV6_PIMSM_V2
1004 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001005 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001006#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001007 if (vifi + 1 > mrt->maxvif)
1008 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001009 write_unlock_bh(&mrt_lock);
1010 return 0;
1011}
1012
Patrick McHardy6bd52142010-05-11 14:40:53 +02001013static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001014 const struct in6_addr *origin,
1015 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001016{
1017 int line = MFC6_HASH(mcastgrp, origin);
1018 struct mfc6_cache *c;
1019
Patrick McHardy6bd52142010-05-11 14:40:53 +02001020 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001021 if (ipv6_addr_equal(&c->mf6c_origin, origin) &&
1022 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp))
Patrick McHardyf30a77842010-05-11 14:40:51 +02001023 return c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001024 }
Patrick McHardyf30a77842010-05-11 14:40:51 +02001025 return NULL;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001026}
1027
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001028/* Look for a (*,*,oif) entry */
1029static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt,
1030 mifi_t mifi)
1031{
1032 int line = MFC6_HASH(&in6addr_any, &in6addr_any);
1033 struct mfc6_cache *c;
1034
1035 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1036 if (ipv6_addr_any(&c->mf6c_origin) &&
1037 ipv6_addr_any(&c->mf6c_mcastgrp) &&
1038 (c->mfc_un.res.ttls[mifi] < 255))
1039 return c;
1040
1041 return NULL;
1042}
1043
1044/* Look for a (*,G) entry */
1045static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt,
1046 struct in6_addr *mcastgrp,
1047 mifi_t mifi)
1048{
1049 int line = MFC6_HASH(mcastgrp, &in6addr_any);
1050 struct mfc6_cache *c, *proxy;
1051
1052 if (ipv6_addr_any(mcastgrp))
1053 goto skip;
1054
1055 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1056 if (ipv6_addr_any(&c->mf6c_origin) &&
1057 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) {
1058 if (c->mfc_un.res.ttls[mifi] < 255)
1059 return c;
1060
1061 /* It's ok if the mifi is part of the static tree */
1062 proxy = ip6mr_cache_find_any_parent(mrt,
1063 c->mf6c_parent);
1064 if (proxy && proxy->mfc_un.res.ttls[mifi] < 255)
1065 return c;
1066 }
1067
1068skip:
1069 return ip6mr_cache_find_any_parent(mrt, mifi);
1070}
1071
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001072/*
1073 * Allocate a multicast cache entry
1074 */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001075static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001076{
Joe Perches36cbac52008-12-03 22:27:25 -08001077 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001078 if (c == NULL)
1079 return NULL;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001080 c->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001081 return c;
1082}
1083
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001084static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001085{
Joe Perches36cbac52008-12-03 22:27:25 -08001086 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001087 if (c == NULL)
1088 return NULL;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001089 skb_queue_head_init(&c->mfc_un.unres.unresolved);
1090 c->mfc_un.unres.expires = jiffies + 10 * HZ;
1091 return c;
1092}
1093
1094/*
1095 * A cache entry has gone into a resolved state from queued
1096 */
1097
Patrick McHardy6bd52142010-05-11 14:40:53 +02001098static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
1099 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001100{
1101 struct sk_buff *skb;
1102
1103 /*
1104 * Play the pending entries through our router
1105 */
1106
1107 while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
1108 if (ipv6_hdr(skb)->version == 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001109 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
1110
Hong zhi guo573ce262013-03-27 06:47:04 +00001111 if (__ip6mr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001112 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001113 } else {
1114 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +00001115 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001116 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +00001117 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001118 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001119 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001120 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001121 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001122 }
1123}
1124
1125/*
1126 * Bounce a cache query up to pim6sd. We could use netlink for this but pim6sd
1127 * expects the following bizarre scheme.
1128 *
1129 * Called under mrt_lock.
1130 */
1131
Patrick McHardy6bd52142010-05-11 14:40:53 +02001132static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
1133 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001134{
1135 struct sk_buff *skb;
1136 struct mrt6msg *msg;
1137 int ret;
1138
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001139#ifdef CONFIG_IPV6_PIMSM_V2
1140 if (assert == MRT6MSG_WHOLEPKT)
1141 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1142 +sizeof(*msg));
1143 else
1144#endif
1145 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001146
1147 if (!skb)
1148 return -ENOBUFS;
1149
1150 /* I suppose that internal messages
1151 * do not require checksums */
1152
1153 skb->ip_summed = CHECKSUM_UNNECESSARY;
1154
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001155#ifdef CONFIG_IPV6_PIMSM_V2
1156 if (assert == MRT6MSG_WHOLEPKT) {
1157 /* Ugly, but we have no choice with this interface.
1158 Duplicate old header, fix length etc.
1159 And all this only to mangle msg->im6_msgtype and
1160 to set msg->im6_mbz to "mbz" :-)
1161 */
1162 skb_push(skb, -skb_network_offset(pkt));
1163
1164 skb_push(skb, sizeof(*msg));
1165 skb_reset_transport_header(skb);
1166 msg = (struct mrt6msg *)skb_transport_header(skb);
1167 msg->im6_mbz = 0;
1168 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001169 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001170 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001171 msg->im6_src = ipv6_hdr(pkt)->saddr;
1172 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001173
1174 skb->ip_summed = CHECKSUM_UNNECESSARY;
1175 } else
1176#endif
1177 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001178 /*
1179 * Copy the IP header
1180 */
1181
1182 skb_put(skb, sizeof(struct ipv6hdr));
1183 skb_reset_network_header(skb);
1184 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1185
1186 /*
1187 * Add our header
1188 */
1189 skb_put(skb, sizeof(*msg));
1190 skb_reset_transport_header(skb);
1191 msg = (struct mrt6msg *)skb_transport_header(skb);
1192
1193 msg->im6_mbz = 0;
1194 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001195 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001196 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001197 msg->im6_src = ipv6_hdr(pkt)->saddr;
1198 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001199
Eric Dumazetadf30902009-06-02 05:19:30 +00001200 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001201 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001202 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001203
Patrick McHardy6bd52142010-05-11 14:40:53 +02001204 if (mrt->mroute6_sk == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001205 kfree_skb(skb);
1206 return -EINVAL;
1207 }
1208
1209 /*
1210 * Deliver to user space multicast routing algorithms
1211 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001212 ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001213 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001214 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001215 kfree_skb(skb);
1216 }
1217
1218 return ret;
1219}
1220
1221/*
1222 * Queue a packet for resolution. It gets locked cache entry!
1223 */
1224
1225static int
Patrick McHardy6bd52142010-05-11 14:40:53 +02001226ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001227{
Patrick McHardyf30a77842010-05-11 14:40:51 +02001228 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001229 int err;
1230 struct mfc6_cache *c;
1231
1232 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001233 list_for_each_entry(c, &mrt->mfc6_unres_queue, list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001234 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001235 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1236 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001237 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001238 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001239 }
1240
Patrick McHardyf30a77842010-05-11 14:40:51 +02001241 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001242 /*
1243 * Create a new entry if allowable
1244 */
1245
Patrick McHardy6bd52142010-05-11 14:40:53 +02001246 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001247 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001248 spin_unlock_bh(&mfc_unres_lock);
1249
1250 kfree_skb(skb);
1251 return -ENOBUFS;
1252 }
1253
1254 /*
1255 * Fill in the new cache entry
1256 */
1257 c->mf6c_parent = -1;
1258 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1259 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1260
1261 /*
1262 * Reflect first query at pim6sd
1263 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001264 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001265 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001266 /* If the report failed throw the cache entry
1267 out - Brad Parker
1268 */
1269 spin_unlock_bh(&mfc_unres_lock);
1270
Benjamin Thery58701ad2008-12-10 16:22:34 -08001271 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001272 kfree_skb(skb);
1273 return err;
1274 }
1275
Patrick McHardy6bd52142010-05-11 14:40:53 +02001276 atomic_inc(&mrt->cache_resolve_queue_len);
1277 list_add(&c->list, &mrt->mfc6_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001278 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001279
Patrick McHardy6bd52142010-05-11 14:40:53 +02001280 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001281 }
1282
1283 /*
1284 * See if we can append the packet
1285 */
1286 if (c->mfc_un.unres.unresolved.qlen > 3) {
1287 kfree_skb(skb);
1288 err = -ENOBUFS;
1289 } else {
1290 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
1291 err = 0;
1292 }
1293
1294 spin_unlock_bh(&mfc_unres_lock);
1295 return err;
1296}
1297
1298/*
1299 * MFC6 cache manipulation by user space
1300 */
1301
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001302static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
1303 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001304{
1305 int line;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001306 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001307
1308 line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
1309
Patrick McHardy6bd52142010-05-11 14:40:53 +02001310 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001311 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001312 ipv6_addr_equal(&c->mf6c_mcastgrp,
1313 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1314 (parent == -1 || parent == c->mf6c_parent)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001315 write_lock_bh(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001316 list_del(&c->list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001317 write_unlock_bh(&mrt_lock);
1318
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001319 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001320 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001321 return 0;
1322 }
1323 }
1324 return -ENOENT;
1325}
1326
1327static int ip6mr_device_event(struct notifier_block *this,
1328 unsigned long event, void *ptr)
1329{
1330 struct net_device *dev = ptr;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001331 struct net *net = dev_net(dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001332 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001333 struct mif_device *v;
1334 int ct;
Eric Dumazetc871e662009-10-28 04:48:11 +00001335 LIST_HEAD(list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001336
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001337 if (event != NETDEV_UNREGISTER)
1338 return NOTIFY_DONE;
1339
Patrick McHardyd1db2752010-05-11 14:40:55 +02001340 ip6mr_for_each_table(mrt, net) {
1341 v = &mrt->vif6_table[0];
1342 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1343 if (v->dev == dev)
1344 mif6_delete(mrt, ct, &list);
1345 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001346 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001347 unregister_netdevice_many(&list);
1348
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001349 return NOTIFY_DONE;
1350}
1351
1352static struct notifier_block ip6_mr_notifier = {
1353 .notifier_call = ip6mr_device_event
1354};
1355
1356/*
1357 * Setup for IP multicast routing
1358 */
1359
Benjamin Thery4e168802008-12-10 16:15:08 -08001360static int __net_init ip6mr_net_init(struct net *net)
1361{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001362 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001363
Patrick McHardyd1db2752010-05-11 14:40:55 +02001364 err = ip6mr_rules_init(net);
1365 if (err < 0)
Benjamin Thery4e168802008-12-10 16:15:08 -08001366 goto fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001367
1368#ifdef CONFIG_PROC_FS
1369 err = -ENOMEM;
Gao fengd4beaa62013-02-18 01:34:54 +00001370 if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001371 goto proc_vif_fail;
Gao fengd4beaa62013-02-18 01:34:54 +00001372 if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001373 goto proc_cache_fail;
1374#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001375
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001376 return 0;
1377
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001378#ifdef CONFIG_PROC_FS
1379proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001380 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001381proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001382 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001383#endif
Benjamin Thery4e168802008-12-10 16:15:08 -08001384fail:
1385 return err;
1386}
1387
1388static void __net_exit ip6mr_net_exit(struct net *net)
1389{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001390#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001391 remove_proc_entry("ip6_mr_cache", net->proc_net);
1392 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001393#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001394 ip6mr_rules_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001395}
1396
1397static struct pernet_operations ip6mr_net_ops = {
1398 .init = ip6mr_net_init,
1399 .exit = ip6mr_net_exit,
1400};
1401
Wang Chen623d1a12008-07-03 12:13:30 +08001402int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001403{
Wang Chen623d1a12008-07-03 12:13:30 +08001404 int err;
1405
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001406 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1407 sizeof(struct mfc6_cache),
1408 0, SLAB_HWCACHE_ALIGN,
1409 NULL);
1410 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001411 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001412
Benjamin Thery4e168802008-12-10 16:15:08 -08001413 err = register_pernet_subsys(&ip6mr_net_ops);
1414 if (err)
1415 goto reg_pernet_fail;
1416
Wang Chen623d1a12008-07-03 12:13:30 +08001417 err = register_netdevice_notifier(&ip6_mr_notifier);
1418 if (err)
1419 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001420#ifdef CONFIG_IPV6_PIMSM_V2
1421 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001422 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001423 err = -EAGAIN;
1424 goto add_proto_fail;
1425 }
1426#endif
Greg Rosec7ac8672011-06-10 01:27:09 +00001427 rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL,
1428 ip6mr_rtm_dumproute, NULL);
Wang Chen623d1a12008-07-03 12:13:30 +08001429 return 0;
Tom Goff403dbb92009-06-14 03:16:13 -07001430#ifdef CONFIG_IPV6_PIMSM_V2
1431add_proto_fail:
1432 unregister_netdevice_notifier(&ip6_mr_notifier);
1433#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001434reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001435 unregister_pernet_subsys(&ip6mr_net_ops);
1436reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001437 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001438 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001439}
1440
Wang Chen623d1a12008-07-03 12:13:30 +08001441void ip6_mr_cleanup(void)
1442{
Wang Chen623d1a12008-07-03 12:13:30 +08001443 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001444 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001445 kmem_cache_destroy(mrt_cachep);
1446}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001447
Patrick McHardy6bd52142010-05-11 14:40:53 +02001448static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001449 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001450{
Patrick McHardyf30a77842010-05-11 14:40:51 +02001451 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001452 int line;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001453 struct mfc6_cache *uc, *c;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001454 unsigned char ttls[MAXMIFS];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001455 int i;
1456
Patrick McHardya50436f22010-03-17 06:04:14 +00001457 if (mfc->mf6cc_parent >= MAXMIFS)
1458 return -ENFILE;
1459
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001460 memset(ttls, 255, MAXMIFS);
1461 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001462 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1463 ttls[i] = 1;
1464
1465 }
1466
1467 line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
1468
Patrick McHardy6bd52142010-05-11 14:40:53 +02001469 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001470 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001471 ipv6_addr_equal(&c->mf6c_mcastgrp,
1472 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1473 (parent == -1 || parent == mfc->mf6cc_parent)) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001474 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001475 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001476 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001477 }
1478
Patrick McHardyf30a77842010-05-11 14:40:51 +02001479 if (found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001480 write_lock_bh(&mrt_lock);
1481 c->mf6c_parent = mfc->mf6cc_parent;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001482 ip6mr_update_thresholds(mrt, c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001483 if (!mrtsock)
1484 c->mfc_flags |= MFC_STATIC;
1485 write_unlock_bh(&mrt_lock);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001486 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001487 return 0;
1488 }
1489
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001490 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1491 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001492 return -EINVAL;
1493
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001494 c = ip6mr_cache_alloc();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001495 if (c == NULL)
1496 return -ENOMEM;
1497
1498 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1499 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
1500 c->mf6c_parent = mfc->mf6cc_parent;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001501 ip6mr_update_thresholds(mrt, c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001502 if (!mrtsock)
1503 c->mfc_flags |= MFC_STATIC;
1504
1505 write_lock_bh(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001506 list_add(&c->list, &mrt->mfc6_cache_array[line]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001507 write_unlock_bh(&mrt_lock);
1508
1509 /*
1510 * Check to see if we resolved a queued list. If so we
1511 * need to send on the frames and tidy up.
1512 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001513 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001514 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001515 list_for_each_entry(uc, &mrt->mfc6_unres_queue, list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001516 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001517 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001518 list_del(&uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001519 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001520 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001521 break;
1522 }
1523 }
Patrick McHardy6bd52142010-05-11 14:40:53 +02001524 if (list_empty(&mrt->mfc6_unres_queue))
1525 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001526 spin_unlock_bh(&mfc_unres_lock);
1527
Patrick McHardyf30a77842010-05-11 14:40:51 +02001528 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001529 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001530 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001531 }
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001532 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001533 return 0;
1534}
1535
1536/*
1537 * Close the multicast socket, and clear the vif tables etc
1538 */
1539
Patrick McHardy6bd52142010-05-11 14:40:53 +02001540static void mroute_clean_tables(struct mr6_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001541{
1542 int i;
Eric Dumazetc871e662009-10-28 04:48:11 +00001543 LIST_HEAD(list);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001544 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001545
1546 /*
1547 * Shut down all active vif entries
1548 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001549 for (i = 0; i < mrt->maxvif; i++) {
1550 if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
1551 mif6_delete(mrt, i, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001552 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001553 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001554
1555 /*
1556 * Wipe the cache
1557 */
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001558 for (i = 0; i < MFC6_LINES; i++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001559 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001560 if (c->mfc_flags & MFC_STATIC)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001561 continue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001562 write_lock_bh(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001563 list_del(&c->list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001564 write_unlock_bh(&mrt_lock);
1565
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001566 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001567 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001568 }
1569 }
1570
Patrick McHardy6bd52142010-05-11 14:40:53 +02001571 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001572 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001573 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001574 list_del(&c->list);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001575 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001576 ip6mr_destroy_unres(mrt, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001577 }
1578 spin_unlock_bh(&mfc_unres_lock);
1579 }
1580}
1581
Patrick McHardy6bd52142010-05-11 14:40:53 +02001582static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001583{
1584 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001585 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001586
1587 rtnl_lock();
1588 write_lock_bh(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001589 if (likely(mrt->mroute6_sk == NULL)) {
1590 mrt->mroute6_sk = sk;
Thomas Goff1d6e55f2009-01-27 22:39:59 -08001591 net->ipv6.devconf_all->mc_forwarding++;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001592 inet6_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
1593 NETCONFA_IFINDEX_ALL,
1594 net->ipv6.devconf_all);
Thomas Goff1d6e55f2009-01-27 22:39:59 -08001595 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001596 else
1597 err = -EADDRINUSE;
1598 write_unlock_bh(&mrt_lock);
1599
1600 rtnl_unlock();
1601
1602 return err;
1603}
1604
1605int ip6mr_sk_done(struct sock *sk)
1606{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001607 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001608 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001609 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001610
1611 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001612 ip6mr_for_each_table(mrt, net) {
1613 if (sk == mrt->mroute6_sk) {
1614 write_lock_bh(&mrt_lock);
1615 mrt->mroute6_sk = NULL;
1616 net->ipv6.devconf_all->mc_forwarding--;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001617 inet6_netconf_notify_devconf(net,
1618 NETCONFA_MC_FORWARDING,
1619 NETCONFA_IFINDEX_ALL,
1620 net->ipv6.devconf_all);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001621 write_unlock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001622
Patrick McHardyd1db2752010-05-11 14:40:55 +02001623 mroute_clean_tables(mrt);
1624 err = 0;
1625 break;
1626 }
1627 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001628 rtnl_unlock();
1629
1630 return err;
1631}
1632
Patrick McHardyd1db2752010-05-11 14:40:55 +02001633struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001634{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001635 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001636 struct flowi6 fl6 = {
1637 .flowi6_iif = skb->skb_iif,
1638 .flowi6_oif = skb->dev->ifindex,
1639 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001640 };
1641
David S. Miller4c9483b2011-03-12 16:22:43 -05001642 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001643 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001644
1645 return mrt->mroute6_sk;
1646}
1647
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001648/*
1649 * Socket options and virtual interface manipulation. The whole
1650 * virtual interface system is a complete heap, but unfortunately
1651 * that's how BSD mrouted happens to think. Maybe one day with a proper
1652 * MOSPF/PIM router set up we can clean this up.
1653 */
1654
David S. Millerb7058842009-09-30 16:12:20 -07001655int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001656{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001657 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001658 struct mif6ctl vif;
1659 struct mf6cctl mfc;
1660 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001661 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001662 struct mr6_table *mrt;
1663
1664 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1665 if (mrt == NULL)
1666 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001667
1668 if (optname != MRT6_INIT) {
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00001669 if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001670 return -EACCES;
1671 }
1672
1673 switch (optname) {
1674 case MRT6_INIT:
1675 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001676 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001677 return -EOPNOTSUPP;
1678 if (optlen < sizeof(int))
1679 return -EINVAL;
1680
Patrick McHardy6bd52142010-05-11 14:40:53 +02001681 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001682
1683 case MRT6_DONE:
1684 return ip6mr_sk_done(sk);
1685
1686 case MRT6_ADD_MIF:
1687 if (optlen < sizeof(vif))
1688 return -EINVAL;
1689 if (copy_from_user(&vif, optval, sizeof(vif)))
1690 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001691 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001692 return -ENFILE;
1693 rtnl_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001694 ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001695 rtnl_unlock();
1696 return ret;
1697
1698 case MRT6_DEL_MIF:
1699 if (optlen < sizeof(mifi_t))
1700 return -EINVAL;
1701 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1702 return -EFAULT;
1703 rtnl_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001704 ret = mif6_delete(mrt, mifi, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001705 rtnl_unlock();
1706 return ret;
1707
1708 /*
1709 * Manipulate the forwarding caches. These live
1710 * in a sort of kernel/user symbiosis.
1711 */
1712 case MRT6_ADD_MFC:
1713 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001714 parent = -1;
1715 case MRT6_ADD_MFC_PROXY:
1716 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001717 if (optlen < sizeof(mfc))
1718 return -EINVAL;
1719 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1720 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001721 if (parent == 0)
1722 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001723 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001724 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1725 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001726 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001727 ret = ip6mr_mfc_add(net, mrt, &mfc,
1728 sk == mrt->mroute6_sk, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001729 rtnl_unlock();
1730 return ret;
1731
1732 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001733 * Control PIM assert (to activate pim will activate assert)
1734 */
1735 case MRT6_ASSERT:
1736 {
1737 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001738
1739 if (optlen != sizeof(v))
1740 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001741 if (get_user(v, (int __user *)optval))
1742 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001743 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001744 return 0;
1745 }
1746
1747#ifdef CONFIG_IPV6_PIMSM_V2
1748 case MRT6_PIM:
1749 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001750 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001751
1752 if (optlen != sizeof(v))
1753 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001754 if (get_user(v, (int __user *)optval))
1755 return -EFAULT;
1756 v = !!v;
1757 rtnl_lock();
1758 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001759 if (v != mrt->mroute_do_pim) {
1760 mrt->mroute_do_pim = v;
1761 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001762 }
1763 rtnl_unlock();
1764 return ret;
1765 }
1766
1767#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001768#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1769 case MRT6_TABLE:
1770 {
1771 u32 v;
1772
1773 if (optlen != sizeof(u32))
1774 return -EINVAL;
1775 if (get_user(v, (u32 __user *)optval))
1776 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001777 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1778 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1779 return -EINVAL;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001780 if (sk == mrt->mroute6_sk)
1781 return -EBUSY;
1782
1783 rtnl_lock();
1784 ret = 0;
1785 if (!ip6mr_new_table(net, v))
1786 ret = -ENOMEM;
1787 raw6_sk(sk)->ip6mr_table = v;
1788 rtnl_unlock();
1789 return ret;
1790 }
1791#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001792 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001793 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001794 * set.
1795 */
1796 default:
1797 return -ENOPROTOOPT;
1798 }
1799}
1800
1801/*
1802 * Getsock opt support for the multicast routing system.
1803 */
1804
1805int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1806 int __user *optlen)
1807{
1808 int olr;
1809 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001810 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001811 struct mr6_table *mrt;
1812
1813 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1814 if (mrt == NULL)
1815 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001816
1817 switch (optname) {
1818 case MRT6_VERSION:
1819 val = 0x0305;
1820 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001821#ifdef CONFIG_IPV6_PIMSM_V2
1822 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001823 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001824 break;
1825#endif
1826 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001827 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001828 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001829 default:
1830 return -ENOPROTOOPT;
1831 }
1832
1833 if (get_user(olr, optlen))
1834 return -EFAULT;
1835
1836 olr = min_t(int, olr, sizeof(int));
1837 if (olr < 0)
1838 return -EINVAL;
1839
1840 if (put_user(olr, optlen))
1841 return -EFAULT;
1842 if (copy_to_user(optval, &val, olr))
1843 return -EFAULT;
1844 return 0;
1845}
1846
1847/*
1848 * The IP multicast ioctl support routines.
1849 */
1850
1851int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1852{
1853 struct sioc_sg_req6 sr;
1854 struct sioc_mif_req6 vr;
1855 struct mif_device *vif;
1856 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001857 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001858 struct mr6_table *mrt;
1859
1860 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1861 if (mrt == NULL)
1862 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001863
1864 switch (cmd) {
1865 case SIOCGETMIFCNT_IN6:
1866 if (copy_from_user(&vr, arg, sizeof(vr)))
1867 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001868 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001869 return -EINVAL;
1870 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001871 vif = &mrt->vif6_table[vr.mifi];
1872 if (MIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001873 vr.icount = vif->pkt_in;
1874 vr.ocount = vif->pkt_out;
1875 vr.ibytes = vif->bytes_in;
1876 vr.obytes = vif->bytes_out;
1877 read_unlock(&mrt_lock);
1878
1879 if (copy_to_user(arg, &vr, sizeof(vr)))
1880 return -EFAULT;
1881 return 0;
1882 }
1883 read_unlock(&mrt_lock);
1884 return -EADDRNOTAVAIL;
1885 case SIOCGETSGCNT_IN6:
1886 if (copy_from_user(&sr, arg, sizeof(sr)))
1887 return -EFAULT;
1888
1889 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001890 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001891 if (c) {
1892 sr.pktcnt = c->mfc_un.res.pkt;
1893 sr.bytecnt = c->mfc_un.res.bytes;
1894 sr.wrong_if = c->mfc_un.res.wrong_if;
1895 read_unlock(&mrt_lock);
1896
1897 if (copy_to_user(arg, &sr, sizeof(sr)))
1898 return -EFAULT;
1899 return 0;
1900 }
1901 read_unlock(&mrt_lock);
1902 return -EADDRNOTAVAIL;
1903 default:
1904 return -ENOIOCTLCMD;
1905 }
1906}
1907
David S. Millere2d57762011-02-03 17:59:32 -08001908#ifdef CONFIG_COMPAT
1909struct compat_sioc_sg_req6 {
1910 struct sockaddr_in6 src;
1911 struct sockaddr_in6 grp;
1912 compat_ulong_t pktcnt;
1913 compat_ulong_t bytecnt;
1914 compat_ulong_t wrong_if;
1915};
1916
1917struct compat_sioc_mif_req6 {
1918 mifi_t mifi;
1919 compat_ulong_t icount;
1920 compat_ulong_t ocount;
1921 compat_ulong_t ibytes;
1922 compat_ulong_t obytes;
1923};
1924
1925int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1926{
1927 struct compat_sioc_sg_req6 sr;
1928 struct compat_sioc_mif_req6 vr;
1929 struct mif_device *vif;
1930 struct mfc6_cache *c;
1931 struct net *net = sock_net(sk);
1932 struct mr6_table *mrt;
1933
1934 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1935 if (mrt == NULL)
1936 return -ENOENT;
1937
1938 switch (cmd) {
1939 case SIOCGETMIFCNT_IN6:
1940 if (copy_from_user(&vr, arg, sizeof(vr)))
1941 return -EFAULT;
1942 if (vr.mifi >= mrt->maxvif)
1943 return -EINVAL;
1944 read_lock(&mrt_lock);
1945 vif = &mrt->vif6_table[vr.mifi];
1946 if (MIF_EXISTS(mrt, vr.mifi)) {
1947 vr.icount = vif->pkt_in;
1948 vr.ocount = vif->pkt_out;
1949 vr.ibytes = vif->bytes_in;
1950 vr.obytes = vif->bytes_out;
1951 read_unlock(&mrt_lock);
1952
1953 if (copy_to_user(arg, &vr, sizeof(vr)))
1954 return -EFAULT;
1955 return 0;
1956 }
1957 read_unlock(&mrt_lock);
1958 return -EADDRNOTAVAIL;
1959 case SIOCGETSGCNT_IN6:
1960 if (copy_from_user(&sr, arg, sizeof(sr)))
1961 return -EFAULT;
1962
1963 read_lock(&mrt_lock);
1964 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1965 if (c) {
1966 sr.pktcnt = c->mfc_un.res.pkt;
1967 sr.bytecnt = c->mfc_un.res.bytes;
1968 sr.wrong_if = c->mfc_un.res.wrong_if;
1969 read_unlock(&mrt_lock);
1970
1971 if (copy_to_user(arg, &sr, sizeof(sr)))
1972 return -EFAULT;
1973 return 0;
1974 }
1975 read_unlock(&mrt_lock);
1976 return -EADDRNOTAVAIL;
1977 default:
1978 return -ENOIOCTLCMD;
1979 }
1980}
1981#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001982
1983static inline int ip6mr_forward2_finish(struct sk_buff *skb)
1984{
Eric Dumazetadf30902009-06-02 05:19:30 +00001985 IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
Denis V. Lunev483a47d2008-10-08 11:09:27 -07001986 IPSTATS_MIB_OUTFORWDATAGRAMS);
Vincent Bernat2d8dbb02012-06-05 03:41:42 +00001987 IP6_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
1988 IPSTATS_MIB_OUTOCTETS, skb->len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001989 return dst_output(skb);
1990}
1991
1992/*
1993 * Processing handlers for ip6mr_forward
1994 */
1995
Patrick McHardy6bd52142010-05-11 14:40:53 +02001996static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
1997 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001998{
1999 struct ipv6hdr *ipv6h;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002000 struct mif_device *vif = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002001 struct net_device *dev;
2002 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05002003 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002004
2005 if (vif->dev == NULL)
2006 goto out_free;
2007
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002008#ifdef CONFIG_IPV6_PIMSM_V2
2009 if (vif->flags & MIFF_REGISTER) {
2010 vif->pkt_out++;
2011 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07002012 vif->dev->stats.tx_bytes += skb->len;
2013 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002014 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08002015 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002016 }
2017#endif
2018
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002019 ipv6h = ipv6_hdr(skb);
2020
David S. Miller4c9483b2011-03-12 16:22:43 -05002021 fl6 = (struct flowi6) {
2022 .flowi6_oif = vif->link,
2023 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002024 };
2025
David S. Miller4c9483b2011-03-12 16:22:43 -05002026 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00002027 if (dst->error) {
2028 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002029 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00002030 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002031
Eric Dumazetadf30902009-06-02 05:19:30 +00002032 skb_dst_drop(skb);
2033 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002034
2035 /*
2036 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
2037 * not only before forwarding, but after forwarding on all output
2038 * interfaces. It is clear, if mrouter runs a multicasting
2039 * program, it should receive packets not depending to what interface
2040 * program is joined.
2041 * If we will not make it, the program will have to join on all
2042 * interfaces. On the other hand, multihoming host (or router, but
2043 * not mrouter) cannot join to more than one interface - it will
2044 * result in receiving multiple packets.
2045 */
2046 dev = vif->dev;
2047 skb->dev = dev;
2048 vif->pkt_out++;
2049 vif->bytes_out += skb->len;
2050
2051 /* We are about to write */
2052 /* XXX: extension headers? */
2053 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2054 goto out_free;
2055
2056 ipv6h = ipv6_hdr(skb);
2057 ipv6h->hop_limit--;
2058
2059 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2060
Jan Engelhardtb2e0b382010-03-23 04:09:07 +01002061 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002062 ip6mr_forward2_finish);
2063
2064out_free:
2065 kfree_skb(skb);
2066 return 0;
2067}
2068
Patrick McHardy6bd52142010-05-11 14:40:53 +02002069static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002070{
2071 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002072
2073 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
2074 if (mrt->vif6_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002075 break;
2076 }
2077 return ct;
2078}
2079
Patrick McHardy6bd52142010-05-11 14:40:53 +02002080static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2081 struct sk_buff *skb, struct mfc6_cache *cache)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002082{
2083 int psend = -1;
2084 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002085 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002086
2087 vif = cache->mf6c_parent;
2088 cache->mfc_un.res.pkt++;
2089 cache->mfc_un.res.bytes += skb->len;
2090
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002091 if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
2092 struct mfc6_cache *cache_proxy;
2093
2094 /* For an (*,G) entry, we only check that the incomming
2095 * interface is part of the static tree.
2096 */
2097 cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
2098 if (cache_proxy &&
2099 cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
2100 goto forward;
2101 }
2102
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002103 /*
2104 * Wrong interface: drop packet and (maybe) send PIM assert.
2105 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002106 if (mrt->vif6_table[vif].dev != skb->dev) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002107 cache->mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002108
Patrick McHardy6bd52142010-05-11 14:40:53 +02002109 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002110 /* pimsm uses asserts, when switching from RPT to SPT,
2111 so that we cannot check that packet arrived on an oif.
2112 It is bad, but otherwise we would need to move pretty
2113 large chunk of pimd to kernel. Ough... --ANK
2114 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002115 (mrt->mroute_do_pim ||
Benjamin Therya21f3f92008-12-10 16:28:44 -08002116 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002117 time_after(jiffies,
2118 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
2119 cache->mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002120 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002121 }
2122 goto dont_forward;
2123 }
2124
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002125forward:
Patrick McHardy6bd52142010-05-11 14:40:53 +02002126 mrt->vif6_table[vif].pkt_in++;
2127 mrt->vif6_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002128
2129 /*
2130 * Forward the frame
2131 */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002132 if (ipv6_addr_any(&cache->mf6c_origin) &&
2133 ipv6_addr_any(&cache->mf6c_mcastgrp)) {
2134 if (true_vifi >= 0 &&
2135 true_vifi != cache->mf6c_parent &&
2136 ipv6_hdr(skb)->hop_limit >
2137 cache->mfc_un.res.ttls[cache->mf6c_parent]) {
2138 /* It's an (*,*) entry and the packet is not coming from
2139 * the upstream: forward the packet to the upstream
2140 * only.
2141 */
2142 psend = cache->mf6c_parent;
2143 goto last_forward;
2144 }
2145 goto dont_forward;
2146 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002147 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002148 /* For (*,G) entry, don't forward to the incoming interface */
2149 if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) &&
2150 ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002151 if (psend != -1) {
2152 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2153 if (skb2)
Patrick McHardy6bd52142010-05-11 14:40:53 +02002154 ip6mr_forward2(net, mrt, skb2, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002155 }
2156 psend = ct;
2157 }
2158 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002159last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002160 if (psend != -1) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002161 ip6mr_forward2(net, mrt, skb, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002162 return 0;
2163 }
2164
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002165dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002166 kfree_skb(skb);
2167 return 0;
2168}
2169
2170
2171/*
2172 * Multicast packets for forwarding arrive here
2173 */
2174
2175int ip6_mr_input(struct sk_buff *skb)
2176{
2177 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002178 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002179 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002180 struct flowi6 fl6 = {
2181 .flowi6_iif = skb->dev->ifindex,
2182 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002183 };
2184 int err;
2185
David S. Miller4c9483b2011-03-12 16:22:43 -05002186 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002187 if (err < 0) {
2188 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002189 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002190 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002191
2192 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002193 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002194 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002195 if (cache == NULL) {
2196 int vif = ip6mr_find_vif(mrt, skb->dev);
2197
2198 if (vif >= 0)
2199 cache = ip6mr_cache_find_any(mrt,
2200 &ipv6_hdr(skb)->daddr,
2201 vif);
2202 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002203
2204 /*
2205 * No usable cache entry
2206 */
2207 if (cache == NULL) {
2208 int vif;
2209
Patrick McHardy6bd52142010-05-11 14:40:53 +02002210 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002211 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002212 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002213 read_unlock(&mrt_lock);
2214
2215 return err;
2216 }
2217 read_unlock(&mrt_lock);
2218 kfree_skb(skb);
2219 return -ENODEV;
2220 }
2221
Patrick McHardy6bd52142010-05-11 14:40:53 +02002222 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002223
2224 read_unlock(&mrt_lock);
2225
2226 return 0;
2227}
2228
2229
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002230static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2231 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002232{
2233 int ct;
2234 struct rtnexthop *nhp;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002235 struct nlattr *mp_attr;
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002236 struct rta_mfc_stats mfcs;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002237
Nicolas Dichtel74381892010-03-25 23:45:35 +00002238 /* If cache is unresolved, don't try to parse IIF and OIF */
Dan Carpentered0f160a2010-05-26 00:38:56 -07002239 if (c->mf6c_parent >= MAXMIFS)
Nicolas Dichtel74381892010-03-25 23:45:35 +00002240 return -ENOENT;
2241
Thomas Graf74a0bd72012-06-26 23:36:14 +00002242 if (MIF_EXISTS(mrt, c->mf6c_parent) &&
2243 nla_put_u32(skb, RTA_IIF, mrt->vif6_table[c->mf6c_parent].dev->ifindex) < 0)
2244 return -EMSGSIZE;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002245 mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
2246 if (mp_attr == NULL)
2247 return -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002248
2249 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002250 if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002251 nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
2252 if (nhp == NULL) {
2253 nla_nest_cancel(skb, mp_attr);
2254 return -EMSGSIZE;
2255 }
2256
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002257 nhp->rtnh_flags = 0;
2258 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Patrick McHardy6bd52142010-05-11 14:40:53 +02002259 nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002260 nhp->rtnh_len = sizeof(*nhp);
2261 }
2262 }
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002263
2264 nla_nest_end(skb, mp_attr);
2265
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002266 mfcs.mfcs_packets = c->mfc_un.res.pkt;
2267 mfcs.mfcs_bytes = c->mfc_un.res.bytes;
2268 mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
2269 if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0)
2270 return -EMSGSIZE;
2271
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002272 rtm->rtm_type = RTN_MULTICAST;
2273 return 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002274}
2275
Benjamin Thery8229efd2008-12-10 16:30:15 -08002276int ip6mr_get_route(struct net *net,
2277 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002278{
2279 int err;
Patrick McHardyd1db2752010-05-11 14:40:55 +02002280 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002281 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002282 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002283
Patrick McHardyd1db2752010-05-11 14:40:55 +02002284 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2285 if (mrt == NULL)
2286 return -ENOENT;
2287
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002288 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002289 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002290 if (!cache && skb->dev) {
2291 int vif = ip6mr_find_vif(mrt, skb->dev);
2292
2293 if (vif >= 0)
2294 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2295 vif);
2296 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002297
2298 if (!cache) {
2299 struct sk_buff *skb2;
2300 struct ipv6hdr *iph;
2301 struct net_device *dev;
2302 int vif;
2303
2304 if (nowait) {
2305 read_unlock(&mrt_lock);
2306 return -EAGAIN;
2307 }
2308
2309 dev = skb->dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002310 if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002311 read_unlock(&mrt_lock);
2312 return -ENODEV;
2313 }
2314
2315 /* really correct? */
2316 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2317 if (!skb2) {
2318 read_unlock(&mrt_lock);
2319 return -ENOMEM;
2320 }
2321
2322 skb_reset_transport_header(skb2);
2323
2324 skb_put(skb2, sizeof(struct ipv6hdr));
2325 skb_reset_network_header(skb2);
2326
2327 iph = ipv6_hdr(skb2);
2328 iph->version = 0;
2329 iph->priority = 0;
2330 iph->flow_lbl[0] = 0;
2331 iph->flow_lbl[1] = 0;
2332 iph->flow_lbl[2] = 0;
2333 iph->payload_len = 0;
2334 iph->nexthdr = IPPROTO_NONE;
2335 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002336 iph->saddr = rt->rt6i_src.addr;
2337 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002338
Patrick McHardy6bd52142010-05-11 14:40:53 +02002339 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002340 read_unlock(&mrt_lock);
2341
2342 return err;
2343 }
2344
2345 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
2346 cache->mfc_flags |= MFC_NOTIFY;
2347
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002348 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002349 read_unlock(&mrt_lock);
2350 return err;
2351}
2352
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002353static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
Nicolas Dichtel29466c92014-03-19 17:47:51 +01002354 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2355 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002356{
2357 struct nlmsghdr *nlh;
2358 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002359 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002360
Nicolas Dichtel29466c92014-03-19 17:47:51 +01002361 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002362 if (nlh == NULL)
2363 return -EMSGSIZE;
2364
2365 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002366 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002367 rtm->rtm_dst_len = 128;
2368 rtm->rtm_src_len = 128;
2369 rtm->rtm_tos = 0;
2370 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002371 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2372 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002373 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002374 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002375 if (c->mfc_flags & MFC_STATIC)
2376 rtm->rtm_protocol = RTPROT_STATIC;
2377 else
2378 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002379 rtm->rtm_flags = 0;
2380
David S. Millerc78679e2012-04-01 20:27:33 -04002381 if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) ||
2382 nla_put(skb, RTA_DST, 16, &c->mf6c_mcastgrp))
2383 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002384 err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
2385 /* do not break the dump if cache is unresolved */
2386 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002387 goto nla_put_failure;
2388
2389 return nlmsg_end(skb, nlh);
2390
2391nla_put_failure:
2392 nlmsg_cancel(skb, nlh);
2393 return -EMSGSIZE;
2394}
2395
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002396static int mr6_msgsize(bool unresolved, int maxvif)
2397{
2398 size_t len =
2399 NLMSG_ALIGN(sizeof(struct rtmsg))
2400 + nla_total_size(4) /* RTA_TABLE */
2401 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2402 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2403 ;
2404
2405 if (!unresolved)
2406 len = len
2407 + nla_total_size(4) /* RTA_IIF */
2408 + nla_total_size(0) /* RTA_MULTIPATH */
2409 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2410 /* RTA_MFC_STATS */
2411 + nla_total_size(sizeof(struct rta_mfc_stats))
2412 ;
2413
2414 return len;
2415}
2416
2417static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
2418 int cmd)
2419{
2420 struct net *net = read_pnet(&mrt->net);
2421 struct sk_buff *skb;
2422 int err = -ENOBUFS;
2423
2424 skb = nlmsg_new(mr6_msgsize(mfc->mf6c_parent >= MAXMIFS, mrt->maxvif),
2425 GFP_ATOMIC);
2426 if (skb == NULL)
2427 goto errout;
2428
Nicolas Dichtel29466c92014-03-19 17:47:51 +01002429 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002430 if (err < 0)
2431 goto errout;
2432
2433 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2434 return;
2435
2436errout:
2437 kfree_skb(skb);
2438 if (err < 0)
2439 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2440}
2441
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002442static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2443{
2444 struct net *net = sock_net(skb->sk);
2445 struct mr6_table *mrt;
2446 struct mfc6_cache *mfc;
2447 unsigned int t = 0, s_t;
2448 unsigned int h = 0, s_h;
2449 unsigned int e = 0, s_e;
2450
2451 s_t = cb->args[0];
2452 s_h = cb->args[1];
2453 s_e = cb->args[2];
2454
2455 read_lock(&mrt_lock);
2456 ip6mr_for_each_table(mrt, net) {
2457 if (t < s_t)
2458 goto next_table;
2459 if (t > s_t)
2460 s_h = 0;
2461 for (h = s_h; h < MFC6_LINES; h++) {
2462 list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) {
2463 if (e < s_e)
2464 goto next_entry;
2465 if (ip6mr_fill_mroute(mrt, skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002466 NETLINK_CB(cb->skb).portid,
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002467 cb->nlh->nlmsg_seq,
Nicolas Dichtel29466c92014-03-19 17:47:51 +01002468 mfc, RTM_NEWROUTE,
2469 NLM_F_MULTI) < 0)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002470 goto done;
2471next_entry:
2472 e++;
2473 }
2474 e = s_e = 0;
2475 }
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002476 spin_lock_bh(&mfc_unres_lock);
2477 list_for_each_entry(mfc, &mrt->mfc6_unres_queue, list) {
2478 if (e < s_e)
2479 goto next_entry2;
2480 if (ip6mr_fill_mroute(mrt, skb,
2481 NETLINK_CB(cb->skb).portid,
2482 cb->nlh->nlmsg_seq,
Nicolas Dichtel29466c92014-03-19 17:47:51 +01002483 mfc, RTM_NEWROUTE,
2484 NLM_F_MULTI) < 0) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002485 spin_unlock_bh(&mfc_unres_lock);
2486 goto done;
2487 }
2488next_entry2:
2489 e++;
2490 }
2491 spin_unlock_bh(&mfc_unres_lock);
2492 e = s_e = 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002493 s_h = 0;
2494next_table:
2495 t++;
2496 }
2497done:
2498 read_unlock(&mrt_lock);
2499
2500 cb->args[2] = e;
2501 cb->args[1] = h;
2502 cb->args[0] = t;
2503
2504 return skb->len;
2505}