blob: fdfd96d288edde02a8f168a33fb5efedd826ed4e [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{
144 struct ip6mr_result res;
145 struct fib_lookup_arg arg = { .result = &res, };
146 int err;
147
David S. Miller4c9483b2011-03-12 16:22:43 -0500148 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
149 flowi6_to_flowi(flp6), 0, &arg);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200150 if (err < 0)
151 return err;
152 *mrt = res.mrt;
153 return 0;
154}
155
156static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
157 int flags, struct fib_lookup_arg *arg)
158{
159 struct ip6mr_result *res = arg->result;
160 struct mr6_table *mrt;
161
162 switch (rule->action) {
163 case FR_ACT_TO_TBL:
164 break;
165 case FR_ACT_UNREACHABLE:
166 return -ENETUNREACH;
167 case FR_ACT_PROHIBIT:
168 return -EACCES;
169 case FR_ACT_BLACKHOLE:
170 default:
171 return -EINVAL;
172 }
173
174 mrt = ip6mr_get_table(rule->fr_net, rule->table);
175 if (mrt == NULL)
176 return -EAGAIN;
177 res->mrt = mrt;
178 return 0;
179}
180
181static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
182{
183 return 1;
184}
185
186static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
187 FRA_GENERIC_POLICY,
188};
189
190static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
191 struct fib_rule_hdr *frh, struct nlattr **tb)
192{
193 return 0;
194}
195
196static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
197 struct nlattr **tb)
198{
199 return 1;
200}
201
202static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
203 struct fib_rule_hdr *frh)
204{
205 frh->dst_len = 0;
206 frh->src_len = 0;
207 frh->tos = 0;
208 return 0;
209}
210
Andi Kleen04a6f822012-10-04 17:12:11 -0700211static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200212 .family = RTNL_FAMILY_IP6MR,
213 .rule_size = sizeof(struct ip6mr_rule),
214 .addr_size = sizeof(struct in6_addr),
215 .action = ip6mr_rule_action,
216 .match = ip6mr_rule_match,
217 .configure = ip6mr_rule_configure,
218 .compare = ip6mr_rule_compare,
219 .default_pref = fib_default_rule_pref,
220 .fill = ip6mr_rule_fill,
221 .nlgroup = RTNLGRP_IPV6_RULE,
222 .policy = ip6mr_rule_policy,
223 .owner = THIS_MODULE,
224};
225
226static int __net_init ip6mr_rules_init(struct net *net)
227{
228 struct fib_rules_ops *ops;
229 struct mr6_table *mrt;
230 int err;
231
232 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
233 if (IS_ERR(ops))
234 return PTR_ERR(ops);
235
236 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
237
238 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
239 if (mrt == NULL) {
240 err = -ENOMEM;
241 goto err1;
242 }
243
244 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
245 if (err < 0)
246 goto err2;
247
248 net->ipv6.mr6_rules_ops = ops;
249 return 0;
250
251err2:
252 kfree(mrt);
253err1:
254 fib_rules_unregister(ops);
255 return err;
256}
257
258static void __net_exit ip6mr_rules_exit(struct net *net)
259{
260 struct mr6_table *mrt, *next;
261
Eric Dumazet035320d2010-06-06 23:48:40 +0000262 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
263 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200264 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000265 }
Patrick McHardyd1db2752010-05-11 14:40:55 +0200266 fib_rules_unregister(net->ipv6.mr6_rules_ops);
267}
268#else
269#define ip6mr_for_each_table(mrt, net) \
270 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
271
272static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
273{
274 return net->ipv6.mrt6;
275}
276
David S. Miller4c9483b2011-03-12 16:22:43 -0500277static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200278 struct mr6_table **mrt)
279{
280 *mrt = net->ipv6.mrt6;
281 return 0;
282}
283
284static int __net_init ip6mr_rules_init(struct net *net)
285{
286 net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
287 return net->ipv6.mrt6 ? 0 : -ENOMEM;
288}
289
290static void __net_exit ip6mr_rules_exit(struct net *net)
291{
292 ip6mr_free_table(net->ipv6.mrt6);
293}
294#endif
295
296static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
297{
298 struct mr6_table *mrt;
299 unsigned int i;
300
301 mrt = ip6mr_get_table(net, id);
302 if (mrt != NULL)
303 return mrt;
304
305 mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
306 if (mrt == NULL)
307 return NULL;
308 mrt->id = id;
309 write_pnet(&mrt->net, net);
310
311 /* Forwarding cache */
312 for (i = 0; i < MFC6_LINES; i++)
313 INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
314
315 INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
316
317 setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
318 (unsigned long)mrt);
319
320#ifdef CONFIG_IPV6_PIMSM_V2
321 mrt->mroute_reg_vif_num = -1;
322#endif
323#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
324 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
325#endif
326 return mrt;
327}
328
329static void ip6mr_free_table(struct mr6_table *mrt)
330{
331 del_timer(&mrt->ipmr_expire_timer);
332 mroute_clean_tables(mrt);
333 kfree(mrt);
334}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900335
336#ifdef CONFIG_PROC_FS
337
338struct ipmr_mfc_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800339 struct seq_net_private p;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200340 struct mr6_table *mrt;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200341 struct list_head *cache;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900342 int ct;
343};
344
345
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800346static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
347 struct ipmr_mfc_iter *it, loff_t pos)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900348{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200349 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900350 struct mfc6_cache *mfc;
351
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900352 read_lock(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200353 for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200354 it->cache = &mrt->mfc6_cache_array[it->ct];
Patrick McHardyf30a77842010-05-11 14:40:51 +0200355 list_for_each_entry(mfc, it->cache, list)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900356 if (pos-- == 0)
357 return mfc;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200358 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900359 read_unlock(&mrt_lock);
360
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900361 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200362 it->cache = &mrt->mfc6_unres_queue;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200363 list_for_each_entry(mfc, it->cache, list)
Patrick McHardyc476efb2010-05-11 14:40:48 +0200364 if (pos-- == 0)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900365 return mfc;
366 spin_unlock_bh(&mfc_unres_lock);
367
368 it->cache = NULL;
369 return NULL;
370}
371
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900372/*
373 * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
374 */
375
376struct ipmr_vif_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800377 struct seq_net_private p;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200378 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900379 int ct;
380};
381
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800382static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
383 struct ipmr_vif_iter *iter,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900384 loff_t pos)
385{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200386 struct mr6_table *mrt = iter->mrt;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200387
388 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
389 if (!MIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900390 continue;
391 if (pos-- == 0)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200392 return &mrt->vif6_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900393 }
394 return NULL;
395}
396
397static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
398 __acquires(mrt_lock)
399{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200400 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800401 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200402 struct mr6_table *mrt;
403
404 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
405 if (mrt == NULL)
406 return ERR_PTR(-ENOENT);
407
408 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800409
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900410 read_lock(&mrt_lock);
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800411 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
412 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900413}
414
415static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
416{
417 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800418 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200419 struct mr6_table *mrt = iter->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900420
421 ++*pos;
422 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800423 return ip6mr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900424
Patrick McHardy6bd52142010-05-11 14:40:53 +0200425 while (++iter->ct < mrt->maxvif) {
426 if (!MIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900427 continue;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200428 return &mrt->vif6_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900429 }
430 return NULL;
431}
432
433static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
434 __releases(mrt_lock)
435{
436 read_unlock(&mrt_lock);
437}
438
439static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
440{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200441 struct ipmr_vif_iter *iter = seq->private;
442 struct mr6_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800443
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900444 if (v == SEQ_START_TOKEN) {
445 seq_puts(seq,
446 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
447 } else {
448 const struct mif_device *vif = v;
449 const char *name = vif->dev ? vif->dev->name : "none";
450
451 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100452 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Patrick McHardy6bd52142010-05-11 14:40:53 +0200453 vif - mrt->vif6_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900454 name, vif->bytes_in, vif->pkt_in,
455 vif->bytes_out, vif->pkt_out,
456 vif->flags);
457 }
458 return 0;
459}
460
Stephen Hemminger98147d52009-09-01 19:25:02 +0000461static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900462 .start = ip6mr_vif_seq_start,
463 .next = ip6mr_vif_seq_next,
464 .stop = ip6mr_vif_seq_stop,
465 .show = ip6mr_vif_seq_show,
466};
467
468static int ip6mr_vif_open(struct inode *inode, struct file *file)
469{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800470 return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
471 sizeof(struct ipmr_vif_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900472}
473
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000474static const struct file_operations ip6mr_vif_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900475 .owner = THIS_MODULE,
476 .open = ip6mr_vif_open,
477 .read = seq_read,
478 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800479 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900480};
481
482static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
483{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200484 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800485 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200486 struct mr6_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800487
Patrick McHardyd1db2752010-05-11 14:40:55 +0200488 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
489 if (mrt == NULL)
490 return ERR_PTR(-ENOENT);
491
492 it->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800493 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
494 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900495}
496
497static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
498{
499 struct mfc6_cache *mfc = v;
500 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800501 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200502 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900503
504 ++*pos;
505
506 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800507 return ipmr_mfc_seq_idx(net, seq->private, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900508
Patrick McHardyf30a77842010-05-11 14:40:51 +0200509 if (mfc->list.next != it->cache)
510 return list_entry(mfc->list.next, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900511
Patrick McHardy6bd52142010-05-11 14:40:53 +0200512 if (it->cache == &mrt->mfc6_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900513 goto end_of_list;
514
Patrick McHardy6bd52142010-05-11 14:40:53 +0200515 BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900516
Benjamin Thery4a6258a2008-12-10 16:24:07 -0800517 while (++it->ct < MFC6_LINES) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200518 it->cache = &mrt->mfc6_cache_array[it->ct];
Patrick McHardyf30a77842010-05-11 14:40:51 +0200519 if (list_empty(it->cache))
520 continue;
521 return list_first_entry(it->cache, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900522 }
523
524 /* exhausted cache_array, show unresolved */
525 read_unlock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200526 it->cache = &mrt->mfc6_unres_queue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900527 it->ct = 0;
528
529 spin_lock_bh(&mfc_unres_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200530 if (!list_empty(it->cache))
531 return list_first_entry(it->cache, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900532
533 end_of_list:
534 spin_unlock_bh(&mfc_unres_lock);
535 it->cache = NULL;
536
537 return NULL;
538}
539
540static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
541{
542 struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200543 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900544
Patrick McHardy6bd52142010-05-11 14:40:53 +0200545 if (it->cache == &mrt->mfc6_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900546 spin_unlock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200547 else if (it->cache == mrt->mfc6_cache_array)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900548 read_unlock(&mrt_lock);
549}
550
551static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
552{
553 int n;
554
555 if (v == SEQ_START_TOKEN) {
556 seq_puts(seq,
557 "Group "
558 "Origin "
559 "Iif Pkts Bytes Wrong Oifs\n");
560 } else {
561 const struct mfc6_cache *mfc = v;
562 const struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200563 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900564
Benjamin Thery999890b2008-12-03 22:22:16 -0800565 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700566 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800567 mfc->mf6c_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900568
Patrick McHardy6bd52142010-05-11 14:40:53 +0200569 if (it->cache != &mrt->mfc6_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800570 seq_printf(seq, " %8lu %8lu %8lu",
571 mfc->mfc_un.res.pkt,
572 mfc->mfc_un.res.bytes,
573 mfc->mfc_un.res.wrong_if);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900574 for (n = mfc->mfc_un.res.minvif;
575 n < mfc->mfc_un.res.maxvif; n++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200576 if (MIF_EXISTS(mrt, n) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900577 mfc->mfc_un.res.ttls[n] < 255)
578 seq_printf(seq,
579 " %2d:%-3d",
580 n, mfc->mfc_un.res.ttls[n]);
581 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800582 } else {
583 /* unresolved mfc_caches don't contain
584 * pkt, bytes and wrong_if values
585 */
586 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900587 }
588 seq_putc(seq, '\n');
589 }
590 return 0;
591}
592
James Morris88e9d342009-09-22 16:43:43 -0700593static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900594 .start = ipmr_mfc_seq_start,
595 .next = ipmr_mfc_seq_next,
596 .stop = ipmr_mfc_seq_stop,
597 .show = ipmr_mfc_seq_show,
598};
599
600static int ipmr_mfc_open(struct inode *inode, struct file *file)
601{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800602 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
603 sizeof(struct ipmr_mfc_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900604}
605
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000606static const struct file_operations ip6mr_mfc_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900607 .owner = THIS_MODULE,
608 .open = ipmr_mfc_open,
609 .read = seq_read,
610 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800611 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900612};
613#endif
614
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900615#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900616
617static int pim6_rcv(struct sk_buff *skb)
618{
619 struct pimreghdr *pim;
620 struct ipv6hdr *encap;
621 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800622 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200623 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500624 struct flowi6 fl6 = {
625 .flowi6_iif = skb->dev->ifindex,
626 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200627 };
628 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900629
630 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
631 goto drop;
632
633 pim = (struct pimreghdr *)skb_transport_header(skb);
634 if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
635 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800636 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
637 sizeof(*pim), IPPROTO_PIM,
638 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700639 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900640 goto drop;
641
642 /* check if the inner packet is destined to mcast group */
643 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
644 sizeof(*pim));
645
646 if (!ipv6_addr_is_multicast(&encap->daddr) ||
647 encap->payload_len == 0 ||
648 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
649 goto drop;
650
David S. Miller4c9483b2011-03-12 16:22:43 -0500651 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200652 goto drop;
653 reg_vif_num = mrt->mroute_reg_vif_num;
654
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900655 read_lock(&mrt_lock);
656 if (reg_vif_num >= 0)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200657 reg_dev = mrt->vif6_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900658 if (reg_dev)
659 dev_hold(reg_dev);
660 read_unlock(&mrt_lock);
661
662 if (reg_dev == NULL)
663 goto drop;
664
665 skb->mac_header = skb->network_header;
666 skb_pull(skb, (u8 *)encap - skb->data);
667 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800668 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000669 skb->ip_summed = CHECKSUM_NONE;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900670 skb->pkt_type = PACKET_HOST;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700671
672 skb_tunnel_rx(skb, reg_dev);
673
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000674 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000675
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900676 dev_put(reg_dev);
677 return 0;
678 drop:
679 kfree_skb(skb);
680 return 0;
681}
682
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000683static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900684 .handler = pim6_rcv,
685};
686
687/* Service routines creating virtual interfaces: PIMREG */
688
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000689static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
690 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900691{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800692 struct net *net = dev_net(dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200693 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500694 struct flowi6 fl6 = {
695 .flowi6_oif = dev->ifindex,
696 .flowi6_iif = skb->skb_iif,
697 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200698 };
699 int err;
700
David S. Miller4c9483b2011-03-12 16:22:43 -0500701 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000702 if (err < 0) {
703 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200704 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000705 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800706
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900707 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700708 dev->stats.tx_bytes += skb->len;
709 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200710 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900711 read_unlock(&mrt_lock);
712 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000713 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900714}
715
Stephen Hemminger007c3832008-11-20 20:28:35 -0800716static const struct net_device_ops reg_vif_netdev_ops = {
717 .ndo_start_xmit = reg_vif_xmit,
718};
719
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900720static void reg_vif_setup(struct net_device *dev)
721{
722 dev->type = ARPHRD_PIMREG;
723 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
724 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800725 dev->netdev_ops = &reg_vif_netdev_ops;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900726 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700727 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900728}
729
Patrick McHardyd1db2752010-05-11 14:40:55 +0200730static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900731{
732 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200733 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900734
Patrick McHardyd1db2752010-05-11 14:40:55 +0200735 if (mrt->id == RT6_TABLE_DFLT)
736 sprintf(name, "pim6reg");
737 else
738 sprintf(name, "pim6reg%u", mrt->id);
739
740 dev = alloc_netdev(0, name, reg_vif_setup);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900741 if (dev == NULL)
742 return NULL;
743
Benjamin Thery8229efd2008-12-10 16:30:15 -0800744 dev_net_set(dev, net);
745
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900746 if (register_netdevice(dev)) {
747 free_netdev(dev);
748 return NULL;
749 }
750 dev->iflink = 0;
751
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900752 if (dev_open(dev))
753 goto failure;
754
Wang Chen7af3db72008-07-14 20:54:54 -0700755 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900756 return dev;
757
758failure:
759 /* allow the register to be completed before unregistering. */
760 rtnl_unlock();
761 rtnl_lock();
762
763 unregister_netdevice(dev);
764 return NULL;
765}
766#endif
767
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900768/*
769 * Delete a VIF entry
770 */
771
Patrick McHardy6bd52142010-05-11 14:40:53 +0200772static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900773{
774 struct mif_device *v;
775 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800776 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200777
778 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900779 return -EADDRNOTAVAIL;
780
Patrick McHardy6bd52142010-05-11 14:40:53 +0200781 v = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900782
783 write_lock_bh(&mrt_lock);
784 dev = v->dev;
785 v->dev = NULL;
786
787 if (!dev) {
788 write_unlock_bh(&mrt_lock);
789 return -EADDRNOTAVAIL;
790 }
791
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900792#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200793 if (vifi == mrt->mroute_reg_vif_num)
794 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900795#endif
796
Patrick McHardy6bd52142010-05-11 14:40:53 +0200797 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900798 int tmp;
799 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200800 if (MIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900801 break;
802 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200803 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900804 }
805
806 write_unlock_bh(&mrt_lock);
807
808 dev_set_allmulti(dev, -1);
809
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800810 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000811 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800812 in6_dev->cnf.mc_forwarding--;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000813 inet6_netconf_notify_devconf(dev_net(dev),
814 NETCONFA_MC_FORWARDING,
815 dev->ifindex, &in6_dev->cnf);
816 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800817
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900818 if (v->flags & MIFF_REGISTER)
Eric Dumazetc871e662009-10-28 04:48:11 +0000819 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900820
821 dev_put(dev);
822 return 0;
823}
824
Benjamin Thery58701ad2008-12-10 16:22:34 -0800825static inline void ip6mr_cache_free(struct mfc6_cache *c)
826{
Benjamin Thery58701ad2008-12-10 16:22:34 -0800827 kmem_cache_free(mrt_cachep, c);
828}
829
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900830/* Destroy an unresolved cache entry, killing queued skbs
831 and reporting error to netlink readers.
832 */
833
Patrick McHardy6bd52142010-05-11 14:40:53 +0200834static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900835{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200836 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900837 struct sk_buff *skb;
838
Patrick McHardy6bd52142010-05-11 14:40:53 +0200839 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900840
841 while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
842 if (ipv6_hdr(skb)->version == 0) {
843 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
844 nlh->nlmsg_type = NLMSG_ERROR;
845 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
846 skb_trim(skb, nlh->nlmsg_len);
847 ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000848 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900849 } else
850 kfree_skb(skb);
851 }
852
Benjamin Thery58701ad2008-12-10 16:22:34 -0800853 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900854}
855
856
Patrick McHardyc476efb2010-05-11 14:40:48 +0200857/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900858
Patrick McHardy6bd52142010-05-11 14:40:53 +0200859static void ipmr_do_expire_process(struct mr6_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900860{
861 unsigned long now = jiffies;
862 unsigned long expires = 10 * HZ;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200863 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900864
Patrick McHardy6bd52142010-05-11 14:40:53 +0200865 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900866 if (time_after(c->mfc_un.unres.expires, now)) {
867 /* not yet... */
868 unsigned long interval = c->mfc_un.unres.expires - now;
869 if (interval < expires)
870 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900871 continue;
872 }
873
Patrick McHardyf30a77842010-05-11 14:40:51 +0200874 list_del(&c->list);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +0000875 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200876 ip6mr_destroy_unres(mrt, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900877 }
878
Patrick McHardy6bd52142010-05-11 14:40:53 +0200879 if (!list_empty(&mrt->mfc6_unres_queue))
880 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900881}
882
Patrick McHardyc476efb2010-05-11 14:40:48 +0200883static void ipmr_expire_process(unsigned long arg)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900884{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200885 struct mr6_table *mrt = (struct mr6_table *)arg;
Patrick McHardyc476efb2010-05-11 14:40:48 +0200886
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900887 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200888 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900889 return;
890 }
891
Patrick McHardy6bd52142010-05-11 14:40:53 +0200892 if (!list_empty(&mrt->mfc6_unres_queue))
893 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900894
895 spin_unlock(&mfc_unres_lock);
896}
897
898/* Fill oifs list. It is called under write locked mrt_lock. */
899
Patrick McHardy6bd52142010-05-11 14:40:53 +0200900static void ip6mr_update_thresholds(struct mr6_table *mrt, struct mfc6_cache *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200901 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900902{
903 int vifi;
904
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300905 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900906 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300907 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900908
Patrick McHardy6bd52142010-05-11 14:40:53 +0200909 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
910 if (MIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800911 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900912 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
913 if (cache->mfc_un.res.minvif > vifi)
914 cache->mfc_un.res.minvif = vifi;
915 if (cache->mfc_un.res.maxvif <= vifi)
916 cache->mfc_un.res.maxvif = vifi + 1;
917 }
918 }
919}
920
Patrick McHardy6bd52142010-05-11 14:40:53 +0200921static int mif6_add(struct net *net, struct mr6_table *mrt,
922 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900923{
924 int vifi = vifc->mif6c_mifi;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200925 struct mif_device *v = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900926 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800927 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700928 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900929
930 /* Is vif busy ? */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200931 if (MIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900932 return -EADDRINUSE;
933
934 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900935#ifdef CONFIG_IPV6_PIMSM_V2
936 case MIFF_REGISTER:
937 /*
938 * Special Purpose VIF in PIM
939 * All the packets will be sent to the daemon
940 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200941 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900942 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200943 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900944 if (!dev)
945 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700946 err = dev_set_allmulti(dev, 1);
947 if (err) {
948 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700949 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700950 return err;
951 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900952 break;
953#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900954 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800955 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900956 if (!dev)
957 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700958 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700959 if (err) {
960 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700961 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700962 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900963 break;
964 default:
965 return -EINVAL;
966 }
967
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800968 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000969 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800970 in6_dev->cnf.mc_forwarding++;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000971 inet6_netconf_notify_devconf(dev_net(dev),
972 NETCONFA_MC_FORWARDING,
973 dev->ifindex, &in6_dev->cnf);
974 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800975
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900976 /*
977 * Fill in the VIF structures
978 */
979 v->rate_limit = vifc->vifc_rate_limit;
980 v->flags = vifc->mif6c_flags;
981 if (!mrtsock)
982 v->flags |= VIFF_STATIC;
983 v->threshold = vifc->vifc_threshold;
984 v->bytes_in = 0;
985 v->bytes_out = 0;
986 v->pkt_in = 0;
987 v->pkt_out = 0;
988 v->link = dev->ifindex;
989 if (v->flags & MIFF_REGISTER)
990 v->link = dev->iflink;
991
992 /* And finish update writing critical data */
993 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900994 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900995#ifdef CONFIG_IPV6_PIMSM_V2
996 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200997 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900998#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200999 if (vifi + 1 > mrt->maxvif)
1000 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001001 write_unlock_bh(&mrt_lock);
1002 return 0;
1003}
1004
Patrick McHardy6bd52142010-05-11 14:40:53 +02001005static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001006 const struct in6_addr *origin,
1007 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001008{
1009 int line = MFC6_HASH(mcastgrp, origin);
1010 struct mfc6_cache *c;
1011
Patrick McHardy6bd52142010-05-11 14:40:53 +02001012 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001013 if (ipv6_addr_equal(&c->mf6c_origin, origin) &&
1014 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp))
Patrick McHardyf30a77842010-05-11 14:40:51 +02001015 return c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001016 }
Patrick McHardyf30a77842010-05-11 14:40:51 +02001017 return NULL;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001018}
1019
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001020/* Look for a (*,*,oif) entry */
1021static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt,
1022 mifi_t mifi)
1023{
1024 int line = MFC6_HASH(&in6addr_any, &in6addr_any);
1025 struct mfc6_cache *c;
1026
1027 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1028 if (ipv6_addr_any(&c->mf6c_origin) &&
1029 ipv6_addr_any(&c->mf6c_mcastgrp) &&
1030 (c->mfc_un.res.ttls[mifi] < 255))
1031 return c;
1032
1033 return NULL;
1034}
1035
1036/* Look for a (*,G) entry */
1037static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt,
1038 struct in6_addr *mcastgrp,
1039 mifi_t mifi)
1040{
1041 int line = MFC6_HASH(mcastgrp, &in6addr_any);
1042 struct mfc6_cache *c, *proxy;
1043
1044 if (ipv6_addr_any(mcastgrp))
1045 goto skip;
1046
1047 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1048 if (ipv6_addr_any(&c->mf6c_origin) &&
1049 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) {
1050 if (c->mfc_un.res.ttls[mifi] < 255)
1051 return c;
1052
1053 /* It's ok if the mifi is part of the static tree */
1054 proxy = ip6mr_cache_find_any_parent(mrt,
1055 c->mf6c_parent);
1056 if (proxy && proxy->mfc_un.res.ttls[mifi] < 255)
1057 return c;
1058 }
1059
1060skip:
1061 return ip6mr_cache_find_any_parent(mrt, mifi);
1062}
1063
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001064/*
1065 * Allocate a multicast cache entry
1066 */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001067static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001068{
Joe Perches36cbac52008-12-03 22:27:25 -08001069 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001070 if (c == NULL)
1071 return NULL;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001072 c->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001073 return c;
1074}
1075
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001076static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001077{
Joe Perches36cbac52008-12-03 22:27:25 -08001078 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001079 if (c == NULL)
1080 return NULL;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001081 skb_queue_head_init(&c->mfc_un.unres.unresolved);
1082 c->mfc_un.unres.expires = jiffies + 10 * HZ;
1083 return c;
1084}
1085
1086/*
1087 * A cache entry has gone into a resolved state from queued
1088 */
1089
Patrick McHardy6bd52142010-05-11 14:40:53 +02001090static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
1091 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001092{
1093 struct sk_buff *skb;
1094
1095 /*
1096 * Play the pending entries through our router
1097 */
1098
1099 while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
1100 if (ipv6_hdr(skb)->version == 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001101 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
1102
Patrick McHardy5b285ca2010-05-11 14:40:56 +02001103 if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001104 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001105 } else {
1106 nlh->nlmsg_type = NLMSG_ERROR;
1107 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
1108 skb_trim(skb, nlh->nlmsg_len);
1109 ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
1110 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001111 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001112 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001113 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001114 }
1115}
1116
1117/*
1118 * Bounce a cache query up to pim6sd. We could use netlink for this but pim6sd
1119 * expects the following bizarre scheme.
1120 *
1121 * Called under mrt_lock.
1122 */
1123
Patrick McHardy6bd52142010-05-11 14:40:53 +02001124static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
1125 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001126{
1127 struct sk_buff *skb;
1128 struct mrt6msg *msg;
1129 int ret;
1130
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001131#ifdef CONFIG_IPV6_PIMSM_V2
1132 if (assert == MRT6MSG_WHOLEPKT)
1133 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1134 +sizeof(*msg));
1135 else
1136#endif
1137 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001138
1139 if (!skb)
1140 return -ENOBUFS;
1141
1142 /* I suppose that internal messages
1143 * do not require checksums */
1144
1145 skb->ip_summed = CHECKSUM_UNNECESSARY;
1146
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001147#ifdef CONFIG_IPV6_PIMSM_V2
1148 if (assert == MRT6MSG_WHOLEPKT) {
1149 /* Ugly, but we have no choice with this interface.
1150 Duplicate old header, fix length etc.
1151 And all this only to mangle msg->im6_msgtype and
1152 to set msg->im6_mbz to "mbz" :-)
1153 */
1154 skb_push(skb, -skb_network_offset(pkt));
1155
1156 skb_push(skb, sizeof(*msg));
1157 skb_reset_transport_header(skb);
1158 msg = (struct mrt6msg *)skb_transport_header(skb);
1159 msg->im6_mbz = 0;
1160 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001161 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001162 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001163 msg->im6_src = ipv6_hdr(pkt)->saddr;
1164 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001165
1166 skb->ip_summed = CHECKSUM_UNNECESSARY;
1167 } else
1168#endif
1169 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001170 /*
1171 * Copy the IP header
1172 */
1173
1174 skb_put(skb, sizeof(struct ipv6hdr));
1175 skb_reset_network_header(skb);
1176 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1177
1178 /*
1179 * Add our header
1180 */
1181 skb_put(skb, sizeof(*msg));
1182 skb_reset_transport_header(skb);
1183 msg = (struct mrt6msg *)skb_transport_header(skb);
1184
1185 msg->im6_mbz = 0;
1186 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001187 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001188 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001189 msg->im6_src = ipv6_hdr(pkt)->saddr;
1190 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001191
Eric Dumazetadf30902009-06-02 05:19:30 +00001192 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001193 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001194 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001195
Patrick McHardy6bd52142010-05-11 14:40:53 +02001196 if (mrt->mroute6_sk == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001197 kfree_skb(skb);
1198 return -EINVAL;
1199 }
1200
1201 /*
1202 * Deliver to user space multicast routing algorithms
1203 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001204 ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001205 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001206 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001207 kfree_skb(skb);
1208 }
1209
1210 return ret;
1211}
1212
1213/*
1214 * Queue a packet for resolution. It gets locked cache entry!
1215 */
1216
1217static int
Patrick McHardy6bd52142010-05-11 14:40:53 +02001218ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001219{
Patrick McHardyf30a77842010-05-11 14:40:51 +02001220 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001221 int err;
1222 struct mfc6_cache *c;
1223
1224 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001225 list_for_each_entry(c, &mrt->mfc6_unres_queue, list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001226 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001227 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1228 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001229 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001230 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001231 }
1232
Patrick McHardyf30a77842010-05-11 14:40:51 +02001233 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001234 /*
1235 * Create a new entry if allowable
1236 */
1237
Patrick McHardy6bd52142010-05-11 14:40:53 +02001238 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001239 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001240 spin_unlock_bh(&mfc_unres_lock);
1241
1242 kfree_skb(skb);
1243 return -ENOBUFS;
1244 }
1245
1246 /*
1247 * Fill in the new cache entry
1248 */
1249 c->mf6c_parent = -1;
1250 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1251 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1252
1253 /*
1254 * Reflect first query at pim6sd
1255 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001256 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001257 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001258 /* If the report failed throw the cache entry
1259 out - Brad Parker
1260 */
1261 spin_unlock_bh(&mfc_unres_lock);
1262
Benjamin Thery58701ad2008-12-10 16:22:34 -08001263 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001264 kfree_skb(skb);
1265 return err;
1266 }
1267
Patrick McHardy6bd52142010-05-11 14:40:53 +02001268 atomic_inc(&mrt->cache_resolve_queue_len);
1269 list_add(&c->list, &mrt->mfc6_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001270 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001271
Patrick McHardy6bd52142010-05-11 14:40:53 +02001272 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001273 }
1274
1275 /*
1276 * See if we can append the packet
1277 */
1278 if (c->mfc_un.unres.unresolved.qlen > 3) {
1279 kfree_skb(skb);
1280 err = -ENOBUFS;
1281 } else {
1282 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
1283 err = 0;
1284 }
1285
1286 spin_unlock_bh(&mfc_unres_lock);
1287 return err;
1288}
1289
1290/*
1291 * MFC6 cache manipulation by user space
1292 */
1293
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001294static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
1295 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001296{
1297 int line;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001298 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001299
1300 line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
1301
Patrick McHardy6bd52142010-05-11 14:40:53 +02001302 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001303 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001304 ipv6_addr_equal(&c->mf6c_mcastgrp,
1305 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1306 (parent == -1 || parent == c->mf6c_parent)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001307 write_lock_bh(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001308 list_del(&c->list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001309 write_unlock_bh(&mrt_lock);
1310
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001311 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001312 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001313 return 0;
1314 }
1315 }
1316 return -ENOENT;
1317}
1318
1319static int ip6mr_device_event(struct notifier_block *this,
1320 unsigned long event, void *ptr)
1321{
1322 struct net_device *dev = ptr;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001323 struct net *net = dev_net(dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001324 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001325 struct mif_device *v;
1326 int ct;
Eric Dumazetc871e662009-10-28 04:48:11 +00001327 LIST_HEAD(list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001328
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001329 if (event != NETDEV_UNREGISTER)
1330 return NOTIFY_DONE;
1331
Patrick McHardyd1db2752010-05-11 14:40:55 +02001332 ip6mr_for_each_table(mrt, net) {
1333 v = &mrt->vif6_table[0];
1334 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1335 if (v->dev == dev)
1336 mif6_delete(mrt, ct, &list);
1337 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001338 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001339 unregister_netdevice_many(&list);
1340
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001341 return NOTIFY_DONE;
1342}
1343
1344static struct notifier_block ip6_mr_notifier = {
1345 .notifier_call = ip6mr_device_event
1346};
1347
1348/*
1349 * Setup for IP multicast routing
1350 */
1351
Benjamin Thery4e168802008-12-10 16:15:08 -08001352static int __net_init ip6mr_net_init(struct net *net)
1353{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001354 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001355
Patrick McHardyd1db2752010-05-11 14:40:55 +02001356 err = ip6mr_rules_init(net);
1357 if (err < 0)
Benjamin Thery4e168802008-12-10 16:15:08 -08001358 goto fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001359
1360#ifdef CONFIG_PROC_FS
1361 err = -ENOMEM;
Gao fengd4beaa62013-02-18 01:34:54 +00001362 if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001363 goto proc_vif_fail;
Gao fengd4beaa62013-02-18 01:34:54 +00001364 if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001365 goto proc_cache_fail;
1366#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001367
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001368 return 0;
1369
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001370#ifdef CONFIG_PROC_FS
1371proc_cache_fail:
1372 proc_net_remove(net, "ip6_mr_vif");
1373proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001374 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001375#endif
Benjamin Thery4e168802008-12-10 16:15:08 -08001376fail:
1377 return err;
1378}
1379
1380static void __net_exit ip6mr_net_exit(struct net *net)
1381{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001382#ifdef CONFIG_PROC_FS
1383 proc_net_remove(net, "ip6_mr_cache");
1384 proc_net_remove(net, "ip6_mr_vif");
1385#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001386 ip6mr_rules_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001387}
1388
1389static struct pernet_operations ip6mr_net_ops = {
1390 .init = ip6mr_net_init,
1391 .exit = ip6mr_net_exit,
1392};
1393
Wang Chen623d1a12008-07-03 12:13:30 +08001394int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001395{
Wang Chen623d1a12008-07-03 12:13:30 +08001396 int err;
1397
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001398 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1399 sizeof(struct mfc6_cache),
1400 0, SLAB_HWCACHE_ALIGN,
1401 NULL);
1402 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001403 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001404
Benjamin Thery4e168802008-12-10 16:15:08 -08001405 err = register_pernet_subsys(&ip6mr_net_ops);
1406 if (err)
1407 goto reg_pernet_fail;
1408
Wang Chen623d1a12008-07-03 12:13:30 +08001409 err = register_netdevice_notifier(&ip6_mr_notifier);
1410 if (err)
1411 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001412#ifdef CONFIG_IPV6_PIMSM_V2
1413 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001414 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001415 err = -EAGAIN;
1416 goto add_proto_fail;
1417 }
1418#endif
Greg Rosec7ac8672011-06-10 01:27:09 +00001419 rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL,
1420 ip6mr_rtm_dumproute, NULL);
Wang Chen623d1a12008-07-03 12:13:30 +08001421 return 0;
Tom Goff403dbb92009-06-14 03:16:13 -07001422#ifdef CONFIG_IPV6_PIMSM_V2
1423add_proto_fail:
1424 unregister_netdevice_notifier(&ip6_mr_notifier);
1425#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001426reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001427 unregister_pernet_subsys(&ip6mr_net_ops);
1428reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001429 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001430 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001431}
1432
Wang Chen623d1a12008-07-03 12:13:30 +08001433void ip6_mr_cleanup(void)
1434{
Wang Chen623d1a12008-07-03 12:13:30 +08001435 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001436 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001437 kmem_cache_destroy(mrt_cachep);
1438}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001439
Patrick McHardy6bd52142010-05-11 14:40:53 +02001440static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001441 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001442{
Patrick McHardyf30a77842010-05-11 14:40:51 +02001443 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001444 int line;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001445 struct mfc6_cache *uc, *c;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001446 unsigned char ttls[MAXMIFS];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001447 int i;
1448
Patrick McHardya50436f22010-03-17 06:04:14 +00001449 if (mfc->mf6cc_parent >= MAXMIFS)
1450 return -ENFILE;
1451
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001452 memset(ttls, 255, MAXMIFS);
1453 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001454 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1455 ttls[i] = 1;
1456
1457 }
1458
1459 line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
1460
Patrick McHardy6bd52142010-05-11 14:40:53 +02001461 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001462 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001463 ipv6_addr_equal(&c->mf6c_mcastgrp,
1464 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1465 (parent == -1 || parent == mfc->mf6cc_parent)) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001466 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001467 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001468 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001469 }
1470
Patrick McHardyf30a77842010-05-11 14:40:51 +02001471 if (found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001472 write_lock_bh(&mrt_lock);
1473 c->mf6c_parent = mfc->mf6cc_parent;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001474 ip6mr_update_thresholds(mrt, c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001475 if (!mrtsock)
1476 c->mfc_flags |= MFC_STATIC;
1477 write_unlock_bh(&mrt_lock);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001478 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001479 return 0;
1480 }
1481
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001482 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1483 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001484 return -EINVAL;
1485
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001486 c = ip6mr_cache_alloc();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001487 if (c == NULL)
1488 return -ENOMEM;
1489
1490 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1491 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
1492 c->mf6c_parent = mfc->mf6cc_parent;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001493 ip6mr_update_thresholds(mrt, c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001494 if (!mrtsock)
1495 c->mfc_flags |= MFC_STATIC;
1496
1497 write_lock_bh(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001498 list_add(&c->list, &mrt->mfc6_cache_array[line]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001499 write_unlock_bh(&mrt_lock);
1500
1501 /*
1502 * Check to see if we resolved a queued list. If so we
1503 * need to send on the frames and tidy up.
1504 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001505 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001506 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001507 list_for_each_entry(uc, &mrt->mfc6_unres_queue, list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001508 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001509 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001510 list_del(&uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001511 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001512 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001513 break;
1514 }
1515 }
Patrick McHardy6bd52142010-05-11 14:40:53 +02001516 if (list_empty(&mrt->mfc6_unres_queue))
1517 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001518 spin_unlock_bh(&mfc_unres_lock);
1519
Patrick McHardyf30a77842010-05-11 14:40:51 +02001520 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001521 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001522 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001523 }
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001524 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001525 return 0;
1526}
1527
1528/*
1529 * Close the multicast socket, and clear the vif tables etc
1530 */
1531
Patrick McHardy6bd52142010-05-11 14:40:53 +02001532static void mroute_clean_tables(struct mr6_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001533{
1534 int i;
Eric Dumazetc871e662009-10-28 04:48:11 +00001535 LIST_HEAD(list);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001536 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001537
1538 /*
1539 * Shut down all active vif entries
1540 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001541 for (i = 0; i < mrt->maxvif; i++) {
1542 if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
1543 mif6_delete(mrt, i, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001544 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001545 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001546
1547 /*
1548 * Wipe the cache
1549 */
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001550 for (i = 0; i < MFC6_LINES; i++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001551 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001552 if (c->mfc_flags & MFC_STATIC)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001553 continue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001554 write_lock_bh(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001555 list_del(&c->list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001556 write_unlock_bh(&mrt_lock);
1557
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001558 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001559 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001560 }
1561 }
1562
Patrick McHardy6bd52142010-05-11 14:40:53 +02001563 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001564 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001565 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001566 list_del(&c->list);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001567 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001568 ip6mr_destroy_unres(mrt, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001569 }
1570 spin_unlock_bh(&mfc_unres_lock);
1571 }
1572}
1573
Patrick McHardy6bd52142010-05-11 14:40:53 +02001574static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001575{
1576 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001577 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001578
1579 rtnl_lock();
1580 write_lock_bh(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001581 if (likely(mrt->mroute6_sk == NULL)) {
1582 mrt->mroute6_sk = sk;
Thomas Goff1d6e55f2009-01-27 22:39:59 -08001583 net->ipv6.devconf_all->mc_forwarding++;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001584 inet6_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
1585 NETCONFA_IFINDEX_ALL,
1586 net->ipv6.devconf_all);
Thomas Goff1d6e55f2009-01-27 22:39:59 -08001587 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001588 else
1589 err = -EADDRINUSE;
1590 write_unlock_bh(&mrt_lock);
1591
1592 rtnl_unlock();
1593
1594 return err;
1595}
1596
1597int ip6mr_sk_done(struct sock *sk)
1598{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001599 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001600 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001601 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001602
1603 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001604 ip6mr_for_each_table(mrt, net) {
1605 if (sk == mrt->mroute6_sk) {
1606 write_lock_bh(&mrt_lock);
1607 mrt->mroute6_sk = NULL;
1608 net->ipv6.devconf_all->mc_forwarding--;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001609 inet6_netconf_notify_devconf(net,
1610 NETCONFA_MC_FORWARDING,
1611 NETCONFA_IFINDEX_ALL,
1612 net->ipv6.devconf_all);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001613 write_unlock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001614
Patrick McHardyd1db2752010-05-11 14:40:55 +02001615 mroute_clean_tables(mrt);
1616 err = 0;
1617 break;
1618 }
1619 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001620 rtnl_unlock();
1621
1622 return err;
1623}
1624
Patrick McHardyd1db2752010-05-11 14:40:55 +02001625struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001626{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001627 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001628 struct flowi6 fl6 = {
1629 .flowi6_iif = skb->skb_iif,
1630 .flowi6_oif = skb->dev->ifindex,
1631 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001632 };
1633
David S. Miller4c9483b2011-03-12 16:22:43 -05001634 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001635 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001636
1637 return mrt->mroute6_sk;
1638}
1639
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001640/*
1641 * Socket options and virtual interface manipulation. The whole
1642 * virtual interface system is a complete heap, but unfortunately
1643 * that's how BSD mrouted happens to think. Maybe one day with a proper
1644 * MOSPF/PIM router set up we can clean this up.
1645 */
1646
David S. Millerb7058842009-09-30 16:12:20 -07001647int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001648{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001649 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001650 struct mif6ctl vif;
1651 struct mf6cctl mfc;
1652 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001653 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001654 struct mr6_table *mrt;
1655
1656 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1657 if (mrt == NULL)
1658 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001659
1660 if (optname != MRT6_INIT) {
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00001661 if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001662 return -EACCES;
1663 }
1664
1665 switch (optname) {
1666 case MRT6_INIT:
1667 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e82009-10-15 06:30:45 +00001668 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001669 return -EOPNOTSUPP;
1670 if (optlen < sizeof(int))
1671 return -EINVAL;
1672
Patrick McHardy6bd52142010-05-11 14:40:53 +02001673 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001674
1675 case MRT6_DONE:
1676 return ip6mr_sk_done(sk);
1677
1678 case MRT6_ADD_MIF:
1679 if (optlen < sizeof(vif))
1680 return -EINVAL;
1681 if (copy_from_user(&vif, optval, sizeof(vif)))
1682 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001683 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001684 return -ENFILE;
1685 rtnl_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001686 ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001687 rtnl_unlock();
1688 return ret;
1689
1690 case MRT6_DEL_MIF:
1691 if (optlen < sizeof(mifi_t))
1692 return -EINVAL;
1693 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1694 return -EFAULT;
1695 rtnl_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001696 ret = mif6_delete(mrt, mifi, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001697 rtnl_unlock();
1698 return ret;
1699
1700 /*
1701 * Manipulate the forwarding caches. These live
1702 * in a sort of kernel/user symbiosis.
1703 */
1704 case MRT6_ADD_MFC:
1705 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001706 parent = -1;
1707 case MRT6_ADD_MFC_PROXY:
1708 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001709 if (optlen < sizeof(mfc))
1710 return -EINVAL;
1711 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1712 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001713 if (parent == 0)
1714 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001715 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001716 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1717 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001718 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001719 ret = ip6mr_mfc_add(net, mrt, &mfc,
1720 sk == mrt->mroute6_sk, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001721 rtnl_unlock();
1722 return ret;
1723
1724 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001725 * Control PIM assert (to activate pim will activate assert)
1726 */
1727 case MRT6_ASSERT:
1728 {
1729 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001730
1731 if (optlen != sizeof(v))
1732 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001733 if (get_user(v, (int __user *)optval))
1734 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001735 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001736 return 0;
1737 }
1738
1739#ifdef CONFIG_IPV6_PIMSM_V2
1740 case MRT6_PIM:
1741 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001742 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001743
1744 if (optlen != sizeof(v))
1745 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001746 if (get_user(v, (int __user *)optval))
1747 return -EFAULT;
1748 v = !!v;
1749 rtnl_lock();
1750 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001751 if (v != mrt->mroute_do_pim) {
1752 mrt->mroute_do_pim = v;
1753 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001754 }
1755 rtnl_unlock();
1756 return ret;
1757 }
1758
1759#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001760#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1761 case MRT6_TABLE:
1762 {
1763 u32 v;
1764
1765 if (optlen != sizeof(u32))
1766 return -EINVAL;
1767 if (get_user(v, (u32 __user *)optval))
1768 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001769 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1770 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1771 return -EINVAL;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001772 if (sk == mrt->mroute6_sk)
1773 return -EBUSY;
1774
1775 rtnl_lock();
1776 ret = 0;
1777 if (!ip6mr_new_table(net, v))
1778 ret = -ENOMEM;
1779 raw6_sk(sk)->ip6mr_table = v;
1780 rtnl_unlock();
1781 return ret;
1782 }
1783#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001784 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001785 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001786 * set.
1787 */
1788 default:
1789 return -ENOPROTOOPT;
1790 }
1791}
1792
1793/*
1794 * Getsock opt support for the multicast routing system.
1795 */
1796
1797int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1798 int __user *optlen)
1799{
1800 int olr;
1801 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001802 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001803 struct mr6_table *mrt;
1804
1805 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1806 if (mrt == NULL)
1807 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001808
1809 switch (optname) {
1810 case MRT6_VERSION:
1811 val = 0x0305;
1812 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001813#ifdef CONFIG_IPV6_PIMSM_V2
1814 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001815 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001816 break;
1817#endif
1818 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001819 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001820 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001821 default:
1822 return -ENOPROTOOPT;
1823 }
1824
1825 if (get_user(olr, optlen))
1826 return -EFAULT;
1827
1828 olr = min_t(int, olr, sizeof(int));
1829 if (olr < 0)
1830 return -EINVAL;
1831
1832 if (put_user(olr, optlen))
1833 return -EFAULT;
1834 if (copy_to_user(optval, &val, olr))
1835 return -EFAULT;
1836 return 0;
1837}
1838
1839/*
1840 * The IP multicast ioctl support routines.
1841 */
1842
1843int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1844{
1845 struct sioc_sg_req6 sr;
1846 struct sioc_mif_req6 vr;
1847 struct mif_device *vif;
1848 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001849 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001850 struct mr6_table *mrt;
1851
1852 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1853 if (mrt == NULL)
1854 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001855
1856 switch (cmd) {
1857 case SIOCGETMIFCNT_IN6:
1858 if (copy_from_user(&vr, arg, sizeof(vr)))
1859 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001860 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001861 return -EINVAL;
1862 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001863 vif = &mrt->vif6_table[vr.mifi];
1864 if (MIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001865 vr.icount = vif->pkt_in;
1866 vr.ocount = vif->pkt_out;
1867 vr.ibytes = vif->bytes_in;
1868 vr.obytes = vif->bytes_out;
1869 read_unlock(&mrt_lock);
1870
1871 if (copy_to_user(arg, &vr, sizeof(vr)))
1872 return -EFAULT;
1873 return 0;
1874 }
1875 read_unlock(&mrt_lock);
1876 return -EADDRNOTAVAIL;
1877 case SIOCGETSGCNT_IN6:
1878 if (copy_from_user(&sr, arg, sizeof(sr)))
1879 return -EFAULT;
1880
1881 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001882 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001883 if (c) {
1884 sr.pktcnt = c->mfc_un.res.pkt;
1885 sr.bytecnt = c->mfc_un.res.bytes;
1886 sr.wrong_if = c->mfc_un.res.wrong_if;
1887 read_unlock(&mrt_lock);
1888
1889 if (copy_to_user(arg, &sr, sizeof(sr)))
1890 return -EFAULT;
1891 return 0;
1892 }
1893 read_unlock(&mrt_lock);
1894 return -EADDRNOTAVAIL;
1895 default:
1896 return -ENOIOCTLCMD;
1897 }
1898}
1899
David S. Millere2d57762011-02-03 17:59:32 -08001900#ifdef CONFIG_COMPAT
1901struct compat_sioc_sg_req6 {
1902 struct sockaddr_in6 src;
1903 struct sockaddr_in6 grp;
1904 compat_ulong_t pktcnt;
1905 compat_ulong_t bytecnt;
1906 compat_ulong_t wrong_if;
1907};
1908
1909struct compat_sioc_mif_req6 {
1910 mifi_t mifi;
1911 compat_ulong_t icount;
1912 compat_ulong_t ocount;
1913 compat_ulong_t ibytes;
1914 compat_ulong_t obytes;
1915};
1916
1917int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1918{
1919 struct compat_sioc_sg_req6 sr;
1920 struct compat_sioc_mif_req6 vr;
1921 struct mif_device *vif;
1922 struct mfc6_cache *c;
1923 struct net *net = sock_net(sk);
1924 struct mr6_table *mrt;
1925
1926 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1927 if (mrt == NULL)
1928 return -ENOENT;
1929
1930 switch (cmd) {
1931 case SIOCGETMIFCNT_IN6:
1932 if (copy_from_user(&vr, arg, sizeof(vr)))
1933 return -EFAULT;
1934 if (vr.mifi >= mrt->maxvif)
1935 return -EINVAL;
1936 read_lock(&mrt_lock);
1937 vif = &mrt->vif6_table[vr.mifi];
1938 if (MIF_EXISTS(mrt, vr.mifi)) {
1939 vr.icount = vif->pkt_in;
1940 vr.ocount = vif->pkt_out;
1941 vr.ibytes = vif->bytes_in;
1942 vr.obytes = vif->bytes_out;
1943 read_unlock(&mrt_lock);
1944
1945 if (copy_to_user(arg, &vr, sizeof(vr)))
1946 return -EFAULT;
1947 return 0;
1948 }
1949 read_unlock(&mrt_lock);
1950 return -EADDRNOTAVAIL;
1951 case SIOCGETSGCNT_IN6:
1952 if (copy_from_user(&sr, arg, sizeof(sr)))
1953 return -EFAULT;
1954
1955 read_lock(&mrt_lock);
1956 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1957 if (c) {
1958 sr.pktcnt = c->mfc_un.res.pkt;
1959 sr.bytecnt = c->mfc_un.res.bytes;
1960 sr.wrong_if = c->mfc_un.res.wrong_if;
1961 read_unlock(&mrt_lock);
1962
1963 if (copy_to_user(arg, &sr, sizeof(sr)))
1964 return -EFAULT;
1965 return 0;
1966 }
1967 read_unlock(&mrt_lock);
1968 return -EADDRNOTAVAIL;
1969 default:
1970 return -ENOIOCTLCMD;
1971 }
1972}
1973#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001974
1975static inline int ip6mr_forward2_finish(struct sk_buff *skb)
1976{
Eric Dumazetadf30902009-06-02 05:19:30 +00001977 IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
Denis V. Lunev483a47d2008-10-08 11:09:27 -07001978 IPSTATS_MIB_OUTFORWDATAGRAMS);
Vincent Bernat2d8dbb02012-06-05 03:41:42 +00001979 IP6_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
1980 IPSTATS_MIB_OUTOCTETS, skb->len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001981 return dst_output(skb);
1982}
1983
1984/*
1985 * Processing handlers for ip6mr_forward
1986 */
1987
Patrick McHardy6bd52142010-05-11 14:40:53 +02001988static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
1989 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001990{
1991 struct ipv6hdr *ipv6h;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001992 struct mif_device *vif = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001993 struct net_device *dev;
1994 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001995 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001996
1997 if (vif->dev == NULL)
1998 goto out_free;
1999
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002000#ifdef CONFIG_IPV6_PIMSM_V2
2001 if (vif->flags & MIFF_REGISTER) {
2002 vif->pkt_out++;
2003 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07002004 vif->dev->stats.tx_bytes += skb->len;
2005 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002006 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08002007 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002008 }
2009#endif
2010
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002011 ipv6h = ipv6_hdr(skb);
2012
David S. Miller4c9483b2011-03-12 16:22:43 -05002013 fl6 = (struct flowi6) {
2014 .flowi6_oif = vif->link,
2015 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002016 };
2017
David S. Miller4c9483b2011-03-12 16:22:43 -05002018 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00002019 if (dst->error) {
2020 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002021 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00002022 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002023
Eric Dumazetadf30902009-06-02 05:19:30 +00002024 skb_dst_drop(skb);
2025 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002026
2027 /*
2028 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
2029 * not only before forwarding, but after forwarding on all output
2030 * interfaces. It is clear, if mrouter runs a multicasting
2031 * program, it should receive packets not depending to what interface
2032 * program is joined.
2033 * If we will not make it, the program will have to join on all
2034 * interfaces. On the other hand, multihoming host (or router, but
2035 * not mrouter) cannot join to more than one interface - it will
2036 * result in receiving multiple packets.
2037 */
2038 dev = vif->dev;
2039 skb->dev = dev;
2040 vif->pkt_out++;
2041 vif->bytes_out += skb->len;
2042
2043 /* We are about to write */
2044 /* XXX: extension headers? */
2045 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2046 goto out_free;
2047
2048 ipv6h = ipv6_hdr(skb);
2049 ipv6h->hop_limit--;
2050
2051 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2052
Jan Engelhardtb2e0b382010-03-23 04:09:07 +01002053 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002054 ip6mr_forward2_finish);
2055
2056out_free:
2057 kfree_skb(skb);
2058 return 0;
2059}
2060
Patrick McHardy6bd52142010-05-11 14:40:53 +02002061static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002062{
2063 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002064
2065 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
2066 if (mrt->vif6_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002067 break;
2068 }
2069 return ct;
2070}
2071
Patrick McHardy6bd52142010-05-11 14:40:53 +02002072static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2073 struct sk_buff *skb, struct mfc6_cache *cache)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002074{
2075 int psend = -1;
2076 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002077 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002078
2079 vif = cache->mf6c_parent;
2080 cache->mfc_un.res.pkt++;
2081 cache->mfc_un.res.bytes += skb->len;
2082
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002083 if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
2084 struct mfc6_cache *cache_proxy;
2085
2086 /* For an (*,G) entry, we only check that the incomming
2087 * interface is part of the static tree.
2088 */
2089 cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
2090 if (cache_proxy &&
2091 cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
2092 goto forward;
2093 }
2094
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002095 /*
2096 * Wrong interface: drop packet and (maybe) send PIM assert.
2097 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002098 if (mrt->vif6_table[vif].dev != skb->dev) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002099 cache->mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002100
Patrick McHardy6bd52142010-05-11 14:40:53 +02002101 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002102 /* pimsm uses asserts, when switching from RPT to SPT,
2103 so that we cannot check that packet arrived on an oif.
2104 It is bad, but otherwise we would need to move pretty
2105 large chunk of pimd to kernel. Ough... --ANK
2106 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002107 (mrt->mroute_do_pim ||
Benjamin Therya21f3f92008-12-10 16:28:44 -08002108 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002109 time_after(jiffies,
2110 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
2111 cache->mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002112 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002113 }
2114 goto dont_forward;
2115 }
2116
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002117forward:
Patrick McHardy6bd52142010-05-11 14:40:53 +02002118 mrt->vif6_table[vif].pkt_in++;
2119 mrt->vif6_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002120
2121 /*
2122 * Forward the frame
2123 */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002124 if (ipv6_addr_any(&cache->mf6c_origin) &&
2125 ipv6_addr_any(&cache->mf6c_mcastgrp)) {
2126 if (true_vifi >= 0 &&
2127 true_vifi != cache->mf6c_parent &&
2128 ipv6_hdr(skb)->hop_limit >
2129 cache->mfc_un.res.ttls[cache->mf6c_parent]) {
2130 /* It's an (*,*) entry and the packet is not coming from
2131 * the upstream: forward the packet to the upstream
2132 * only.
2133 */
2134 psend = cache->mf6c_parent;
2135 goto last_forward;
2136 }
2137 goto dont_forward;
2138 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002139 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002140 /* For (*,G) entry, don't forward to the incoming interface */
2141 if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) &&
2142 ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002143 if (psend != -1) {
2144 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2145 if (skb2)
Patrick McHardy6bd52142010-05-11 14:40:53 +02002146 ip6mr_forward2(net, mrt, skb2, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002147 }
2148 psend = ct;
2149 }
2150 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002151last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002152 if (psend != -1) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002153 ip6mr_forward2(net, mrt, skb, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002154 return 0;
2155 }
2156
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002157dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002158 kfree_skb(skb);
2159 return 0;
2160}
2161
2162
2163/*
2164 * Multicast packets for forwarding arrive here
2165 */
2166
2167int ip6_mr_input(struct sk_buff *skb)
2168{
2169 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002170 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002171 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002172 struct flowi6 fl6 = {
2173 .flowi6_iif = skb->dev->ifindex,
2174 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002175 };
2176 int err;
2177
David S. Miller4c9483b2011-03-12 16:22:43 -05002178 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002179 if (err < 0) {
2180 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002181 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002182 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002183
2184 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002185 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002186 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002187 if (cache == NULL) {
2188 int vif = ip6mr_find_vif(mrt, skb->dev);
2189
2190 if (vif >= 0)
2191 cache = ip6mr_cache_find_any(mrt,
2192 &ipv6_hdr(skb)->daddr,
2193 vif);
2194 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002195
2196 /*
2197 * No usable cache entry
2198 */
2199 if (cache == NULL) {
2200 int vif;
2201
Patrick McHardy6bd52142010-05-11 14:40:53 +02002202 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002203 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002204 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002205 read_unlock(&mrt_lock);
2206
2207 return err;
2208 }
2209 read_unlock(&mrt_lock);
2210 kfree_skb(skb);
2211 return -ENODEV;
2212 }
2213
Patrick McHardy6bd52142010-05-11 14:40:53 +02002214 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002215
2216 read_unlock(&mrt_lock);
2217
2218 return 0;
2219}
2220
2221
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002222static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2223 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002224{
2225 int ct;
2226 struct rtnexthop *nhp;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002227 struct nlattr *mp_attr;
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002228 struct rta_mfc_stats mfcs;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002229
Nicolas Dichtel74381892010-03-25 23:45:35 +00002230 /* If cache is unresolved, don't try to parse IIF and OIF */
Dan Carpentered0f160a2010-05-26 00:38:56 -07002231 if (c->mf6c_parent >= MAXMIFS)
Nicolas Dichtel74381892010-03-25 23:45:35 +00002232 return -ENOENT;
2233
Thomas Graf74a0bd72012-06-26 23:36:14 +00002234 if (MIF_EXISTS(mrt, c->mf6c_parent) &&
2235 nla_put_u32(skb, RTA_IIF, mrt->vif6_table[c->mf6c_parent].dev->ifindex) < 0)
2236 return -EMSGSIZE;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002237 mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
2238 if (mp_attr == NULL)
2239 return -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002240
2241 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002242 if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002243 nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
2244 if (nhp == NULL) {
2245 nla_nest_cancel(skb, mp_attr);
2246 return -EMSGSIZE;
2247 }
2248
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002249 nhp->rtnh_flags = 0;
2250 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Patrick McHardy6bd52142010-05-11 14:40:53 +02002251 nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002252 nhp->rtnh_len = sizeof(*nhp);
2253 }
2254 }
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002255
2256 nla_nest_end(skb, mp_attr);
2257
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002258 mfcs.mfcs_packets = c->mfc_un.res.pkt;
2259 mfcs.mfcs_bytes = c->mfc_un.res.bytes;
2260 mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
2261 if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0)
2262 return -EMSGSIZE;
2263
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002264 rtm->rtm_type = RTN_MULTICAST;
2265 return 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002266}
2267
Benjamin Thery8229efd2008-12-10 16:30:15 -08002268int ip6mr_get_route(struct net *net,
2269 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002270{
2271 int err;
Patrick McHardyd1db2752010-05-11 14:40:55 +02002272 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002273 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002274 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002275
Patrick McHardyd1db2752010-05-11 14:40:55 +02002276 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2277 if (mrt == NULL)
2278 return -ENOENT;
2279
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002280 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002281 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002282 if (!cache && skb->dev) {
2283 int vif = ip6mr_find_vif(mrt, skb->dev);
2284
2285 if (vif >= 0)
2286 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2287 vif);
2288 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002289
2290 if (!cache) {
2291 struct sk_buff *skb2;
2292 struct ipv6hdr *iph;
2293 struct net_device *dev;
2294 int vif;
2295
2296 if (nowait) {
2297 read_unlock(&mrt_lock);
2298 return -EAGAIN;
2299 }
2300
2301 dev = skb->dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002302 if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002303 read_unlock(&mrt_lock);
2304 return -ENODEV;
2305 }
2306
2307 /* really correct? */
2308 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2309 if (!skb2) {
2310 read_unlock(&mrt_lock);
2311 return -ENOMEM;
2312 }
2313
2314 skb_reset_transport_header(skb2);
2315
2316 skb_put(skb2, sizeof(struct ipv6hdr));
2317 skb_reset_network_header(skb2);
2318
2319 iph = ipv6_hdr(skb2);
2320 iph->version = 0;
2321 iph->priority = 0;
2322 iph->flow_lbl[0] = 0;
2323 iph->flow_lbl[1] = 0;
2324 iph->flow_lbl[2] = 0;
2325 iph->payload_len = 0;
2326 iph->nexthdr = IPPROTO_NONE;
2327 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002328 iph->saddr = rt->rt6i_src.addr;
2329 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002330
Patrick McHardy6bd52142010-05-11 14:40:53 +02002331 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002332 read_unlock(&mrt_lock);
2333
2334 return err;
2335 }
2336
2337 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
2338 cache->mfc_flags |= MFC_NOTIFY;
2339
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002340 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002341 read_unlock(&mrt_lock);
2342 return err;
2343}
2344
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002345static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002346 u32 portid, u32 seq, struct mfc6_cache *c, int cmd)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002347{
2348 struct nlmsghdr *nlh;
2349 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002350 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002351
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002352 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002353 if (nlh == NULL)
2354 return -EMSGSIZE;
2355
2356 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002357 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002358 rtm->rtm_dst_len = 128;
2359 rtm->rtm_src_len = 128;
2360 rtm->rtm_tos = 0;
2361 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002362 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2363 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002364 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002365 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002366 if (c->mfc_flags & MFC_STATIC)
2367 rtm->rtm_protocol = RTPROT_STATIC;
2368 else
2369 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002370 rtm->rtm_flags = 0;
2371
David S. Millerc78679e2012-04-01 20:27:33 -04002372 if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) ||
2373 nla_put(skb, RTA_DST, 16, &c->mf6c_mcastgrp))
2374 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002375 err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
2376 /* do not break the dump if cache is unresolved */
2377 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002378 goto nla_put_failure;
2379
2380 return nlmsg_end(skb, nlh);
2381
2382nla_put_failure:
2383 nlmsg_cancel(skb, nlh);
2384 return -EMSGSIZE;
2385}
2386
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002387static int mr6_msgsize(bool unresolved, int maxvif)
2388{
2389 size_t len =
2390 NLMSG_ALIGN(sizeof(struct rtmsg))
2391 + nla_total_size(4) /* RTA_TABLE */
2392 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2393 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2394 ;
2395
2396 if (!unresolved)
2397 len = len
2398 + nla_total_size(4) /* RTA_IIF */
2399 + nla_total_size(0) /* RTA_MULTIPATH */
2400 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2401 /* RTA_MFC_STATS */
2402 + nla_total_size(sizeof(struct rta_mfc_stats))
2403 ;
2404
2405 return len;
2406}
2407
2408static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
2409 int cmd)
2410{
2411 struct net *net = read_pnet(&mrt->net);
2412 struct sk_buff *skb;
2413 int err = -ENOBUFS;
2414
2415 skb = nlmsg_new(mr6_msgsize(mfc->mf6c_parent >= MAXMIFS, mrt->maxvif),
2416 GFP_ATOMIC);
2417 if (skb == NULL)
2418 goto errout;
2419
2420 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
2421 if (err < 0)
2422 goto errout;
2423
2424 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2425 return;
2426
2427errout:
2428 kfree_skb(skb);
2429 if (err < 0)
2430 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2431}
2432
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002433static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2434{
2435 struct net *net = sock_net(skb->sk);
2436 struct mr6_table *mrt;
2437 struct mfc6_cache *mfc;
2438 unsigned int t = 0, s_t;
2439 unsigned int h = 0, s_h;
2440 unsigned int e = 0, s_e;
2441
2442 s_t = cb->args[0];
2443 s_h = cb->args[1];
2444 s_e = cb->args[2];
2445
2446 read_lock(&mrt_lock);
2447 ip6mr_for_each_table(mrt, net) {
2448 if (t < s_t)
2449 goto next_table;
2450 if (t > s_t)
2451 s_h = 0;
2452 for (h = s_h; h < MFC6_LINES; h++) {
2453 list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) {
2454 if (e < s_e)
2455 goto next_entry;
2456 if (ip6mr_fill_mroute(mrt, skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002457 NETLINK_CB(cb->skb).portid,
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002458 cb->nlh->nlmsg_seq,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002459 mfc, RTM_NEWROUTE) < 0)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002460 goto done;
2461next_entry:
2462 e++;
2463 }
2464 e = s_e = 0;
2465 }
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002466 spin_lock_bh(&mfc_unres_lock);
2467 list_for_each_entry(mfc, &mrt->mfc6_unres_queue, list) {
2468 if (e < s_e)
2469 goto next_entry2;
2470 if (ip6mr_fill_mroute(mrt, skb,
2471 NETLINK_CB(cb->skb).portid,
2472 cb->nlh->nlmsg_seq,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002473 mfc, RTM_NEWROUTE) < 0) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002474 spin_unlock_bh(&mfc_unres_lock);
2475 goto done;
2476 }
2477next_entry2:
2478 e++;
2479 }
2480 spin_unlock_bh(&mfc_unres_lock);
2481 e = s_e = 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002482 s_h = 0;
2483next_table:
2484 t++;
2485 }
2486done:
2487 read_unlock(&mrt_lock);
2488
2489 cb->args[2] = e;
2490 cb->args[1] = h;
2491 cb->args[0] = t;
2492
2493 return skb->len;
2494}