blob: 5aa3981a392273891881ea8defc1d70fff7adde4 [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
19#include <asm/system.h>
20#include <asm/uaccess.h>
21#include <linux/types.h>
22#include <linux/sched.h>
23#include <linux/errno.h>
24#include <linux/timer.h>
25#include <linux/mm.h>
26#include <linux/kernel.h>
27#include <linux/fcntl.h>
28#include <linux/stat.h>
29#include <linux/socket.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090030#include <linux/inet.h>
31#include <linux/netdevice.h>
32#include <linux/inetdevice.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090033#include <linux/proc_fs.h>
34#include <linux/seq_file.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090035#include <linux/init.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090036#include <linux/slab.h>
David S. Millere2d57762011-02-03 17:59:32 -080037#include <linux/compat.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090038#include <net/protocol.h>
39#include <linux/skbuff.h>
40#include <net/sock.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090041#include <net/raw.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090042#include <linux/notifier.h>
43#include <linux/if_arp.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090044#include <net/checksum.h>
45#include <net/netlink.h>
Patrick McHardyd1db2752010-05-11 14:40:55 +020046#include <net/fib_rules.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090047
48#include <net/ipv6.h>
49#include <net/ip6_route.h>
50#include <linux/mroute6.h>
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +090051#include <linux/pim.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090052#include <net/addrconf.h>
53#include <linux/netfilter_ipv6.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040054#include <linux/export.h>
Dave Jones5d6e4302009-01-31 00:51:49 -080055#include <net/ip6_checksum.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;
70 int mroute_do_assert;
71 int mroute_do_pim;
72#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);
119static int ip6mr_rtm_dumproute(struct sk_buff *skb,
120 struct netlink_callback *cb);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200121static void mroute_clean_tables(struct mr6_table *mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200122static void ipmr_expire_process(unsigned long arg);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900123
Patrick McHardyd1db2752010-05-11 14:40:55 +0200124#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
Eric Dumazet8ffb3352010-06-06 15:34:40 -0700125#define ip6mr_for_each_table(mrt, net) \
Patrick McHardyd1db2752010-05-11 14:40:55 +0200126 list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
127
128static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
129{
130 struct mr6_table *mrt;
131
132 ip6mr_for_each_table(mrt, net) {
133 if (mrt->id == id)
134 return mrt;
135 }
136 return NULL;
137}
138
David S. Miller4c9483b2011-03-12 16:22:43 -0500139static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200140 struct mr6_table **mrt)
141{
142 struct ip6mr_result res;
143 struct fib_lookup_arg arg = { .result = &res, };
144 int err;
145
David S. Miller4c9483b2011-03-12 16:22:43 -0500146 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
147 flowi6_to_flowi(flp6), 0, &arg);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200148 if (err < 0)
149 return err;
150 *mrt = res.mrt;
151 return 0;
152}
153
154static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
155 int flags, struct fib_lookup_arg *arg)
156{
157 struct ip6mr_result *res = arg->result;
158 struct mr6_table *mrt;
159
160 switch (rule->action) {
161 case FR_ACT_TO_TBL:
162 break;
163 case FR_ACT_UNREACHABLE:
164 return -ENETUNREACH;
165 case FR_ACT_PROHIBIT:
166 return -EACCES;
167 case FR_ACT_BLACKHOLE:
168 default:
169 return -EINVAL;
170 }
171
172 mrt = ip6mr_get_table(rule->fr_net, rule->table);
173 if (mrt == NULL)
174 return -EAGAIN;
175 res->mrt = mrt;
176 return 0;
177}
178
179static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
180{
181 return 1;
182}
183
184static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
185 FRA_GENERIC_POLICY,
186};
187
188static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
189 struct fib_rule_hdr *frh, struct nlattr **tb)
190{
191 return 0;
192}
193
194static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
195 struct nlattr **tb)
196{
197 return 1;
198}
199
200static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
201 struct fib_rule_hdr *frh)
202{
203 frh->dst_len = 0;
204 frh->src_len = 0;
205 frh->tos = 0;
206 return 0;
207}
208
209static const struct fib_rules_ops __net_initdata ip6mr_rules_ops_template = {
210 .family = RTNL_FAMILY_IP6MR,
211 .rule_size = sizeof(struct ip6mr_rule),
212 .addr_size = sizeof(struct in6_addr),
213 .action = ip6mr_rule_action,
214 .match = ip6mr_rule_match,
215 .configure = ip6mr_rule_configure,
216 .compare = ip6mr_rule_compare,
217 .default_pref = fib_default_rule_pref,
218 .fill = ip6mr_rule_fill,
219 .nlgroup = RTNLGRP_IPV6_RULE,
220 .policy = ip6mr_rule_policy,
221 .owner = THIS_MODULE,
222};
223
224static int __net_init ip6mr_rules_init(struct net *net)
225{
226 struct fib_rules_ops *ops;
227 struct mr6_table *mrt;
228 int err;
229
230 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
231 if (IS_ERR(ops))
232 return PTR_ERR(ops);
233
234 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
235
236 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
237 if (mrt == NULL) {
238 err = -ENOMEM;
239 goto err1;
240 }
241
242 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
243 if (err < 0)
244 goto err2;
245
246 net->ipv6.mr6_rules_ops = ops;
247 return 0;
248
249err2:
250 kfree(mrt);
251err1:
252 fib_rules_unregister(ops);
253 return err;
254}
255
256static void __net_exit ip6mr_rules_exit(struct net *net)
257{
258 struct mr6_table *mrt, *next;
259
Eric Dumazet035320d2010-06-06 23:48:40 +0000260 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
261 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200262 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000263 }
Patrick McHardyd1db2752010-05-11 14:40:55 +0200264 fib_rules_unregister(net->ipv6.mr6_rules_ops);
265}
266#else
267#define ip6mr_for_each_table(mrt, net) \
268 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
269
270static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
271{
272 return net->ipv6.mrt6;
273}
274
David S. Miller4c9483b2011-03-12 16:22:43 -0500275static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200276 struct mr6_table **mrt)
277{
278 *mrt = net->ipv6.mrt6;
279 return 0;
280}
281
282static int __net_init ip6mr_rules_init(struct net *net)
283{
284 net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
285 return net->ipv6.mrt6 ? 0 : -ENOMEM;
286}
287
288static void __net_exit ip6mr_rules_exit(struct net *net)
289{
290 ip6mr_free_table(net->ipv6.mrt6);
291}
292#endif
293
294static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
295{
296 struct mr6_table *mrt;
297 unsigned int i;
298
299 mrt = ip6mr_get_table(net, id);
300 if (mrt != NULL)
301 return mrt;
302
303 mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
304 if (mrt == NULL)
305 return NULL;
306 mrt->id = id;
307 write_pnet(&mrt->net, net);
308
309 /* Forwarding cache */
310 for (i = 0; i < MFC6_LINES; i++)
311 INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
312
313 INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
314
315 setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
316 (unsigned long)mrt);
317
318#ifdef CONFIG_IPV6_PIMSM_V2
319 mrt->mroute_reg_vif_num = -1;
320#endif
321#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
322 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
323#endif
324 return mrt;
325}
326
327static void ip6mr_free_table(struct mr6_table *mrt)
328{
329 del_timer(&mrt->ipmr_expire_timer);
330 mroute_clean_tables(mrt);
331 kfree(mrt);
332}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900333
334#ifdef CONFIG_PROC_FS
335
336struct ipmr_mfc_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800337 struct seq_net_private p;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200338 struct mr6_table *mrt;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200339 struct list_head *cache;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900340 int ct;
341};
342
343
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800344static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
345 struct ipmr_mfc_iter *it, loff_t pos)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900346{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200347 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900348 struct mfc6_cache *mfc;
349
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900350 read_lock(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200351 for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200352 it->cache = &mrt->mfc6_cache_array[it->ct];
Patrick McHardyf30a77842010-05-11 14:40:51 +0200353 list_for_each_entry(mfc, it->cache, list)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900354 if (pos-- == 0)
355 return mfc;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200356 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900357 read_unlock(&mrt_lock);
358
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900359 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200360 it->cache = &mrt->mfc6_unres_queue;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200361 list_for_each_entry(mfc, it->cache, list)
Patrick McHardyc476efb2010-05-11 14:40:48 +0200362 if (pos-- == 0)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900363 return mfc;
364 spin_unlock_bh(&mfc_unres_lock);
365
366 it->cache = NULL;
367 return NULL;
368}
369
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900370/*
371 * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
372 */
373
374struct ipmr_vif_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800375 struct seq_net_private p;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200376 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900377 int ct;
378};
379
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800380static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
381 struct ipmr_vif_iter *iter,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900382 loff_t pos)
383{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200384 struct mr6_table *mrt = iter->mrt;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200385
386 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
387 if (!MIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900388 continue;
389 if (pos-- == 0)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200390 return &mrt->vif6_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900391 }
392 return NULL;
393}
394
395static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
396 __acquires(mrt_lock)
397{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200398 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800399 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200400 struct mr6_table *mrt;
401
402 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
403 if (mrt == NULL)
404 return ERR_PTR(-ENOENT);
405
406 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800407
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900408 read_lock(&mrt_lock);
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800409 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
410 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900411}
412
413static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
414{
415 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800416 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200417 struct mr6_table *mrt = iter->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900418
419 ++*pos;
420 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800421 return ip6mr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900422
Patrick McHardy6bd52142010-05-11 14:40:53 +0200423 while (++iter->ct < mrt->maxvif) {
424 if (!MIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900425 continue;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200426 return &mrt->vif6_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900427 }
428 return NULL;
429}
430
431static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
432 __releases(mrt_lock)
433{
434 read_unlock(&mrt_lock);
435}
436
437static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
438{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200439 struct ipmr_vif_iter *iter = seq->private;
440 struct mr6_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800441
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900442 if (v == SEQ_START_TOKEN) {
443 seq_puts(seq,
444 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
445 } else {
446 const struct mif_device *vif = v;
447 const char *name = vif->dev ? vif->dev->name : "none";
448
449 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100450 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Patrick McHardy6bd52142010-05-11 14:40:53 +0200451 vif - mrt->vif6_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900452 name, vif->bytes_in, vif->pkt_in,
453 vif->bytes_out, vif->pkt_out,
454 vif->flags);
455 }
456 return 0;
457}
458
Stephen Hemminger98147d52009-09-01 19:25:02 +0000459static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900460 .start = ip6mr_vif_seq_start,
461 .next = ip6mr_vif_seq_next,
462 .stop = ip6mr_vif_seq_stop,
463 .show = ip6mr_vif_seq_show,
464};
465
466static int ip6mr_vif_open(struct inode *inode, struct file *file)
467{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800468 return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
469 sizeof(struct ipmr_vif_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900470}
471
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000472static const struct file_operations ip6mr_vif_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900473 .owner = THIS_MODULE,
474 .open = ip6mr_vif_open,
475 .read = seq_read,
476 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800477 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900478};
479
480static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
481{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200482 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800483 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200484 struct mr6_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800485
Patrick McHardyd1db2752010-05-11 14:40:55 +0200486 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
487 if (mrt == NULL)
488 return ERR_PTR(-ENOENT);
489
490 it->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800491 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
492 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900493}
494
495static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
496{
497 struct mfc6_cache *mfc = v;
498 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800499 struct net *net = seq_file_net(seq);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200500 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900501
502 ++*pos;
503
504 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800505 return ipmr_mfc_seq_idx(net, seq->private, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900506
Patrick McHardyf30a77842010-05-11 14:40:51 +0200507 if (mfc->list.next != it->cache)
508 return list_entry(mfc->list.next, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900509
Patrick McHardy6bd52142010-05-11 14:40:53 +0200510 if (it->cache == &mrt->mfc6_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900511 goto end_of_list;
512
Patrick McHardy6bd52142010-05-11 14:40:53 +0200513 BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900514
Benjamin Thery4a6258a2008-12-10 16:24:07 -0800515 while (++it->ct < MFC6_LINES) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200516 it->cache = &mrt->mfc6_cache_array[it->ct];
Patrick McHardyf30a77842010-05-11 14:40:51 +0200517 if (list_empty(it->cache))
518 continue;
519 return list_first_entry(it->cache, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900520 }
521
522 /* exhausted cache_array, show unresolved */
523 read_unlock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200524 it->cache = &mrt->mfc6_unres_queue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900525 it->ct = 0;
526
527 spin_lock_bh(&mfc_unres_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200528 if (!list_empty(it->cache))
529 return list_first_entry(it->cache, struct mfc6_cache, list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900530
531 end_of_list:
532 spin_unlock_bh(&mfc_unres_lock);
533 it->cache = NULL;
534
535 return NULL;
536}
537
538static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
539{
540 struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200541 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900542
Patrick McHardy6bd52142010-05-11 14:40:53 +0200543 if (it->cache == &mrt->mfc6_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900544 spin_unlock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200545 else if (it->cache == mrt->mfc6_cache_array)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900546 read_unlock(&mrt_lock);
547}
548
549static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
550{
551 int n;
552
553 if (v == SEQ_START_TOKEN) {
554 seq_puts(seq,
555 "Group "
556 "Origin "
557 "Iif Pkts Bytes Wrong Oifs\n");
558 } else {
559 const struct mfc6_cache *mfc = v;
560 const struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200561 struct mr6_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900562
Benjamin Thery999890b2008-12-03 22:22:16 -0800563 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700564 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800565 mfc->mf6c_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900566
Patrick McHardy6bd52142010-05-11 14:40:53 +0200567 if (it->cache != &mrt->mfc6_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800568 seq_printf(seq, " %8lu %8lu %8lu",
569 mfc->mfc_un.res.pkt,
570 mfc->mfc_un.res.bytes,
571 mfc->mfc_un.res.wrong_if);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900572 for (n = mfc->mfc_un.res.minvif;
573 n < mfc->mfc_un.res.maxvif; n++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200574 if (MIF_EXISTS(mrt, n) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900575 mfc->mfc_un.res.ttls[n] < 255)
576 seq_printf(seq,
577 " %2d:%-3d",
578 n, mfc->mfc_un.res.ttls[n]);
579 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800580 } else {
581 /* unresolved mfc_caches don't contain
582 * pkt, bytes and wrong_if values
583 */
584 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900585 }
586 seq_putc(seq, '\n');
587 }
588 return 0;
589}
590
James Morris88e9d342009-09-22 16:43:43 -0700591static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900592 .start = ipmr_mfc_seq_start,
593 .next = ipmr_mfc_seq_next,
594 .stop = ipmr_mfc_seq_stop,
595 .show = ipmr_mfc_seq_show,
596};
597
598static int ipmr_mfc_open(struct inode *inode, struct file *file)
599{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800600 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
601 sizeof(struct ipmr_mfc_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900602}
603
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000604static const struct file_operations ip6mr_mfc_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900605 .owner = THIS_MODULE,
606 .open = ipmr_mfc_open,
607 .read = seq_read,
608 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800609 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900610};
611#endif
612
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900613#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900614
615static int pim6_rcv(struct sk_buff *skb)
616{
617 struct pimreghdr *pim;
618 struct ipv6hdr *encap;
619 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800620 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200621 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500622 struct flowi6 fl6 = {
623 .flowi6_iif = skb->dev->ifindex,
624 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200625 };
626 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900627
628 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
629 goto drop;
630
631 pim = (struct pimreghdr *)skb_transport_header(skb);
632 if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
633 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800634 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
635 sizeof(*pim), IPPROTO_PIM,
636 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700637 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900638 goto drop;
639
640 /* check if the inner packet is destined to mcast group */
641 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
642 sizeof(*pim));
643
644 if (!ipv6_addr_is_multicast(&encap->daddr) ||
645 encap->payload_len == 0 ||
646 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
647 goto drop;
648
David S. Miller4c9483b2011-03-12 16:22:43 -0500649 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200650 goto drop;
651 reg_vif_num = mrt->mroute_reg_vif_num;
652
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900653 read_lock(&mrt_lock);
654 if (reg_vif_num >= 0)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200655 reg_dev = mrt->vif6_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900656 if (reg_dev)
657 dev_hold(reg_dev);
658 read_unlock(&mrt_lock);
659
660 if (reg_dev == NULL)
661 goto drop;
662
663 skb->mac_header = skb->network_header;
664 skb_pull(skb, (u8 *)encap - skb->data);
665 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800666 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000667 skb->ip_summed = CHECKSUM_NONE;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900668 skb->pkt_type = PACKET_HOST;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700669
670 skb_tunnel_rx(skb, reg_dev);
671
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000672 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000673
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900674 dev_put(reg_dev);
675 return 0;
676 drop:
677 kfree_skb(skb);
678 return 0;
679}
680
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000681static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900682 .handler = pim6_rcv,
683};
684
685/* Service routines creating virtual interfaces: PIMREG */
686
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000687static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
688 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900689{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800690 struct net *net = dev_net(dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200691 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500692 struct flowi6 fl6 = {
693 .flowi6_oif = dev->ifindex,
694 .flowi6_iif = skb->skb_iif,
695 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200696 };
697 int err;
698
David S. Miller4c9483b2011-03-12 16:22:43 -0500699 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000700 if (err < 0) {
701 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200702 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000703 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800704
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900705 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700706 dev->stats.tx_bytes += skb->len;
707 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200708 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900709 read_unlock(&mrt_lock);
710 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000711 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900712}
713
Stephen Hemminger007c3832008-11-20 20:28:35 -0800714static const struct net_device_ops reg_vif_netdev_ops = {
715 .ndo_start_xmit = reg_vif_xmit,
716};
717
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900718static void reg_vif_setup(struct net_device *dev)
719{
720 dev->type = ARPHRD_PIMREG;
721 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
722 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800723 dev->netdev_ops = &reg_vif_netdev_ops;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900724 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700725 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900726}
727
Patrick McHardyd1db2752010-05-11 14:40:55 +0200728static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900729{
730 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200731 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900732
Patrick McHardyd1db2752010-05-11 14:40:55 +0200733 if (mrt->id == RT6_TABLE_DFLT)
734 sprintf(name, "pim6reg");
735 else
736 sprintf(name, "pim6reg%u", mrt->id);
737
738 dev = alloc_netdev(0, name, reg_vif_setup);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900739 if (dev == NULL)
740 return NULL;
741
Benjamin Thery8229efd2008-12-10 16:30:15 -0800742 dev_net_set(dev, net);
743
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900744 if (register_netdevice(dev)) {
745 free_netdev(dev);
746 return NULL;
747 }
748 dev->iflink = 0;
749
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900750 if (dev_open(dev))
751 goto failure;
752
Wang Chen7af3db72008-07-14 20:54:54 -0700753 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900754 return dev;
755
756failure:
757 /* allow the register to be completed before unregistering. */
758 rtnl_unlock();
759 rtnl_lock();
760
761 unregister_netdevice(dev);
762 return NULL;
763}
764#endif
765
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900766/*
767 * Delete a VIF entry
768 */
769
Patrick McHardy6bd52142010-05-11 14:40:53 +0200770static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900771{
772 struct mif_device *v;
773 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800774 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200775
776 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900777 return -EADDRNOTAVAIL;
778
Patrick McHardy6bd52142010-05-11 14:40:53 +0200779 v = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900780
781 write_lock_bh(&mrt_lock);
782 dev = v->dev;
783 v->dev = NULL;
784
785 if (!dev) {
786 write_unlock_bh(&mrt_lock);
787 return -EADDRNOTAVAIL;
788 }
789
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900790#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200791 if (vifi == mrt->mroute_reg_vif_num)
792 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900793#endif
794
Patrick McHardy6bd52142010-05-11 14:40:53 +0200795 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900796 int tmp;
797 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200798 if (MIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900799 break;
800 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200801 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900802 }
803
804 write_unlock_bh(&mrt_lock);
805
806 dev_set_allmulti(dev, -1);
807
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800808 in6_dev = __in6_dev_get(dev);
809 if (in6_dev)
810 in6_dev->cnf.mc_forwarding--;
811
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900812 if (v->flags & MIFF_REGISTER)
Eric Dumazetc871e662009-10-28 04:48:11 +0000813 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900814
815 dev_put(dev);
816 return 0;
817}
818
Benjamin Thery58701ad2008-12-10 16:22:34 -0800819static inline void ip6mr_cache_free(struct mfc6_cache *c)
820{
Benjamin Thery58701ad2008-12-10 16:22:34 -0800821 kmem_cache_free(mrt_cachep, c);
822}
823
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900824/* Destroy an unresolved cache entry, killing queued skbs
825 and reporting error to netlink readers.
826 */
827
Patrick McHardy6bd52142010-05-11 14:40:53 +0200828static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900829{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200830 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900831 struct sk_buff *skb;
832
Patrick McHardy6bd52142010-05-11 14:40:53 +0200833 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900834
835 while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
836 if (ipv6_hdr(skb)->version == 0) {
837 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
838 nlh->nlmsg_type = NLMSG_ERROR;
839 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
840 skb_trim(skb, nlh->nlmsg_len);
841 ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800842 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900843 } else
844 kfree_skb(skb);
845 }
846
Benjamin Thery58701ad2008-12-10 16:22:34 -0800847 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900848}
849
850
Patrick McHardyc476efb2010-05-11 14:40:48 +0200851/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900852
Patrick McHardy6bd52142010-05-11 14:40:53 +0200853static void ipmr_do_expire_process(struct mr6_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900854{
855 unsigned long now = jiffies;
856 unsigned long expires = 10 * HZ;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200857 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900858
Patrick McHardy6bd52142010-05-11 14:40:53 +0200859 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900860 if (time_after(c->mfc_un.unres.expires, now)) {
861 /* not yet... */
862 unsigned long interval = c->mfc_un.unres.expires - now;
863 if (interval < expires)
864 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900865 continue;
866 }
867
Patrick McHardyf30a77842010-05-11 14:40:51 +0200868 list_del(&c->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +0200869 ip6mr_destroy_unres(mrt, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900870 }
871
Patrick McHardy6bd52142010-05-11 14:40:53 +0200872 if (!list_empty(&mrt->mfc6_unres_queue))
873 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900874}
875
Patrick McHardyc476efb2010-05-11 14:40:48 +0200876static void ipmr_expire_process(unsigned long arg)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900877{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200878 struct mr6_table *mrt = (struct mr6_table *)arg;
Patrick McHardyc476efb2010-05-11 14:40:48 +0200879
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900880 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200881 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900882 return;
883 }
884
Patrick McHardy6bd52142010-05-11 14:40:53 +0200885 if (!list_empty(&mrt->mfc6_unres_queue))
886 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900887
888 spin_unlock(&mfc_unres_lock);
889}
890
891/* Fill oifs list. It is called under write locked mrt_lock. */
892
Patrick McHardy6bd52142010-05-11 14:40:53 +0200893static void ip6mr_update_thresholds(struct mr6_table *mrt, struct mfc6_cache *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200894 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900895{
896 int vifi;
897
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300898 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900899 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300900 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900901
Patrick McHardy6bd52142010-05-11 14:40:53 +0200902 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
903 if (MIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800904 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900905 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
906 if (cache->mfc_un.res.minvif > vifi)
907 cache->mfc_un.res.minvif = vifi;
908 if (cache->mfc_un.res.maxvif <= vifi)
909 cache->mfc_un.res.maxvif = vifi + 1;
910 }
911 }
912}
913
Patrick McHardy6bd52142010-05-11 14:40:53 +0200914static int mif6_add(struct net *net, struct mr6_table *mrt,
915 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900916{
917 int vifi = vifc->mif6c_mifi;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200918 struct mif_device *v = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900919 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800920 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700921 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900922
923 /* Is vif busy ? */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200924 if (MIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900925 return -EADDRINUSE;
926
927 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900928#ifdef CONFIG_IPV6_PIMSM_V2
929 case MIFF_REGISTER:
930 /*
931 * Special Purpose VIF in PIM
932 * All the packets will be sent to the daemon
933 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200934 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900935 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200936 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900937 if (!dev)
938 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700939 err = dev_set_allmulti(dev, 1);
940 if (err) {
941 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700942 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700943 return err;
944 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900945 break;
946#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900947 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800948 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900949 if (!dev)
950 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700951 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700952 if (err) {
953 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700954 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700955 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900956 break;
957 default:
958 return -EINVAL;
959 }
960
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800961 in6_dev = __in6_dev_get(dev);
962 if (in6_dev)
963 in6_dev->cnf.mc_forwarding++;
964
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900965 /*
966 * Fill in the VIF structures
967 */
968 v->rate_limit = vifc->vifc_rate_limit;
969 v->flags = vifc->mif6c_flags;
970 if (!mrtsock)
971 v->flags |= VIFF_STATIC;
972 v->threshold = vifc->vifc_threshold;
973 v->bytes_in = 0;
974 v->bytes_out = 0;
975 v->pkt_in = 0;
976 v->pkt_out = 0;
977 v->link = dev->ifindex;
978 if (v->flags & MIFF_REGISTER)
979 v->link = dev->iflink;
980
981 /* And finish update writing critical data */
982 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900983 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900984#ifdef CONFIG_IPV6_PIMSM_V2
985 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200986 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900987#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200988 if (vifi + 1 > mrt->maxvif)
989 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900990 write_unlock_bh(&mrt_lock);
991 return 0;
992}
993
Patrick McHardy6bd52142010-05-11 14:40:53 +0200994static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000995 const struct in6_addr *origin,
996 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900997{
998 int line = MFC6_HASH(mcastgrp, origin);
999 struct mfc6_cache *c;
1000
Patrick McHardy6bd52142010-05-11 14:40:53 +02001001 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001002 if (ipv6_addr_equal(&c->mf6c_origin, origin) &&
1003 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp))
Patrick McHardyf30a77842010-05-11 14:40:51 +02001004 return c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001005 }
Patrick McHardyf30a77842010-05-11 14:40:51 +02001006 return NULL;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001007}
1008
1009/*
1010 * Allocate a multicast cache entry
1011 */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001012static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001013{
Joe Perches36cbac52008-12-03 22:27:25 -08001014 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001015 if (c == NULL)
1016 return NULL;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001017 c->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001018 return c;
1019}
1020
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001021static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001022{
Joe Perches36cbac52008-12-03 22:27:25 -08001023 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001024 if (c == NULL)
1025 return NULL;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001026 skb_queue_head_init(&c->mfc_un.unres.unresolved);
1027 c->mfc_un.unres.expires = jiffies + 10 * HZ;
1028 return c;
1029}
1030
1031/*
1032 * A cache entry has gone into a resolved state from queued
1033 */
1034
Patrick McHardy6bd52142010-05-11 14:40:53 +02001035static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
1036 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001037{
1038 struct sk_buff *skb;
1039
1040 /*
1041 * Play the pending entries through our router
1042 */
1043
1044 while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
1045 if (ipv6_hdr(skb)->version == 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001046 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
1047
Patrick McHardy5b285ca2010-05-11 14:40:56 +02001048 if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001049 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001050 } else {
1051 nlh->nlmsg_type = NLMSG_ERROR;
1052 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
1053 skb_trim(skb, nlh->nlmsg_len);
1054 ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
1055 }
Hagen Paul Pfeiferddc37312011-02-25 05:45:20 +00001056 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001057 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001058 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001059 }
1060}
1061
1062/*
1063 * Bounce a cache query up to pim6sd. We could use netlink for this but pim6sd
1064 * expects the following bizarre scheme.
1065 *
1066 * Called under mrt_lock.
1067 */
1068
Patrick McHardy6bd52142010-05-11 14:40:53 +02001069static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
1070 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001071{
1072 struct sk_buff *skb;
1073 struct mrt6msg *msg;
1074 int ret;
1075
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001076#ifdef CONFIG_IPV6_PIMSM_V2
1077 if (assert == MRT6MSG_WHOLEPKT)
1078 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1079 +sizeof(*msg));
1080 else
1081#endif
1082 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001083
1084 if (!skb)
1085 return -ENOBUFS;
1086
1087 /* I suppose that internal messages
1088 * do not require checksums */
1089
1090 skb->ip_summed = CHECKSUM_UNNECESSARY;
1091
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001092#ifdef CONFIG_IPV6_PIMSM_V2
1093 if (assert == MRT6MSG_WHOLEPKT) {
1094 /* Ugly, but we have no choice with this interface.
1095 Duplicate old header, fix length etc.
1096 And all this only to mangle msg->im6_msgtype and
1097 to set msg->im6_mbz to "mbz" :-)
1098 */
1099 skb_push(skb, -skb_network_offset(pkt));
1100
1101 skb_push(skb, sizeof(*msg));
1102 skb_reset_transport_header(skb);
1103 msg = (struct mrt6msg *)skb_transport_header(skb);
1104 msg->im6_mbz = 0;
1105 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001106 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001107 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001108 msg->im6_src = ipv6_hdr(pkt)->saddr;
1109 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001110
1111 skb->ip_summed = CHECKSUM_UNNECESSARY;
1112 } else
1113#endif
1114 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001115 /*
1116 * Copy the IP header
1117 */
1118
1119 skb_put(skb, sizeof(struct ipv6hdr));
1120 skb_reset_network_header(skb);
1121 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1122
1123 /*
1124 * Add our header
1125 */
1126 skb_put(skb, sizeof(*msg));
1127 skb_reset_transport_header(skb);
1128 msg = (struct mrt6msg *)skb_transport_header(skb);
1129
1130 msg->im6_mbz = 0;
1131 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001132 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001133 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001134 msg->im6_src = ipv6_hdr(pkt)->saddr;
1135 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001136
Eric Dumazetadf30902009-06-02 05:19:30 +00001137 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001138 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001139 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001140
Patrick McHardy6bd52142010-05-11 14:40:53 +02001141 if (mrt->mroute6_sk == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001142 kfree_skb(skb);
1143 return -EINVAL;
1144 }
1145
1146 /*
1147 * Deliver to user space multicast routing algorithms
1148 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001149 ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001150 if (ret < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001151 if (net_ratelimit())
1152 printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n");
1153 kfree_skb(skb);
1154 }
1155
1156 return ret;
1157}
1158
1159/*
1160 * Queue a packet for resolution. It gets locked cache entry!
1161 */
1162
1163static int
Patrick McHardy6bd52142010-05-11 14:40:53 +02001164ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001165{
Patrick McHardyf30a77842010-05-11 14:40:51 +02001166 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001167 int err;
1168 struct mfc6_cache *c;
1169
1170 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001171 list_for_each_entry(c, &mrt->mfc6_unres_queue, list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001172 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001173 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1174 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001175 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001176 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001177 }
1178
Patrick McHardyf30a77842010-05-11 14:40:51 +02001179 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001180 /*
1181 * Create a new entry if allowable
1182 */
1183
Patrick McHardy6bd52142010-05-11 14:40:53 +02001184 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001185 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001186 spin_unlock_bh(&mfc_unres_lock);
1187
1188 kfree_skb(skb);
1189 return -ENOBUFS;
1190 }
1191
1192 /*
1193 * Fill in the new cache entry
1194 */
1195 c->mf6c_parent = -1;
1196 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1197 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1198
1199 /*
1200 * Reflect first query at pim6sd
1201 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001202 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001203 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001204 /* If the report failed throw the cache entry
1205 out - Brad Parker
1206 */
1207 spin_unlock_bh(&mfc_unres_lock);
1208
Benjamin Thery58701ad2008-12-10 16:22:34 -08001209 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001210 kfree_skb(skb);
1211 return err;
1212 }
1213
Patrick McHardy6bd52142010-05-11 14:40:53 +02001214 atomic_inc(&mrt->cache_resolve_queue_len);
1215 list_add(&c->list, &mrt->mfc6_unres_queue);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001216
Patrick McHardy6bd52142010-05-11 14:40:53 +02001217 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001218 }
1219
1220 /*
1221 * See if we can append the packet
1222 */
1223 if (c->mfc_un.unres.unresolved.qlen > 3) {
1224 kfree_skb(skb);
1225 err = -ENOBUFS;
1226 } else {
1227 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
1228 err = 0;
1229 }
1230
1231 spin_unlock_bh(&mfc_unres_lock);
1232 return err;
1233}
1234
1235/*
1236 * MFC6 cache manipulation by user space
1237 */
1238
Patrick McHardy6bd52142010-05-11 14:40:53 +02001239static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001240{
1241 int line;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001242 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001243
1244 line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
1245
Patrick McHardy6bd52142010-05-11 14:40:53 +02001246 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001247 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
1248 ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
1249 write_lock_bh(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001250 list_del(&c->list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001251 write_unlock_bh(&mrt_lock);
1252
Benjamin Thery58701ad2008-12-10 16:22:34 -08001253 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001254 return 0;
1255 }
1256 }
1257 return -ENOENT;
1258}
1259
1260static int ip6mr_device_event(struct notifier_block *this,
1261 unsigned long event, void *ptr)
1262{
1263 struct net_device *dev = ptr;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001264 struct net *net = dev_net(dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001265 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001266 struct mif_device *v;
1267 int ct;
Eric Dumazetc871e662009-10-28 04:48:11 +00001268 LIST_HEAD(list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001269
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001270 if (event != NETDEV_UNREGISTER)
1271 return NOTIFY_DONE;
1272
Patrick McHardyd1db2752010-05-11 14:40:55 +02001273 ip6mr_for_each_table(mrt, net) {
1274 v = &mrt->vif6_table[0];
1275 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1276 if (v->dev == dev)
1277 mif6_delete(mrt, ct, &list);
1278 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001279 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001280 unregister_netdevice_many(&list);
1281
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001282 return NOTIFY_DONE;
1283}
1284
1285static struct notifier_block ip6_mr_notifier = {
1286 .notifier_call = ip6mr_device_event
1287};
1288
1289/*
1290 * Setup for IP multicast routing
1291 */
1292
Benjamin Thery4e168802008-12-10 16:15:08 -08001293static int __net_init ip6mr_net_init(struct net *net)
1294{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001295 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001296
Patrick McHardyd1db2752010-05-11 14:40:55 +02001297 err = ip6mr_rules_init(net);
1298 if (err < 0)
Benjamin Thery4e168802008-12-10 16:15:08 -08001299 goto fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001300
1301#ifdef CONFIG_PROC_FS
1302 err = -ENOMEM;
1303 if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
1304 goto proc_vif_fail;
1305 if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops))
1306 goto proc_cache_fail;
1307#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001308
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001309 return 0;
1310
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001311#ifdef CONFIG_PROC_FS
1312proc_cache_fail:
1313 proc_net_remove(net, "ip6_mr_vif");
1314proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001315 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001316#endif
Benjamin Thery4e168802008-12-10 16:15:08 -08001317fail:
1318 return err;
1319}
1320
1321static void __net_exit ip6mr_net_exit(struct net *net)
1322{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001323#ifdef CONFIG_PROC_FS
1324 proc_net_remove(net, "ip6_mr_cache");
1325 proc_net_remove(net, "ip6_mr_vif");
1326#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001327 ip6mr_rules_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001328}
1329
1330static struct pernet_operations ip6mr_net_ops = {
1331 .init = ip6mr_net_init,
1332 .exit = ip6mr_net_exit,
1333};
1334
Wang Chen623d1a12008-07-03 12:13:30 +08001335int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001336{
Wang Chen623d1a12008-07-03 12:13:30 +08001337 int err;
1338
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001339 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1340 sizeof(struct mfc6_cache),
1341 0, SLAB_HWCACHE_ALIGN,
1342 NULL);
1343 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001344 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001345
Benjamin Thery4e168802008-12-10 16:15:08 -08001346 err = register_pernet_subsys(&ip6mr_net_ops);
1347 if (err)
1348 goto reg_pernet_fail;
1349
Wang Chen623d1a12008-07-03 12:13:30 +08001350 err = register_netdevice_notifier(&ip6_mr_notifier);
1351 if (err)
1352 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001353#ifdef CONFIG_IPV6_PIMSM_V2
1354 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
1355 printk(KERN_ERR "ip6_mr_init: can't add PIM protocol\n");
1356 err = -EAGAIN;
1357 goto add_proto_fail;
1358 }
1359#endif
Greg Rosec7ac8672011-06-10 01:27:09 +00001360 rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL,
1361 ip6mr_rtm_dumproute, NULL);
Wang Chen623d1a12008-07-03 12:13:30 +08001362 return 0;
Tom Goff403dbb92009-06-14 03:16:13 -07001363#ifdef CONFIG_IPV6_PIMSM_V2
1364add_proto_fail:
1365 unregister_netdevice_notifier(&ip6_mr_notifier);
1366#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001367reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001368 unregister_pernet_subsys(&ip6mr_net_ops);
1369reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001370 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001371 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001372}
1373
Wang Chen623d1a12008-07-03 12:13:30 +08001374void ip6_mr_cleanup(void)
1375{
Wang Chen623d1a12008-07-03 12:13:30 +08001376 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001377 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001378 kmem_cache_destroy(mrt_cachep);
1379}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001380
Patrick McHardy6bd52142010-05-11 14:40:53 +02001381static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1382 struct mf6cctl *mfc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001383{
Patrick McHardyf30a77842010-05-11 14:40:51 +02001384 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001385 int line;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001386 struct mfc6_cache *uc, *c;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001387 unsigned char ttls[MAXMIFS];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001388 int i;
1389
Patrick McHardya50436f22010-03-17 06:04:14 +00001390 if (mfc->mf6cc_parent >= MAXMIFS)
1391 return -ENFILE;
1392
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001393 memset(ttls, 255, MAXMIFS);
1394 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001395 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1396 ttls[i] = 1;
1397
1398 }
1399
1400 line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
1401
Patrick McHardy6bd52142010-05-11 14:40:53 +02001402 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001403 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001404 ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
1405 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001406 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001407 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001408 }
1409
Patrick McHardyf30a77842010-05-11 14:40:51 +02001410 if (found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001411 write_lock_bh(&mrt_lock);
1412 c->mf6c_parent = mfc->mf6cc_parent;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001413 ip6mr_update_thresholds(mrt, c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001414 if (!mrtsock)
1415 c->mfc_flags |= MFC_STATIC;
1416 write_unlock_bh(&mrt_lock);
1417 return 0;
1418 }
1419
1420 if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
1421 return -EINVAL;
1422
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001423 c = ip6mr_cache_alloc();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001424 if (c == NULL)
1425 return -ENOMEM;
1426
1427 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1428 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
1429 c->mf6c_parent = mfc->mf6cc_parent;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001430 ip6mr_update_thresholds(mrt, c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001431 if (!mrtsock)
1432 c->mfc_flags |= MFC_STATIC;
1433
1434 write_lock_bh(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001435 list_add(&c->list, &mrt->mfc6_cache_array[line]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001436 write_unlock_bh(&mrt_lock);
1437
1438 /*
1439 * Check to see if we resolved a queued list. If so we
1440 * need to send on the frames and tidy up.
1441 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001442 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001443 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001444 list_for_each_entry(uc, &mrt->mfc6_unres_queue, list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001445 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001446 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001447 list_del(&uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001448 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001449 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001450 break;
1451 }
1452 }
Patrick McHardy6bd52142010-05-11 14:40:53 +02001453 if (list_empty(&mrt->mfc6_unres_queue))
1454 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001455 spin_unlock_bh(&mfc_unres_lock);
1456
Patrick McHardyf30a77842010-05-11 14:40:51 +02001457 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001458 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001459 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001460 }
1461 return 0;
1462}
1463
1464/*
1465 * Close the multicast socket, and clear the vif tables etc
1466 */
1467
Patrick McHardy6bd52142010-05-11 14:40:53 +02001468static void mroute_clean_tables(struct mr6_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001469{
1470 int i;
Eric Dumazetc871e662009-10-28 04:48:11 +00001471 LIST_HEAD(list);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001472 struct mfc6_cache *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001473
1474 /*
1475 * Shut down all active vif entries
1476 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001477 for (i = 0; i < mrt->maxvif; i++) {
1478 if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
1479 mif6_delete(mrt, i, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001480 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001481 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001482
1483 /*
1484 * Wipe the cache
1485 */
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001486 for (i = 0; i < MFC6_LINES; i++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001487 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001488 if (c->mfc_flags & MFC_STATIC)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001489 continue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001490 write_lock_bh(&mrt_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001491 list_del(&c->list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001492 write_unlock_bh(&mrt_lock);
1493
Benjamin Thery58701ad2008-12-10 16:22:34 -08001494 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001495 }
1496 }
1497
Patrick McHardy6bd52142010-05-11 14:40:53 +02001498 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001499 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001500 list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001501 list_del(&c->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001502 ip6mr_destroy_unres(mrt, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001503 }
1504 spin_unlock_bh(&mfc_unres_lock);
1505 }
1506}
1507
Patrick McHardy6bd52142010-05-11 14:40:53 +02001508static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001509{
1510 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001511 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001512
1513 rtnl_lock();
1514 write_lock_bh(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001515 if (likely(mrt->mroute6_sk == NULL)) {
1516 mrt->mroute6_sk = sk;
Thomas Goff1d6e55f2009-01-27 22:39:59 -08001517 net->ipv6.devconf_all->mc_forwarding++;
1518 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001519 else
1520 err = -EADDRINUSE;
1521 write_unlock_bh(&mrt_lock);
1522
1523 rtnl_unlock();
1524
1525 return err;
1526}
1527
1528int ip6mr_sk_done(struct sock *sk)
1529{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001530 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001531 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001532 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001533
1534 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001535 ip6mr_for_each_table(mrt, net) {
1536 if (sk == mrt->mroute6_sk) {
1537 write_lock_bh(&mrt_lock);
1538 mrt->mroute6_sk = NULL;
1539 net->ipv6.devconf_all->mc_forwarding--;
1540 write_unlock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001541
Patrick McHardyd1db2752010-05-11 14:40:55 +02001542 mroute_clean_tables(mrt);
1543 err = 0;
1544 break;
1545 }
1546 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001547 rtnl_unlock();
1548
1549 return err;
1550}
1551
Patrick McHardyd1db2752010-05-11 14:40:55 +02001552struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001553{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001554 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001555 struct flowi6 fl6 = {
1556 .flowi6_iif = skb->skb_iif,
1557 .flowi6_oif = skb->dev->ifindex,
1558 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001559 };
1560
David S. Miller4c9483b2011-03-12 16:22:43 -05001561 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001562 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001563
1564 return mrt->mroute6_sk;
1565}
1566
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001567/*
1568 * Socket options and virtual interface manipulation. The whole
1569 * virtual interface system is a complete heap, but unfortunately
1570 * that's how BSD mrouted happens to think. Maybe one day with a proper
1571 * MOSPF/PIM router set up we can clean this up.
1572 */
1573
David S. Millerb7058842009-09-30 16:12:20 -07001574int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001575{
1576 int ret;
1577 struct mif6ctl vif;
1578 struct mf6cctl mfc;
1579 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001580 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001581 struct mr6_table *mrt;
1582
1583 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1584 if (mrt == NULL)
1585 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001586
1587 if (optname != MRT6_INIT) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001588 if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001589 return -EACCES;
1590 }
1591
1592 switch (optname) {
1593 case MRT6_INIT:
1594 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001595 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001596 return -EOPNOTSUPP;
1597 if (optlen < sizeof(int))
1598 return -EINVAL;
1599
Patrick McHardy6bd52142010-05-11 14:40:53 +02001600 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001601
1602 case MRT6_DONE:
1603 return ip6mr_sk_done(sk);
1604
1605 case MRT6_ADD_MIF:
1606 if (optlen < sizeof(vif))
1607 return -EINVAL;
1608 if (copy_from_user(&vif, optval, sizeof(vif)))
1609 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001610 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001611 return -ENFILE;
1612 rtnl_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001613 ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001614 rtnl_unlock();
1615 return ret;
1616
1617 case MRT6_DEL_MIF:
1618 if (optlen < sizeof(mifi_t))
1619 return -EINVAL;
1620 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1621 return -EFAULT;
1622 rtnl_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001623 ret = mif6_delete(mrt, mifi, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001624 rtnl_unlock();
1625 return ret;
1626
1627 /*
1628 * Manipulate the forwarding caches. These live
1629 * in a sort of kernel/user symbiosis.
1630 */
1631 case MRT6_ADD_MFC:
1632 case MRT6_DEL_MFC:
1633 if (optlen < sizeof(mfc))
1634 return -EINVAL;
1635 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1636 return -EFAULT;
1637 rtnl_lock();
1638 if (optname == MRT6_DEL_MFC)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001639 ret = ip6mr_mfc_delete(mrt, &mfc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001640 else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001641 ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001642 rtnl_unlock();
1643 return ret;
1644
1645 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001646 * Control PIM assert (to activate pim will activate assert)
1647 */
1648 case MRT6_ASSERT:
1649 {
1650 int v;
1651 if (get_user(v, (int __user *)optval))
1652 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001653 mrt->mroute_do_assert = !!v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001654 return 0;
1655 }
1656
1657#ifdef CONFIG_IPV6_PIMSM_V2
1658 case MRT6_PIM:
1659 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001660 int v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001661 if (get_user(v, (int __user *)optval))
1662 return -EFAULT;
1663 v = !!v;
1664 rtnl_lock();
1665 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001666 if (v != mrt->mroute_do_pim) {
1667 mrt->mroute_do_pim = v;
1668 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001669 }
1670 rtnl_unlock();
1671 return ret;
1672 }
1673
1674#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001675#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1676 case MRT6_TABLE:
1677 {
1678 u32 v;
1679
1680 if (optlen != sizeof(u32))
1681 return -EINVAL;
1682 if (get_user(v, (u32 __user *)optval))
1683 return -EFAULT;
1684 if (sk == mrt->mroute6_sk)
1685 return -EBUSY;
1686
1687 rtnl_lock();
1688 ret = 0;
1689 if (!ip6mr_new_table(net, v))
1690 ret = -ENOMEM;
1691 raw6_sk(sk)->ip6mr_table = v;
1692 rtnl_unlock();
1693 return ret;
1694 }
1695#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001696 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001697 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001698 * set.
1699 */
1700 default:
1701 return -ENOPROTOOPT;
1702 }
1703}
1704
1705/*
1706 * Getsock opt support for the multicast routing system.
1707 */
1708
1709int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1710 int __user *optlen)
1711{
1712 int olr;
1713 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001714 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001715 struct mr6_table *mrt;
1716
1717 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1718 if (mrt == NULL)
1719 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001720
1721 switch (optname) {
1722 case MRT6_VERSION:
1723 val = 0x0305;
1724 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001725#ifdef CONFIG_IPV6_PIMSM_V2
1726 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001727 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001728 break;
1729#endif
1730 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001731 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001732 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001733 default:
1734 return -ENOPROTOOPT;
1735 }
1736
1737 if (get_user(olr, optlen))
1738 return -EFAULT;
1739
1740 olr = min_t(int, olr, sizeof(int));
1741 if (olr < 0)
1742 return -EINVAL;
1743
1744 if (put_user(olr, optlen))
1745 return -EFAULT;
1746 if (copy_to_user(optval, &val, olr))
1747 return -EFAULT;
1748 return 0;
1749}
1750
1751/*
1752 * The IP multicast ioctl support routines.
1753 */
1754
1755int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1756{
1757 struct sioc_sg_req6 sr;
1758 struct sioc_mif_req6 vr;
1759 struct mif_device *vif;
1760 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001761 struct net *net = sock_net(sk);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001762 struct mr6_table *mrt;
1763
1764 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1765 if (mrt == NULL)
1766 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001767
1768 switch (cmd) {
1769 case SIOCGETMIFCNT_IN6:
1770 if (copy_from_user(&vr, arg, sizeof(vr)))
1771 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001772 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001773 return -EINVAL;
1774 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001775 vif = &mrt->vif6_table[vr.mifi];
1776 if (MIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001777 vr.icount = vif->pkt_in;
1778 vr.ocount = vif->pkt_out;
1779 vr.ibytes = vif->bytes_in;
1780 vr.obytes = vif->bytes_out;
1781 read_unlock(&mrt_lock);
1782
1783 if (copy_to_user(arg, &vr, sizeof(vr)))
1784 return -EFAULT;
1785 return 0;
1786 }
1787 read_unlock(&mrt_lock);
1788 return -EADDRNOTAVAIL;
1789 case SIOCGETSGCNT_IN6:
1790 if (copy_from_user(&sr, arg, sizeof(sr)))
1791 return -EFAULT;
1792
1793 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001794 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001795 if (c) {
1796 sr.pktcnt = c->mfc_un.res.pkt;
1797 sr.bytecnt = c->mfc_un.res.bytes;
1798 sr.wrong_if = c->mfc_un.res.wrong_if;
1799 read_unlock(&mrt_lock);
1800
1801 if (copy_to_user(arg, &sr, sizeof(sr)))
1802 return -EFAULT;
1803 return 0;
1804 }
1805 read_unlock(&mrt_lock);
1806 return -EADDRNOTAVAIL;
1807 default:
1808 return -ENOIOCTLCMD;
1809 }
1810}
1811
David S. Millere2d57762011-02-03 17:59:32 -08001812#ifdef CONFIG_COMPAT
1813struct compat_sioc_sg_req6 {
1814 struct sockaddr_in6 src;
1815 struct sockaddr_in6 grp;
1816 compat_ulong_t pktcnt;
1817 compat_ulong_t bytecnt;
1818 compat_ulong_t wrong_if;
1819};
1820
1821struct compat_sioc_mif_req6 {
1822 mifi_t mifi;
1823 compat_ulong_t icount;
1824 compat_ulong_t ocount;
1825 compat_ulong_t ibytes;
1826 compat_ulong_t obytes;
1827};
1828
1829int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1830{
1831 struct compat_sioc_sg_req6 sr;
1832 struct compat_sioc_mif_req6 vr;
1833 struct mif_device *vif;
1834 struct mfc6_cache *c;
1835 struct net *net = sock_net(sk);
1836 struct mr6_table *mrt;
1837
1838 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1839 if (mrt == NULL)
1840 return -ENOENT;
1841
1842 switch (cmd) {
1843 case SIOCGETMIFCNT_IN6:
1844 if (copy_from_user(&vr, arg, sizeof(vr)))
1845 return -EFAULT;
1846 if (vr.mifi >= mrt->maxvif)
1847 return -EINVAL;
1848 read_lock(&mrt_lock);
1849 vif = &mrt->vif6_table[vr.mifi];
1850 if (MIF_EXISTS(mrt, vr.mifi)) {
1851 vr.icount = vif->pkt_in;
1852 vr.ocount = vif->pkt_out;
1853 vr.ibytes = vif->bytes_in;
1854 vr.obytes = vif->bytes_out;
1855 read_unlock(&mrt_lock);
1856
1857 if (copy_to_user(arg, &vr, sizeof(vr)))
1858 return -EFAULT;
1859 return 0;
1860 }
1861 read_unlock(&mrt_lock);
1862 return -EADDRNOTAVAIL;
1863 case SIOCGETSGCNT_IN6:
1864 if (copy_from_user(&sr, arg, sizeof(sr)))
1865 return -EFAULT;
1866
1867 read_lock(&mrt_lock);
1868 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1869 if (c) {
1870 sr.pktcnt = c->mfc_un.res.pkt;
1871 sr.bytecnt = c->mfc_un.res.bytes;
1872 sr.wrong_if = c->mfc_un.res.wrong_if;
1873 read_unlock(&mrt_lock);
1874
1875 if (copy_to_user(arg, &sr, sizeof(sr)))
1876 return -EFAULT;
1877 return 0;
1878 }
1879 read_unlock(&mrt_lock);
1880 return -EADDRNOTAVAIL;
1881 default:
1882 return -ENOIOCTLCMD;
1883 }
1884}
1885#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001886
1887static inline int ip6mr_forward2_finish(struct sk_buff *skb)
1888{
Eric Dumazetadf30902009-06-02 05:19:30 +00001889 IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
Denis V. Lunev483a47d2008-10-08 11:09:27 -07001890 IPSTATS_MIB_OUTFORWDATAGRAMS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001891 return dst_output(skb);
1892}
1893
1894/*
1895 * Processing handlers for ip6mr_forward
1896 */
1897
Patrick McHardy6bd52142010-05-11 14:40:53 +02001898static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
1899 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001900{
1901 struct ipv6hdr *ipv6h;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001902 struct mif_device *vif = &mrt->vif6_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001903 struct net_device *dev;
1904 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001905 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001906
1907 if (vif->dev == NULL)
1908 goto out_free;
1909
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001910#ifdef CONFIG_IPV6_PIMSM_V2
1911 if (vif->flags & MIFF_REGISTER) {
1912 vif->pkt_out++;
1913 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001914 vif->dev->stats.tx_bytes += skb->len;
1915 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001916 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001917 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001918 }
1919#endif
1920
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001921 ipv6h = ipv6_hdr(skb);
1922
David S. Miller4c9483b2011-03-12 16:22:43 -05001923 fl6 = (struct flowi6) {
1924 .flowi6_oif = vif->link,
1925 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001926 };
1927
David S. Miller4c9483b2011-03-12 16:22:43 -05001928 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001929 if (dst->error) {
1930 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001931 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00001932 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001933
Eric Dumazetadf30902009-06-02 05:19:30 +00001934 skb_dst_drop(skb);
1935 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001936
1937 /*
1938 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1939 * not only before forwarding, but after forwarding on all output
1940 * interfaces. It is clear, if mrouter runs a multicasting
1941 * program, it should receive packets not depending to what interface
1942 * program is joined.
1943 * If we will not make it, the program will have to join on all
1944 * interfaces. On the other hand, multihoming host (or router, but
1945 * not mrouter) cannot join to more than one interface - it will
1946 * result in receiving multiple packets.
1947 */
1948 dev = vif->dev;
1949 skb->dev = dev;
1950 vif->pkt_out++;
1951 vif->bytes_out += skb->len;
1952
1953 /* We are about to write */
1954 /* XXX: extension headers? */
1955 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
1956 goto out_free;
1957
1958 ipv6h = ipv6_hdr(skb);
1959 ipv6h->hop_limit--;
1960
1961 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
1962
Jan Engelhardtb2e0b382010-03-23 04:09:07 +01001963 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001964 ip6mr_forward2_finish);
1965
1966out_free:
1967 kfree_skb(skb);
1968 return 0;
1969}
1970
Patrick McHardy6bd52142010-05-11 14:40:53 +02001971static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001972{
1973 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001974
1975 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
1976 if (mrt->vif6_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001977 break;
1978 }
1979 return ct;
1980}
1981
Patrick McHardy6bd52142010-05-11 14:40:53 +02001982static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
1983 struct sk_buff *skb, struct mfc6_cache *cache)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001984{
1985 int psend = -1;
1986 int vif, ct;
1987
1988 vif = cache->mf6c_parent;
1989 cache->mfc_un.res.pkt++;
1990 cache->mfc_un.res.bytes += skb->len;
1991
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001992 /*
1993 * Wrong interface: drop packet and (maybe) send PIM assert.
1994 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001995 if (mrt->vif6_table[vif].dev != skb->dev) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001996 int true_vifi;
1997
1998 cache->mfc_un.res.wrong_if++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001999 true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002000
Patrick McHardy6bd52142010-05-11 14:40:53 +02002001 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002002 /* pimsm uses asserts, when switching from RPT to SPT,
2003 so that we cannot check that packet arrived on an oif.
2004 It is bad, but otherwise we would need to move pretty
2005 large chunk of pimd to kernel. Ough... --ANK
2006 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002007 (mrt->mroute_do_pim ||
Benjamin Therya21f3f92008-12-10 16:28:44 -08002008 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002009 time_after(jiffies,
2010 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
2011 cache->mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002012 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002013 }
2014 goto dont_forward;
2015 }
2016
Patrick McHardy6bd52142010-05-11 14:40:53 +02002017 mrt->vif6_table[vif].pkt_in++;
2018 mrt->vif6_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002019
2020 /*
2021 * Forward the frame
2022 */
2023 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
2024 if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
2025 if (psend != -1) {
2026 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2027 if (skb2)
Patrick McHardy6bd52142010-05-11 14:40:53 +02002028 ip6mr_forward2(net, mrt, skb2, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002029 }
2030 psend = ct;
2031 }
2032 }
2033 if (psend != -1) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002034 ip6mr_forward2(net, mrt, skb, cache, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002035 return 0;
2036 }
2037
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002038dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002039 kfree_skb(skb);
2040 return 0;
2041}
2042
2043
2044/*
2045 * Multicast packets for forwarding arrive here
2046 */
2047
2048int ip6_mr_input(struct sk_buff *skb)
2049{
2050 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002051 struct net *net = dev_net(skb->dev);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002052 struct mr6_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002053 struct flowi6 fl6 = {
2054 .flowi6_iif = skb->dev->ifindex,
2055 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002056 };
2057 int err;
2058
David S. Miller4c9483b2011-03-12 16:22:43 -05002059 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002060 if (err < 0) {
2061 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002062 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002063 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002064
2065 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002066 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002067 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002068
2069 /*
2070 * No usable cache entry
2071 */
2072 if (cache == NULL) {
2073 int vif;
2074
Patrick McHardy6bd52142010-05-11 14:40:53 +02002075 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002076 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002077 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002078 read_unlock(&mrt_lock);
2079
2080 return err;
2081 }
2082 read_unlock(&mrt_lock);
2083 kfree_skb(skb);
2084 return -ENODEV;
2085 }
2086
Patrick McHardy6bd52142010-05-11 14:40:53 +02002087 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002088
2089 read_unlock(&mrt_lock);
2090
2091 return 0;
2092}
2093
2094
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002095static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2096 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002097{
2098 int ct;
2099 struct rtnexthop *nhp;
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09002100 u8 *b = skb_tail_pointer(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002101 struct rtattr *mp_head;
2102
Nicolas Dichtel74381892010-03-25 23:45:35 +00002103 /* If cache is unresolved, don't try to parse IIF and OIF */
Dan Carpentered0f160a2010-05-26 00:38:56 -07002104 if (c->mf6c_parent >= MAXMIFS)
Nicolas Dichtel74381892010-03-25 23:45:35 +00002105 return -ENOENT;
2106
Patrick McHardy6bd52142010-05-11 14:40:53 +02002107 if (MIF_EXISTS(mrt, c->mf6c_parent))
2108 RTA_PUT(skb, RTA_IIF, 4, &mrt->vif6_table[c->mf6c_parent].dev->ifindex);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002109
2110 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
2111
2112 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002113 if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002114 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
2115 goto rtattr_failure;
2116 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
2117 nhp->rtnh_flags = 0;
2118 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Patrick McHardy6bd52142010-05-11 14:40:53 +02002119 nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002120 nhp->rtnh_len = sizeof(*nhp);
2121 }
2122 }
2123 mp_head->rta_type = RTA_MULTIPATH;
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09002124 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002125 rtm->rtm_type = RTN_MULTICAST;
2126 return 1;
2127
2128rtattr_failure:
2129 nlmsg_trim(skb, b);
2130 return -EMSGSIZE;
2131}
2132
Benjamin Thery8229efd2008-12-10 16:30:15 -08002133int ip6mr_get_route(struct net *net,
2134 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002135{
2136 int err;
Patrick McHardyd1db2752010-05-11 14:40:55 +02002137 struct mr6_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002138 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002139 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002140
Patrick McHardyd1db2752010-05-11 14:40:55 +02002141 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2142 if (mrt == NULL)
2143 return -ENOENT;
2144
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002145 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002146 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002147
2148 if (!cache) {
2149 struct sk_buff *skb2;
2150 struct ipv6hdr *iph;
2151 struct net_device *dev;
2152 int vif;
2153
2154 if (nowait) {
2155 read_unlock(&mrt_lock);
2156 return -EAGAIN;
2157 }
2158
2159 dev = skb->dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002160 if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002161 read_unlock(&mrt_lock);
2162 return -ENODEV;
2163 }
2164
2165 /* really correct? */
2166 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2167 if (!skb2) {
2168 read_unlock(&mrt_lock);
2169 return -ENOMEM;
2170 }
2171
2172 skb_reset_transport_header(skb2);
2173
2174 skb_put(skb2, sizeof(struct ipv6hdr));
2175 skb_reset_network_header(skb2);
2176
2177 iph = ipv6_hdr(skb2);
2178 iph->version = 0;
2179 iph->priority = 0;
2180 iph->flow_lbl[0] = 0;
2181 iph->flow_lbl[1] = 0;
2182 iph->flow_lbl[2] = 0;
2183 iph->payload_len = 0;
2184 iph->nexthdr = IPPROTO_NONE;
2185 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002186 iph->saddr = rt->rt6i_src.addr;
2187 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002188
Patrick McHardy6bd52142010-05-11 14:40:53 +02002189 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002190 read_unlock(&mrt_lock);
2191
2192 return err;
2193 }
2194
2195 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
2196 cache->mfc_flags |= MFC_NOTIFY;
2197
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002198 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002199 read_unlock(&mrt_lock);
2200 return err;
2201}
2202
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002203static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2204 u32 pid, u32 seq, struct mfc6_cache *c)
2205{
2206 struct nlmsghdr *nlh;
2207 struct rtmsg *rtm;
2208
2209 nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI);
2210 if (nlh == NULL)
2211 return -EMSGSIZE;
2212
2213 rtm = nlmsg_data(nlh);
2214 rtm->rtm_family = RTNL_FAMILY_IPMR;
2215 rtm->rtm_dst_len = 128;
2216 rtm->rtm_src_len = 128;
2217 rtm->rtm_tos = 0;
2218 rtm->rtm_table = mrt->id;
2219 NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
2220 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2221 rtm->rtm_protocol = RTPROT_UNSPEC;
2222 rtm->rtm_flags = 0;
2223
2224 NLA_PUT(skb, RTA_SRC, 16, &c->mf6c_origin);
2225 NLA_PUT(skb, RTA_DST, 16, &c->mf6c_mcastgrp);
2226
2227 if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0)
2228 goto nla_put_failure;
2229
2230 return nlmsg_end(skb, nlh);
2231
2232nla_put_failure:
2233 nlmsg_cancel(skb, nlh);
2234 return -EMSGSIZE;
2235}
2236
2237static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2238{
2239 struct net *net = sock_net(skb->sk);
2240 struct mr6_table *mrt;
2241 struct mfc6_cache *mfc;
2242 unsigned int t = 0, s_t;
2243 unsigned int h = 0, s_h;
2244 unsigned int e = 0, s_e;
2245
2246 s_t = cb->args[0];
2247 s_h = cb->args[1];
2248 s_e = cb->args[2];
2249
2250 read_lock(&mrt_lock);
2251 ip6mr_for_each_table(mrt, net) {
2252 if (t < s_t)
2253 goto next_table;
2254 if (t > s_t)
2255 s_h = 0;
2256 for (h = s_h; h < MFC6_LINES; h++) {
2257 list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) {
2258 if (e < s_e)
2259 goto next_entry;
2260 if (ip6mr_fill_mroute(mrt, skb,
2261 NETLINK_CB(cb->skb).pid,
2262 cb->nlh->nlmsg_seq,
2263 mfc) < 0)
2264 goto done;
2265next_entry:
2266 e++;
2267 }
2268 e = s_e = 0;
2269 }
2270 s_h = 0;
2271next_table:
2272 t++;
2273 }
2274done:
2275 read_unlock(&mrt_lock);
2276
2277 cb->args[2] = e;
2278 cb->args[1] = h;
2279 cb->args[0] = t;
2280
2281 return skb->len;
2282}