blob: 377a2ee5d9ad8a6aec96a5fea7f63e6890399771 [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
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080019#include <linux/uaccess.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090020#include <linux/types.h>
21#include <linux/sched.h>
22#include <linux/errno.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090023#include <linux/mm.h>
24#include <linux/kernel.h>
25#include <linux/fcntl.h>
26#include <linux/stat.h>
27#include <linux/socket.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090028#include <linux/inet.h>
29#include <linux/netdevice.h>
30#include <linux/inetdevice.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090031#include <linux/proc_fs.h>
32#include <linux/seq_file.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090033#include <linux/init.h>
David S. Millere2d57762011-02-03 17:59:32 -080034#include <linux/compat.h>
NeilBrown0eb71a92018-06-18 12:52:50 +100035#include <linux/rhashtable.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090036#include <net/protocol.h>
37#include <linux/skbuff.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090038#include <net/raw.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090039#include <linux/notifier.h>
40#include <linux/if_arp.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090041#include <net/checksum.h>
42#include <net/netlink.h>
Patrick McHardyd1db2752010-05-11 14:40:55 +020043#include <net/fib_rules.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090044
45#include <net/ipv6.h>
46#include <net/ip6_route.h>
47#include <linux/mroute6.h>
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +090048#include <linux/pim.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090049#include <net/addrconf.h>
50#include <linux/netfilter_ipv6.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040051#include <linux/export.h>
Dave Jones5d6e4302009-01-31 00:51:49 -080052#include <net/ip6_checksum.h>
Nicolas Dichteld67b8c62012-12-04 01:13:35 +000053#include <linux/netconf.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090054
Gustavo A. R. Silva69d2c862018-12-11 14:10:08 -060055#include <linux/nospec.h>
56
Patrick McHardyd1db2752010-05-11 14:40:55 +020057struct ip6mr_rule {
58 struct fib_rule common;
59};
60
61struct ip6mr_result {
Yuval Mintzb70432f2018-02-28 23:29:32 +020062 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +020063};
64
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090065/* Big lock, protecting vif table, mrt cache and mroute socket state.
66 Note that the changes are semaphored via rtnl_lock.
67 */
68
69static DEFINE_RWLOCK(mrt_lock);
70
Yuval Mintzb70432f2018-02-28 23:29:32 +020071/* Multicast router control variables */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090072
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090073/* Special spinlock for queue of unresolved entries */
74static DEFINE_SPINLOCK(mfc_unres_lock);
75
76/* We return to original Alan's scheme. Hash table of resolved
77 entries is changed only in process context and protected
78 with weak lock mrt_lock. Queue of unresolved entries is protected
79 with strong spinlock mfc_unres_lock.
80
81 In this case data path is free of exclusive locks at all.
82 */
83
84static struct kmem_cache *mrt_cachep __read_mostly;
85
Yuval Mintzb70432f2018-02-28 23:29:32 +020086static struct mr_table *ip6mr_new_table(struct net *net, u32 id);
87static void ip6mr_free_table(struct mr_table *mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +020088
Yuval Mintzb70432f2018-02-28 23:29:32 +020089static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Patrick Ruddye4a38c02018-10-01 09:41:27 +010090 struct net_device *dev, struct sk_buff *skb,
91 struct mfc6_cache *cache);
Yuval Mintzb70432f2018-02-28 23:29:32 +020092static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Benjamin Thery8229efd2008-12-10 16:30:15 -080093 mifi_t mifi, int assert);
Yuval Mintzb70432f2018-02-28 23:29:32 +020094static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +000095 int cmd);
Yuval Mintzb70432f2018-02-28 23:29:32 +020096static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
Patrick McHardy5b285ca2010-05-11 14:40:56 +020097static int ip6mr_rtm_dumproute(struct sk_buff *skb,
98 struct netlink_callback *cb);
Yuval Mintzb70432f2018-02-28 23:29:32 +020099static void mroute_clean_tables(struct mr_table *mrt, bool all);
Kees Cooke99e88a2017-10-16 14:43:17 -0700100static void ipmr_expire_process(struct timer_list *t);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900101
Patrick McHardyd1db2752010-05-11 14:40:55 +0200102#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
Eric Dumazet8ffb3352010-06-06 15:34:40 -0700103#define ip6mr_for_each_table(mrt, net) \
Patrick McHardyd1db2752010-05-11 14:40:55 +0200104 list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
105
Yuval Mintz7b0db852018-02-28 23:29:39 +0200106static struct mr_table *ip6mr_mr_table_iter(struct net *net,
107 struct mr_table *mrt)
108{
109 struct mr_table *ret;
110
111 if (!mrt)
112 ret = list_entry_rcu(net->ipv6.mr6_tables.next,
113 struct mr_table, list);
114 else
115 ret = list_entry_rcu(mrt->list.next,
116 struct mr_table, list);
117
118 if (&ret->list == &net->ipv6.mr6_tables)
119 return NULL;
120 return ret;
121}
122
Yuval Mintzb70432f2018-02-28 23:29:32 +0200123static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200124{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200125 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200126
127 ip6mr_for_each_table(mrt, net) {
128 if (mrt->id == id)
129 return mrt;
130 }
131 return NULL;
132}
133
David S. Miller4c9483b2011-03-12 16:22:43 -0500134static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200135 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200136{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200137 int err;
Hannes Frederic Sowa95f4a452014-01-13 02:45:22 +0100138 struct ip6mr_result res;
139 struct fib_lookup_arg arg = {
140 .result = &res,
141 .flags = FIB_LOOKUP_NOREF,
142 };
Patrick McHardyd1db2752010-05-11 14:40:55 +0200143
Patrick Ruddye4a38c02018-10-01 09:41:27 +0100144 /* update flow if oif or iif point to device enslaved to l3mdev */
145 l3mdev_update_flow(net, flowi6_to_flowi(flp6));
146
David S. Miller4c9483b2011-03-12 16:22:43 -0500147 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
148 flowi6_to_flowi(flp6), 0, &arg);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200149 if (err < 0)
150 return err;
151 *mrt = res.mrt;
152 return 0;
153}
154
155static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
156 int flags, struct fib_lookup_arg *arg)
157{
158 struct ip6mr_result *res = arg->result;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200159 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200160
161 switch (rule->action) {
162 case FR_ACT_TO_TBL:
163 break;
164 case FR_ACT_UNREACHABLE:
165 return -ENETUNREACH;
166 case FR_ACT_PROHIBIT:
167 return -EACCES;
168 case FR_ACT_BLACKHOLE:
169 default:
170 return -EINVAL;
171 }
172
Patrick Ruddye4a38c02018-10-01 09:41:27 +0100173 arg->table = fib_rule_get_table(rule, arg);
174
175 mrt = ip6mr_get_table(rule->fr_net, arg->table);
Ian Morris63159f22015-03-29 14:00:04 +0100176 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200177 return -EAGAIN;
178 res->mrt = mrt;
179 return 0;
180}
181
182static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
183{
184 return 1;
185}
186
187static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
188 FRA_GENERIC_POLICY,
189};
190
191static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
Roopa Prabhub16fb412018-04-21 09:41:31 -0700192 struct fib_rule_hdr *frh, struct nlattr **tb,
193 struct netlink_ext_ack *extack)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200194{
195 return 0;
196}
197
198static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
199 struct nlattr **tb)
200{
201 return 1;
202}
203
204static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
205 struct fib_rule_hdr *frh)
206{
207 frh->dst_len = 0;
208 frh->src_len = 0;
209 frh->tos = 0;
210 return 0;
211}
212
Andi Kleen04a6f822012-10-04 17:12:11 -0700213static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200214 .family = RTNL_FAMILY_IP6MR,
215 .rule_size = sizeof(struct ip6mr_rule),
216 .addr_size = sizeof(struct in6_addr),
217 .action = ip6mr_rule_action,
218 .match = ip6mr_rule_match,
219 .configure = ip6mr_rule_configure,
220 .compare = ip6mr_rule_compare,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200221 .fill = ip6mr_rule_fill,
222 .nlgroup = RTNLGRP_IPV6_RULE,
223 .policy = ip6mr_rule_policy,
224 .owner = THIS_MODULE,
225};
226
227static int __net_init ip6mr_rules_init(struct net *net)
228{
229 struct fib_rules_ops *ops;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200230 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200231 int err;
232
233 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
234 if (IS_ERR(ops))
235 return PTR_ERR(ops);
236
237 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
238
239 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
Sabrina Dubrocae783bb02018-06-05 15:02:00 +0200240 if (IS_ERR(mrt)) {
241 err = PTR_ERR(mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200242 goto err1;
243 }
244
245 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
246 if (err < 0)
247 goto err2;
248
249 net->ipv6.mr6_rules_ops = ops;
250 return 0;
251
252err2:
WANG Congf243e5a2015-03-25 14:45:03 -0700253 ip6mr_free_table(mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200254err1:
255 fib_rules_unregister(ops);
256 return err;
257}
258
259static void __net_exit ip6mr_rules_exit(struct net *net)
260{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200261 struct mr_table *mrt, *next;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200262
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200263 rtnl_lock();
Eric Dumazet035320d2010-06-06 23:48:40 +0000264 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
265 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200266 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000267 }
Patrick McHardyd1db2752010-05-11 14:40:55 +0200268 fib_rules_unregister(net->ipv6.mr6_rules_ops);
WANG Cong419df122015-03-31 11:01:46 -0700269 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200270}
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300271
272static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
273{
274 return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR);
275}
276
277static unsigned int ip6mr_rules_seq_read(struct net *net)
278{
279 return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR);
280}
Yuval Mintzd3c07e52018-03-26 15:01:35 +0300281
282bool ip6mr_rule_default(const struct fib_rule *rule)
283{
284 return fib_rule_matchall(rule) && rule->action == FR_ACT_TO_TBL &&
285 rule->table == RT6_TABLE_DFLT && !rule->l3mdev;
286}
287EXPORT_SYMBOL(ip6mr_rule_default);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200288#else
289#define ip6mr_for_each_table(mrt, net) \
290 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
291
Yuval Mintz7b0db852018-02-28 23:29:39 +0200292static struct mr_table *ip6mr_mr_table_iter(struct net *net,
293 struct mr_table *mrt)
294{
295 if (!mrt)
296 return net->ipv6.mrt6;
297 return NULL;
298}
299
Yuval Mintzb70432f2018-02-28 23:29:32 +0200300static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200301{
302 return net->ipv6.mrt6;
303}
304
David S. Miller4c9483b2011-03-12 16:22:43 -0500305static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200306 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200307{
308 *mrt = net->ipv6.mrt6;
309 return 0;
310}
311
312static int __net_init ip6mr_rules_init(struct net *net)
313{
Sabrina Dubrocae783bb02018-06-05 15:02:00 +0200314 struct mr_table *mrt;
315
316 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
317 if (IS_ERR(mrt))
318 return PTR_ERR(mrt);
319 net->ipv6.mrt6 = mrt;
320 return 0;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200321}
322
323static void __net_exit ip6mr_rules_exit(struct net *net)
324{
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200325 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200326 ip6mr_free_table(net->ipv6.mrt6);
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200327 net->ipv6.mrt6 = NULL;
328 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200329}
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300330
331static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
332{
333 return 0;
334}
335
336static unsigned int ip6mr_rules_seq_read(struct net *net)
337{
338 return 0;
339}
Patrick McHardyd1db2752010-05-11 14:40:55 +0200340#endif
341
Yuval Mintz87c418b2018-02-28 23:29:31 +0200342static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
343 const void *ptr)
344{
345 const struct mfc6_cache_cmp_arg *cmparg = arg->key;
346 struct mfc6_cache *c = (struct mfc6_cache *)ptr;
347
348 return !ipv6_addr_equal(&c->mf6c_mcastgrp, &cmparg->mf6c_mcastgrp) ||
349 !ipv6_addr_equal(&c->mf6c_origin, &cmparg->mf6c_origin);
350}
351
352static const struct rhashtable_params ip6mr_rht_params = {
Yuval Mintz494fff52018-02-28 23:29:34 +0200353 .head_offset = offsetof(struct mr_mfc, mnode),
Yuval Mintz87c418b2018-02-28 23:29:31 +0200354 .key_offset = offsetof(struct mfc6_cache, cmparg),
355 .key_len = sizeof(struct mfc6_cache_cmp_arg),
356 .nelem_hint = 3,
357 .locks_mul = 1,
358 .obj_cmpfn = ip6mr_hash_cmp,
359 .automatic_shrinking = true,
360};
361
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200362static void ip6mr_new_table_set(struct mr_table *mrt,
363 struct net *net)
364{
365#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
366 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
367#endif
368}
369
Yuval Mintz845c9a72018-02-28 23:29:35 +0200370static struct mfc6_cache_cmp_arg ip6mr_mr_table_ops_cmparg_any = {
371 .mf6c_origin = IN6ADDR_ANY_INIT,
372 .mf6c_mcastgrp = IN6ADDR_ANY_INIT,
373};
374
375static struct mr_table_ops ip6mr_mr_table_ops = {
376 .rht_params = &ip6mr_rht_params,
377 .cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
378};
379
Yuval Mintzb70432f2018-02-28 23:29:32 +0200380static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200381{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200382 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200383
384 mrt = ip6mr_get_table(net, id);
Ian Morris53b24b82015-03-29 14:00:05 +0100385 if (mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200386 return mrt;
387
Yuval Mintz845c9a72018-02-28 23:29:35 +0200388 return mr_table_alloc(net, id, &ip6mr_mr_table_ops,
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200389 ipmr_expire_process, ip6mr_new_table_set);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200390}
391
Yuval Mintzb70432f2018-02-28 23:29:32 +0200392static void ip6mr_free_table(struct mr_table *mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200393{
WANG Cong7ba0c472015-03-31 11:01:47 -0700394 del_timer_sync(&mrt->ipmr_expire_timer);
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +0100395 mroute_clean_tables(mrt, true);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200396 rhltable_destroy(&mrt->mfc_hash);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200397 kfree(mrt);
398}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900399
400#ifdef CONFIG_PROC_FS
Yuval Mintzc8d61962018-02-28 23:29:36 +0200401/* The /proc interfaces to multicast routing
402 * /proc/ip6_mr_cache /proc/ip6_mr_vif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900403 */
404
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900405static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
406 __acquires(mrt_lock)
407{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200408 struct mr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800409 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200410 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200411
412 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100413 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200414 return ERR_PTR(-ENOENT);
415
416 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800417
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900418 read_lock(&mrt_lock);
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200419 return mr_vif_seq_start(seq, pos);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900420}
421
422static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
423 __releases(mrt_lock)
424{
425 read_unlock(&mrt_lock);
426}
427
428static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
429{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200430 struct mr_vif_iter *iter = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200431 struct mr_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800432
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900433 if (v == SEQ_START_TOKEN) {
434 seq_puts(seq,
435 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
436 } else {
Yuval Mintz6853f212018-02-28 23:29:29 +0200437 const struct vif_device *vif = v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900438 const char *name = vif->dev ? vif->dev->name : "none";
439
440 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100441 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Yuval Mintzb70432f2018-02-28 23:29:32 +0200442 vif - mrt->vif_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900443 name, vif->bytes_in, vif->pkt_in,
444 vif->bytes_out, vif->pkt_out,
445 vif->flags);
446 }
447 return 0;
448}
449
Stephen Hemminger98147d52009-09-01 19:25:02 +0000450static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900451 .start = ip6mr_vif_seq_start,
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200452 .next = mr_vif_seq_next,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900453 .stop = ip6mr_vif_seq_stop,
454 .show = ip6mr_vif_seq_show,
455};
456
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900457static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
458{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800459 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200460 struct mr_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800461
Patrick McHardyd1db2752010-05-11 14:40:55 +0200462 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100463 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200464 return ERR_PTR(-ENOENT);
465
Yuval Mintzc8d61962018-02-28 23:29:36 +0200466 return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900467}
468
469static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
470{
471 int n;
472
473 if (v == SEQ_START_TOKEN) {
474 seq_puts(seq,
475 "Group "
476 "Origin "
477 "Iif Pkts Bytes Wrong Oifs\n");
478 } else {
479 const struct mfc6_cache *mfc = v;
Yuval Mintzc8d61962018-02-28 23:29:36 +0200480 const struct mr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200481 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900482
Benjamin Thery999890b2008-12-03 22:22:16 -0800483 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700484 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Yuval Mintz494fff52018-02-28 23:29:34 +0200485 mfc->_c.mfc_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900486
Yuval Mintzb70432f2018-02-28 23:29:32 +0200487 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800488 seq_printf(seq, " %8lu %8lu %8lu",
Yuval Mintz494fff52018-02-28 23:29:34 +0200489 mfc->_c.mfc_un.res.pkt,
490 mfc->_c.mfc_un.res.bytes,
491 mfc->_c.mfc_un.res.wrong_if);
492 for (n = mfc->_c.mfc_un.res.minvif;
493 n < mfc->_c.mfc_un.res.maxvif; n++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200494 if (VIF_EXISTS(mrt, n) &&
Yuval Mintz494fff52018-02-28 23:29:34 +0200495 mfc->_c.mfc_un.res.ttls[n] < 255)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900496 seq_printf(seq,
Yuval Mintz494fff52018-02-28 23:29:34 +0200497 " %2d:%-3d", n,
498 mfc->_c.mfc_un.res.ttls[n]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900499 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800500 } else {
501 /* unresolved mfc_caches don't contain
502 * pkt, bytes and wrong_if values
503 */
504 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900505 }
506 seq_putc(seq, '\n');
507 }
508 return 0;
509}
510
James Morris88e9d342009-09-22 16:43:43 -0700511static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900512 .start = ipmr_mfc_seq_start,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200513 .next = mr_mfc_seq_next,
514 .stop = mr_mfc_seq_stop,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900515 .show = ipmr_mfc_seq_show,
516};
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900517#endif
518
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900519#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900520
521static int pim6_rcv(struct sk_buff *skb)
522{
523 struct pimreghdr *pim;
524 struct ipv6hdr *encap;
525 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800526 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200527 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500528 struct flowi6 fl6 = {
529 .flowi6_iif = skb->dev->ifindex,
530 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200531 };
532 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900533
534 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
535 goto drop;
536
537 pim = (struct pimreghdr *)skb_transport_header(skb);
Nikolay Aleksandrov56245ca2016-10-31 13:21:04 +0100538 if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900539 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800540 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
541 sizeof(*pim), IPPROTO_PIM,
542 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700543 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900544 goto drop;
545
546 /* check if the inner packet is destined to mcast group */
547 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
548 sizeof(*pim));
549
550 if (!ipv6_addr_is_multicast(&encap->daddr) ||
551 encap->payload_len == 0 ||
552 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
553 goto drop;
554
David S. Miller4c9483b2011-03-12 16:22:43 -0500555 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200556 goto drop;
557 reg_vif_num = mrt->mroute_reg_vif_num;
558
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900559 read_lock(&mrt_lock);
560 if (reg_vif_num >= 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200561 reg_dev = mrt->vif_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900562 if (reg_dev)
563 dev_hold(reg_dev);
564 read_unlock(&mrt_lock);
565
Ian Morris63159f22015-03-29 14:00:04 +0100566 if (!reg_dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900567 goto drop;
568
569 skb->mac_header = skb->network_header;
570 skb_pull(skb, (u8 *)encap - skb->data);
571 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800572 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000573 skb->ip_summed = CHECKSUM_NONE;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700574
Nicolas Dichtelea231922013-09-02 15:34:58 +0200575 skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700576
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000577 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000578
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900579 dev_put(reg_dev);
580 return 0;
581 drop:
582 kfree_skb(skb);
583 return 0;
584}
585
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000586static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900587 .handler = pim6_rcv,
588};
589
590/* Service routines creating virtual interfaces: PIMREG */
591
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000592static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
593 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900594{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800595 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200596 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500597 struct flowi6 fl6 = {
598 .flowi6_oif = dev->ifindex,
Cong Wang6a662712014-04-15 16:25:34 -0700599 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -0500600 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200601 };
602 int err;
603
David S. Miller4c9483b2011-03-12 16:22:43 -0500604 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000605 if (err < 0) {
606 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200607 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000608 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800609
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900610 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700611 dev->stats.tx_bytes += skb->len;
612 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200613 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900614 read_unlock(&mrt_lock);
615 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000616 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900617}
618
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200619static int reg_vif_get_iflink(const struct net_device *dev)
620{
621 return 0;
622}
623
Stephen Hemminger007c3832008-11-20 20:28:35 -0800624static const struct net_device_ops reg_vif_netdev_ops = {
625 .ndo_start_xmit = reg_vif_xmit,
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200626 .ndo_get_iflink = reg_vif_get_iflink,
Stephen Hemminger007c3832008-11-20 20:28:35 -0800627};
628
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900629static void reg_vif_setup(struct net_device *dev)
630{
631 dev->type = ARPHRD_PIMREG;
632 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
633 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800634 dev->netdev_ops = &reg_vif_netdev_ops;
David S. Millercf124db2017-05-08 12:52:56 -0400635 dev->needs_free_netdev = true;
Tom Goff403dbb92009-06-14 03:16:13 -0700636 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900637}
638
Yuval Mintzb70432f2018-02-28 23:29:32 +0200639static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900640{
641 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200642 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900643
Patrick McHardyd1db2752010-05-11 14:40:55 +0200644 if (mrt->id == RT6_TABLE_DFLT)
645 sprintf(name, "pim6reg");
646 else
647 sprintf(name, "pim6reg%u", mrt->id);
648
Tom Gundersenc835a672014-07-14 16:37:24 +0200649 dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
Ian Morris63159f22015-03-29 14:00:04 +0100650 if (!dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900651 return NULL;
652
Benjamin Thery8229efd2008-12-10 16:30:15 -0800653 dev_net_set(dev, net);
654
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900655 if (register_netdevice(dev)) {
656 free_netdev(dev);
657 return NULL;
658 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900659
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900660 if (dev_open(dev))
661 goto failure;
662
Wang Chen7af3db72008-07-14 20:54:54 -0700663 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900664 return dev;
665
666failure:
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900667 unregister_netdevice(dev);
668 return NULL;
669}
670#endif
671
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300672static int call_ip6mr_vif_entry_notifiers(struct net *net,
673 enum fib_event_type event_type,
674 struct vif_device *vif,
675 mifi_t vif_index, u32 tb_id)
676{
677 return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
678 vif, vif_index, tb_id,
679 &net->ipv6.ipmr_seq);
680}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900681
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300682static int call_ip6mr_mfc_entry_notifiers(struct net *net,
683 enum fib_event_type event_type,
684 struct mfc6_cache *mfc, u32 tb_id)
685{
686 return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
687 &mfc->_c, tb_id, &net->ipv6.ipmr_seq);
688}
689
690/* Delete a VIF entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200691static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300692 struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900693{
Yuval Mintz6853f212018-02-28 23:29:29 +0200694 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900695 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800696 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200697
698 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900699 return -EADDRNOTAVAIL;
700
Yuval Mintzb70432f2018-02-28 23:29:32 +0200701 v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900702
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300703 if (VIF_EXISTS(mrt, vifi))
704 call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
705 FIB_EVENT_VIF_DEL, v, vifi,
706 mrt->id);
707
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900708 write_lock_bh(&mrt_lock);
709 dev = v->dev;
710 v->dev = NULL;
711
712 if (!dev) {
713 write_unlock_bh(&mrt_lock);
714 return -EADDRNOTAVAIL;
715 }
716
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900717#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200718 if (vifi == mrt->mroute_reg_vif_num)
719 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900720#endif
721
Patrick McHardy6bd52142010-05-11 14:40:53 +0200722 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900723 int tmp;
724 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200725 if (VIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900726 break;
727 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200728 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900729 }
730
731 write_unlock_bh(&mrt_lock);
732
733 dev_set_allmulti(dev, -1);
734
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800735 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000736 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800737 in6_dev->cnf.mc_forwarding--;
David Ahern85b3daa2017-03-28 14:28:04 -0700738 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000739 NETCONFA_MC_FORWARDING,
740 dev->ifindex, &in6_dev->cnf);
741 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800742
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300743 if ((v->flags & MIFF_REGISTER) && !notify)
Eric Dumazetc871e662009-10-28 04:48:11 +0000744 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900745
746 dev_put(dev);
747 return 0;
748}
749
Yuval Mintz87c418b2018-02-28 23:29:31 +0200750static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
751{
Yuval Mintz494fff52018-02-28 23:29:34 +0200752 struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200753
Yuval Mintz494fff52018-02-28 23:29:34 +0200754 kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200755}
756
Benjamin Thery58701ad2008-12-10 16:22:34 -0800757static inline void ip6mr_cache_free(struct mfc6_cache *c)
758{
Yuval Mintz494fff52018-02-28 23:29:34 +0200759 call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
Benjamin Thery58701ad2008-12-10 16:22:34 -0800760}
761
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900762/* Destroy an unresolved cache entry, killing queued skbs
763 and reporting error to netlink readers.
764 */
765
Yuval Mintzb70432f2018-02-28 23:29:32 +0200766static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900767{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200768 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900769 struct sk_buff *skb;
770
Patrick McHardy6bd52142010-05-11 14:40:53 +0200771 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900772
Yuval Mintz494fff52018-02-28 23:29:34 +0200773 while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900774 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200775 struct nlmsghdr *nlh = skb_pull(skb,
776 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900777 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000778 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900779 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000780 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000781 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900782 } else
783 kfree_skb(skb);
784 }
785
Benjamin Thery58701ad2008-12-10 16:22:34 -0800786 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900787}
788
789
Patrick McHardyc476efb2010-05-11 14:40:48 +0200790/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900791
Yuval Mintzb70432f2018-02-28 23:29:32 +0200792static void ipmr_do_expire_process(struct mr_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900793{
794 unsigned long now = jiffies;
795 unsigned long expires = 10 * HZ;
Yuval Mintz494fff52018-02-28 23:29:34 +0200796 struct mr_mfc *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900797
Yuval Mintzb70432f2018-02-28 23:29:32 +0200798 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900799 if (time_after(c->mfc_un.unres.expires, now)) {
800 /* not yet... */
801 unsigned long interval = c->mfc_un.unres.expires - now;
802 if (interval < expires)
803 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900804 continue;
805 }
806
Patrick McHardyf30a77842010-05-11 14:40:51 +0200807 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +0200808 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
809 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900810 }
811
Yuval Mintzb70432f2018-02-28 23:29:32 +0200812 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200813 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900814}
815
Kees Cooke99e88a2017-10-16 14:43:17 -0700816static void ipmr_expire_process(struct timer_list *t)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900817{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200818 struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
Patrick McHardyc476efb2010-05-11 14:40:48 +0200819
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900820 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200821 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900822 return;
823 }
824
Yuval Mintzb70432f2018-02-28 23:29:32 +0200825 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200826 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900827
828 spin_unlock(&mfc_unres_lock);
829}
830
831/* Fill oifs list. It is called under write locked mrt_lock. */
832
Yuval Mintzb70432f2018-02-28 23:29:32 +0200833static void ip6mr_update_thresholds(struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +0200834 struct mr_mfc *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200835 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900836{
837 int vifi;
838
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300839 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900840 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300841 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900842
Patrick McHardy6bd52142010-05-11 14:40:53 +0200843 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200844 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800845 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900846 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
847 if (cache->mfc_un.res.minvif > vifi)
848 cache->mfc_un.res.minvif = vifi;
849 if (cache->mfc_un.res.maxvif <= vifi)
850 cache->mfc_un.res.maxvif = vifi + 1;
851 }
852 }
Nikolay Aleksandrov90b5ca12016-07-26 18:54:52 +0200853 cache->mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900854}
855
Yuval Mintzb70432f2018-02-28 23:29:32 +0200856static int mif6_add(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200857 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900858{
859 int vifi = vifc->mif6c_mifi;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200860 struct vif_device *v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900861 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800862 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700863 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900864
865 /* Is vif busy ? */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200866 if (VIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900867 return -EADDRINUSE;
868
869 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900870#ifdef CONFIG_IPV6_PIMSM_V2
871 case MIFF_REGISTER:
872 /*
873 * Special Purpose VIF in PIM
874 * All the packets will be sent to the daemon
875 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200876 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900877 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200878 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900879 if (!dev)
880 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700881 err = dev_set_allmulti(dev, 1);
882 if (err) {
883 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700884 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700885 return err;
886 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900887 break;
888#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900889 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800890 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900891 if (!dev)
892 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700893 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700894 if (err) {
895 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700896 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700897 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900898 break;
899 default:
900 return -EINVAL;
901 }
902
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800903 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000904 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800905 in6_dev->cnf.mc_forwarding++;
David Ahern85b3daa2017-03-28 14:28:04 -0700906 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000907 NETCONFA_MC_FORWARDING,
908 dev->ifindex, &in6_dev->cnf);
909 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800910
Yuval Mintz6853f212018-02-28 23:29:29 +0200911 /* Fill in the VIF structures */
912 vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
913 vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
914 MIFF_REGISTER);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900915
916 /* And finish update writing critical data */
917 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900918 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900919#ifdef CONFIG_IPV6_PIMSM_V2
920 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200921 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900922#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200923 if (vifi + 1 > mrt->maxvif)
924 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900925 write_unlock_bh(&mrt_lock);
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300926 call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD,
927 v, vifi, mrt->id);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900928 return 0;
929}
930
Yuval Mintzb70432f2018-02-28 23:29:32 +0200931static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000932 const struct in6_addr *origin,
933 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900934{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200935 struct mfc6_cache_cmp_arg arg = {
936 .mf6c_origin = *origin,
937 .mf6c_mcastgrp = *mcastgrp,
938 };
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900939
Yuval Mintz845c9a72018-02-28 23:29:35 +0200940 return mr_mfc_find(mrt, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000941}
942
943/* Look for a (*,G) entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200944static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000945 struct in6_addr *mcastgrp,
946 mifi_t mifi)
947{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200948 struct mfc6_cache_cmp_arg arg = {
949 .mf6c_origin = in6addr_any,
950 .mf6c_mcastgrp = *mcastgrp,
951 };
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000952
953 if (ipv6_addr_any(mcastgrp))
Yuval Mintz845c9a72018-02-28 23:29:35 +0200954 return mr_mfc_find_any_parent(mrt, mifi);
955 return mr_mfc_find_any(mrt, mifi, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000956}
957
Yuval Mintz87c418b2018-02-28 23:29:31 +0200958/* Look for a (S,G,iif) entry if parent != -1 */
959static struct mfc6_cache *
Yuval Mintzb70432f2018-02-28 23:29:32 +0200960ip6mr_cache_find_parent(struct mr_table *mrt,
Yuval Mintz87c418b2018-02-28 23:29:31 +0200961 const struct in6_addr *origin,
962 const struct in6_addr *mcastgrp,
963 int parent)
964{
965 struct mfc6_cache_cmp_arg arg = {
966 .mf6c_origin = *origin,
967 .mf6c_mcastgrp = *mcastgrp,
968 };
Yuval Mintz87c418b2018-02-28 23:29:31 +0200969
Yuval Mintz845c9a72018-02-28 23:29:35 +0200970 return mr_mfc_find_parent(mrt, &arg, parent);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200971}
972
Yuval Mintz845c9a72018-02-28 23:29:35 +0200973/* Allocate a multicast cache entry */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200974static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900975{
Joe Perches36cbac52008-12-03 22:27:25 -0800976 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +0100977 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900978 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200979 c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
980 c->_c.mfc_un.res.minvif = MAXMIFS;
Yuval Mintz8c13af22018-03-26 15:01:36 +0300981 c->_c.free = ip6mr_cache_free_rcu;
982 refcount_set(&c->_c.mfc_un.res.refcount, 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900983 return c;
984}
985
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200986static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900987{
Joe Perches36cbac52008-12-03 22:27:25 -0800988 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +0100989 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900990 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200991 skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
992 c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900993 return c;
994}
995
996/*
997 * A cache entry has gone into a resolved state from queued
998 */
999
Yuval Mintzb70432f2018-02-28 23:29:32 +02001000static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001001 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001002{
1003 struct sk_buff *skb;
1004
1005 /*
1006 * Play the pending entries through our router
1007 */
1008
Yuval Mintz494fff52018-02-28 23:29:34 +02001009 while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001010 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +02001011 struct nlmsghdr *nlh = skb_pull(skb,
1012 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001013
Yuval Mintz7b0db852018-02-28 23:29:39 +02001014 if (mr_fill_mroute(mrt, skb, &c->_c,
1015 nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001016 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001017 } else {
1018 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +00001019 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001020 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +00001021 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001022 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001023 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001024 } else
Patrick Ruddye4a38c02018-10-01 09:41:27 +01001025 ip6_mr_forward(net, mrt, skb->dev, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001026 }
1027}
1028
1029/*
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001030 * Bounce a cache query up to pim6sd and netlink.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001031 *
1032 * Called under mrt_lock.
1033 */
1034
Yuval Mintzb70432f2018-02-28 23:29:32 +02001035static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001036 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001037{
Yuval Mintz8571ab42018-02-28 23:29:30 +02001038 struct sock *mroute6_sk;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001039 struct sk_buff *skb;
1040 struct mrt6msg *msg;
1041 int ret;
1042
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001043#ifdef CONFIG_IPV6_PIMSM_V2
1044 if (assert == MRT6MSG_WHOLEPKT)
1045 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1046 +sizeof(*msg));
1047 else
1048#endif
1049 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001050
1051 if (!skb)
1052 return -ENOBUFS;
1053
1054 /* I suppose that internal messages
1055 * do not require checksums */
1056
1057 skb->ip_summed = CHECKSUM_UNNECESSARY;
1058
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001059#ifdef CONFIG_IPV6_PIMSM_V2
1060 if (assert == MRT6MSG_WHOLEPKT) {
1061 /* Ugly, but we have no choice with this interface.
1062 Duplicate old header, fix length etc.
1063 And all this only to mangle msg->im6_msgtype and
1064 to set msg->im6_mbz to "mbz" :-)
1065 */
1066 skb_push(skb, -skb_network_offset(pkt));
1067
1068 skb_push(skb, sizeof(*msg));
1069 skb_reset_transport_header(skb);
1070 msg = (struct mrt6msg *)skb_transport_header(skb);
1071 msg->im6_mbz = 0;
1072 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001073 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001074 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001075 msg->im6_src = ipv6_hdr(pkt)->saddr;
1076 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001077
1078 skb->ip_summed = CHECKSUM_UNNECESSARY;
1079 } else
1080#endif
1081 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001082 /*
1083 * Copy the IP header
1084 */
1085
1086 skb_put(skb, sizeof(struct ipv6hdr));
1087 skb_reset_network_header(skb);
1088 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1089
1090 /*
1091 * Add our header
1092 */
1093 skb_put(skb, sizeof(*msg));
1094 skb_reset_transport_header(skb);
1095 msg = (struct mrt6msg *)skb_transport_header(skb);
1096
1097 msg->im6_mbz = 0;
1098 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001099 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001100 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001101 msg->im6_src = ipv6_hdr(pkt)->saddr;
1102 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001103
Eric Dumazetadf30902009-06-02 05:19:30 +00001104 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001105 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001106 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001107
Yuval Mintz8571ab42018-02-28 23:29:30 +02001108 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +02001109 mroute6_sk = rcu_dereference(mrt->mroute_sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001110 if (!mroute6_sk) {
1111 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001112 kfree_skb(skb);
1113 return -EINVAL;
1114 }
1115
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001116 mrt6msg_netlink_event(mrt, skb);
1117
Yuval Mintz8571ab42018-02-28 23:29:30 +02001118 /* Deliver to user space multicast routing algorithms */
1119 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1120 rcu_read_unlock();
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001121 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001122 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001123 kfree_skb(skb);
1124 }
1125
1126 return ret;
1127}
1128
Yuval Mintz494fff52018-02-28 23:29:34 +02001129/* Queue a packet for resolution. It gets locked cache entry! */
1130static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
Patrick Ruddye4a38c02018-10-01 09:41:27 +01001131 struct sk_buff *skb, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001132{
Yuval Mintz494fff52018-02-28 23:29:34 +02001133 struct mfc6_cache *c;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001134 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001135 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001136
1137 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001138 list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001139 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001140 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1141 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001142 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001143 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001144 }
1145
Patrick McHardyf30a77842010-05-11 14:40:51 +02001146 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001147 /*
1148 * Create a new entry if allowable
1149 */
1150
Patrick McHardy6bd52142010-05-11 14:40:53 +02001151 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001152 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001153 spin_unlock_bh(&mfc_unres_lock);
1154
1155 kfree_skb(skb);
1156 return -ENOBUFS;
1157 }
1158
Yuval Mintz494fff52018-02-28 23:29:34 +02001159 /* Fill in the new cache entry */
1160 c->_c.mfc_parent = -1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001161 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1162 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1163
1164 /*
1165 * Reflect first query at pim6sd
1166 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001167 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001168 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001169 /* If the report failed throw the cache entry
1170 out - Brad Parker
1171 */
1172 spin_unlock_bh(&mfc_unres_lock);
1173
Benjamin Thery58701ad2008-12-10 16:22:34 -08001174 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001175 kfree_skb(skb);
1176 return err;
1177 }
1178
Patrick McHardy6bd52142010-05-11 14:40:53 +02001179 atomic_inc(&mrt->cache_resolve_queue_len);
Yuval Mintz494fff52018-02-28 23:29:34 +02001180 list_add(&c->_c.list, &mrt->mfc_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001181 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001182
Patrick McHardy6bd52142010-05-11 14:40:53 +02001183 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001184 }
1185
Yuval Mintz494fff52018-02-28 23:29:34 +02001186 /* See if we can append the packet */
1187 if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001188 kfree_skb(skb);
1189 err = -ENOBUFS;
1190 } else {
Patrick Ruddye4a38c02018-10-01 09:41:27 +01001191 if (dev) {
1192 skb->dev = dev;
1193 skb->skb_iif = dev->ifindex;
1194 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001195 skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001196 err = 0;
1197 }
1198
1199 spin_unlock_bh(&mfc_unres_lock);
1200 return err;
1201}
1202
1203/*
1204 * MFC6 cache manipulation by user space
1205 */
1206
Yuval Mintzb70432f2018-02-28 23:29:32 +02001207static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001208 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001209{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001210 struct mfc6_cache *c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001211
Yuval Mintz87c418b2018-02-28 23:29:31 +02001212 /* The entries are added/deleted only under RTNL */
1213 rcu_read_lock();
1214 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1215 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1216 rcu_read_unlock();
1217 if (!c)
1218 return -ENOENT;
Yuval Mintz494fff52018-02-28 23:29:34 +02001219 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
1220 list_del_rcu(&c->_c.list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001221
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001222 call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1223 FIB_EVENT_ENTRY_DEL, c, mrt->id);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001224 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Yuval Mintz8c13af22018-03-26 15:01:36 +03001225 mr_cache_put(&c->_c);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001226 return 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001227}
1228
1229static int ip6mr_device_event(struct notifier_block *this,
1230 unsigned long event, void *ptr)
1231{
Jiri Pirko351638e2013-05-28 01:30:21 +00001232 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001233 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001234 struct mr_table *mrt;
Yuval Mintz6853f212018-02-28 23:29:29 +02001235 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001236 int ct;
1237
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001238 if (event != NETDEV_UNREGISTER)
1239 return NOTIFY_DONE;
1240
Patrick McHardyd1db2752010-05-11 14:40:55 +02001241 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001242 v = &mrt->vif_table[0];
Patrick McHardyd1db2752010-05-11 14:40:55 +02001243 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1244 if (v->dev == dev)
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001245 mif6_delete(mrt, ct, 1, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001246 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001247 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001248
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001249 return NOTIFY_DONE;
1250}
1251
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001252static unsigned int ip6mr_seq_read(struct net *net)
1253{
1254 ASSERT_RTNL();
1255
1256 return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net);
1257}
1258
1259static int ip6mr_dump(struct net *net, struct notifier_block *nb)
1260{
1261 return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump,
1262 ip6mr_mr_table_iter, &mrt_lock);
1263}
1264
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001265static struct notifier_block ip6_mr_notifier = {
1266 .notifier_call = ip6mr_device_event
1267};
1268
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001269static const struct fib_notifier_ops ip6mr_notifier_ops_template = {
1270 .family = RTNL_FAMILY_IP6MR,
1271 .fib_seq_read = ip6mr_seq_read,
1272 .fib_dump = ip6mr_dump,
1273 .owner = THIS_MODULE,
1274};
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001275
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001276static int __net_init ip6mr_notifier_init(struct net *net)
1277{
1278 struct fib_notifier_ops *ops;
1279
1280 net->ipv6.ipmr_seq = 0;
1281
1282 ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net);
1283 if (IS_ERR(ops))
1284 return PTR_ERR(ops);
1285
1286 net->ipv6.ip6mr_notifier_ops = ops;
1287
1288 return 0;
1289}
1290
1291static void __net_exit ip6mr_notifier_exit(struct net *net)
1292{
1293 fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops);
1294 net->ipv6.ip6mr_notifier_ops = NULL;
1295}
1296
1297/* Setup for IP multicast routing */
Benjamin Thery4e168802008-12-10 16:15:08 -08001298static int __net_init ip6mr_net_init(struct net *net)
1299{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001300 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001301
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001302 err = ip6mr_notifier_init(net);
1303 if (err)
1304 return err;
1305
Patrick McHardyd1db2752010-05-11 14:40:55 +02001306 err = ip6mr_rules_init(net);
1307 if (err < 0)
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001308 goto ip6mr_rules_fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001309
1310#ifdef CONFIG_PROC_FS
1311 err = -ENOMEM;
Christoph Hellwigc3506372018-04-10 19:42:55 +02001312 if (!proc_create_net("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_seq_ops,
1313 sizeof(struct mr_vif_iter)))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001314 goto proc_vif_fail;
Christoph Hellwigc3506372018-04-10 19:42:55 +02001315 if (!proc_create_net("ip6_mr_cache", 0, net->proc_net, &ipmr_mfc_seq_ops,
1316 sizeof(struct mr_mfc_iter)))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001317 goto proc_cache_fail;
1318#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001319
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001320 return 0;
1321
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001322#ifdef CONFIG_PROC_FS
1323proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001324 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001325proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001326 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001327#endif
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001328ip6mr_rules_fail:
1329 ip6mr_notifier_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001330 return err;
1331}
1332
1333static void __net_exit ip6mr_net_exit(struct net *net)
1334{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001335#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001336 remove_proc_entry("ip6_mr_cache", net->proc_net);
1337 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001338#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001339 ip6mr_rules_exit(net);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001340 ip6mr_notifier_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001341}
1342
1343static struct pernet_operations ip6mr_net_ops = {
1344 .init = ip6mr_net_init,
1345 .exit = ip6mr_net_exit,
1346};
1347
Wang Chen623d1a12008-07-03 12:13:30 +08001348int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001349{
Wang Chen623d1a12008-07-03 12:13:30 +08001350 int err;
1351
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001352 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1353 sizeof(struct mfc6_cache),
1354 0, SLAB_HWCACHE_ALIGN,
1355 NULL);
1356 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001357 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001358
Benjamin Thery4e168802008-12-10 16:15:08 -08001359 err = register_pernet_subsys(&ip6mr_net_ops);
1360 if (err)
1361 goto reg_pernet_fail;
1362
Wang Chen623d1a12008-07-03 12:13:30 +08001363 err = register_netdevice_notifier(&ip6_mr_notifier);
1364 if (err)
1365 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001366#ifdef CONFIG_IPV6_PIMSM_V2
1367 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001368 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001369 err = -EAGAIN;
1370 goto add_proto_fail;
1371 }
1372#endif
Florian Westphala3fde2a2017-12-04 19:19:18 +01001373 err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1374 NULL, ip6mr_rtm_dumproute, 0);
1375 if (err == 0)
1376 return 0;
1377
Tom Goff403dbb92009-06-14 03:16:13 -07001378#ifdef CONFIG_IPV6_PIMSM_V2
Florian Westphala3fde2a2017-12-04 19:19:18 +01001379 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
Tom Goff403dbb92009-06-14 03:16:13 -07001380add_proto_fail:
1381 unregister_netdevice_notifier(&ip6_mr_notifier);
1382#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001383reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001384 unregister_pernet_subsys(&ip6mr_net_ops);
1385reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001386 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001387 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001388}
1389
Wang Chen623d1a12008-07-03 12:13:30 +08001390void ip6_mr_cleanup(void)
1391{
Duan Jiongffb13882014-11-19 09:35:39 +08001392 rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
1393#ifdef CONFIG_IPV6_PIMSM_V2
1394 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
1395#endif
Wang Chen623d1a12008-07-03 12:13:30 +08001396 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001397 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001398 kmem_cache_destroy(mrt_cachep);
1399}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001400
Yuval Mintzb70432f2018-02-28 23:29:32 +02001401static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001402 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001403{
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001404 unsigned char ttls[MAXMIFS];
Yuval Mintz87c418b2018-02-28 23:29:31 +02001405 struct mfc6_cache *uc, *c;
Yuval Mintz494fff52018-02-28 23:29:34 +02001406 struct mr_mfc *_uc;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001407 bool found;
1408 int i, err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001409
Patrick McHardya50436f22010-03-17 06:04:14 +00001410 if (mfc->mf6cc_parent >= MAXMIFS)
1411 return -ENFILE;
1412
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001413 memset(ttls, 255, MAXMIFS);
1414 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001415 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1416 ttls[i] = 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001417 }
1418
Yuval Mintz87c418b2018-02-28 23:29:31 +02001419 /* The entries are added/deleted only under RTNL */
1420 rcu_read_lock();
1421 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1422 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1423 rcu_read_unlock();
1424 if (c) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001425 write_lock_bh(&mrt_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001426 c->_c.mfc_parent = mfc->mf6cc_parent;
1427 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001428 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001429 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001430 write_unlock_bh(&mrt_lock);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001431 call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
1432 c, mrt->id);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001433 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001434 return 0;
1435 }
1436
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001437 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1438 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001439 return -EINVAL;
1440
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001441 c = ip6mr_cache_alloc();
Ian Morris63159f22015-03-29 14:00:04 +01001442 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001443 return -ENOMEM;
1444
1445 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1446 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
Yuval Mintz494fff52018-02-28 23:29:34 +02001447 c->_c.mfc_parent = mfc->mf6cc_parent;
1448 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001449 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001450 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001451
Yuval Mintz494fff52018-02-28 23:29:34 +02001452 err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001453 ip6mr_rht_params);
1454 if (err) {
1455 pr_err("ip6mr: rhtable insert error %d\n", err);
1456 ip6mr_cache_free(c);
1457 return err;
1458 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001459 list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001460
Yuval Mintz87c418b2018-02-28 23:29:31 +02001461 /* Check to see if we resolved a queued list. If so we
1462 * need to send on the frames and tidy up.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001463 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001464 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001465 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001466 list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
1467 uc = (struct mfc6_cache *)_uc;
Patrick McHardyc476efb2010-05-11 14:40:48 +02001468 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001469 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001470 list_del(&_uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001471 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001472 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001473 break;
1474 }
1475 }
Yuval Mintzb70432f2018-02-28 23:29:32 +02001476 if (list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +02001477 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001478 spin_unlock_bh(&mfc_unres_lock);
1479
Patrick McHardyf30a77842010-05-11 14:40:51 +02001480 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001481 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001482 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001483 }
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001484 call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD,
1485 c, mrt->id);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001486 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001487 return 0;
1488}
1489
1490/*
1491 * Close the multicast socket, and clear the vif tables etc
1492 */
1493
Yuval Mintzb70432f2018-02-28 23:29:32 +02001494static void mroute_clean_tables(struct mr_table *mrt, bool all)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001495{
Yuval Mintz494fff52018-02-28 23:29:34 +02001496 struct mr_mfc *c, *tmp;
Eric Dumazetc871e662009-10-28 04:48:11 +00001497 LIST_HEAD(list);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001498 int i;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001499
Yuval Mintz87c418b2018-02-28 23:29:31 +02001500 /* Shut down all active vif entries */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001501 for (i = 0; i < mrt->maxvif; i++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001502 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001503 continue;
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001504 mif6_delete(mrt, i, 0, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001505 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001506 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001507
Yuval Mintz87c418b2018-02-28 23:29:31 +02001508 /* Wipe the cache */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001509 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001510 if (!all && (c->mfc_flags & MFC_STATIC))
1511 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001512 rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001513 list_del_rcu(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001514 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
Yuval Mintz8c13af22018-03-26 15:01:36 +03001515 mr_cache_put(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001516 }
1517
Patrick McHardy6bd52142010-05-11 14:40:53 +02001518 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001519 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001520 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001521 list_del(&c->list);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001522 call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1523 FIB_EVENT_ENTRY_DEL,
1524 (struct mfc6_cache *)c,
1525 mrt->id);
Yuval Mintz494fff52018-02-28 23:29:34 +02001526 mr6_netlink_event(mrt, (struct mfc6_cache *)c,
1527 RTM_DELROUTE);
1528 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001529 }
1530 spin_unlock_bh(&mfc_unres_lock);
1531 }
1532}
1533
Yuval Mintzb70432f2018-02-28 23:29:32 +02001534static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001535{
1536 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001537 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001538
1539 rtnl_lock();
1540 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001541 if (rtnl_dereference(mrt->mroute_sk)) {
Eric Dumazet927265b2016-07-08 05:46:04 +02001542 err = -EADDRINUSE;
Yuval Mintz8571ab42018-02-28 23:29:30 +02001543 } else {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001544 rcu_assign_pointer(mrt->mroute_sk, sk);
Eric Dumazeta366e302018-03-07 08:43:19 -08001545 sock_set_flag(sk, SOCK_RCU_FREE);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001546 net->ipv6.devconf_all->mc_forwarding++;
Eric Dumazet927265b2016-07-08 05:46:04 +02001547 }
1548 write_unlock_bh(&mrt_lock);
1549
1550 if (!err)
David Ahern85b3daa2017-03-28 14:28:04 -07001551 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1552 NETCONFA_MC_FORWARDING,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001553 NETCONFA_IFINDEX_ALL,
1554 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001555 rtnl_unlock();
1556
1557 return err;
1558}
1559
1560int ip6mr_sk_done(struct sock *sk)
1561{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001562 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001563 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001564 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001565
Francesco Ruggeri338d1822017-11-08 11:23:46 -08001566 if (sk->sk_type != SOCK_RAW ||
1567 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1568 return err;
1569
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001570 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001571 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001572 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyd1db2752010-05-11 14:40:55 +02001573 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001574 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
Eric Dumazeta366e302018-03-07 08:43:19 -08001575 /* Note that mroute_sk had SOCK_RCU_FREE set,
1576 * so the RCU grace period before sk freeing
1577 * is guaranteed by sk_destruct()
1578 */
Patrick McHardyd1db2752010-05-11 14:40:55 +02001579 net->ipv6.devconf_all->mc_forwarding--;
Eric Dumazet927265b2016-07-08 05:46:04 +02001580 write_unlock_bh(&mrt_lock);
David Ahern85b3daa2017-03-28 14:28:04 -07001581 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001582 NETCONFA_MC_FORWARDING,
1583 NETCONFA_IFINDEX_ALL,
1584 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001585
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001586 mroute_clean_tables(mrt, false);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001587 err = 0;
1588 break;
1589 }
1590 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001591 rtnl_unlock();
1592
1593 return err;
1594}
1595
Yuval Mintz8571ab42018-02-28 23:29:30 +02001596bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001597{
Yuval Mintzb70432f2018-02-28 23:29:32 +02001598 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001599 struct flowi6 fl6 = {
Julian Anastasove374c612014-04-28 10:51:56 +03001600 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -05001601 .flowi6_oif = skb->dev->ifindex,
1602 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001603 };
1604
David S. Miller4c9483b2011-03-12 16:22:43 -05001605 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001606 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001607
Yuval Mintzb70432f2018-02-28 23:29:32 +02001608 return rcu_access_pointer(mrt->mroute_sk);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001609}
Yuval Mintz8571ab42018-02-28 23:29:30 +02001610EXPORT_SYMBOL(mroute6_is_socket);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001611
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001612/*
1613 * Socket options and virtual interface manipulation. The whole
1614 * virtual interface system is a complete heap, but unfortunately
1615 * that's how BSD mrouted happens to think. Maybe one day with a proper
1616 * MOSPF/PIM router set up we can clean this up.
1617 */
1618
David S. Millerb7058842009-09-30 16:12:20 -07001619int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001620{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001621 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001622 struct mif6ctl vif;
1623 struct mf6cctl mfc;
1624 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001625 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001626 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001627
Xin Long99253eb2017-02-24 16:29:06 +08001628 if (sk->sk_type != SOCK_RAW ||
1629 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1630 return -EOPNOTSUPP;
1631
Patrick McHardyd1db2752010-05-11 14:40:55 +02001632 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001633 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001634 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001635
1636 if (optname != MRT6_INIT) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001637 if (sk != rcu_access_pointer(mrt->mroute_sk) &&
Yuval Mintz8571ab42018-02-28 23:29:30 +02001638 !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001639 return -EACCES;
1640 }
1641
1642 switch (optname) {
1643 case MRT6_INIT:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001644 if (optlen < sizeof(int))
1645 return -EINVAL;
1646
Patrick McHardy6bd52142010-05-11 14:40:53 +02001647 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001648
1649 case MRT6_DONE:
1650 return ip6mr_sk_done(sk);
1651
1652 case MRT6_ADD_MIF:
1653 if (optlen < sizeof(vif))
1654 return -EINVAL;
1655 if (copy_from_user(&vif, optval, sizeof(vif)))
1656 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001657 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001658 return -ENFILE;
1659 rtnl_lock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001660 ret = mif6_add(net, mrt, &vif,
Yuval Mintzb70432f2018-02-28 23:29:32 +02001661 sk == rtnl_dereference(mrt->mroute_sk));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001662 rtnl_unlock();
1663 return ret;
1664
1665 case MRT6_DEL_MIF:
1666 if (optlen < sizeof(mifi_t))
1667 return -EINVAL;
1668 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1669 return -EFAULT;
1670 rtnl_lock();
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001671 ret = mif6_delete(mrt, mifi, 0, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001672 rtnl_unlock();
1673 return ret;
1674
1675 /*
1676 * Manipulate the forwarding caches. These live
1677 * in a sort of kernel/user symbiosis.
1678 */
1679 case MRT6_ADD_MFC:
1680 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001681 parent = -1;
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -05001682 /* fall through */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001683 case MRT6_ADD_MFC_PROXY:
1684 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001685 if (optlen < sizeof(mfc))
1686 return -EINVAL;
1687 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1688 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001689 if (parent == 0)
1690 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001691 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001692 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1693 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001694 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001695 ret = ip6mr_mfc_add(net, mrt, &mfc,
Yuval Mintz8571ab42018-02-28 23:29:30 +02001696 sk ==
Yuval Mintzb70432f2018-02-28 23:29:32 +02001697 rtnl_dereference(mrt->mroute_sk),
Yuval Mintz8571ab42018-02-28 23:29:30 +02001698 parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001699 rtnl_unlock();
1700 return ret;
1701
1702 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001703 * Control PIM assert (to activate pim will activate assert)
1704 */
1705 case MRT6_ASSERT:
1706 {
1707 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001708
1709 if (optlen != sizeof(v))
1710 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001711 if (get_user(v, (int __user *)optval))
1712 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001713 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001714 return 0;
1715 }
1716
1717#ifdef CONFIG_IPV6_PIMSM_V2
1718 case MRT6_PIM:
1719 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001720 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001721
1722 if (optlen != sizeof(v))
1723 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001724 if (get_user(v, (int __user *)optval))
1725 return -EFAULT;
1726 v = !!v;
1727 rtnl_lock();
1728 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001729 if (v != mrt->mroute_do_pim) {
1730 mrt->mroute_do_pim = v;
1731 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001732 }
1733 rtnl_unlock();
1734 return ret;
1735 }
1736
1737#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001738#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1739 case MRT6_TABLE:
1740 {
1741 u32 v;
1742
1743 if (optlen != sizeof(u32))
1744 return -EINVAL;
1745 if (get_user(v, (u32 __user *)optval))
1746 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001747 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1748 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1749 return -EINVAL;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001750 if (sk == rcu_access_pointer(mrt->mroute_sk))
Patrick McHardyd1db2752010-05-11 14:40:55 +02001751 return -EBUSY;
1752
1753 rtnl_lock();
1754 ret = 0;
Sabrina Dubrocae783bb02018-06-05 15:02:00 +02001755 mrt = ip6mr_new_table(net, v);
1756 if (IS_ERR(mrt))
1757 ret = PTR_ERR(mrt);
Sabrina Dubroca848235e2018-06-05 15:01:59 +02001758 else
1759 raw6_sk(sk)->ip6mr_table = v;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001760 rtnl_unlock();
1761 return ret;
1762 }
1763#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001764 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001765 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001766 * set.
1767 */
1768 default:
1769 return -ENOPROTOOPT;
1770 }
1771}
1772
1773/*
1774 * Getsock opt support for the multicast routing system.
1775 */
1776
1777int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1778 int __user *optlen)
1779{
1780 int olr;
1781 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001782 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001783 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001784
Xin Long99253eb2017-02-24 16:29:06 +08001785 if (sk->sk_type != SOCK_RAW ||
1786 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1787 return -EOPNOTSUPP;
1788
Patrick McHardyd1db2752010-05-11 14:40:55 +02001789 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001790 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001791 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001792
1793 switch (optname) {
1794 case MRT6_VERSION:
1795 val = 0x0305;
1796 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001797#ifdef CONFIG_IPV6_PIMSM_V2
1798 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001799 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001800 break;
1801#endif
1802 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001803 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001804 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001805 default:
1806 return -ENOPROTOOPT;
1807 }
1808
1809 if (get_user(olr, optlen))
1810 return -EFAULT;
1811
1812 olr = min_t(int, olr, sizeof(int));
1813 if (olr < 0)
1814 return -EINVAL;
1815
1816 if (put_user(olr, optlen))
1817 return -EFAULT;
1818 if (copy_to_user(optval, &val, olr))
1819 return -EFAULT;
1820 return 0;
1821}
1822
1823/*
1824 * The IP multicast ioctl support routines.
1825 */
1826
1827int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1828{
1829 struct sioc_sg_req6 sr;
1830 struct sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001831 struct vif_device *vif;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001832 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001833 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001834 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001835
1836 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001837 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001838 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001839
1840 switch (cmd) {
1841 case SIOCGETMIFCNT_IN6:
1842 if (copy_from_user(&vr, arg, sizeof(vr)))
1843 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001844 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001845 return -EINVAL;
Gustavo A. R. Silva69d2c862018-12-11 14:10:08 -06001846 vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001847 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001848 vif = &mrt->vif_table[vr.mifi];
1849 if (VIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001850 vr.icount = vif->pkt_in;
1851 vr.ocount = vif->pkt_out;
1852 vr.ibytes = vif->bytes_in;
1853 vr.obytes = vif->bytes_out;
1854 read_unlock(&mrt_lock);
1855
1856 if (copy_to_user(arg, &vr, sizeof(vr)))
1857 return -EFAULT;
1858 return 0;
1859 }
1860 read_unlock(&mrt_lock);
1861 return -EADDRNOTAVAIL;
1862 case SIOCGETSGCNT_IN6:
1863 if (copy_from_user(&sr, arg, sizeof(sr)))
1864 return -EFAULT;
1865
Yuval Mintz87c418b2018-02-28 23:29:31 +02001866 rcu_read_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001867 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001868 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001869 sr.pktcnt = c->_c.mfc_un.res.pkt;
1870 sr.bytecnt = c->_c.mfc_un.res.bytes;
1871 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001872 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001873
1874 if (copy_to_user(arg, &sr, sizeof(sr)))
1875 return -EFAULT;
1876 return 0;
1877 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001878 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001879 return -EADDRNOTAVAIL;
1880 default:
1881 return -ENOIOCTLCMD;
1882 }
1883}
1884
David S. Millere2d57762011-02-03 17:59:32 -08001885#ifdef CONFIG_COMPAT
1886struct compat_sioc_sg_req6 {
1887 struct sockaddr_in6 src;
1888 struct sockaddr_in6 grp;
1889 compat_ulong_t pktcnt;
1890 compat_ulong_t bytecnt;
1891 compat_ulong_t wrong_if;
1892};
1893
1894struct compat_sioc_mif_req6 {
1895 mifi_t mifi;
1896 compat_ulong_t icount;
1897 compat_ulong_t ocount;
1898 compat_ulong_t ibytes;
1899 compat_ulong_t obytes;
1900};
1901
1902int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1903{
1904 struct compat_sioc_sg_req6 sr;
1905 struct compat_sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001906 struct vif_device *vif;
David S. Millere2d57762011-02-03 17:59:32 -08001907 struct mfc6_cache *c;
1908 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001909 struct mr_table *mrt;
David S. Millere2d57762011-02-03 17:59:32 -08001910
1911 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001912 if (!mrt)
David S. Millere2d57762011-02-03 17:59:32 -08001913 return -ENOENT;
1914
1915 switch (cmd) {
1916 case SIOCGETMIFCNT_IN6:
1917 if (copy_from_user(&vr, arg, sizeof(vr)))
1918 return -EFAULT;
1919 if (vr.mifi >= mrt->maxvif)
1920 return -EINVAL;
Gustavo A. R. Silva69d2c862018-12-11 14:10:08 -06001921 vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
David S. Millere2d57762011-02-03 17:59:32 -08001922 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001923 vif = &mrt->vif_table[vr.mifi];
1924 if (VIF_EXISTS(mrt, vr.mifi)) {
David S. Millere2d57762011-02-03 17:59:32 -08001925 vr.icount = vif->pkt_in;
1926 vr.ocount = vif->pkt_out;
1927 vr.ibytes = vif->bytes_in;
1928 vr.obytes = vif->bytes_out;
1929 read_unlock(&mrt_lock);
1930
1931 if (copy_to_user(arg, &vr, sizeof(vr)))
1932 return -EFAULT;
1933 return 0;
1934 }
1935 read_unlock(&mrt_lock);
1936 return -EADDRNOTAVAIL;
1937 case SIOCGETSGCNT_IN6:
1938 if (copy_from_user(&sr, arg, sizeof(sr)))
1939 return -EFAULT;
1940
Yuval Mintz87c418b2018-02-28 23:29:31 +02001941 rcu_read_lock();
David S. Millere2d57762011-02-03 17:59:32 -08001942 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1943 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001944 sr.pktcnt = c->_c.mfc_un.res.pkt;
1945 sr.bytecnt = c->_c.mfc_un.res.bytes;
1946 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001947 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001948
1949 if (copy_to_user(arg, &sr, sizeof(sr)))
1950 return -EFAULT;
1951 return 0;
1952 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001953 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001954 return -EADDRNOTAVAIL;
1955 default:
1956 return -ENOIOCTLCMD;
1957 }
1958}
1959#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001960
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -05001961static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001962{
Eric Dumazet1d015502016-04-27 16:44:40 -07001963 __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
1964 IPSTATS_MIB_OUTFORWDATAGRAMS);
1965 __IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
1966 IPSTATS_MIB_OUTOCTETS, skb->len);
Eric W. Biederman13206b62015-10-07 16:48:35 -05001967 return dst_output(net, sk, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001968}
1969
1970/*
1971 * Processing handlers for ip6mr_forward
1972 */
1973
Yuval Mintzb70432f2018-02-28 23:29:32 +02001974static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001975 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001976{
1977 struct ipv6hdr *ipv6h;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001978 struct vif_device *vif = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001979 struct net_device *dev;
1980 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001981 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001982
Ian Morris63159f22015-03-29 14:00:04 +01001983 if (!vif->dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001984 goto out_free;
1985
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001986#ifdef CONFIG_IPV6_PIMSM_V2
1987 if (vif->flags & MIFF_REGISTER) {
1988 vif->pkt_out++;
1989 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001990 vif->dev->stats.tx_bytes += skb->len;
1991 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001992 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001993 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001994 }
1995#endif
1996
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001997 ipv6h = ipv6_hdr(skb);
1998
David S. Miller4c9483b2011-03-12 16:22:43 -05001999 fl6 = (struct flowi6) {
2000 .flowi6_oif = vif->link,
2001 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002002 };
2003
David S. Miller4c9483b2011-03-12 16:22:43 -05002004 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00002005 if (dst->error) {
2006 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002007 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00002008 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002009
Eric Dumazetadf30902009-06-02 05:19:30 +00002010 skb_dst_drop(skb);
2011 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002012
2013 /*
2014 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
2015 * not only before forwarding, but after forwarding on all output
2016 * interfaces. It is clear, if mrouter runs a multicasting
2017 * program, it should receive packets not depending to what interface
2018 * program is joined.
2019 * If we will not make it, the program will have to join on all
2020 * interfaces. On the other hand, multihoming host (or router, but
2021 * not mrouter) cannot join to more than one interface - it will
2022 * result in receiving multiple packets.
2023 */
2024 dev = vif->dev;
2025 skb->dev = dev;
2026 vif->pkt_out++;
2027 vif->bytes_out += skb->len;
2028
2029 /* We are about to write */
2030 /* XXX: extension headers? */
2031 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2032 goto out_free;
2033
2034 ipv6h = ipv6_hdr(skb);
2035 ipv6h->hop_limit--;
2036
2037 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2038
Eric W. Biederman29a26a52015-09-15 20:04:16 -05002039 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
2040 net, NULL, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002041 ip6mr_forward2_finish);
2042
2043out_free:
2044 kfree_skb(skb);
2045 return 0;
2046}
2047
Yuval Mintzb70432f2018-02-28 23:29:32 +02002048static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002049{
2050 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002051
2052 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02002053 if (mrt->vif_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002054 break;
2055 }
2056 return ct;
2057}
2058
Yuval Mintzb70432f2018-02-28 23:29:32 +02002059static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002060 struct net_device *dev, struct sk_buff *skb,
2061 struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002062{
2063 int psend = -1;
2064 int vif, ct;
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002065 int true_vifi = ip6mr_find_vif(mrt, dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002066
Yuval Mintz494fff52018-02-28 23:29:34 +02002067 vif = c->_c.mfc_parent;
2068 c->_c.mfc_un.res.pkt++;
2069 c->_c.mfc_un.res.bytes += skb->len;
2070 c->_c.mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002071
Yuval Mintz494fff52018-02-28 23:29:34 +02002072 if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002073 struct mfc6_cache *cache_proxy;
2074
Fabian Frederick40dc2ca2014-10-29 10:00:26 +01002075 /* For an (*,G) entry, we only check that the incoming
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002076 * interface is part of the static tree.
2077 */
Yuval Mintz87c418b2018-02-28 23:29:31 +02002078 rcu_read_lock();
Yuval Mintz845c9a72018-02-28 23:29:35 +02002079 cache_proxy = mr_mfc_find_any_parent(mrt, vif);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002080 if (cache_proxy &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002081 cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002082 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002083 goto forward;
Yuval Mintz87c418b2018-02-28 23:29:31 +02002084 }
2085 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002086 }
2087
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002088 /*
2089 * Wrong interface: drop packet and (maybe) send PIM assert.
2090 */
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002091 if (mrt->vif_table[vif].dev != dev) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002092 c->_c.mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002093
Patrick McHardy6bd52142010-05-11 14:40:53 +02002094 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002095 /* pimsm uses asserts, when switching from RPT to SPT,
2096 so that we cannot check that packet arrived on an oif.
2097 It is bad, but otherwise we would need to move pretty
2098 large chunk of pimd to kernel. Ough... --ANK
2099 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002100 (mrt->mroute_do_pim ||
Yuval Mintz494fff52018-02-28 23:29:34 +02002101 c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002102 time_after(jiffies,
Yuval Mintz494fff52018-02-28 23:29:34 +02002103 c->_c.mfc_un.res.last_assert +
2104 MFC_ASSERT_THRESH)) {
2105 c->_c.mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002106 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002107 }
2108 goto dont_forward;
2109 }
2110
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002111forward:
Yuval Mintzb70432f2018-02-28 23:29:32 +02002112 mrt->vif_table[vif].pkt_in++;
2113 mrt->vif_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002114
2115 /*
2116 * Forward the frame
2117 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002118 if (ipv6_addr_any(&c->mf6c_origin) &&
2119 ipv6_addr_any(&c->mf6c_mcastgrp)) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002120 if (true_vifi >= 0 &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002121 true_vifi != c->_c.mfc_parent &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002122 ipv6_hdr(skb)->hop_limit >
Yuval Mintz494fff52018-02-28 23:29:34 +02002123 c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002124 /* It's an (*,*) entry and the packet is not coming from
2125 * the upstream: forward the packet to the upstream
2126 * only.
2127 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002128 psend = c->_c.mfc_parent;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002129 goto last_forward;
2130 }
2131 goto dont_forward;
2132 }
Yuval Mintz494fff52018-02-28 23:29:34 +02002133 for (ct = c->_c.mfc_un.res.maxvif - 1;
2134 ct >= c->_c.mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002135 /* For (*,G) entry, don't forward to the incoming interface */
Yuval Mintz494fff52018-02-28 23:29:34 +02002136 if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
2137 ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002138 if (psend != -1) {
2139 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2140 if (skb2)
Yuval Mintz494fff52018-02-28 23:29:34 +02002141 ip6mr_forward2(net, mrt, skb2,
2142 c, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002143 }
2144 psend = ct;
2145 }
2146 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002147last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002148 if (psend != -1) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002149 ip6mr_forward2(net, mrt, skb, c, psend);
Rami Rosen2b52c3a2013-07-21 03:00:31 +03002150 return;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002151 }
2152
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002153dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002154 kfree_skb(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002155}
2156
2157
2158/*
2159 * Multicast packets for forwarding arrive here
2160 */
2161
2162int ip6_mr_input(struct sk_buff *skb)
2163{
2164 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002165 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002166 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002167 struct flowi6 fl6 = {
2168 .flowi6_iif = skb->dev->ifindex,
2169 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002170 };
2171 int err;
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002172 struct net_device *dev;
2173
2174 /* skb->dev passed in is the master dev for vrfs.
2175 * Get the proper interface that does have a vif associated with it.
2176 */
2177 dev = skb->dev;
2178 if (netif_is_l3_master(skb->dev)) {
2179 dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
2180 if (!dev) {
2181 kfree_skb(skb);
2182 return -ENODEV;
2183 }
2184 }
Patrick McHardyd1db2752010-05-11 14:40:55 +02002185
David S. Miller4c9483b2011-03-12 16:22:43 -05002186 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002187 if (err < 0) {
2188 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002189 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002190 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002191
2192 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002193 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002194 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Ian Morris63159f22015-03-29 14:00:04 +01002195 if (!cache) {
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002196 int vif = ip6mr_find_vif(mrt, dev);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002197
2198 if (vif >= 0)
2199 cache = ip6mr_cache_find_any(mrt,
2200 &ipv6_hdr(skb)->daddr,
2201 vif);
2202 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002203
2204 /*
2205 * No usable cache entry
2206 */
Ian Morris63159f22015-03-29 14:00:04 +01002207 if (!cache) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002208 int vif;
2209
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002210 vif = ip6mr_find_vif(mrt, dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002211 if (vif >= 0) {
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002212 int err = ip6mr_cache_unresolved(mrt, vif, skb, dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002213 read_unlock(&mrt_lock);
2214
2215 return err;
2216 }
2217 read_unlock(&mrt_lock);
2218 kfree_skb(skb);
2219 return -ENODEV;
2220 }
2221
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002222 ip6_mr_forward(net, mrt, dev, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002223
2224 read_unlock(&mrt_lock);
2225
2226 return 0;
2227}
2228
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002229int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
David Ahernfd61c6b2017-01-17 15:51:07 -08002230 u32 portid)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002231{
2232 int err;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002233 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002234 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002235 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002236
Patrick McHardyd1db2752010-05-11 14:40:55 +02002237 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01002238 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02002239 return -ENOENT;
2240
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002241 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002242 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002243 if (!cache && skb->dev) {
2244 int vif = ip6mr_find_vif(mrt, skb->dev);
2245
2246 if (vif >= 0)
2247 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2248 vif);
2249 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002250
2251 if (!cache) {
2252 struct sk_buff *skb2;
2253 struct ipv6hdr *iph;
2254 struct net_device *dev;
2255 int vif;
2256
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002257 dev = skb->dev;
Ian Morris63159f22015-03-29 14:00:04 +01002258 if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002259 read_unlock(&mrt_lock);
2260 return -ENODEV;
2261 }
2262
2263 /* really correct? */
2264 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2265 if (!skb2) {
2266 read_unlock(&mrt_lock);
2267 return -ENOMEM;
2268 }
2269
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002270 NETLINK_CB(skb2).portid = portid;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002271 skb_reset_transport_header(skb2);
2272
2273 skb_put(skb2, sizeof(struct ipv6hdr));
2274 skb_reset_network_header(skb2);
2275
2276 iph = ipv6_hdr(skb2);
2277 iph->version = 0;
2278 iph->priority = 0;
2279 iph->flow_lbl[0] = 0;
2280 iph->flow_lbl[1] = 0;
2281 iph->flow_lbl[2] = 0;
2282 iph->payload_len = 0;
2283 iph->nexthdr = IPPROTO_NONE;
2284 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002285 iph->saddr = rt->rt6i_src.addr;
2286 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002287
Patrick Ruddye4a38c02018-10-01 09:41:27 +01002288 err = ip6mr_cache_unresolved(mrt, vif, skb2, dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002289 read_unlock(&mrt_lock);
2290
2291 return err;
2292 }
2293
Yuval Mintz7b0db852018-02-28 23:29:39 +02002294 err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002295 read_unlock(&mrt_lock);
2296 return err;
2297}
2298
Yuval Mintzb70432f2018-02-28 23:29:32 +02002299static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002300 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2301 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002302{
2303 struct nlmsghdr *nlh;
2304 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002305 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002306
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002307 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Ian Morris63159f22015-03-29 14:00:04 +01002308 if (!nlh)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002309 return -EMSGSIZE;
2310
2311 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002312 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002313 rtm->rtm_dst_len = 128;
2314 rtm->rtm_src_len = 128;
2315 rtm->rtm_tos = 0;
2316 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002317 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2318 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002319 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002320 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Yuval Mintz494fff52018-02-28 23:29:34 +02002321 if (c->_c.mfc_flags & MFC_STATIC)
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002322 rtm->rtm_protocol = RTPROT_STATIC;
2323 else
2324 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002325 rtm->rtm_flags = 0;
2326
Jiri Benc930345e2015-03-29 16:59:25 +02002327 if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
2328 nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
David S. Millerc78679e2012-04-01 20:27:33 -04002329 goto nla_put_failure;
Yuval Mintz7b0db852018-02-28 23:29:39 +02002330 err = mr_fill_mroute(mrt, skb, &c->_c, rtm);
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002331 /* do not break the dump if cache is unresolved */
2332 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002333 goto nla_put_failure;
2334
Johannes Berg053c0952015-01-16 22:09:00 +01002335 nlmsg_end(skb, nlh);
2336 return 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002337
2338nla_put_failure:
2339 nlmsg_cancel(skb, nlh);
2340 return -EMSGSIZE;
2341}
2342
Yuval Mintz7b0db852018-02-28 23:29:39 +02002343static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
2344 u32 portid, u32 seq, struct mr_mfc *c,
2345 int cmd, int flags)
2346{
2347 return ip6mr_fill_mroute(mrt, skb, portid, seq, (struct mfc6_cache *)c,
2348 cmd, flags);
2349}
2350
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002351static int mr6_msgsize(bool unresolved, int maxvif)
2352{
2353 size_t len =
2354 NLMSG_ALIGN(sizeof(struct rtmsg))
2355 + nla_total_size(4) /* RTA_TABLE */
2356 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2357 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2358 ;
2359
2360 if (!unresolved)
2361 len = len
2362 + nla_total_size(4) /* RTA_IIF */
2363 + nla_total_size(0) /* RTA_MULTIPATH */
2364 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2365 /* RTA_MFC_STATS */
Nicolas Dichtel3d6b66c2016-04-21 18:58:27 +02002366 + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002367 ;
2368
2369 return len;
2370}
2371
Yuval Mintzb70432f2018-02-28 23:29:32 +02002372static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002373 int cmd)
2374{
2375 struct net *net = read_pnet(&mrt->net);
2376 struct sk_buff *skb;
2377 int err = -ENOBUFS;
2378
Yuval Mintz494fff52018-02-28 23:29:34 +02002379 skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002380 GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01002381 if (!skb)
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002382 goto errout;
2383
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002384 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002385 if (err < 0)
2386 goto errout;
2387
2388 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2389 return;
2390
2391errout:
2392 kfree_skb(skb);
2393 if (err < 0)
2394 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2395}
2396
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002397static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
2398{
2399 size_t len =
2400 NLMSG_ALIGN(sizeof(struct rtgenmsg))
2401 + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */
2402 + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */
2403 /* IP6MRA_CREPORT_SRC_ADDR */
2404 + nla_total_size(sizeof(struct in6_addr))
2405 /* IP6MRA_CREPORT_DST_ADDR */
2406 + nla_total_size(sizeof(struct in6_addr))
2407 /* IP6MRA_CREPORT_PKT */
2408 + nla_total_size(payloadlen)
2409 ;
2410
2411 return len;
2412}
2413
Yuval Mintzb70432f2018-02-28 23:29:32 +02002414static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002415{
2416 struct net *net = read_pnet(&mrt->net);
2417 struct nlmsghdr *nlh;
2418 struct rtgenmsg *rtgenm;
2419 struct mrt6msg *msg;
2420 struct sk_buff *skb;
2421 struct nlattr *nla;
2422 int payloadlen;
2423
2424 payloadlen = pkt->len - sizeof(struct mrt6msg);
2425 msg = (struct mrt6msg *)skb_transport_header(pkt);
2426
2427 skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
2428 if (!skb)
2429 goto errout;
2430
2431 nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
2432 sizeof(struct rtgenmsg), 0);
2433 if (!nlh)
2434 goto errout;
2435 rtgenm = nlmsg_data(nlh);
2436 rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
2437 if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
2438 nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
2439 nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
2440 &msg->im6_src) ||
2441 nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
2442 &msg->im6_dst))
2443 goto nla_put_failure;
2444
2445 nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
2446 if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
2447 nla_data(nla), payloadlen))
2448 goto nla_put_failure;
2449
2450 nlmsg_end(skb, nlh);
2451
2452 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
2453 return;
2454
2455nla_put_failure:
2456 nlmsg_cancel(skb, nlh);
2457errout:
2458 kfree_skb(skb);
2459 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
2460}
2461
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002462static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2463{
David Aherne8ba3302018-10-07 20:16:35 -07002464 const struct nlmsghdr *nlh = cb->nlh;
David Ahern47246762018-10-15 18:56:42 -07002465 struct fib_dump_filter filter = {};
David Aherncb167892018-10-15 18:56:47 -07002466 int err;
David Aherne8ba3302018-10-07 20:16:35 -07002467
2468 if (cb->strict_check) {
David Ahern47246762018-10-15 18:56:42 -07002469 err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh,
David Aherneffe6792018-10-15 18:56:48 -07002470 &filter, cb);
David Aherne8ba3302018-10-07 20:16:35 -07002471 if (err < 0)
2472 return err;
2473 }
2474
David Aherncb167892018-10-15 18:56:47 -07002475 if (filter.table_id) {
2476 struct mr_table *mrt;
2477
2478 mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
2479 if (!mrt) {
David Ahernae677bb2018-10-24 12:59:01 -07002480 if (filter.dump_all_families)
2481 return skb->len;
2482
David Aherncb167892018-10-15 18:56:47 -07002483 NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
2484 return -ENOENT;
2485 }
2486 err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,
2487 &mfc_unres_lock, &filter);
2488 return skb->len ? : err;
2489 }
2490
Yuval Mintz7b0db852018-02-28 23:29:39 +02002491 return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
David Aherncb167892018-10-15 18:56:47 -07002492 _ip6mr_fill_mroute, &mfc_unres_lock, &filter);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002493}