blob: acc32494006a2ccf5a1993ba7f6c9b9c325aaf17 [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;
1362 if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
1363 goto proc_vif_fail;
1364 if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops))
1365 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 Dumazetc720c7e2009-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;
1769 if (sk == mrt->mroute6_sk)
1770 return -EBUSY;
1771
1772 rtnl_lock();
1773 ret = 0;
1774 if (!ip6mr_new_table(net, v))
1775 ret = -ENOMEM;
1776 raw6_sk(sk)->ip6mr_table = v;
1777 rtnl_unlock();
1778 return ret;
1779 }
1780#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001781 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001782 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001783 * set.
1784 */
1785 default:
1786 return -ENOPROTOOPT;
1787 }
1788}
1789
1790/*
1791 * Getsock opt support for the multicast routing system.
1792 */
1793
1794int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1795 int __user *optlen)
1796{
1797 int olr;
1798 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001799 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001800 struct mr6_table *mrt;
1801
1802 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1803 if (mrt == NULL)
1804 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001805
1806 switch (optname) {
1807 case MRT6_VERSION:
1808 val = 0x0305;
1809 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001810#ifdef CONFIG_IPV6_PIMSM_V2
1811 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001812 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001813 break;
1814#endif
1815 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001816 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001817 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001818 default:
1819 return -ENOPROTOOPT;
1820 }
1821
1822 if (get_user(olr, optlen))
1823 return -EFAULT;
1824
1825 olr = min_t(int, olr, sizeof(int));
1826 if (olr < 0)
1827 return -EINVAL;
1828
1829 if (put_user(olr, optlen))
1830 return -EFAULT;
1831 if (copy_to_user(optval, &val, olr))
1832 return -EFAULT;
1833 return 0;
1834}
1835
1836/*
1837 * The IP multicast ioctl support routines.
1838 */
1839
1840int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1841{
1842 struct sioc_sg_req6 sr;
1843 struct sioc_mif_req6 vr;
1844 struct mif_device *vif;
1845 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001846 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001847 struct mr6_table *mrt;
1848
1849 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1850 if (mrt == NULL)
1851 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001852
1853 switch (cmd) {
1854 case SIOCGETMIFCNT_IN6:
1855 if (copy_from_user(&vr, arg, sizeof(vr)))
1856 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001857 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001858 return -EINVAL;
1859 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001860 vif = &mrt->vif6_table[vr.mifi];
1861 if (MIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001862 vr.icount = vif->pkt_in;
1863 vr.ocount = vif->pkt_out;
1864 vr.ibytes = vif->bytes_in;
1865 vr.obytes = vif->bytes_out;
1866 read_unlock(&mrt_lock);
1867
1868 if (copy_to_user(arg, &vr, sizeof(vr)))
1869 return -EFAULT;
1870 return 0;
1871 }
1872 read_unlock(&mrt_lock);
1873 return -EADDRNOTAVAIL;
1874 case SIOCGETSGCNT_IN6:
1875 if (copy_from_user(&sr, arg, sizeof(sr)))
1876 return -EFAULT;
1877
1878 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001879 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001880 if (c) {
1881 sr.pktcnt = c->mfc_un.res.pkt;
1882 sr.bytecnt = c->mfc_un.res.bytes;
1883 sr.wrong_if = c->mfc_un.res.wrong_if;
1884 read_unlock(&mrt_lock);
1885
1886 if (copy_to_user(arg, &sr, sizeof(sr)))
1887 return -EFAULT;
1888 return 0;
1889 }
1890 read_unlock(&mrt_lock);
1891 return -EADDRNOTAVAIL;
1892 default:
1893 return -ENOIOCTLCMD;
1894 }
1895}
1896
David S. Millere2d57762011-02-03 17:59:32 -08001897#ifdef CONFIG_COMPAT
1898struct compat_sioc_sg_req6 {
1899 struct sockaddr_in6 src;
1900 struct sockaddr_in6 grp;
1901 compat_ulong_t pktcnt;
1902 compat_ulong_t bytecnt;
1903 compat_ulong_t wrong_if;
1904};
1905
1906struct compat_sioc_mif_req6 {
1907 mifi_t mifi;
1908 compat_ulong_t icount;
1909 compat_ulong_t ocount;
1910 compat_ulong_t ibytes;
1911 compat_ulong_t obytes;
1912};
1913
1914int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1915{
1916 struct compat_sioc_sg_req6 sr;
1917 struct compat_sioc_mif_req6 vr;
1918 struct mif_device *vif;
1919 struct mfc6_cache *c;
1920 struct net *net = sock_net(sk);
1921 struct mr6_table *mrt;
1922
1923 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1924 if (mrt == NULL)
1925 return -ENOENT;
1926
1927 switch (cmd) {
1928 case SIOCGETMIFCNT_IN6:
1929 if (copy_from_user(&vr, arg, sizeof(vr)))
1930 return -EFAULT;
1931 if (vr.mifi >= mrt->maxvif)
1932 return -EINVAL;
1933 read_lock(&mrt_lock);
1934 vif = &mrt->vif6_table[vr.mifi];
1935 if (MIF_EXISTS(mrt, vr.mifi)) {
1936 vr.icount = vif->pkt_in;
1937 vr.ocount = vif->pkt_out;
1938 vr.ibytes = vif->bytes_in;
1939 vr.obytes = vif->bytes_out;
1940 read_unlock(&mrt_lock);
1941
1942 if (copy_to_user(arg, &vr, sizeof(vr)))
1943 return -EFAULT;
1944 return 0;
1945 }
1946 read_unlock(&mrt_lock);
1947 return -EADDRNOTAVAIL;
1948 case SIOCGETSGCNT_IN6:
1949 if (copy_from_user(&sr, arg, sizeof(sr)))
1950 return -EFAULT;
1951
1952 read_lock(&mrt_lock);
1953 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1954 if (c) {
1955 sr.pktcnt = c->mfc_un.res.pkt;
1956 sr.bytecnt = c->mfc_un.res.bytes;
1957 sr.wrong_if = c->mfc_un.res.wrong_if;
1958 read_unlock(&mrt_lock);
1959
1960 if (copy_to_user(arg, &sr, sizeof(sr)))
1961 return -EFAULT;
1962 return 0;
1963 }
1964 read_unlock(&mrt_lock);
1965 return -EADDRNOTAVAIL;
1966 default:
1967 return -ENOIOCTLCMD;
1968 }
1969}
1970#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001971
1972static inline int ip6mr_forward2_finish(struct sk_buff *skb)
1973{
Eric Dumazetadf30902009-06-02 05:19:30 +00001974 IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
Denis V. Lunev483a47d2008-10-08 11:09:27 -07001975 IPSTATS_MIB_OUTFORWDATAGRAMS);
Vincent Bernat2d8dbb02012-06-05 03:41:42 +00001976 IP6_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
1977 IPSTATS_MIB_OUTOCTETS, skb->len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001978 return dst_output(skb);
1979}
1980
1981/*
1982 * Processing handlers for ip6mr_forward
1983 */
1984
Patrick McHardy6bd52142010-05-11 14:40:53 +02001985static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
1986 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001987{
1988 struct ipv6hdr *ipv6h;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001989 struct mif_device *vif = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001990 struct net_device *dev;
1991 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001992 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001993
1994 if (vif->dev == NULL)
1995 goto out_free;
1996
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001997#ifdef CONFIG_IPV6_PIMSM_V2
1998 if (vif->flags & MIFF_REGISTER) {
1999 vif->pkt_out++;
2000 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07002001 vif->dev->stats.tx_bytes += skb->len;
2002 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002003 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08002004 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002005 }
2006#endif
2007
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002008 ipv6h = ipv6_hdr(skb);
2009
David S. Miller4c9483b2011-03-12 16:22:43 -05002010 fl6 = (struct flowi6) {
2011 .flowi6_oif = vif->link,
2012 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002013 };
2014
David S. Miller4c9483b2011-03-12 16:22:43 -05002015 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00002016 if (dst->error) {
2017 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002018 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00002019 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002020
Eric Dumazetadf30902009-06-02 05:19:30 +00002021 skb_dst_drop(skb);
2022 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002023
2024 /*
2025 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
2026 * not only before forwarding, but after forwarding on all output
2027 * interfaces. It is clear, if mrouter runs a multicasting
2028 * program, it should receive packets not depending to what interface
2029 * program is joined.
2030 * If we will not make it, the program will have to join on all
2031 * interfaces. On the other hand, multihoming host (or router, but
2032 * not mrouter) cannot join to more than one interface - it will
2033 * result in receiving multiple packets.
2034 */
2035 dev = vif->dev;
2036 skb->dev = dev;
2037 vif->pkt_out++;
2038 vif->bytes_out += skb->len;
2039
2040 /* We are about to write */
2041 /* XXX: extension headers? */
2042 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2043 goto out_free;
2044
2045 ipv6h = ipv6_hdr(skb);
2046 ipv6h->hop_limit--;
2047
2048 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2049
Jan Engelhardtb2e0b382010-03-23 04:09:07 +01002050 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002051 ip6mr_forward2_finish);
2052
2053out_free:
2054 kfree_skb(skb);
2055 return 0;
2056}
2057
Patrick McHardy6bd52142010-05-11 14:40:53 +02002058static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002059{
2060 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002061
2062 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
2063 if (mrt->vif6_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002064 break;
2065 }
2066 return ct;
2067}
2068
Patrick McHardy6bd52142010-05-11 14:40:53 +02002069static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2070 struct sk_buff *skb, struct mfc6_cache *cache)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002071{
2072 int psend = -1;
2073 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002074 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002075
2076 vif = cache->mf6c_parent;
2077 cache->mfc_un.res.pkt++;
2078 cache->mfc_un.res.bytes += skb->len;
2079
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002080 if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
2081 struct mfc6_cache *cache_proxy;
2082
2083 /* For an (*,G) entry, we only check that the incomming
2084 * interface is part of the static tree.
2085 */
2086 cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
2087 if (cache_proxy &&
2088 cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
2089 goto forward;
2090 }
2091
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002092 /*
2093 * Wrong interface: drop packet and (maybe) send PIM assert.
2094 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002095 if (mrt->vif6_table[vif].dev != skb->dev) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002096 cache->mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002097
Patrick McHardy6bd52142010-05-11 14:40:53 +02002098 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002099 /* pimsm uses asserts, when switching from RPT to SPT,
2100 so that we cannot check that packet arrived on an oif.
2101 It is bad, but otherwise we would need to move pretty
2102 large chunk of pimd to kernel. Ough... --ANK
2103 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002104 (mrt->mroute_do_pim ||
Benjamin Therya21f3f92008-12-10 16:28:44 -08002105 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002106 time_after(jiffies,
2107 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
2108 cache->mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002109 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002110 }
2111 goto dont_forward;
2112 }
2113
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002114forward:
Patrick McHardy6bd52142010-05-11 14:40:53 +02002115 mrt->vif6_table[vif].pkt_in++;
2116 mrt->vif6_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002117
2118 /*
2119 * Forward the frame
2120 */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002121 if (ipv6_addr_any(&cache->mf6c_origin) &&
2122 ipv6_addr_any(&cache->mf6c_mcastgrp)) {
2123 if (true_vifi >= 0 &&
2124 true_vifi != cache->mf6c_parent &&
2125 ipv6_hdr(skb)->hop_limit >
2126 cache->mfc_un.res.ttls[cache->mf6c_parent]) {
2127 /* It's an (*,*) entry and the packet is not coming from
2128 * the upstream: forward the packet to the upstream
2129 * only.
2130 */
2131 psend = cache->mf6c_parent;
2132 goto last_forward;
2133 }
2134 goto dont_forward;
2135 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002136 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002137 /* For (*,G) entry, don't forward to the incoming interface */
2138 if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) &&
2139 ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002140 if (psend != -1) {
2141 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2142 if (skb2)
Patrick McHardy6bd52142010-05-11 14:40:53 +02002143 ip6mr_forward2(net, mrt, skb2, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002144 }
2145 psend = ct;
2146 }
2147 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002148last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002149 if (psend != -1) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002150 ip6mr_forward2(net, mrt, skb, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002151 return 0;
2152 }
2153
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002154dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002155 kfree_skb(skb);
2156 return 0;
2157}
2158
2159
2160/*
2161 * Multicast packets for forwarding arrive here
2162 */
2163
2164int ip6_mr_input(struct sk_buff *skb)
2165{
2166 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002167 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002168 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002169 struct flowi6 fl6 = {
2170 .flowi6_iif = skb->dev->ifindex,
2171 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002172 };
2173 int err;
2174
David S. Miller4c9483b2011-03-12 16:22:43 -05002175 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002176 if (err < 0) {
2177 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002178 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002179 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002180
2181 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002182 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002183 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002184 if (cache == NULL) {
2185 int vif = ip6mr_find_vif(mrt, skb->dev);
2186
2187 if (vif >= 0)
2188 cache = ip6mr_cache_find_any(mrt,
2189 &ipv6_hdr(skb)->daddr,
2190 vif);
2191 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002192
2193 /*
2194 * No usable cache entry
2195 */
2196 if (cache == NULL) {
2197 int vif;
2198
Patrick McHardy6bd52142010-05-11 14:40:53 +02002199 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002200 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002201 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002202 read_unlock(&mrt_lock);
2203
2204 return err;
2205 }
2206 read_unlock(&mrt_lock);
2207 kfree_skb(skb);
2208 return -ENODEV;
2209 }
2210
Patrick McHardy6bd52142010-05-11 14:40:53 +02002211 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002212
2213 read_unlock(&mrt_lock);
2214
2215 return 0;
2216}
2217
2218
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002219static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2220 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002221{
2222 int ct;
2223 struct rtnexthop *nhp;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002224 struct nlattr *mp_attr;
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002225 struct rta_mfc_stats mfcs;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002226
Nicolas Dichtel74381892010-03-25 23:45:35 +00002227 /* If cache is unresolved, don't try to parse IIF and OIF */
Dan Carpentered0f160a2010-05-26 00:38:56 -07002228 if (c->mf6c_parent >= MAXMIFS)
Nicolas Dichtel74381892010-03-25 23:45:35 +00002229 return -ENOENT;
2230
Thomas Graf74a0bd72012-06-26 23:36:14 +00002231 if (MIF_EXISTS(mrt, c->mf6c_parent) &&
2232 nla_put_u32(skb, RTA_IIF, mrt->vif6_table[c->mf6c_parent].dev->ifindex) < 0)
2233 return -EMSGSIZE;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002234 mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
2235 if (mp_attr == NULL)
2236 return -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002237
2238 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002239 if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002240 nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
2241 if (nhp == NULL) {
2242 nla_nest_cancel(skb, mp_attr);
2243 return -EMSGSIZE;
2244 }
2245
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002246 nhp->rtnh_flags = 0;
2247 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Patrick McHardy6bd52142010-05-11 14:40:53 +02002248 nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002249 nhp->rtnh_len = sizeof(*nhp);
2250 }
2251 }
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002252
2253 nla_nest_end(skb, mp_attr);
2254
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002255 mfcs.mfcs_packets = c->mfc_un.res.pkt;
2256 mfcs.mfcs_bytes = c->mfc_un.res.bytes;
2257 mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
2258 if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0)
2259 return -EMSGSIZE;
2260
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002261 rtm->rtm_type = RTN_MULTICAST;
2262 return 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002263}
2264
Benjamin Thery8229efd2008-12-10 16:30:15 -08002265int ip6mr_get_route(struct net *net,
2266 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002267{
2268 int err;
Patrick McHardyd1db2752010-05-11 14:40:55 +02002269 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002270 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002271 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002272
Patrick McHardyd1db2752010-05-11 14:40:55 +02002273 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2274 if (mrt == NULL)
2275 return -ENOENT;
2276
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002277 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002278 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002279 if (!cache && skb->dev) {
2280 int vif = ip6mr_find_vif(mrt, skb->dev);
2281
2282 if (vif >= 0)
2283 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2284 vif);
2285 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002286
2287 if (!cache) {
2288 struct sk_buff *skb2;
2289 struct ipv6hdr *iph;
2290 struct net_device *dev;
2291 int vif;
2292
2293 if (nowait) {
2294 read_unlock(&mrt_lock);
2295 return -EAGAIN;
2296 }
2297
2298 dev = skb->dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002299 if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002300 read_unlock(&mrt_lock);
2301 return -ENODEV;
2302 }
2303
2304 /* really correct? */
2305 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2306 if (!skb2) {
2307 read_unlock(&mrt_lock);
2308 return -ENOMEM;
2309 }
2310
2311 skb_reset_transport_header(skb2);
2312
2313 skb_put(skb2, sizeof(struct ipv6hdr));
2314 skb_reset_network_header(skb2);
2315
2316 iph = ipv6_hdr(skb2);
2317 iph->version = 0;
2318 iph->priority = 0;
2319 iph->flow_lbl[0] = 0;
2320 iph->flow_lbl[1] = 0;
2321 iph->flow_lbl[2] = 0;
2322 iph->payload_len = 0;
2323 iph->nexthdr = IPPROTO_NONE;
2324 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002325 iph->saddr = rt->rt6i_src.addr;
2326 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002327
Patrick McHardy6bd52142010-05-11 14:40:53 +02002328 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002329 read_unlock(&mrt_lock);
2330
2331 return err;
2332 }
2333
2334 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
2335 cache->mfc_flags |= MFC_NOTIFY;
2336
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002337 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002338 read_unlock(&mrt_lock);
2339 return err;
2340}
2341
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002342static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002343 u32 portid, u32 seq, struct mfc6_cache *c, int cmd)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002344{
2345 struct nlmsghdr *nlh;
2346 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002347 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002348
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002349 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002350 if (nlh == NULL)
2351 return -EMSGSIZE;
2352
2353 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002354 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002355 rtm->rtm_dst_len = 128;
2356 rtm->rtm_src_len = 128;
2357 rtm->rtm_tos = 0;
2358 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002359 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2360 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002361 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002362 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002363 if (c->mfc_flags & MFC_STATIC)
2364 rtm->rtm_protocol = RTPROT_STATIC;
2365 else
2366 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002367 rtm->rtm_flags = 0;
2368
David S. Millerc78679e2012-04-01 20:27:33 -04002369 if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) ||
2370 nla_put(skb, RTA_DST, 16, &c->mf6c_mcastgrp))
2371 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002372 err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
2373 /* do not break the dump if cache is unresolved */
2374 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002375 goto nla_put_failure;
2376
2377 return nlmsg_end(skb, nlh);
2378
2379nla_put_failure:
2380 nlmsg_cancel(skb, nlh);
2381 return -EMSGSIZE;
2382}
2383
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002384static int mr6_msgsize(bool unresolved, int maxvif)
2385{
2386 size_t len =
2387 NLMSG_ALIGN(sizeof(struct rtmsg))
2388 + nla_total_size(4) /* RTA_TABLE */
2389 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2390 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2391 ;
2392
2393 if (!unresolved)
2394 len = len
2395 + nla_total_size(4) /* RTA_IIF */
2396 + nla_total_size(0) /* RTA_MULTIPATH */
2397 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2398 /* RTA_MFC_STATS */
2399 + nla_total_size(sizeof(struct rta_mfc_stats))
2400 ;
2401
2402 return len;
2403}
2404
2405static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
2406 int cmd)
2407{
2408 struct net *net = read_pnet(&mrt->net);
2409 struct sk_buff *skb;
2410 int err = -ENOBUFS;
2411
2412 skb = nlmsg_new(mr6_msgsize(mfc->mf6c_parent >= MAXMIFS, mrt->maxvif),
2413 GFP_ATOMIC);
2414 if (skb == NULL)
2415 goto errout;
2416
2417 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
2418 if (err < 0)
2419 goto errout;
2420
2421 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2422 return;
2423
2424errout:
2425 kfree_skb(skb);
2426 if (err < 0)
2427 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2428}
2429
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002430static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2431{
2432 struct net *net = sock_net(skb->sk);
2433 struct mr6_table *mrt;
2434 struct mfc6_cache *mfc;
2435 unsigned int t = 0, s_t;
2436 unsigned int h = 0, s_h;
2437 unsigned int e = 0, s_e;
2438
2439 s_t = cb->args[0];
2440 s_h = cb->args[1];
2441 s_e = cb->args[2];
2442
2443 read_lock(&mrt_lock);
2444 ip6mr_for_each_table(mrt, net) {
2445 if (t < s_t)
2446 goto next_table;
2447 if (t > s_t)
2448 s_h = 0;
2449 for (h = s_h; h < MFC6_LINES; h++) {
2450 list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) {
2451 if (e < s_e)
2452 goto next_entry;
2453 if (ip6mr_fill_mroute(mrt, skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002454 NETLINK_CB(cb->skb).portid,
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002455 cb->nlh->nlmsg_seq,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002456 mfc, RTM_NEWROUTE) < 0)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002457 goto done;
2458next_entry:
2459 e++;
2460 }
2461 e = s_e = 0;
2462 }
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002463 spin_lock_bh(&mfc_unres_lock);
2464 list_for_each_entry(mfc, &mrt->mfc6_unres_queue, list) {
2465 if (e < s_e)
2466 goto next_entry2;
2467 if (ip6mr_fill_mroute(mrt, skb,
2468 NETLINK_CB(cb->skb).portid,
2469 cb->nlh->nlmsg_seq,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002470 mfc, RTM_NEWROUTE) < 0) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002471 spin_unlock_bh(&mfc_unres_lock);
2472 goto done;
2473 }
2474next_entry2:
2475 e++;
2476 }
2477 spin_unlock_bh(&mfc_unres_lock);
2478 e = s_e = 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002479 s_h = 0;
2480next_table:
2481 t++;
2482 }
2483done:
2484 read_unlock(&mrt_lock);
2485
2486 cb->args[2] = e;
2487 cb->args[1] = h;
2488 cb->args[0] = t;
2489
2490 return skb->len;
2491}